Merge branch 'develop' into patch-7
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..24f122a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,14 @@
+# Root editor config file
+root = true
+
+# Common settings
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+
+# python, js indentation settings
+[{*.py,*.js}]
+indent_style = tab
+indent_size = 4
diff --git a/.eslintrc b/.eslintrc
index 757aa3c..3b6ab74 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -5,7 +5,7 @@
"es6": true
},
"parserOptions": {
- "ecmaVersion": 6,
+ "ecmaVersion": 9,
"sourceType": "module"
},
"extends": "eslint:recommended",
@@ -15,6 +15,14 @@
"tab",
{ "SwitchCase": 1 }
],
+ "brace-style": [
+ "error",
+ "1tbs"
+ ],
+ "space-unary-ops": [
+ "error",
+ { "words": true }
+ ],
"linebreak-style": [
"error",
"unix"
@@ -44,12 +52,10 @@
"no-control-regex": [
"off"
],
- "spaced-comment": [
- "warn"
- ],
- "no-trailing-spaces": [
- "warn"
- ]
+ "space-before-blocks": "warn",
+ "keyword-spacing": "warn",
+ "comma-spacing": "warn",
+ "key-spacing": "warn"
},
"root": true,
"globals": {
@@ -86,6 +92,7 @@
"cur_page": true,
"cur_list": true,
"cur_tree": true,
+ "cur_pos": true,
"msg_dialog": true,
"is_null": true,
"in_list": true,
@@ -143,6 +150,7 @@
"it": true,
"context": true,
"before": true,
- "beforeEach": true
+ "beforeEach": true,
+ "onScan": true
}
}
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..399b176
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,32 @@
+[flake8]
+ignore =
+ E121,
+ E126,
+ E127,
+ E128,
+ E203,
+ E225,
+ E226,
+ E231,
+ E241,
+ E251,
+ E261,
+ E265,
+ E302,
+ E303,
+ E305,
+ E402,
+ E501,
+ E741,
+ W291,
+ W292,
+ W293,
+ W391,
+ W503,
+ W504,
+ F403,
+ B007,
+ B950,
+ W191,
+
+max-line-length = 200
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..26bb7ab
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Community Forum
+ url: https://discuss.erpnext.com/
+ about: For general QnA, discussions and community help.
diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py
new file mode 100644
index 0000000..9cc4663
--- /dev/null
+++ b/.github/helper/documentation.py
@@ -0,0 +1,48 @@
+import sys
+import requests
+from urllib.parse import urlparse
+
+
+docs_repos = [
+ "frappe_docs",
+ "erpnext_documentation",
+ "erpnext_com",
+ "frappe_io",
+]
+
+
+def uri_validator(x):
+ result = urlparse(x)
+ return all([result.scheme, result.netloc, result.path])
+
+def docs_link_exists(body):
+ for line in body.splitlines():
+ for word in line.split():
+ if word.startswith('http') and uri_validator(word):
+ parsed_url = urlparse(word)
+ if parsed_url.netloc == "github.com":
+ parts = parsed_url.path.split('/')
+ if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos:
+ return True
+
+
+if __name__ == "__main__":
+ pr = sys.argv[1]
+ response = requests.get("https://api.github.com/repos/frappe/erpnext/pulls/{}".format(pr))
+
+ if response.ok:
+ payload = response.json()
+ title = payload.get("title", "").lower()
+ head_sha = payload.get("head", {}).get("sha")
+ body = payload.get("body", "").lower()
+
+ if title.startswith("feat") and head_sha and "no-docs" not in body:
+ if docs_link_exists(body):
+ print("Documentation Link Found. You're Awesome! 🎉")
+
+ else:
+ print("Documentation Link Not Found! ⚠️")
+ sys.exit(1)
+
+ else:
+ print("Skipping documentation checks... 🏃")
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
new file mode 100644
index 0000000..7b0f944
--- /dev/null
+++ b/.github/helper/install.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+set -e
+
+cd ~ || exit
+
+sudo apt-get install redis-server
+
+sudo apt install nodejs
+
+sudo apt install npm
+
+pip install frappe-bench
+
+git clone https://github.com/frappe/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1
+bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
+
+mkdir ~/frappe-bench/sites/test_site
+cp -r "${GITHUB_WORKSPACE}/.github/helper/site_config.json" ~/frappe-bench/sites/test_site/
+
+mysql --host 127.0.0.1 --port 3306 -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
+mysql --host 127.0.0.1 --port 3306 -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
+
+mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
+mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE DATABASE test_frappe"
+mysql --host 127.0.0.1 --port 3306 -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
+
+mysql --host 127.0.0.1 --port 3306 -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
+mysql --host 127.0.0.1 --port 3306 -u root -e "FLUSH PRIVILEGES"
+
+wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
+tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
+sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
+sudo chmod o+x /usr/local/bin/wkhtmltopdf
+sudo apt-get install libcups2-dev
+
+cd ~/frappe-bench || exit
+
+sed -i 's/watch:/# watch:/g' Procfile
+sed -i 's/schedule:/# schedule:/g' Procfile
+sed -i 's/socketio:/# socketio:/g' Procfile
+sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
+
+bench get-app erpnext "${GITHUB_WORKSPACE}"
+bench start &
+bench --site test_site reinstall --yes
diff --git a/.travis/site_config.json b/.github/helper/site_config.json
similarity index 75%
rename from .travis/site_config.json
rename to .github/helper/site_config.json
index dae8009..60ef80c 100644
--- a/.travis/site_config.json
+++ b/.github/helper/site_config.json
@@ -1,4 +1,6 @@
{
+ "db_host": "127.0.0.1",
+ "db_port": 3306,
"db_name": "test_frappe",
"db_password": "test_frappe",
"auto_email_id": "test@example.com",
@@ -9,5 +11,6 @@
"root_login": "root",
"root_password": "travis",
"host_name": "http://test_site:8000",
- "install_apps": ["erpnext"]
+ "install_apps": ["erpnext"],
+ "throttle_user_limit": 100
}
\ No newline at end of file
diff --git a/.github/helper/translation.py b/.github/helper/translation.py
new file mode 100644
index 0000000..9146b3b
--- /dev/null
+++ b/.github/helper/translation.py
@@ -0,0 +1,60 @@
+import re
+import sys
+
+errors_encounter = 0
+pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)")
+words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]")
+start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}")
+f_string_pattern = re.compile(r"_\(f[\"']")
+starts_with_f_pattern = re.compile(r"_\(f")
+
+# skip first argument
+files = sys.argv[1:]
+files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))]
+
+for _file in files_to_scan:
+ with open(_file, 'r') as f:
+ print(f'Checking: {_file}')
+ file_lines = f.readlines()
+ for line_number, line in enumerate(file_lines, 1):
+ if 'frappe-lint: disable-translate' in line:
+ continue
+
+ start_matches = start_pattern.search(line)
+ if start_matches:
+ starts_with_f = starts_with_f_pattern.search(line)
+
+ if starts_with_f:
+ has_f_string = f_string_pattern.search(line)
+ if has_f_string:
+ errors_encounter += 1
+ print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}')
+ continue
+ else:
+ continue
+
+ match = pattern.search(line)
+ error_found = False
+
+ if not match and line.endswith((',\n', '[\n')):
+ # concat remaining text to validate multiline pattern
+ line = "".join(file_lines[line_number - 1:])
+ line = line[start_matches.start() + 1:]
+ match = pattern.match(line)
+
+ if not match:
+ error_found = True
+ print(f'\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}')
+
+ if not error_found and not words_pattern.search(line):
+ error_found = True
+ print(f'\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}')
+
+ if error_found:
+ errors_encounter += 1
+
+if errors_encounter > 0:
+ print('\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.')
+ sys.exit(1)
+else:
+ print('\nGood To Go!')
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
new file mode 100644
index 0000000..78c2f5a
--- /dev/null
+++ b/.github/workflows/ci-tests.yml
@@ -0,0 +1,94 @@
+name: CI
+
+on: [pull_request, workflow_dispatch, push]
+
+jobs:
+ test:
+ runs-on: ubuntu-18.04
+
+ strategy:
+ fail-fast: false
+
+ matrix:
+ include:
+ - TYPE: "server"
+ JOB_NAME: "Server"
+ RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-tests --app erpnext --coverage
+ - TYPE: "patch"
+ JOB_NAME: "Patch"
+ RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
+
+ name: ${{ matrix.JOB_NAME }}
+
+ services:
+ mysql:
+ image: mariadb:10.3
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: YES
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
+
+ steps:
+ - name: Clone
+ uses: actions/checkout@v2
+
+ - name: Setup Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.6
+
+ - name: Add to Hosts
+ run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
+
+ - name: Cache pip
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+ ${{ runner.os }}-
+ - name: Cache node modules
+ uses: actions/cache@v2
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - uses: actions/cache@v2
+ id: yarn-cache
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Install
+ run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
+
+ - name: Run Tests
+ run: ${{ matrix.RUN_COMMAND }}
+ env:
+ TYPE: ${{ matrix.TYPE }}
+
+ - name: Coverage
+ if: matrix.TYPE == 'server'
+ run: |
+ cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
+ cd ${GITHUB_WORKSPACE}
+ pip install coveralls==2.2.0
+ pip install coverage==4.5.4
+ coveralls
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
+
diff --git a/.github/workflows/docs-checker.yml b/.github/workflows/docs-checker.yml
new file mode 100644
index 0000000..cdf676d
--- /dev/null
+++ b/.github/workflows/docs-checker.yml
@@ -0,0 +1,24 @@
+name: 'Documentation Required'
+on:
+ pull_request:
+ types: [ opened, synchronize, reopened, edited ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: 'Setup Environment'
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.6
+
+ - name: 'Clone repo'
+ uses: actions/checkout@v2
+
+ - name: Validate Docs
+ env:
+ PR_NUMBER: ${{ github.event.number }}
+ run: |
+ pip install requests --quiet
+ python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER
diff --git a/.github/workflows/translation_linter.yml b/.github/workflows/translation_linter.yml
new file mode 100644
index 0000000..4becaeb
--- /dev/null
+++ b/.github/workflows/translation_linter.yml
@@ -0,0 +1,22 @@
+name: Frappe Linter
+on:
+ pull_request:
+ branches:
+ - develop
+ - version-12-hotfix
+ - version-11-hotfix
+jobs:
+ check_translation:
+ name: Translation Syntax Check
+ runs-on: ubuntu-18.04
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup python3
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.6
+ - name: Validating Translation Syntax
+ run: |
+ git fetch origin $GITHUB_BASE_REF:$GITHUB_BASE_REF -q
+ files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF)
+ python $GITHUB_WORKSPACE/.github/helper/translation.py $files
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 77d427e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-language: python
-dist: trusty
-
-git:
- depth: 1
-
-cache:
- - pip
-
-addons:
- hosts: test_site
- mariadb: 10.3
-
-jobs:
- include:
- - name: "Python 3.6 Server Side Test"
- python: 3.6
- script: bench --site test_site run-tests --app erpnext --coverage
-
- - name: "Python 3.6 Patch Test"
- python: 3.6
- before_script:
- - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
- script: bench --site test_site migrate
-
-install:
- - cd ~
- - nvm install 10
-
- - pip install frappe-bench
-
- - git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
- - bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
-
- - mkdir ~/frappe-bench/sites/test_site
- - cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
-
- - mysql -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
- - mysql -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
-
- - mysql -u root -e "CREATE DATABASE test_frappe"
- - mysql -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
- - mysql -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
-
- - mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
- - mysql -u root -e "FLUSH PRIVILEGES"
-
- - wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
- - tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
- - sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
- - sudo chmod o+x /usr/local/bin/wkhtmltopdf
- - sudo apt-get install libcups2-dev
-
- - cd ~/frappe-bench
-
- - sed -i 's/watch:/# watch:/g' Procfile
- - sed -i 's/schedule:/# schedule:/g' Procfile
- - sed -i 's/socketio:/# socketio:/g' Procfile
- - sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
-
- - bench get-app erpnext $TRAVIS_BUILD_DIR
- - bench start &
- - bench --site test_site reinstall --yes
-
-after_script:
- - pip install coverage==4.5.4
- - pip install python-coveralls
- - coveralls -b apps/erpnext -d ../../sites/.coverage
diff --git a/README.md b/README.md
index 0f6a521..bb592ae 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
<p>ERP made simple</p>
</p>
-[](https://travis-ci.com/frappe/erpnext)
+[](https://github.com/frappe/erpnext/actions/workflows/ci-tests.yml)
[](https://www.codetriage.com/frappe/erpnext)
[](https://coveralls.io/github/frappe/erpnext?branch=develop)
diff --git a/erpnext/.stylelintrc b/erpnext/.stylelintrc
new file mode 100644
index 0000000..1e05d1f
--- /dev/null
+++ b/erpnext/.stylelintrc
@@ -0,0 +1,9 @@
+{
+ "extends": ["stylelint-config-recommended"],
+ "plugins": ["stylelint-scss"],
+ "rules": {
+ "at-rule-no-unknown": null,
+ "scss/at-rule-no-unknown": true,
+ "no-descending-specificity": null
+ }
+}
\ No newline at end of file
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 38d8a62..199a183 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -109,7 +109,7 @@
'''
if company or frappe.flags.company:
return frappe.get_cached_value('Company',
- company or frappe.flags.company, 'country')
+ company or frappe.flags.company, 'country')
elif frappe.flags.country:
return frappe.flags.country
else:
@@ -132,16 +132,10 @@
return caller
-def get_last_membership():
+def get_last_membership(member):
'''Returns last membership if exists'''
last_membership = frappe.get_all('Membership', 'name,to_date,membership_type',
- dict(member=frappe.session.user, paid=1), order_by='to_date desc', limit=1)
+ dict(member=member, paid=1), order_by='to_date desc', limit=1)
- return last_membership and last_membership[0]
-
-def is_member():
- '''Returns true if the user is still a member'''
- last_membership = get_last_membership()
- if last_membership and getdate(last_membership.to_date) > getdate():
- return True
- return False
+ if last_membership:
+ return last_membership[0]
diff --git a/erpnext/accounts/custom/address.json b/erpnext/accounts/custom/address.json
index 08f972d..5c921da 100644
--- a/erpnext/accounts/custom/address.json
+++ b/erpnext/accounts/custom/address.json
@@ -1,58 +1,126 @@
{
"custom_fields": [
{
- "_assign": null,
- "_comments": null,
- "_liked_by": null,
- "_user_tags": null,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": null,
- "columns": 0,
- "creation": "2018-12-28 22:29:21.828090",
- "default": null,
- "depends_on": null,
- "description": null,
- "docstatus": 0,
- "dt": "Address",
- "fetch_from": null,
- "fieldname": "tax_category",
- "fieldtype": "Link",
- "hidden": 0,
- "idx": 14,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "insert_after": "fax",
- "label": "Tax Category",
- "modified": "2018-12-28 22:29:21.828090",
- "modified_by": "Administrator",
- "name": "Address-tax_category",
- "no_copy": 0,
- "options": "Tax Category",
- "owner": "Administrator",
- "parent": null,
- "parentfield": null,
- "parenttype": null,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": null,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "translatable": 0,
- "unique": 0,
+ "_assign": null,
+ "_comments": null,
+ "_liked_by": null,
+ "_user_tags": null,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "collapsible_depends_on": null,
+ "columns": 0,
+ "creation": "2018-12-28 22:29:21.828090",
+ "default": null,
+ "depends_on": null,
+ "description": null,
+ "docstatus": 0,
+ "dt": "Address",
+ "fetch_from": null,
+ "fetch_if_empty": 0,
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "hide_border": 0,
+ "hide_days": 0,
+ "hide_seconds": 0,
+ "idx": 15,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_preview": 0,
+ "in_standard_filter": 0,
+ "insert_after": "fax",
+ "label": "Tax Category",
+ "length": 0,
+ "mandatory_depends_on": null,
+ "modified": "2018-12-28 22:29:21.828090",
+ "modified_by": "Administrator",
+ "name": "Address-tax_category",
+ "no_copy": 0,
+ "options": "Tax Category",
+ "owner": "Administrator",
+ "parent": null,
+ "parentfield": null,
+ "parenttype": null,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "print_width": null,
+ "read_only": 0,
+ "read_only_depends_on": null,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "translatable": 0,
+ "unique": 0,
+ "width": null
+ },
+ {
+ "_assign": null,
+ "_comments": null,
+ "_liked_by": null,
+ "_user_tags": null,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "collapsible_depends_on": null,
+ "columns": 0,
+ "creation": "2020-10-14 17:41:40.878179",
+ "default": "0",
+ "depends_on": null,
+ "description": null,
+ "docstatus": 0,
+ "dt": "Address",
+ "fetch_from": null,
+ "fetch_if_empty": 0,
+ "fieldname": "is_your_company_address",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "hide_border": 0,
+ "hide_days": 0,
+ "hide_seconds": 0,
+ "idx": 20,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_preview": 0,
+ "in_standard_filter": 0,
+ "insert_after": "linked_with",
+ "label": "Is Your Company Address",
+ "length": 0,
+ "mandatory_depends_on": null,
+ "modified": "2020-10-14 17:41:40.878179",
+ "modified_by": "Administrator",
+ "name": "Address-is_your_company_address",
+ "no_copy": 0,
+ "options": null,
+ "owner": "Administrator",
+ "parent": null,
+ "parentfield": null,
+ "parenttype": null,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "print_width": null,
+ "read_only": 0,
+ "read_only_depends_on": null,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "translatable": 0,
+ "unique": 0,
"width": null
}
- ],
- "custom_perms": [],
- "doctype": "Address",
- "property_setters": [],
+ ],
+ "custom_perms": [],
+ "doctype": "Address",
+ "property_setters": [],
"sync_on_migrate": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/custom/address.py b/erpnext/accounts/custom/address.py
new file mode 100644
index 0000000..5e76403
--- /dev/null
+++ b/erpnext/accounts/custom/address.py
@@ -0,0 +1,42 @@
+import frappe
+from frappe import _
+from frappe.contacts.doctype.address.address import Address
+from frappe.contacts.doctype.address.address import get_address_templates
+
+class ERPNextAddress(Address):
+ def validate(self):
+ self.validate_reference()
+ super(ERPNextAddress, self).validate()
+
+ def link_address(self):
+ """Link address based on owner"""
+ if self.is_your_company_address:
+ return
+
+ return super(ERPNextAddress, self).link_address()
+
+ def validate_reference(self):
+ if self.is_your_company_address and not [
+ row for row in self.links if row.link_doctype == "Company"
+ ]:
+ frappe.throw(_("Address needs to be linked to a Company. Please add a row for Company in the Links table."),
+ title=_("Company Not Linked"))
+
+@frappe.whitelist()
+def get_shipping_address(company, address = None):
+ filters = [
+ ["Dynamic Link", "link_doctype", "=", "Company"],
+ ["Dynamic Link", "link_name", "=", company],
+ ["Address", "is_your_company_address", "=", 1]
+ ]
+ fields = ["*"]
+ if address and frappe.db.get_value('Dynamic Link',
+ {'parent': address, 'link_name': company}):
+ filters.append(["Address", "name", "=", address])
+
+ address = frappe.get_all("Address", filters=filters, fields=fields) or {}
+
+ if address:
+ address_as_dict = address[0]
+ name, address_template = get_address_templates(address_as_dict)
+ return address_as_dict.get("name"), frappe.render_template(address_template, address_as_dict)
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 39bf4b0..85f54f9 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
@@ -6,9 +6,8 @@
from frappe import _
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
from erpnext.accounts.report.general_ledger.general_ledger import execute
-from frappe.utils.dashboard import cache_source, get_from_date_from_timespan
-from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
-
+from frappe.utils.dashboard import cache_source
+from frappe.utils.dateutils import get_from_date_from_timespan, get_period_ending
from frappe.utils.nestedset import get_descendants_of
@frappe.whitelist()
diff --git a/erpnext/accounts/desk_page/accounting/accounting.json b/erpnext/accounts/desk_page/accounting/accounting.json
deleted file mode 100644
index 3f23ba9..0000000
--- a/erpnext/accounts/desk_page/accounting/accounting.json
+++ /dev/null
@@ -1,156 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Accounting Masters",
- "links": "[\n {\n \"description\": \"Company (not Customer or Supplier) master.\",\n \"label\": \"Company\",\n \"name\": \"Company\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of financial accounts.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Accounts\",\n \"name\": \"Account\",\n \"onboard\": 1,\n \"route\": \"#Tree/Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounts Settings\",\n \"name\": \"Accounts Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Financial / accounting year.\",\n \"label\": \"Fiscal Year\",\n \"name\": \"Fiscal Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Finance Book\",\n \"name\": \"Finance Book\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Period\",\n \"name\": \"Accounting Period\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Terms based on conditions\",\n \"label\": \"Payment Term\",\n \"name\": \"Payment Term\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "General Ledger",
- "links": "[\n {\n \"description\": \"Accounting journal entries.\",\n \"label\": \"Journal Entry\",\n \"name\": \"Journal Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Make journal entries from a template.\",\n \"label\": \"Journal Entry Template\",\n \"name\": \"Journal Entry Template\",\n \"type\": \"doctype\"\n },\n \n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"General Ledger\",\n \"name\": \"General Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Customer Ledger Summary\",\n \"name\": \"Customer Ledger Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Supplier Ledger Summary\",\n \"name\": \"Supplier Ledger Summary\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Accounts Receivable",
- "links": "[\n {\n \"description\": \"Bills raised to Customers.\",\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Request\",\n \"label\": \"Payment Request\",\n \"name\": \"Payment Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable\",\n \"name\": \"Accounts Receivable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable Summary\",\n \"name\": \"Accounts Receivable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Register\",\n \"name\": \"Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales Register\",\n \"name\": \"Item-wise Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Order Analysis\",\n \"name\": \"Sales Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Delivered Items To Be Billed\",\n \"name\": \"Delivered Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Accounts Payable",
- "links": "[\n {\n \"description\": \"Bills raised by Suppliers.\",\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable\",\n \"name\": \"Accounts Payable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable Summary\",\n \"name\": \"Accounts Payable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Register\",\n \"name\": \"Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase Register\",\n \"name\": \"Item-wise Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Order\"\n ],\n \"doctype\": \"Purchase Order\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Analysis\",\n \"name\": \"Purchase Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Received Items To Be Billed\",\n \"name\": \"Received Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Financial Statements",
- "links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance\",\n \"name\": \"Trial Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profit and Loss Statement\",\n \"name\": \"Profit and Loss Statement\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Balance Sheet\",\n \"name\": \"Balance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Cash Flow\",\n \"name\": \"Cash Flow\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Consolidated Financial Statement\",\n \"name\": \"Consolidated Financial Statement\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Multi Currency",
- "links": "[\n {\n \"description\": \"Enable / disable currencies.\",\n \"label\": \"Currency\",\n \"name\": \"Currency\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Currency exchange rate master.\",\n \"label\": \"Currency Exchange\",\n \"name\": \"Currency Exchange\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Exchange Rate Revaluation master.\",\n \"label\": \"Exchange Rate Revaluation\",\n \"name\": \"Exchange Rate Revaluation\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"description\": \"Setup Gateway accounts.\",\n \"label\": \"Payment Gateway Account\",\n \"name\": \"Payment Gateway Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"e.g. Bank, Cash, Credit Card\",\n \"label\": \"Mode of Payment\",\n \"name\": \"Mode of Payment\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Bank Statement",
- "links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Subscription Management",
- "links": "[\n {\n \"label\": \"Subscription Plan\",\n \"name\": \"Subscription Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription\",\n \"name\": \"Subscription\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription Settings\",\n \"name\": \"Subscription Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Goods and Services Tax (GST India)",
- "links": "[\n {\n \"label\": \"GST Settings\",\n \"name\": \"GST Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"GST HSN Code\",\n \"name\": \"GST HSN Code\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-1\",\n \"name\": \"GSTR-1\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-2\",\n \"name\": \"GSTR-2\",\n \"type\": \"report\"\n },\n {\n \"label\": \"GSTR 3B Report\",\n \"name\": \"GSTR 3B Report\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Sales Register\",\n \"name\": \"GST Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Purchase Register\",\n \"name\": \"GST Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Sales Register\",\n \"name\": \"GST Itemised Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Purchase Register\",\n \"name\": \"GST Itemised Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"country\": \"India\",\n \"description\": \"C-Form records\",\n \"label\": \"C-Form\",\n \"name\": \"C-Form\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Share Management",
- "links": "[\n {\n \"description\": \"List of available Shareholders with folio numbers\",\n \"label\": \"Shareholder\",\n \"name\": \"Shareholder\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of all share transactions\",\n \"label\": \"Share Transfer\",\n \"name\": \"Share Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Ledger\",\n \"name\": \"Share Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Balance\",\n \"name\": \"Share Balance\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Cost Center and Budgeting",
- "links": "[\n {\n \"description\": \"Tree of financial Cost Centers.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Cost Centers\",\n \"name\": \"Cost Center\",\n \"route\": \"#Tree/Cost Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Define budget for a financial year.\",\n \"label\": \"Budget\",\n \"name\": \"Budget\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Cost Center\"\n ],\n \"doctype\": \"Cost Center\",\n \"is_query_report\": true,\n \"label\": \"Budget Variance Report\",\n \"name\": \"Budget Variance Report\",\n \"type\": \"report\"\n },\n {\n \"description\": \"Seasonality for setting budgets, targets etc.\",\n \"label\": \"Monthly Distribution\",\n \"name\": \"Monthly Distribution\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Opening and Closing",
- "links": "[\n {\n \"label\": \"Opening Invoice Creation Tool\",\n \"name\": \"Opening Invoice Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Chart of Accounts Importer\",\n \"name\": \"Chart of Accounts Importer\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Close Balance Sheet and book Profit or Loss.\",\n \"label\": \"Period Closing Voucher\",\n \"name\": \"Period Closing Voucher\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Taxes",
- "links": "[\n {\n \"description\": \"Tax template for selling transactions.\",\n \"label\": \"Sales Taxes and Charges Template\",\n \"name\": \"Sales Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for item tax rates.\",\n \"label\": \"Item Tax Template\",\n \"name\": \"Item Tax Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Category for overriding tax rates.\",\n \"label\": \"Tax Category\",\n \"name\": \"Tax Category\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Rule for transactions.\",\n \"label\": \"Tax Rule\",\n \"name\": \"Tax Rule\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Withholding rates to be applied on transactions.\",\n \"label\": \"Tax Withholding Category\",\n \"name\": \"Tax Withholding Category\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Profitability",
- "links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Profit and Loss",
- "label": "Profit and Loss"
- }
- ],
- "creation": "2020-03-02 15:41:59.515192",
- "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": "Accounting",
- "modified": "2020-09-09 11:45:33.766400",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Accounting",
- "onboarding": "Accounts",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "label": "Chart Of Accounts",
- "link_to": "Account",
- "type": "DocType"
- },
- {
- "label": "Sales Invoice",
- "link_to": "Sales Invoice",
- "type": "DocType"
- },
- {
- "label": "Purchase Invoice",
- "link_to": "Purchase Invoice",
- "type": "DocType"
- },
- {
- "label": "Journal Entry",
- "link_to": "Journal Entry",
- "type": "DocType"
- },
- {
- "label": "Payment Entry",
- "link_to": "Payment Entry",
- "type": "DocType"
- },
- {
- "label": "Accounts Receivable",
- "link_to": "Accounts Receivable",
- "type": "Report"
- },
- {
- "label": "General Ledger",
- "link_to": "General Ledger",
- "type": "Report"
- },
- {
- "label": "Trial Balance",
- "link_to": "Trial Balance",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Accounts",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 2c15144..c801cfc 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -101,7 +101,7 @@
return
if not frappe.db.get_value("Account",
{'account_name': self.account_name, 'company': ancestors[0]}, 'name'):
- frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
+ frappe.throw(_("Please add the account to root level Company - {}").format(ancestors[0]))
elif self.parent_account:
descendants = get_descendants_of('Company', self.company)
if not descendants: return
@@ -164,9 +164,19 @@
def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name):
for company in descendants:
+ company_bold = frappe.bold(company)
+ parent_acc_name_bold = frappe.bold(parent_acc_name)
if not parent_acc_name_map.get(company):
- frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
- .format(company, parent_acc_name))
+ frappe.throw(_("While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
+ .format(company_bold, parent_acc_name_bold), title=_("Account Not Found"))
+
+ # validate if parent of child company account to be added is a group
+ if (frappe.db.get_value("Account", self.parent_account, "is_group")
+ and not frappe.db.get_value("Account", parent_acc_name_map[company], "is_group")):
+ msg = _("While creating account for Child Company {0}, parent account {1} found as a ledger account.").format(company_bold, parent_acc_name_bold)
+ msg += "<br><br>"
+ msg += _("Please convert the parent account in corresponding child company to a group account.")
+ frappe.throw(msg, title=_("Invalid Parent Account"))
filters = {
"account_name": self.account_name,
@@ -309,8 +319,9 @@
allow_child_account_creation = _("Allow Account Creation Against Child Company")
message = _("Account {0} exists in parent company {1}.").format(frappe.bold(old_acc_name), frappe.bold(ancestor))
- message += "<br>" + _("Renaming it is only allowed via parent company {0}, \
- to avoid mismatch.").format(frappe.bold(ancestor)) + "<br><br>"
+ message += "<br>"
+ message += _("Renaming it is only allowed via parent company {0}, to avoid mismatch.").format(frappe.bold(ancestor))
+ message += "<br><br>"
message += _("To overrule this, enable '{0}' in company {1}").format(allow_child_account_creation, frappe.bold(account.company))
frappe.throw(message, title=_("Rename Not Allowed"))
diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js
index 28b090b..7516134 100644
--- a/erpnext/accounts/doctype/account/account_tree.js
+++ b/erpnext/accounts/doctype/account/account_tree.js
@@ -2,7 +2,7 @@
frappe.treeview_settings["Account"] = {
breadcrumb: "Accounts",
- title: __("Chart Of Accounts"),
+ title: __("Chart of Accounts"),
get_tree_root: false,
filters: [
{
@@ -97,7 +97,7 @@
treeview.page.add_inner_button(__("Journal Entry"), function() {
frappe.new_doc('Journal Entry', {company: get_company()});
}, __('Create'));
- treeview.page.add_inner_button(__("New Company"), function() {
+ treeview.page.add_inner_button(__("Company"), function() {
frappe.new_doc('Company');
}, __('Create'));
@@ -120,17 +120,17 @@
} else {
treeview.new_node();
}
- }, "octicon octicon-plus");
+ }, "add");
},
onrender: function(node) {
- if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
+ 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) {
- $('<span class="balance-area pull-right text-muted small">'
+ $('<span class="balance-area pull-right">'
+ (node.data.balance_in_account_currency ?
(format_currency(Math.abs(node.data.balance_in_account_currency),
node.data.account_currency) + " / ") : "")
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR03_gnucash.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR03_gnucash.json
index 89465ee..ee501f6 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR03_gnucash.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR03_gnucash.json
@@ -63,17 +63,21 @@
"Gewinnermittlung \u00a74/3 nicht Ergebniswirksam": {
"account_number": "1371"
},
- "Abziehbare VSt. 7%": {
- "account_number": "1571"
- },
- "Abziehbare VSt. 19%": {
- "account_number": "1576"
- },
- "Abziehbare VStr. nach \u00a713b UStG 19%": {
- "account_number": "1577"
- },
- "Leistungen \u00a713b UStG 19% Vorsteuer, 19% Umsatzsteuer": {
- "account_number": "3120"
+ "Abziehbare Vorsteuer": {
+ "account_type": "Tax",
+ "is_group": 1,
+ "Abziehbare Vorsteuer 7%": {
+ "account_number": "1571"
+ },
+ "Abziehbare Vorsteuer 19%": {
+ "account_number": "1576"
+ },
+ "Abziehbare Vorsteuer nach \u00a713b UStG 19%": {
+ "account_number": "1577"
+ },
+ "Leistungen \u00a713b UStG 19% Vorsteuer, 19% Umsatzsteuer": {
+ "account_number": "3120"
+ }
}
},
"III. Wertpapiere": {
@@ -196,6 +200,7 @@
},
"Umsatzsteuer": {
"is_group": 1,
+ "account_type": "Tax",
"Umsatzsteuer 7%": {
"account_number": "1771"
},
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04.json
index 7fa6708..57e8bdd 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04.json
@@ -292,18 +292,21 @@
"Umsatzsteuerforderungen fr\u00fchere Jahre": {}
},
"Sonstige Verm\u00f6gensgegenst\u00e4nde oder sonstige Verbindlichkeiten": {
- "Abziehbare Vorsteuer": {},
- "Abziehbare Vorsteuer 16%": {},
- "Abziehbare Vorsteuer 19%": {},
- "Abziehbare Vorsteuer 7%": {},
- "Abziehbare Vorsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Unsatzsteuerlager": {},
- "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb": {},
- "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 16%": {},
- "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 19%": {},
- "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb von Neufahrzeugen von Lieferanten ohne Ust-Identifikationsnummer": {},
- "Abziehbare Vorsteuer nach \u00a7 13b UStG ": {},
- "Abziehbare Vorsteuer nach \u00a7 13b UStG 16%": {},
- "Abziehbare Vorsteuer nach \u00a7 13b UStG 19%": {},
+ "Abziehbare Vorsteuer": {
+ "account_type": "Tax",
+ "is_group": 1,
+ "Abziehbare Vorsteuer 16%": {},
+ "Abziehbare Vorsteuer 19%": {},
+ "Abziehbare Vorsteuer 7%": {},
+ "Abziehbare Vorsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Unsatzsteuerlager": {},
+ "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb": {},
+ "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 16%": {},
+ "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 19%": {},
+ "Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb von Neufahrzeugen von Lieferanten ohne Ust-Identifikationsnummer": {},
+ "Abziehbare Vorsteuer nach \u00a7 13b UStG ": {},
+ "Abziehbare Vorsteuer nach \u00a7 13b UStG 16%": {},
+ "Abziehbare Vorsteuer nach \u00a7 13b UStG 19%": {}
+ },
"Aufl\u00f6sung Vorsteuer aus Vorjahr \u00a7 4/3 EStG": {},
"Aufzuteilende Vorsteuer": {},
"Aufzuteilende Vorsteuer 16%": {},
@@ -673,23 +676,26 @@
"Sonstige Verrechnungskonten (Interimskonto)": {
"account_type": "Stock Received But Not Billed"
},
- "Umsatzsteuer": {},
- "Umsatzsteuer 16%": {},
- "Umsatzsteuer 19%": {},
- "Umsatzsteuer 7%": {},
- "Umsatzsteuer Vorjahr": {},
- "Umsatzsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Umsatzsteuerlager": {},
- "Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen": {},
- "Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen 19%": {},
- "Umsatzsteuer aus innergemeinschaftlichem Erwerb ": {},
- "Umsatzsteuer aus innergemeinschaftlichem Erwerb 16%": {},
- "Umsatzsteuer aus innergemeinschaftlichem Erwerb 19%": {},
- "Umsatzsteuer aus innergemeinschaftlichem Erwerb ohne Vorsteuerabzug": {},
- "Umsatzsteuer fr\u00fchere Jahre": {},
- "Umsatzsteuer laufendes Jahr": {},
- "Umsatzsteuer nach \u00a713b UStG": {},
- "Umsatzsteuer nach \u00a713b UStG 16%": {},
- "Umsatzsteuer nach \u00a713b UStG 19%": {},
+ "Umsatzsteuer": {
+ "account_type": "Tax",
+ "is_group": 1,
+ "Umsatzsteuer 16%": {},
+ "Umsatzsteuer 19%": {},
+ "Umsatzsteuer 7%": {},
+ "Umsatzsteuer Vorjahr": {},
+ "Umsatzsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Umsatzsteuerlager": {},
+ "Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen": {},
+ "Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen 19%": {},
+ "Umsatzsteuer aus innergemeinschaftlichem Erwerb ": {},
+ "Umsatzsteuer aus innergemeinschaftlichem Erwerb 16%": {},
+ "Umsatzsteuer aus innergemeinschaftlichem Erwerb 19%": {},
+ "Umsatzsteuer aus innergemeinschaftlichem Erwerb ohne Vorsteuerabzug": {},
+ "Umsatzsteuer fr\u00fchere Jahre": {},
+ "Umsatzsteuer laufendes Jahr": {},
+ "Umsatzsteuer nach \u00a713b UStG": {},
+ "Umsatzsteuer nach \u00a713b UStG 16%": {},
+ "Umsatzsteuer nach \u00a713b UStG 19%": {}
+ },
"Umsatzsteuer- Vorauszahlungen": {},
"Umsatzsteuer- Vorauszahlungen 1/11": {},
"Verbindlichkeiten aus Lohn- und Kirchensteuer": {}
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json
index 3fc109b..2bf55cf 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json
@@ -659,6 +659,7 @@
},
"Abziehbare Vorsteuer (Gruppe)": {
"is_group": 1,
+ "account_type": "Tax",
"Abziehbare Vorsteuer": {
"account_number": "1400"
},
@@ -910,98 +911,8 @@
},
"is_group": 1
},
- "Passiva": {
+ "Passiva - Verbindlichkeiten": {
"root_type": "Liability",
- "A - Eigenkapital": {
- "account_type": "Equity",
- "is_group": 1,
- "I - Gezeichnetes Kapital": {
- "account_type": "Equity",
- "is_group": 1,
- "Gezeichnetes Kapital": {
- "account_type": "Equity",
- "account_number": "2900"
- },
- "Ausstehende Einlagen auf das gezeichnete Kapital": {
- "account_number": "2910",
- "is_group": 1
- }
- },
- "II - Kapitalr\u00fccklage": {
- "account_type": "Equity",
- "is_group": 1,
- "Kapitalr\u00fccklage": {
- "account_number": "2920"
- }
- },
- "III - Gewinnr\u00fccklagen": {
- "account_type": "Equity",
- "1 - gesetzliche R\u00fccklage": {
- "account_type": "Equity",
- "is_group": 1,
- "Gesetzliche R\u00fccklage": {
- "account_number": "2930"
- }
- },
- "2 - R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": {
- "account_type": "Equity",
- "is_group": 1
- },
- "3 - satzungsm\u00e4\u00dfige R\u00fccklagen": {
- "account_type": "Equity",
- "is_group": 1,
- "Satzungsm\u00e4\u00dfige R\u00fccklagen": {
- "account_number": "2950"
- }
- },
- "4 - andere Gewinnr\u00fccklagen": {
- "account_type": "Equity",
- "is_group": 1,
- "Gewinnr\u00fccklagen aus den \u00dcbergangsvorschriften BilMoG": {
- "is_group": 1,
- "Gewinnr\u00fccklagen (BilMoG)": {
- "account_number": "2963"
- },
- "Gewinnr\u00fccklagen aus Zuschreibung Sachanlageverm\u00f6gen (BilMoG)": {
- "account_number": "2964"
- },
- "Gewinnr\u00fccklagen aus Zuschreibung Finanzanlageverm\u00f6gen (BilMoG)": {
- "account_number": "2965"
- },
- "Gewinnr\u00fccklagen aus Aufl\u00f6sung der Sonderposten mit R\u00fccklageanteil (BilMoG)": {
- "account_number": "2966"
- }
- },
- "Latente Steuern (Gewinnr\u00fccklage Haben) aus erfolgsneutralen Verrechnungen": {
- "account_number": "2967"
- },
- "Latente Steuern (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
- "account_number": "2968"
- },
- "Rechnungsabgrenzungsposten (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
- "account_number": "2969"
- }
- },
- "is_group": 1
- },
- "IV - Gewinnvortrag/Verlustvortrag": {
- "account_type": "Equity",
- "is_group": 1,
- "Gewinnvortrag vor Verwendung": {
- "account_number": "2970"
- },
- "Verlustvortrag vor Verwendung": {
- "account_number": "2978"
- }
- },
- "V - Jahres\u00fcberschu\u00df/Jahresfehlbetrag": {
- "account_type": "Equity",
- "is_group": 1
- },
- "Einlagen stiller Gesellschafter": {
- "account_number": "9295"
- }
- },
"B - R\u00fcckstellungen": {
"is_group": 1,
"1 - R\u00fcckstellungen f. Pensionen und \u00e4hnliche Verplicht.": {
@@ -1618,6 +1529,143 @@
},
"is_group": 1
},
+ "Passiva - Eigenkapital": {
+ "root_type": "Equity",
+ "A - Eigenkapital": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "I - Gezeichnetes Kapital": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "Gezeichnetes Kapital": {
+ "account_number": "2900",
+ "account_type": "Equity"
+ },
+ "Gesch\u00e4ftsguthaben der verbleibenden Mitglieder": {
+ "account_number": "2901"
+ },
+ "Gesch\u00e4ftsguthaben der ausscheidenden Mitglieder": {
+ "account_number": "2902"
+ },
+ "Gesch\u00e4ftsguthaben aus gek\u00fcndigten Gesch\u00e4ftsanteilen": {
+ "account_number": "2903"
+ },
+ "R\u00fcckst\u00e4ndige f\u00e4llige Einzahlungen auf Gesch\u00e4ftsanteile, vermerkt": {
+ "account_number": "2906"
+ },
+ "Gegenkonto R\u00fcckst\u00e4ndige f\u00e4llige Einzahlungen auf Gesch\u00e4ftsanteile, vermerkt": {
+ "account_number": "2907"
+ },
+ "Kapitalerh\u00f6hung aus Gesellschaftsmitteln": {
+ "account_number": "2908"
+ },
+ "Ausstehende Einlagen auf das gezeichnete Kapital, nicht eingefordert": {
+ "account_number": "2910"
+ }
+ },
+ "II - Kapitalr\u00fccklage": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "Kapitalr\u00fccklage": {
+ "account_number": "2920"
+ },
+ "Kapitalr\u00fccklage durch Ausgabe von Anteilen \u00fcber Nennbetrag": {
+ "account_number": "2925"
+ },
+ "Kapitalr\u00fccklage durch Ausgabe von Schuldverschreibungen": {
+ "account_number": "2926"
+ },
+ "Kapitalr\u00fccklage durch Zuzahlungen gegen Gew\u00e4hrung eines Vorzugs": {
+ "account_number": "2927"
+ },
+ "Kapitalr\u00fccklage durch Zuzahlungen in das Eigenkapital": {
+ "account_number": "2928"
+ },
+ "Nachschusskapital (Gegenkonto 1299)": {
+ "account_number": "2929"
+ }
+ },
+ "III - Gewinnr\u00fccklagen": {
+ "account_type": "Equity",
+ "1 - gesetzliche R\u00fccklage": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "Gesetzliche R\u00fccklage": {
+ "account_number": "2930"
+ }
+ },
+ "2 - R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": {
+ "account_number": "2935"
+ }
+ },
+ "3 - satzungsm\u00e4\u00dfige R\u00fccklagen": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "Satzungsm\u00e4\u00dfige R\u00fccklagen": {
+ "account_number": "2950"
+ }
+ },
+ "4 - andere Gewinnr\u00fccklagen": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "Andere Gewinnr\u00fccklagen": {
+ "account_number": "2960"
+ },
+ "Andere Gewinnr\u00fccklagen aus dem Erwerb eigener Anteile": {
+ "account_number": "2961"
+ },
+ "Eigenkapitalanteil von Wertaufholungen": {
+ "account_number": "2962"
+ },
+ "Gewinnr\u00fccklagen aus den \u00dcbergangsvorschriften BilMoG": {
+ "is_group": 1,
+ "Gewinnr\u00fccklagen (BilMoG)": {
+ "account_number": "2963"
+ },
+ "Gewinnr\u00fccklagen aus Zuschreibung Sachanlageverm\u00f6gen (BilMoG)": {
+ "account_number": "2964"
+ },
+ "Gewinnr\u00fccklagen aus Zuschreibung Finanzanlageverm\u00f6gen (BilMoG)": {
+ "account_number": "2965"
+ },
+ "Gewinnr\u00fccklagen aus Aufl\u00f6sung der Sonderposten mit R\u00fccklageanteil (BilMoG)": {
+ "account_number": "2966"
+ }
+ },
+ "Latente Steuern (Gewinnr\u00fccklage Haben) aus erfolgsneutralen Verrechnungen": {
+ "account_number": "2967"
+ },
+ "Latente Steuern (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
+ "account_number": "2968"
+ },
+ "Rechnungsabgrenzungsposten (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
+ "account_number": "2969"
+ }
+ },
+ "is_group": 1
+ },
+ "IV - Gewinnvortrag/Verlustvortrag": {
+ "account_type": "Equity",
+ "is_group": 1,
+ "Gewinnvortrag vor Verwendung": {
+ "account_number": "2970"
+ },
+ "Verlustvortrag vor Verwendung": {
+ "account_number": "2978"
+ }
+ },
+ "V - Jahres\u00fcberschu\u00df/Jahresfehlbetrag": {
+ "account_type": "Equity",
+ "is_group": 1
+ },
+ "Einlagen stiller Gesellschafter": {
+ "account_number": "9295"
+ }
+ }
+ },
"1 - Umsatzerl\u00f6se": {
"root_type": "Income",
"is_group": 1,
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 6c83e3b..acb11e5 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
@@ -245,6 +245,9 @@
"account_number": "2200"
},
_("Duties and Taxes"): {
+ _("TDS Payable"): {
+ "account_number": "2310"
+ },
"account_type": "Tax",
"is_group": 1,
"account_number": "2300"
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index b6a950b..533eda3 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -111,6 +111,17 @@
self.assertEqual(acc_tc_4, "Test Sync Account - _TC4")
self.assertEqual(acc_tc_5, "Test Sync Account - _TC5")
+ def test_add_account_to_a_group(self):
+ frappe.db.set_value("Account", "Office Rent - _TC3", "is_group", 1)
+
+ acc = frappe.new_doc("Account")
+ acc.account_name = "Test Group Account"
+ acc.parent_account = "Office Rent - _TC3"
+ acc.company = "_Test Company 3"
+ self.assertRaises(frappe.ValidationError, acc.insert)
+
+ frappe.db.set_value("Account", "Office Rent - _TC3", "is_group", 0)
+
def test_account_rename_sync(self):
frappe.local.flags.pop("ignore_root_company_validation", None)
@@ -160,7 +171,8 @@
for doc in to_delete:
frappe.delete_doc("Account", doc)
-def _make_test_records(verbose):
+
+def _make_test_records(verbose=None):
from frappe.test_runner import make_test_objects
accounts = [
@@ -242,7 +254,8 @@
account_name = kwargs.get('account_name'),
account_type = kwargs.get('account_type'),
parent_account = kwargs.get('parent_account'),
- company = kwargs.get('company')
+ company = kwargs.get('company'),
+ account_currency = kwargs.get('account_currency')
))
account.save()
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index 3c12f85..65c5ff1 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -2,12 +2,11 @@
// For license information, please see license.txt
frappe.ui.form.on('Accounting Dimension', {
-
refresh: function(frm) {
frm.set_query('document_type', () => {
let invalid_doctypes = frappe.model.core_doctypes_list;
invalid_doctypes.push('Accounting Dimension', 'Project',
- 'Cost Center', 'Accounting Dimension Detail');
+ 'Cost Center', 'Accounting Dimension Detail', 'Company');
return {
filters: {
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
index cf55d55..5858f10 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -30,6 +30,7 @@
"fieldtype": "Link",
"label": "Reference Document Type",
"options": "DocType",
+ "read_only_depends_on": "eval:!doc.__islocal",
"reqd": 1
},
{
@@ -48,7 +49,7 @@
}
],
"links": [],
- "modified": "2020-03-22 20:34:39.805728",
+ "modified": "2021-02-08 16:37:53.936656",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 8834385..0ebf0eb 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -19,7 +19,7 @@
def validate(self):
if self.document_type in core_doctypes_list + ('Accounting Dimension', 'Project',
- 'Cost Center', 'Accounting Dimension Detail') :
+ 'Cost Center', 'Accounting Dimension Detail', 'Company') :
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)
@@ -29,15 +29,25 @@
if exists and self.is_new():
frappe.throw("Document Type already used as a dimension")
+ if not self.is_new():
+ self.validate_document_type_change()
+
+ def validate_document_type_change(self):
+ doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
+ if doctype_before_save != self.document_type:
+ message = _("Cannot change Reference Document Type.")
+ message += _("Please create a new Accounting Dimension if required.")
+ frappe.throw(message)
+
def after_insert(self):
if frappe.flags.in_test:
make_dimension_in_accounting_doctypes(doc=self)
else:
- frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self)
+ frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self, queue='long')
def on_trash(self):
if frappe.flags.in_test:
- delete_accounting_dimension(doc=self)
+ delete_accounting_dimension(doc=self, queue='long')
else:
frappe.enqueue(delete_accounting_dimension, doc=self)
@@ -48,8 +58,13 @@
if not self.fieldname:
self.fieldname = scrub(self.label)
-def make_dimension_in_accounting_doctypes(doc):
- doclist = get_doctypes_with_dimensions()
+ def on_update(self):
+ frappe.flags.accounting_dimensions = None
+
+def make_dimension_in_accounting_doctypes(doc, doclist=None):
+ if not doclist:
+ doclist = get_doctypes_with_dimensions()
+
doc_count = len(get_accounting_dimensions())
count = 0
@@ -69,13 +84,13 @@
"owner": "Administrator"
}
- if doctype == "Budget":
- add_dimension_to_budget_doctype(df, doc)
- else:
- meta = frappe.get_meta(doctype, cached=False)
- fieldnames = [d.fieldname for d in meta.get("fields")]
+ meta = frappe.get_meta(doctype, cached=False)
+ fieldnames = [d.fieldname for d in meta.get("fields")]
- if df['fieldname'] not in fieldnames:
+ if df['fieldname'] not in fieldnames:
+ if doctype == "Budget":
+ add_dimension_to_budget_doctype(df.copy(), doc)
+ else:
create_custom_field(doctype, df)
count += 1
@@ -165,23 +180,17 @@
frappe.clear_cache(doctype=doctype)
def get_doctypes_with_dimensions():
- doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
- "Expense Claim", "Expense Claim Detail", "Expense Taxes and Charges", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note",
- "Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
- "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"]
-
- return doclist
+ return frappe.get_hooks("accounting_dimension_doctypes")
def get_accounting_dimensions(as_list=True):
- accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled", "document_type"])
+ if frappe.flags.accounting_dimensions is None:
+ frappe.flags.accounting_dimensions = frappe.get_all("Accounting Dimension",
+ fields=["label", "fieldname", "disabled", "document_type"])
if as_list:
- return [d.fieldname for d in accounting_dimensions]
+ return [d.fieldname for d in frappe.flags.accounting_dimensions]
else:
- return accounting_dimensions
+ return frappe.flags.accounting_dimensions
def get_checks_for_pl_and_bs_accounts():
dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
@@ -203,7 +212,7 @@
return all_dimensions
@frappe.whitelist()
-def get_dimension_filters():
+def get_dimensions(with_cost_center_and_project=False):
dimension_filters = frappe.db.sql("""
SELECT label, fieldname, document_type
FROM `tabAccounting Dimension`
@@ -214,6 +223,18 @@
FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
WHERE c.parent = p.name""", as_dict=1)
+ if with_cost_center_and_project:
+ dimension_filters.extend([
+ {
+ 'fieldname': 'cost_center',
+ 'document_type': 'Cost Center'
+ },
+ {
+ 'fieldname': 'project',
+ 'document_type': 'Project'
+ }
+ ])
+
default_dimensions_map = {}
for dimension in default_dimensions:
default_dimensions_map.setdefault(dimension.company, {})
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index 104880f..fc1d7e3 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -11,37 +11,7 @@
class TestAccountingDimension(unittest.TestCase):
def setUp(self):
- frappe.set_user("Administrator")
-
- if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
- dimension = frappe.get_doc({
- "doctype": "Accounting Dimension",
- "document_type": "Department",
- }).insert()
- else:
- dimension1 = frappe.get_doc("Accounting Dimension", "Department")
- dimension1.disabled = 0
- dimension1.save()
-
- if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
- dimension1 = frappe.get_doc({
- "doctype": "Accounting Dimension",
- "document_type": "Location",
- })
-
- dimension1.append("dimension_defaults", {
- "company": "_Test Company",
- "reference_document": "Location",
- "default_dimension": "Block 1",
- "mandatory_for_bs": 1
- })
-
- dimension1.insert()
- dimension1.save()
- else:
- dimension1 = frappe.get_doc("Accounting Dimension", "Location")
- dimension1.disabled = 0
- dimension1.save()
+ create_dimension()
def test_dimension_against_sales_invoice(self):
si = create_sales_invoice(do_not_save=1)
@@ -101,6 +71,38 @@
def tearDown(self):
disable_dimension()
+def create_dimension():
+ frappe.set_user("Administrator")
+
+ if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
+ frappe.get_doc({
+ "doctype": "Accounting Dimension",
+ "document_type": "Department",
+ }).insert()
+ else:
+ dimension = frappe.get_doc("Accounting Dimension", "Department")
+ dimension.disabled = 0
+ dimension.save()
+
+ if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
+ dimension1 = frappe.get_doc({
+ "doctype": "Accounting Dimension",
+ "document_type": "Location",
+ })
+
+ dimension1.append("dimension_defaults", {
+ "company": "_Test Company",
+ "reference_document": "Location",
+ "default_dimension": "Block 1",
+ "mandatory_for_bs": 1
+ })
+
+ dimension1.insert()
+ dimension1.save()
+ else:
+ dimension1 = frappe.get_doc("Accounting Dimension", "Location")
+ dimension1.disabled = 0
+ dimension1.save()
def disable_dimension():
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/accounting_dimension_filter/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/accounts/doctype/accounting_dimension_filter/__init__.py
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
new file mode 100644
index 0000000..74b7b51
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
@@ -0,0 +1,82 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Accounting Dimension Filter', {
+ refresh: function(frm, cdt, cdn) {
+ if (frm.doc.accounting_dimension) {
+ frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value');
+ }
+
+ let help_content =
+ `<table class="table table-bordered" style="background-color: #f9f9f9;">
+ <tr><td>
+ <p>
+ <i class="fa fa-hand-right"></i>
+ {{__('Note: On checking Is Mandatory the accounting dimension will become mandatory against that specific account for all accounting transactions')}}
+ </p>
+ </td></tr>
+ </table>`;
+
+ frm.set_df_property('dimension_filter_help', 'options', help_content);
+ },
+ onload: function(frm) {
+ frm.set_query('applicable_on_account', 'accounts', function() {
+ return {
+ filters: {
+ 'company': frm.doc.company
+ }
+ };
+ });
+
+ frappe.db.get_list('Accounting Dimension',
+ {fields: ['document_type']}).then((res) => {
+ let options = ['Cost Center', 'Project'];
+
+ res.forEach((dimension) => {
+ options.push(dimension.document_type);
+ });
+
+ frm.set_df_property('accounting_dimension', 'options', options);
+ });
+
+ frm.trigger('setup_filters');
+ },
+
+ setup_filters: function(frm) {
+ let filters = {};
+
+ if (frm.doc.accounting_dimension) {
+ frappe.model.with_doctype(frm.doc.accounting_dimension, function() {
+ if (frappe.model.is_tree(frm.doc.accounting_dimension)) {
+ filters['is_group'] = 0;
+ }
+
+ if (frappe.meta.has_field(frm.doc.accounting_dimension, 'company')) {
+ filters['company'] = frm.doc.company;
+ }
+
+ frm.set_query('dimension_value', 'dimensions', function() {
+ return {
+ filters: filters
+ };
+ });
+ });
+ }
+ },
+
+ accounting_dimension: function(frm) {
+ frm.clear_table("dimensions");
+ let row = frm.add_child("dimensions");
+ row.accounting_dimension = frm.doc.accounting_dimension;
+ frm.refresh_field("dimensions");
+ frm.trigger('setup_filters');
+ },
+});
+
+frappe.ui.form.on('Allowed Dimension', {
+ dimensions_add: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ row.accounting_dimension = frm.doc.accounting_dimension;
+ frm.refresh_field("dimensions");
+ }
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json
new file mode 100644
index 0000000..0f3fbc0
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json
@@ -0,0 +1,158 @@
+{
+ "actions": [],
+ "autoname": "format:{accounting_dimension}-{#####}",
+ "creation": "2020-11-08 18:28:11.906146",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "accounting_dimension",
+ "disabled",
+ "column_break_2",
+ "company",
+ "allow_or_restrict",
+ "section_break_4",
+ "accounts",
+ "column_break_6",
+ "dimensions",
+ "section_break_10",
+ "dimension_filter_help"
+ ],
+ "fields": [
+ {
+ "fieldname": "accounting_dimension",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Accounting Dimension",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "allow_or_restrict",
+ "fieldtype": "Select",
+ "label": "Allow Or Restrict Dimension",
+ "options": "Allow\nRestrict",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Applicable On Account",
+ "options": "Applicable On Account",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "depends_on": "eval:doc.accounting_dimension",
+ "fieldname": "dimensions",
+ "fieldtype": "Table",
+ "label": "Applicable Dimension",
+ "options": "Allowed Dimension",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "dimension_filter_help",
+ "fieldtype": "HTML",
+ "label": "Dimension Filter Help",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-02-03 12:04:58.678402",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Accounting Dimension Filter",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py
new file mode 100644
index 0000000..6aef9ca
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py
@@ -0,0 +1,61 @@
+# -*- 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
+from frappe.model.document import Document
+
+class AccountingDimensionFilter(Document):
+ def validate(self):
+ self.validate_applicable_accounts()
+
+ def validate_applicable_accounts(self):
+ accounts = frappe.db.sql(
+ """
+ SELECT a.applicable_on_account as account
+ FROM `tabApplicable On Account` a, `tabAccounting Dimension Filter` d
+ WHERE d.name = a.parent
+ and d.name != %s
+ and d.accounting_dimension = %s
+ """, (self.name, self.accounting_dimension), as_dict=1)
+
+ account_list = [d.account for d in accounts]
+
+ for account in self.get('accounts'):
+ if account.applicable_on_account in account_list:
+ frappe.throw(_("Row {0}: {1} account already applied for Accounting Dimension {2}").format(
+ account.idx, frappe.bold(account.applicable_on_account), frappe.bold(self.accounting_dimension)))
+
+def get_dimension_filter_map():
+ filters = frappe.db.sql("""
+ SELECT
+ a.applicable_on_account, d.dimension_value, p.accounting_dimension,
+ p.allow_or_restrict, a.is_mandatory
+ FROM
+ `tabApplicable On Account` a, `tabAllowed Dimension` d,
+ `tabAccounting Dimension Filter` p
+ WHERE
+ p.name = a.parent
+ AND p.disabled = 0
+ AND p.name = d.parent
+ """, as_dict=1)
+
+ dimension_filter_map = {}
+
+ for f in filters:
+ f.fieldname = scrub(f.accounting_dimension)
+
+ build_map(dimension_filter_map, f.fieldname, f.applicable_on_account, f.dimension_value,
+ f.allow_or_restrict, f.is_mandatory)
+
+ return dimension_filter_map
+
+def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory):
+ map_object.setdefault((dimension, account), {
+ 'allowed_dimensions': [],
+ 'is_mandatory': is_mandatory,
+ 'allow_or_restrict': allow_or_restrict
+ })
+ map_object[(dimension, account)]['allowed_dimensions'].append(filter_value)
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
new file mode 100644
index 0000000..7877abd
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
+from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
+
+class TestAccountingDimensionFilter(unittest.TestCase):
+ def setUp(self):
+ create_dimension()
+ create_accounting_dimension_filter()
+ self.invoice_list = []
+
+ def test_allowed_dimension_validation(self):
+ si = create_sales_invoice(do_not_save=1)
+ si.items[0].cost_center = 'Main - _TC'
+ si.department = 'Accounts - _TC'
+ si.location = 'Block 1'
+ si.save()
+
+ self.assertRaises(InvalidAccountDimensionError, si.submit)
+ self.invoice_list.append(si)
+
+ def test_mandatory_dimension_validation(self):
+ si = create_sales_invoice(do_not_save=1)
+ si.department = ''
+ si.location = 'Block 1'
+
+ # Test with no department for Sales Account
+ si.items[0].department = ''
+ si.items[0].cost_center = '_Test Cost Center 2 - _TC'
+ si.save()
+
+ self.assertRaises(MandatoryAccountDimensionError, si.submit)
+ self.invoice_list.append(si)
+
+ def tearDown(self):
+ disable_dimension_filter()
+ disable_dimension()
+
+ for si in self.invoice_list:
+ si.load_from_db()
+ if si.docstatus == 1:
+ si.cancel()
+
+def create_accounting_dimension_filter():
+ if not frappe.db.get_value('Accounting Dimension Filter',
+ {'accounting_dimension': 'Cost Center'}):
+ frappe.get_doc({
+ 'doctype': 'Accounting Dimension Filter',
+ 'accounting_dimension': 'Cost Center',
+ 'allow_or_restrict': 'Allow',
+ 'company': '_Test Company',
+ 'accounts': [{
+ 'applicable_on_account': 'Sales - _TC',
+ }],
+ 'dimensions': [{
+ 'accounting_dimension': 'Cost Center',
+ 'dimension_value': '_Test Cost Center 2 - _TC'
+ }]
+ }).insert()
+ else:
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Cost Center'})
+ doc.disabled = 0
+ doc.save()
+
+ if not frappe.db.get_value('Accounting Dimension Filter',
+ {'accounting_dimension': 'Department'}):
+ frappe.get_doc({
+ 'doctype': 'Accounting Dimension Filter',
+ 'accounting_dimension': 'Department',
+ 'allow_or_restrict': 'Allow',
+ 'company': '_Test Company',
+ 'accounts': [{
+ 'applicable_on_account': 'Sales - _TC',
+ 'is_mandatory': 1
+ }],
+ 'dimensions': [{
+ 'accounting_dimension': 'Department',
+ 'dimension_value': 'Accounts - _TC'
+ }]
+ }).insert()
+ else:
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Department'})
+ doc.disabled = 0
+ doc.save()
+
+def disable_dimension_filter():
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Cost Center'})
+ doc.disabled = 1
+ doc.save()
+
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Department'})
+ doc.disabled = 1
+ doc.save()
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 022d7a7..10cd939 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -11,36 +11,36 @@
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
class TestAccountingPeriod(unittest.TestCase):
- def test_overlap(self):
- ap1 = create_accounting_period(start_date = "2018-04-01",
- end_date = "2018-06-30", company = "Wind Power LLC")
- ap1.save()
+ def test_overlap(self):
+ ap1 = create_accounting_period(start_date = "2018-04-01",
+ end_date = "2018-06-30", company = "Wind Power LLC")
+ ap1.save()
- ap2 = create_accounting_period(start_date = "2018-06-30",
- end_date = "2018-07-10", company = "Wind Power LLC", period_name = "Test Accounting Period 1")
- self.assertRaises(OverlapError, ap2.save)
+ ap2 = create_accounting_period(start_date = "2018-06-30",
+ end_date = "2018-07-10", company = "Wind Power LLC", period_name = "Test Accounting Period 1")
+ self.assertRaises(OverlapError, ap2.save)
- def test_accounting_period(self):
- ap1 = create_accounting_period(period_name = "Test Accounting Period 2")
- ap1.save()
+ def test_accounting_period(self):
+ ap1 = create_accounting_period(period_name = "Test Accounting Period 2")
+ ap1.save()
- doc = create_sales_invoice(do_not_submit=1, cost_center = "_Test Company - _TC", warehouse = "Stores - _TC")
- self.assertRaises(ClosedAccountingPeriod, doc.submit)
+ doc = create_sales_invoice(do_not_submit=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC")
+ self.assertRaises(ClosedAccountingPeriod, doc.submit)
- def tearDown(self):
- for d in frappe.get_all("Accounting Period"):
- frappe.delete_doc("Accounting Period", d.name)
+ def tearDown(self):
+ for d in frappe.get_all("Accounting Period"):
+ frappe.delete_doc("Accounting Period", d.name)
def create_accounting_period(**args):
- args = frappe._dict(args)
+ args = frappe._dict(args)
- accounting_period = frappe.new_doc("Accounting Period")
- accounting_period.start_date = args.start_date or nowdate()
- accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
- accounting_period.company = args.company or "_Test Company"
- accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
- accounting_period.append("closed_documents", {
- "document_type": 'Sales Invoice', "closed": 1
- })
+ accounting_period = frappe.new_doc("Accounting Period")
+ accounting_period.start_date = args.start_date or nowdate()
+ accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
+ accounting_period.company = args.company or "_Test Company"
+ accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
+ accounting_period.append("closed_documents", {
+ "document_type": 'Sales Invoice', "closed": 1
+ })
- return accounting_period
\ No newline at end of file
+ return accounting_period
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.js b/erpnext/accounts/doctype/accounts_settings/accounts_settings.js
index 0627675..541901c 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.js
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.js
@@ -6,3 +6,46 @@
}
});
+
+frappe.tour['Accounts Settings'] = [
+ {
+ fieldname: "acc_frozen_upto",
+ title: "Accounts Frozen Upto",
+ description: __("Freeze accounting transactions up to specified date, nobody can make/modify entry except the specified Role."),
+ },
+ {
+ fieldname: "frozen_accounts_modifier",
+ title: "Role Allowed to Set Frozen Accounts & Edit Frozen Entries",
+ description: __("Users with this Role are allowed to set frozen accounts and create/modify accounting entries against frozen accounts.")
+ },
+ {
+ fieldname: "determine_address_tax_category_from",
+ title: "Determine Address Tax Category From",
+ description: __("Tax category can be set on Addresses. An address can be Shipping or Billing address. Set which addres to select when applying Tax Category.")
+ },
+ {
+ fieldname: "over_billing_allowance",
+ title: "Over Billing Allowance Percentage",
+ description: __("The percentage by which you can overbill transactions. For example, if the order value is $100 for an Item and percentage here is set as 10% then you are allowed to bill for $110.")
+ },
+ {
+ fieldname: "credit_controller",
+ title: "Credit Controller",
+ description: __("Select the role that is allowed to submit transactions that exceed credit limits set. The credit limit can be set in the Customer form.")
+ },
+ {
+ fieldname: "make_payment_via_journal_entry",
+ title: "Make Payment via Journal Entry",
+ description: __("When checked, if user proceeds to make payment from an invoice, the system will open a Journal Entry instead of a Payment Entry.")
+ },
+ {
+ fieldname: "unlink_payment_on_cancellation_of_invoice",
+ title: "Unlink Payment on Cancellation of Invoice",
+ description: __("If checked, system will unlink the payment against the respective invoice.")
+ },
+ {
+ fieldname: "unlink_advance_payment_on_cancelation_of_order",
+ title: "Unlink Advance Payment on Cancellation of Order",
+ description: __("Similar to the previous option, this unlinks any advance payments made against Purchase/Sales Orders.")
+ }
+];
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index b2e8b09..a3c29b6 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -21,6 +21,7 @@
"book_asset_depreciation_entry_automatically",
"add_taxes_from_item_tax_template",
"automatically_fetch_payment_terms",
+ "delete_linked_ledger_entries",
"deferred_accounting_settings_section",
"automatically_process_deferred_accounting_entry",
"book_deferred_entries_based_on",
@@ -40,7 +41,7 @@
"fields": [
{
"default": "1",
- "description": "If enabled, the system will post accounting entries for inventory automatically.",
+ "description": "If enabled, the system will post accounting entries for inventory automatically",
"fieldname": "auto_accounting_for_stock",
"fieldtype": "Check",
"hidden": 1,
@@ -48,23 +49,23 @@
"label": "Make Accounting Entry For Every Stock Movement"
},
{
- "description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",
+ "description": "Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below",
"fieldname": "acc_frozen_upto",
"fieldtype": "Date",
"in_list_view": 1,
- "label": "Accounts Frozen Upto"
+ "label": "Accounts Frozen Till Date"
},
{
"description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts",
"fieldname": "frozen_accounts_modifier",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries",
+ "label": "Role Allowed to Set Frozen Accounts and Edit Frozen Entries",
"options": "Role"
},
{
"default": "Billing Address",
- "description": "Address used to determine Tax Category in transactions.",
+ "description": "Address used to determine Tax Category in transactions",
"fieldname": "determine_address_tax_category_from",
"fieldtype": "Select",
"label": "Determine Address Tax Category From",
@@ -75,7 +76,7 @@
"fieldtype": "Column Break"
},
{
- "description": "Role that is allowed to submit transactions that exceed credit limits set.",
+ "description": "This role is allowed to submit transactions that exceed credit limits",
"fieldname": "credit_controller",
"fieldtype": "Link",
"in_list_view": 1,
@@ -104,7 +105,7 @@
"default": "1",
"fieldname": "unlink_advance_payment_on_cancelation_of_order",
"fieldtype": "Check",
- "label": "Unlink Advance Payment on Cancelation of Order"
+ "label": "Unlink Advance Payment on Cancellation of Order"
},
{
"default": "1",
@@ -127,7 +128,7 @@
"default": "0",
"fieldname": "show_inclusive_tax_in_print",
"fieldtype": "Check",
- "label": "Show Inclusive Tax In Print"
+ "label": "Show Inclusive Tax in Print"
},
{
"fieldname": "column_break_12",
@@ -165,7 +166,7 @@
},
{
"default": "0",
- "description": "Only select if you have setup Cash Flow Mapper documents",
+ "description": "Only select this if you have set up the Cash Flow Mapper documents",
"fieldname": "use_custom_cash_flow",
"fieldtype": "Check",
"label": "Use Custom Cash Flow Format"
@@ -177,7 +178,7 @@
"label": "Automatically Fetch Payment Terms"
},
{
- "description": "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 for $110.",
+ "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 ",
"fieldname": "over_billing_allowance",
"fieldtype": "Currency",
"label": "Over Billing Allowance (%)"
@@ -199,7 +200,7 @@
},
{
"default": "0",
- "description": "If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense",
+ "description": "If this is unchecked, direct GL entries will be created to book deferred revenue or expense",
"fieldname": "book_deferred_entries_via_journal_entry",
"fieldtype": "Check",
"label": "Book Deferred Entries Via Journal Entry"
@@ -214,18 +215,25 @@
},
{
"default": "Days",
- "description": "If \"Months\" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",
+ "description": "If \"Months\" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",
"fieldname": "book_deferred_entries_based_on",
"fieldtype": "Select",
"label": "Book Deferred Entries Based On",
"options": "Days\nMonths"
+ },
+ {
+ "default": "0",
+ "fieldname": "delete_linked_ledger_entries",
+ "fieldtype": "Check",
+ "label": "Delete Accounting and Stock Ledger Entries on deletion of Transaction"
}
],
"icon": "icon-cog",
"idx": 1,
+ "index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-08-03 20:13:26.043092",
+ "modified": "2021-01-05 13:04:00.118892",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/allowed_dimension/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/accounts/doctype/allowed_dimension/__init__.py
diff --git a/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.json b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.json
new file mode 100644
index 0000000..7fe2a3c
--- /dev/null
+++ b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.json
@@ -0,0 +1,43 @@
+{
+ "actions": [],
+ "creation": "2020-11-08 18:22:36.001131",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "accounting_dimension",
+ "dimension_value"
+ ],
+ "fields": [
+ {
+ "fieldname": "accounting_dimension",
+ "fieldtype": "Link",
+ "label": "Accounting Dimension",
+ "options": "DocType",
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "dimension_value",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "options": "accounting_dimension",
+ "show_days": 1,
+ "show_seconds": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-11-23 09:56:19.744200",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Allowed Dimension",
+ "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/allowed_dimension/allowed_dimension.py b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py
new file mode 100644
index 0000000..c2afc1a
--- /dev/null
+++ b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class AllowedDimension(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/applicable_on_account/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/accounts/doctype/applicable_on_account/__init__.py
diff --git a/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.json b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.json
new file mode 100644
index 0000000..95e98d0
--- /dev/null
+++ b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.json
@@ -0,0 +1,46 @@
+{
+ "actions": [],
+ "creation": "2020-11-08 18:20:00.944449",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "applicable_on_account",
+ "is_mandatory"
+ ],
+ "fields": [
+ {
+ "fieldname": "applicable_on_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Accounts",
+ "options": "Account",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "columns": 2,
+ "default": "0",
+ "fieldname": "is_mandatory",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Is Mandatory",
+ "show_days": 1,
+ "show_seconds": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-11-22 19:55:13.324136",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Applicable On Account",
+ "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/applicable_on_account/applicable_on_account.py b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py
new file mode 100644
index 0000000..0fccaf3
--- /dev/null
+++ b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class ApplicableOnAccount(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js
index de9498e..49b2b18 100644
--- a/erpnext/accounts/doctype/bank/bank.js
+++ b/erpnext/accounts/doctype/bank/bank.js
@@ -1,5 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide('erpnext.integrations');
frappe.ui.form.on('Bank', {
onload: function(frm) {
@@ -20,7 +21,12 @@
frm.set_df_property('address_and_contact', 'hidden', 0);
frappe.contacts.render_address_and_contact(frm);
}
- },
+ if (frm.doc.plaid_access_token) {
+ frm.add_custom_button(__('Refresh Plaid Link'), () => {
+ new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token);
+ });
+ }
+ }
});
@@ -40,4 +46,79 @@
frm.doc.name).options = options;
frm.fields_dict.bank_transaction_mapping.grid.refresh();
-};
\ No newline at end of file
+};
+
+erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
+ constructor(access_token) {
+ this.access_token = access_token;
+ this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js';
+ this.init_config();
+ }
+
+ async init_config() {
+ this.plaid_env = await frappe.db.get_single_value('Plaid Settings', 'plaid_env');
+ this.token = await this.get_link_token_for_update();
+ this.init_plaid();
+ }
+
+ async get_link_token_for_update() {
+ const token = frappe.xcall(
+ 'erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_link_token_for_update',
+ { access_token: this.access_token }
+ )
+ if (!token) {
+ frappe.throw(__('Cannot retrieve link token for update. Check Error Log for more information'));
+ }
+ return token;
+ }
+
+ init_plaid() {
+ const me = this;
+ me.loadScript(me.plaidUrl)
+ .then(() => {
+ me.onScriptLoaded(me);
+ })
+ .then(() => {
+ if (me.linkHandler) {
+ me.linkHandler.open();
+ }
+ })
+ .catch((error) => {
+ me.onScriptError(error);
+ });
+ }
+
+ loadScript(src) {
+ return new Promise(function (resolve, reject) {
+ if (document.querySelector("script[src='" + src + "']")) {
+ resolve();
+ return;
+ }
+ const el = document.createElement('script');
+ el.type = 'text/javascript';
+ el.async = true;
+ el.src = src;
+ el.addEventListener('load', resolve);
+ el.addEventListener('error', reject);
+ el.addEventListener('abort', reject);
+ document.head.appendChild(el);
+ });
+ }
+
+ onScriptLoaded(me) {
+ me.linkHandler = Plaid.create({
+ env: me.plaid_env,
+ token: me.token,
+ onSuccess: me.plaid_success
+ });
+ }
+
+ onScriptError(error) {
+ frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information"));
+ console.log(error);
+ }
+
+ plaid_success(token, response) {
+ frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
+ }
+};
diff --git a/erpnext/accounts/doctype/bank_account/bank_account.json b/erpnext/accounts/doctype/bank_account/bank_account.json
index b42f1f9..de67ab1 100644
--- a/erpnext/accounts/doctype/bank_account/bank_account.json
+++ b/erpnext/accounts/doctype/bank_account/bank_account.json
@@ -86,6 +86,7 @@
},
{
"default": "0",
+ "description": "Setting the account as a Company Account is necessary for Bank Reconciliation",
"fieldname": "is_company_account",
"fieldtype": "Check",
"label": "Is Company Account"
@@ -207,7 +208,7 @@
}
],
"links": [],
- "modified": "2020-07-17 13:59:50.795412",
+ "modified": "2020-10-23 16:48:06.303658",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/bank_reconciliation_tool/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/accounts/doctype/bank_reconciliation_tool/__init__.py
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
new file mode 100644
index 0000000..10f660a
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
@@ -0,0 +1,163 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+frappe.ui.form.on("Bank Reconciliation Tool", {
+ setup: function (frm) {
+ frm.set_query("bank_account", function () {
+ return {
+ filters: {
+ company: ["in", frm.doc.company],
+ 'is_company_account': 1
+ },
+ };
+ });
+ },
+
+ refresh: function (frm) {
+ frappe.require("assets/js/bank-reconciliation-tool.min.js", () =>
+ frm.trigger("make_reconciliation_tool")
+ );
+ frm.upload_statement_button = frm.page.set_secondary_action(
+ __("Upload Bank Statement"),
+ () =>
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
+ args: {
+ dt: frm.doc.doctype,
+ dn: frm.doc.name,
+ company: frm.doc.company,
+ bank_account: frm.doc.bank_account,
+ },
+ callback: function (r) {
+ if (!r.exc) {
+ var doc = frappe.model.sync(r.message);
+ frappe.set_route(
+ "Form",
+ doc[0].doctype,
+ doc[0].name
+ );
+ }
+ },
+ })
+ );
+ },
+
+ after_save: function (frm) {
+ frm.trigger("make_reconciliation_tool");
+ },
+
+ bank_account: function (frm) {
+ frappe.db.get_value(
+ "Bank Account",
+ frm.bank_account,
+ "account",
+ (r) => {
+ frappe.db.get_value(
+ "Account",
+ r.account,
+ "account_currency",
+ (r) => {
+ frm.currency = r.account_currency;
+ }
+ );
+ }
+ );
+ frm.trigger("get_account_opening_balance");
+ },
+
+ bank_statement_from_date: function (frm) {
+ frm.trigger("get_account_opening_balance");
+ },
+
+ make_reconciliation_tool(frm) {
+ frm.get_field("reconciliation_tool_cards").$wrapper.empty();
+ if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
+ frm.trigger("get_cleared_balance").then(() => {
+ if (
+ frm.doc.bank_account &&
+ frm.doc.bank_statement_from_date &&
+ frm.doc.bank_statement_to_date &&
+ frm.doc.bank_statement_closing_balance
+ ) {
+ frm.trigger("render_chart");
+ frm.trigger("render");
+ frappe.utils.scroll_to(
+ frm.get_field("reconciliation_tool_cards").$wrapper,
+ true,
+ 30
+ );
+ }
+ });
+ }
+ },
+
+ get_account_opening_balance(frm) {
+ if (frm.doc.bank_account && frm.doc.bank_statement_from_date) {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
+ args: {
+ bank_account: frm.doc.bank_account,
+ till_date: frm.doc.bank_statement_from_date,
+ },
+ callback: (response) => {
+ frm.set_value("account_opening_balance", response.message);
+ },
+ });
+ }
+ },
+
+ get_cleared_balance(frm) {
+ if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
+ return frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
+ args: {
+ bank_account: frm.doc.bank_account,
+ till_date: frm.doc.bank_statement_to_date,
+ },
+ callback: (response) => {
+ frm.cleared_balance = response.message;
+ },
+ });
+ }
+ },
+
+ render_chart(frm) {
+ frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager(
+ {
+ $reconciliation_tool_cards: frm.get_field(
+ "reconciliation_tool_cards"
+ ).$wrapper,
+ bank_statement_closing_balance:
+ frm.doc.bank_statement_closing_balance,
+ cleared_balance: frm.cleared_balance,
+ currency: frm.currency,
+ }
+ );
+ },
+
+ render(frm) {
+ if (frm.doc.bank_account) {
+ frm.bank_reconciliation_data_table_manager = new erpnext.accounts.bank_reconciliation.DataTableManager(
+ {
+ company: frm.doc.company,
+ bank_account: frm.doc.bank_account,
+ $reconciliation_tool_dt: frm.get_field(
+ "reconciliation_tool_dt"
+ ).$wrapper,
+ $no_bank_transactions: frm.get_field(
+ "no_bank_transactions"
+ ).$wrapper,
+ bank_statement_from_date: frm.doc.bank_statement_from_date,
+ bank_statement_to_date: frm.doc.bank_statement_to_date,
+ bank_statement_closing_balance:
+ frm.doc.bank_statement_closing_balance,
+ cards_manager: frm.cards_manager,
+ }
+ );
+ }
+ },
+});
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
new file mode 100644
index 0000000..4837db3
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
@@ -0,0 +1,113 @@
+{
+ "actions": [],
+ "creation": "2020-12-02 10:13:02.148040",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "bank_account",
+ "column_break_1",
+ "bank_statement_from_date",
+ "bank_statement_to_date",
+ "column_break_2",
+ "account_opening_balance",
+ "bank_statement_closing_balance",
+ "section_break_1",
+ "reconciliation_tool_cards",
+ "reconciliation_tool_dt",
+ "no_bank_transactions"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "fieldname": "bank_account",
+ "fieldtype": "Link",
+ "label": "Bank Account",
+ "options": "Bank Account"
+ },
+ {
+ "fieldname": "column_break_1",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval: doc.bank_account",
+ "fieldname": "bank_statement_from_date",
+ "fieldtype": "Date",
+ "label": "Bank Statement From Date"
+ },
+ {
+ "depends_on": "eval: doc.bank_statement_from_date",
+ "fieldname": "bank_statement_to_date",
+ "fieldtype": "Date",
+ "label": "Bank Statement To Date"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval: doc.bank_statement_from_date",
+ "fieldname": "account_opening_balance",
+ "fieldtype": "Currency",
+ "label": "Account Opening Balance",
+ "options": "Currency",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.bank_statement_to_date",
+ "fieldname": "bank_statement_closing_balance",
+ "fieldtype": "Currency",
+ "label": "Bank Statement Closing Balance",
+ "options": "Currency"
+ },
+ {
+ "depends_on": "eval: doc.bank_statement_closing_balance",
+ "fieldname": "section_break_1",
+ "fieldtype": "Section Break",
+ "label": "Reconcile"
+ },
+ {
+ "fieldname": "reconciliation_tool_cards",
+ "fieldtype": "HTML"
+ },
+ {
+ "fieldname": "reconciliation_tool_dt",
+ "fieldtype": "HTML"
+ },
+ {
+ "fieldname": "no_bank_transactions",
+ "fieldtype": "HTML",
+ "options": "<div class=\"text-muted text-center\">No Matching Bank Transactions Found</div>"
+ }
+ ],
+ "hide_toolbar": 1,
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-02-02 01:35:53.043578",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Bank Reconciliation Tool",
+ "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"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
new file mode 100644
index 0000000..8a17233
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
@@ -0,0 +1,452 @@
+# -*- 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.model.document import Document
+from frappe import _
+from frappe.utils import flt
+
+from erpnext import get_company_currency
+from erpnext.accounts.utils import get_balance_on
+from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import get_entries, get_amounts_not_reflected_in_system
+from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount
+
+
+class BankReconciliationTool(Document):
+ pass
+
+@frappe.whitelist()
+def get_bank_transactions(bank_account, from_date = None, to_date = None):
+ # returns bank transactions for a bank account
+ filters = []
+ filters.append(['bank_account', '=', bank_account])
+ filters.append(['docstatus', '=', 1])
+ filters.append(['unallocated_amount', '>', 0])
+ if to_date:
+ filters.append(['date', '<=', to_date])
+ if from_date:
+ filters.append(['date', '>=', from_date])
+ transactions = frappe.get_all(
+ 'Bank Transaction',
+ fields = ['date', 'deposit', 'withdrawal', 'currency',
+ 'description', 'name', 'bank_account', 'company',
+ 'unallocated_amount', 'reference_number', 'party_type', 'party'],
+ filters = filters
+ )
+ return transactions
+
+@frappe.whitelist()
+def get_account_balance(bank_account, till_date):
+ # returns account balance till the specified date
+ account = frappe.db.get_value('Bank Account', bank_account, 'account')
+ filters = frappe._dict({
+ "account": account,
+ "report_date": till_date,
+ "include_pos_transactions": 1
+ })
+ data = get_entries(filters)
+
+ balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
+
+ total_debit, total_credit = 0,0
+ for d in data:
+ total_debit += flt(d.debit)
+ total_credit += flt(d.credit)
+
+ amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
+
+ bank_bal = flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) \
+ + amounts_not_reflected_in_system
+
+ return bank_bal
+
+
+@frappe.whitelist()
+def update_bank_transaction(bank_transaction_name, reference_number, party_type=None, party=None):
+ # updates bank transaction based on the new parameters provided by the user from Vouchers
+ bank_transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
+ bank_transaction.reference_number = reference_number
+ bank_transaction.party_type = party_type
+ bank_transaction.party = party
+ bank_transaction.save()
+ return frappe.db.get_all('Bank Transaction',
+ filters={
+ 'name': bank_transaction_name
+ },
+ fields=['date', 'deposit', 'withdrawal', 'currency',
+ 'description', 'name', 'bank_account', 'company',
+ 'unallocated_amount', 'reference_number',
+ 'party_type', 'party'],
+ )[0]
+
+
+@frappe.whitelist()
+def create_journal_entry_bts( bank_transaction_name, reference_number=None, reference_date=None, posting_date=None, entry_type=None,
+ second_account=None, mode_of_payment=None, party_type=None, party=None, allow_edit=None):
+ # Create a new journal entry based on the bank transaction
+ bank_transaction = frappe.db.get_values(
+ "Bank Transaction", bank_transaction_name,
+ fieldname=["name", "deposit", "withdrawal", "bank_account"] ,
+ as_dict=True
+ )[0]
+ company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
+ account_type = frappe.db.get_value("Account", second_account, "account_type")
+ if account_type in ["Receivable", "Payable"]:
+ if not (party_type and party):
+ frappe.throw(_("Party Type and Party is required for Receivable / Payable account {0}").format( second_account))
+ accounts = []
+ # Multi Currency?
+ accounts.append({
+ "account": second_account,
+ "credit_in_account_currency": bank_transaction.deposit
+ if bank_transaction.deposit > 0
+ else 0,
+ "debit_in_account_currency":bank_transaction.withdrawal
+ if bank_transaction.withdrawal > 0
+ else 0,
+ "party_type":party_type,
+ "party":party,
+ })
+
+ accounts.append({
+ "account": company_account,
+ "bank_account": bank_transaction.bank_account,
+ "credit_in_account_currency": bank_transaction.withdrawal
+ if bank_transaction.withdrawal > 0
+ else 0,
+ "debit_in_account_currency":bank_transaction.deposit
+ if bank_transaction.deposit > 0
+ else 0,
+ })
+
+ company = frappe.get_value("Account", company_account, "company")
+
+ journal_entry_dict = {
+ "voucher_type" : entry_type,
+ "company" : company,
+ "posting_date" : posting_date,
+ "cheque_date" : reference_date,
+ "cheque_no" : reference_number,
+ "mode_of_payment" : mode_of_payment
+ }
+ journal_entry = frappe.new_doc('Journal Entry')
+ journal_entry.update(journal_entry_dict)
+ journal_entry.set("accounts", accounts)
+
+
+ if allow_edit:
+ return journal_entry
+
+ journal_entry.insert()
+ journal_entry.submit()
+
+ if bank_transaction.deposit > 0:
+ paid_amount = bank_transaction.deposit
+ else:
+ paid_amount = bank_transaction.withdrawal
+
+ vouchers = json.dumps([{
+ "payment_doctype":"Journal Entry",
+ "payment_name":journal_entry.name,
+ "amount":paid_amount}])
+
+ return reconcile_vouchers(bank_transaction.name, vouchers)
+
+@frappe.whitelist()
+def create_payment_entry_bts( bank_transaction_name, reference_number=None, reference_date=None, party_type=None, party=None, posting_date=None,
+ mode_of_payment=None, project=None, cost_center=None, allow_edit=None):
+ # Create a new payment entry based on the bank transaction
+ bank_transaction = frappe.db.get_values(
+ "Bank Transaction", bank_transaction_name,
+ fieldname=["name", "unallocated_amount", "deposit", "bank_account"] ,
+ as_dict=True
+ )[0]
+ paid_amount = bank_transaction.unallocated_amount
+ payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay"
+
+ company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
+ company = frappe.get_value("Account", company_account, "company")
+ payment_entry_dict = {
+ "company" : company,
+ "payment_type" : payment_type,
+ "reference_no" : reference_number,
+ "reference_date" : reference_date,
+ "party_type" : party_type,
+ "party" : party,
+ "posting_date" : posting_date,
+ "paid_amount": paid_amount,
+ "received_amount": paid_amount
+ }
+ payment_entry = frappe.new_doc("Payment Entry")
+
+
+ payment_entry.update(payment_entry_dict)
+
+ if mode_of_payment:
+ payment_entry.mode_of_payment = mode_of_payment
+ if project:
+ payment_entry.project = project
+ if cost_center:
+ payment_entry.cost_center = cost_center
+ if payment_type == "Receive":
+ payment_entry.paid_to = company_account
+ else:
+ payment_entry.paid_from = company_account
+
+ payment_entry.validate()
+
+ if allow_edit:
+ return payment_entry
+
+ payment_entry.insert()
+
+ payment_entry.submit()
+ vouchers = json.dumps([{
+ "payment_doctype":"Payment Entry",
+ "payment_name":payment_entry.name,
+ "amount":paid_amount}])
+ return reconcile_vouchers(bank_transaction.name, vouchers)
+
+@frappe.whitelist()
+def reconcile_vouchers(bank_transaction_name, vouchers):
+ # updated clear date of all the vouchers based on the bank transaction
+ vouchers = json.loads(vouchers)
+ transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
+ if transaction.unallocated_amount == 0:
+ frappe.throw(_("This bank transaction is already fully reconciled"))
+ total_amount = 0
+ for voucher in vouchers:
+ voucher['payment_entry'] = frappe.get_doc(voucher['payment_doctype'], voucher['payment_name'])
+ total_amount += get_paid_amount(frappe._dict({
+ 'payment_document': voucher['payment_doctype'],
+ 'payment_entry': voucher['payment_name'],
+ }), transaction.currency)
+
+ if total_amount > transaction.unallocated_amount:
+ frappe.throw(_("The Sum Total of Amounts of All Selected Vouchers Should be Less than the Unallocated Amount of the Bank Transaction"))
+ account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
+
+ for voucher in vouchers:
+ gl_entry = frappe.db.get_value("GL Entry", dict(account=account, voucher_type=voucher['payment_doctype'], voucher_no=voucher['payment_name']), ['credit', 'debit'], as_dict=1)
+ gl_amount, transaction_amount = (gl_entry.credit, transaction.deposit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.withdrawal)
+ allocated_amount = gl_amount if gl_amount >= transaction_amount else transaction_amount
+
+ transaction.append("payment_entries", {
+ "payment_document": voucher['payment_entry'].doctype,
+ "payment_entry": voucher['payment_entry'].name,
+ "allocated_amount": allocated_amount
+ })
+
+ transaction.save()
+ transaction.update_allocations()
+ return frappe.get_doc("Bank Transaction", bank_transaction_name)
+
+@frappe.whitelist()
+def get_linked_payments(bank_transaction_name, document_types = None):
+ # get all matching payments for a bank transaction
+ transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
+ bank_account = frappe.db.get_values(
+ "Bank Account",
+ transaction.bank_account,
+ ["account", "company"],
+ as_dict=True)[0]
+ (account, company) = (bank_account.account, bank_account.company)
+ matching = check_matching(account, company, transaction, document_types)
+ return matching
+
+def check_matching(bank_account, company, transaction, document_types):
+ # combine all types of vocuhers
+ subquery = get_queries(bank_account, company, transaction, document_types)
+ filters = {
+ "amount": transaction.unallocated_amount,
+ "payment_type" : "Receive" if transaction.deposit > 0 else "Pay",
+ "reference_no": transaction.reference_number,
+ "party_type": transaction.party_type,
+ "party": transaction.party,
+ "bank_account": bank_account
+ }
+
+ matching_vouchers = []
+ for query in subquery:
+ matching_vouchers.extend(
+ frappe.db.sql(query, filters,)
+ )
+
+ return sorted(matching_vouchers, key = lambda x: x[0], reverse=True) if matching_vouchers else []
+
+def get_queries(bank_account, company, transaction, document_types):
+ # get queries to get matching vouchers
+ amount_condition = "=" if "exact_match" in document_types else "<="
+ account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from"
+ queries = []
+
+ if "payment_entry" in document_types:
+ pe_amount_matching = get_pe_matching_query(amount_condition, account_from_to, transaction)
+ queries.extend([pe_amount_matching])
+
+ if "journal_entry" in document_types:
+ je_amount_matching = get_je_matching_query(amount_condition, transaction)
+ queries.extend([je_amount_matching])
+
+ if transaction.deposit > 0 and "sales_invoice" in document_types:
+ si_amount_matching = get_si_matching_query(amount_condition)
+ queries.extend([si_amount_matching])
+
+ if transaction.withdrawal > 0:
+ if "purchase_invoice" in document_types:
+ pi_amount_matching = get_pi_matching_query(amount_condition)
+ queries.extend([pi_amount_matching])
+
+ if "expense_claim" in document_types:
+ ec_amount_matching = get_ec_matching_query(bank_account, company, amount_condition)
+ queries.extend([ec_amount_matching])
+
+ return queries
+
+def get_pe_matching_query(amount_condition, account_from_to, transaction):
+ # get matching payment entries query
+ if transaction.deposit > 0:
+ currency_field = "paid_to_account_currency as currency"
+ else:
+ currency_field = "paid_from_account_currency as currency"
+ return f"""
+ SELECT
+ (CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END
+ + CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END
+ + 1 ) AS rank,
+ 'Payment Entry' as doctype,
+ name,
+ paid_amount,
+ reference_no,
+ reference_date,
+ party,
+ party_type,
+ posting_date,
+ {currency_field}
+ FROM
+ `tabPayment Entry`
+ WHERE
+ paid_amount {amount_condition} %(amount)s
+ AND docstatus = 1
+ AND payment_type IN (%(payment_type)s, 'Internal Transfer')
+ AND ifnull(clearance_date, '') = ""
+ AND {account_from_to} = %(bank_account)s
+ """
+
+
+def get_je_matching_query(amount_condition, transaction):
+ # get matching journal entry query
+ cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit"
+ return f"""
+
+ SELECT
+ (CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END
+ + 1) AS rank ,
+ 'Journal Entry' as doctype,
+ je.name,
+ jea.{cr_or_dr}_in_account_currency as paid_amount,
+ je.cheque_no as reference_no,
+ je.cheque_date as reference_date,
+ je.pay_to_recd_from as party,
+ jea.party_type,
+ je.posting_date,
+ jea.account_currency as currency
+ FROM
+ `tabJournal Entry Account` as jea
+ JOIN
+ `tabJournal Entry` as je
+ ON
+ jea.parent = je.name
+ WHERE
+ (je.clearance_date is null or je.clearance_date='0000-00-00')
+ AND jea.account = %(bank_account)s
+ AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s
+ AND je.docstatus = 1
+ """
+
+
+def get_si_matching_query(amount_condition):
+ # get matchin sales invoice query
+ return f"""
+ SELECT
+ ( CASE WHEN si.customer = %(party)s THEN 1 ELSE 0 END
+ + 1 ) AS rank,
+ 'Sales Invoice' as doctype,
+ si.name,
+ sip.amount as paid_amount,
+ '' as reference_no,
+ '' as reference_date,
+ si.customer as party,
+ 'Customer' as party_type,
+ si.posting_date,
+ si.currency
+
+ FROM
+ `tabSales Invoice Payment` as sip
+ JOIN
+ `tabSales Invoice` as si
+ ON
+ sip.parent = si.name
+ WHERE (sip.clearance_date is null or sip.clearance_date='0000-00-00')
+ AND sip.account = %(bank_account)s
+ AND sip.amount {amount_condition} %(amount)s
+ AND si.docstatus = 1
+ """
+
+def get_pi_matching_query(amount_condition):
+ # get matching purchase invoice query
+ return f"""
+ SELECT
+ ( CASE WHEN supplier = %(party)s THEN 1 ELSE 0 END
+ + 1 ) AS rank,
+ 'Purchase Invoice' as doctype,
+ name,
+ paid_amount,
+ '' as reference_no,
+ '' as reference_date,
+ supplier as party,
+ 'Supplier' as party_type,
+ posting_date,
+ currency
+ FROM
+ `tabPurchase Invoice`
+ WHERE
+ paid_amount {amount_condition} %(amount)s
+ AND docstatus = 1
+ AND is_paid = 1
+ AND ifnull(clearance_date, '') = ""
+ AND cash_bank_account = %(bank_account)s
+ """
+
+def get_ec_matching_query(bank_account, company, amount_condition):
+ # get matching Expense Claim query
+ mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
+ filters={"default_account": bank_account}, fields=["parent"])]
+ mode_of_payments = '(\'' + '\', \''.join(mode_of_payments) + '\' )'
+ company_currency = get_company_currency(company)
+ return f"""
+ SELECT
+ ( CASE WHEN employee = %(party)s THEN 1 ELSE 0 END
+ + 1 ) AS rank,
+ 'Expense Claim' as doctype,
+ name,
+ total_sanctioned_amount as paid_amount,
+ '' as reference_no,
+ '' as reference_date,
+ employee as party,
+ 'Employee' as party_type,
+ posting_date,
+ '{company_currency}' as currency
+ FROM
+ `tabExpense Claim`
+ WHERE
+ total_sanctioned_amount {amount_condition} %(amount)s
+ AND docstatus = 1
+ AND is_paid = 1
+ AND ifnull(clearance_date, '') = ""
+ AND mode_of_payment in {mode_of_payments}
+ """
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py
similarity index 77%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py
index 2ad7984..d96950a 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestBankReconciliationTool(unittest.TestCase):
pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/bank_statement_import/__init__.py
similarity index 100%
rename from erpnext/accounts/doctype/bank_statement_settings/__init__.py
rename to erpnext/accounts/doctype/bank_statement_import/__init__.py
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css
new file mode 100644
index 0000000..5206540
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css
@@ -0,0 +1,3 @@
+.warnings .warning {
+ margin-bottom: 40px;
+}
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
new file mode 100644
index 0000000..ad4ff9e
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -0,0 +1,574 @@
+// Copyright (c) 2019, Frappe Technologies and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Bank Statement Import", {
+ setup(frm) {
+ frappe.realtime.on("data_import_refresh", ({ data_import }) => {
+ frm.import_in_progress = false;
+ if (data_import !== frm.doc.name) return;
+ frappe.model.clear_doc("Bank Statement Import", frm.doc.name);
+ frappe.model
+ .with_doc("Bank Statement Import", frm.doc.name)
+ .then(() => {
+ frm.refresh();
+ });
+ });
+ frappe.realtime.on("data_import_progress", (data) => {
+ frm.import_in_progress = true;
+ if (data.data_import !== frm.doc.name) {
+ return;
+ }
+ let percent = Math.floor((data.current * 100) / data.total);
+ let seconds = Math.floor(data.eta);
+ let minutes = Math.floor(data.eta / 60);
+ let eta_message =
+ // prettier-ignore
+ seconds < 60
+ ? __('About {0} seconds remaining', [seconds])
+ : minutes === 1
+ ? __('About {0} minute remaining', [minutes])
+ : __('About {0} minutes remaining', [minutes]);
+
+ let message;
+ if (data.success) {
+ let message_args = [data.current, data.total, eta_message];
+ message =
+ frm.doc.import_type === "Insert New Records"
+ ? __("Importing {0} of {1}, {2}", message_args)
+ : __("Updating {0} of {1}, {2}", message_args);
+ }
+ if (data.skipping) {
+ message = __(
+ "Skipping {0} of {1}, {2}",
+ [
+ data.current,
+ data.total,
+ eta_message,
+ ]
+ );
+ }
+ frm.dashboard.show_progress(
+ __("Import Progress"),
+ percent,
+ message
+ );
+ frm.page.set_indicator(__("In Progress"), "orange");
+
+ // hide progress when complete
+ if (data.current === data.total) {
+ setTimeout(() => {
+ frm.dashboard.hide();
+ frm.refresh();
+ }, 2000);
+ }
+ });
+
+ frm.set_query("reference_doctype", () => {
+ return {
+ filters: {
+ name: ["in", frappe.boot.user.can_import],
+ },
+ };
+ });
+
+ frm.get_field("import_file").df.options = {
+ restrictions: {
+ allowed_file_types: [".csv", ".xls", ".xlsx"],
+ },
+ };
+
+ frm.has_import_file = () => {
+ return frm.doc.import_file || frm.doc.google_sheets_url;
+ };
+ },
+
+ refresh(frm) {
+ frm.page.hide_icon_group();
+ frm.trigger("update_indicators");
+ frm.trigger("import_file");
+ frm.trigger("show_import_log");
+ frm.trigger("show_import_warnings");
+ frm.trigger("toggle_submit_after_import");
+ frm.trigger("show_import_status");
+ frm.trigger("show_report_error_button");
+
+ if (frm.doc.status === "Partial Success") {
+ frm.add_custom_button(__("Export Errored Rows"), () =>
+ frm.trigger("export_errored_rows")
+ );
+ }
+
+ if (frm.doc.status.includes("Success")) {
+ frm.add_custom_button(
+ __("Go to {0} List", [frm.doc.reference_doctype]),
+ () => frappe.set_route("List", frm.doc.reference_doctype)
+ );
+ }
+ },
+
+ onload_post_render(frm) {
+ frm.trigger("update_primary_action");
+ },
+
+ update_primary_action(frm) {
+ if (frm.is_dirty()) {
+ frm.enable_save();
+ return;
+ }
+ frm.disable_save();
+ if (frm.doc.status !== "Success") {
+ if (!frm.is_new() && frm.has_import_file()) {
+ let label =
+ frm.doc.status === "Pending"
+ ? __("Start Import")
+ : __("Retry");
+ frm.page.set_primary_action(label, () =>
+ frm.events.start_import(frm)
+ );
+ } else {
+ frm.page.set_primary_action(__("Save"), () => frm.save());
+ }
+ }
+ },
+
+ update_indicators(frm) {
+ const indicator = frappe.get_indicator(frm.doc);
+ if (indicator) {
+ frm.page.set_indicator(indicator[0], indicator[1]);
+ } else {
+ frm.page.clear_indicator();
+ }
+ },
+
+ show_import_status(frm) {
+ let import_log = JSON.parse(frm.doc.import_log || "[]");
+ let successful_records = import_log.filter((log) => log.success);
+ let failed_records = import_log.filter((log) => !log.success);
+ if (successful_records.length === 0) return;
+
+ let message;
+ if (failed_records.length === 0) {
+ let message_args = [successful_records.length];
+ if (frm.doc.import_type === "Insert New Records") {
+ message =
+ successful_records.length > 1
+ ? __("Successfully imported {0} records.", message_args)
+ : __("Successfully imported {0} record.", message_args);
+ } else {
+ message =
+ successful_records.length > 1
+ ? __("Successfully updated {0} records.", message_args)
+ : __("Successfully updated {0} record.", message_args);
+ }
+ } else {
+ let message_args = [successful_records.length, import_log.length];
+ if (frm.doc.import_type === "Insert New Records") {
+ message =
+ successful_records.length > 1
+ ? __(
+ "Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+ message_args
+ )
+ : __(
+ "Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+ message_args
+ );
+ } else {
+ message =
+ successful_records.length > 1
+ ? __(
+ "Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+ message_args
+ )
+ : __(
+ "Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+ message_args
+ );
+ }
+ }
+ frm.dashboard.set_headline(message);
+ },
+
+ show_report_error_button(frm) {
+ if (frm.doc.status === "Error") {
+ frappe.db
+ .get_list("Error Log", {
+ filters: { method: frm.doc.name },
+ fields: ["method", "error"],
+ order_by: "creation desc",
+ limit: 1,
+ })
+ .then((result) => {
+ if (result.length > 0) {
+ frm.add_custom_button("Report Error", () => {
+ let fake_xhr = {
+ responseText: JSON.stringify({
+ exc: result[0].error,
+ }),
+ };
+ frappe.request.report_error(fake_xhr, {});
+ });
+ }
+ });
+ }
+ },
+
+ start_import(frm) {
+ frm.call({
+ method: "form_start_import",
+ args: { data_import: frm.doc.name },
+ btn: frm.page.btn_primary,
+ }).then((r) => {
+ if (r.message === true) {
+ frm.disable_save();
+ }
+ });
+ },
+
+ download_template() {
+ let method =
+ "/api/method/frappe.core.doctype.data_import.data_import.download_template";
+
+ open_url_post(method, {
+ doctype: "Bank Transaction",
+ export_records: "5_records",
+ export_fields: {
+ "Bank Transaction": [
+ "date",
+ "deposit",
+ "withdrawal",
+ "description",
+ "reference_number",
+ ],
+ },
+ });
+ },
+
+ reference_doctype(frm) {
+ frm.trigger("toggle_submit_after_import");
+ },
+
+ toggle_submit_after_import(frm) {
+ frm.toggle_display("submit_after_import", false);
+ let doctype = frm.doc.reference_doctype;
+ if (doctype) {
+ frappe.model.with_doctype(doctype, () => {
+ let meta = frappe.get_meta(doctype);
+ frm.toggle_display("submit_after_import", meta.is_submittable);
+ });
+ }
+ },
+
+ google_sheets_url(frm) {
+ if (!frm.is_dirty()) {
+ frm.trigger("import_file");
+ } else {
+ frm.trigger("update_primary_action");
+ }
+ },
+
+ refresh_google_sheet(frm) {
+ frm.trigger("import_file");
+ },
+
+ import_file(frm) {
+ frm.toggle_display("section_import_preview", frm.has_import_file());
+ if (!frm.has_import_file()) {
+ frm.get_field("import_preview").$wrapper.empty();
+ return;
+ } else {
+ frm.trigger("update_primary_action");
+ }
+
+ // load import preview
+ frm.get_field("import_preview").$wrapper.empty();
+ $('<span class="text-muted">')
+ .html(__("Loading import file..."))
+ .appendTo(frm.get_field("import_preview").$wrapper);
+
+ frm.call({
+ method: "get_preview_from_template",
+ args: {
+ data_import: frm.doc.name,
+ import_file: frm.doc.import_file,
+ google_sheets_url: frm.doc.google_sheets_url,
+ },
+ error_handlers: {
+ TimestampMismatchError() {
+ // ignore this error
+ },
+ },
+ }).then((r) => {
+ let preview_data = r.message;
+ frm.events.show_import_preview(frm, preview_data);
+ frm.events.show_import_warnings(frm, preview_data);
+ });
+ },
+ // method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
+
+ show_import_preview(frm, preview_data) {
+ let import_log = JSON.parse(frm.doc.import_log || "[]");
+
+ if (
+ frm.import_preview &&
+ frm.import_preview.doctype === frm.doc.reference_doctype
+ ) {
+ frm.import_preview.preview_data = preview_data;
+ frm.import_preview.import_log = import_log;
+ frm.import_preview.refresh();
+ return;
+ }
+
+ frappe.require("/assets/js/data_import_tools.min.js", () => {
+ frm.import_preview = new frappe.data_import.ImportPreview({
+ wrapper: frm.get_field("import_preview").$wrapper,
+ doctype: frm.doc.reference_doctype,
+ preview_data,
+ import_log,
+ frm,
+ events: {
+ remap_column(changed_map) {
+ let template_options = JSON.parse(
+ frm.doc.template_options || "{}"
+ );
+ template_options.column_to_field_map =
+ template_options.column_to_field_map || {};
+ Object.assign(
+ template_options.column_to_field_map,
+ changed_map
+ );
+ frm.set_value(
+ "template_options",
+ JSON.stringify(template_options)
+ );
+ frm.save().then(() => frm.trigger("import_file"));
+ },
+ },
+ });
+ });
+ },
+
+ export_errored_rows(frm) {
+ open_url_post(
+ "/api/method/frappe.core.doctype.data_import.data_import.download_errored_template",
+ {
+ data_import_name: frm.doc.name,
+ }
+ );
+ },
+
+ show_import_warnings(frm, preview_data) {
+ let columns = preview_data.columns;
+ let warnings = JSON.parse(frm.doc.template_warnings || "[]");
+ warnings = warnings.concat(preview_data.warnings || []);
+
+ frm.toggle_display("import_warnings_section", warnings.length > 0);
+ if (warnings.length === 0) {
+ frm.get_field("import_warnings").$wrapper.html("");
+ return;
+ }
+
+ // group warnings by row
+ let warnings_by_row = {};
+ let other_warnings = [];
+ for (let warning of warnings) {
+ if (warning.row) {
+ warnings_by_row[warning.row] =
+ warnings_by_row[warning.row] || [];
+ warnings_by_row[warning.row].push(warning);
+ } else {
+ other_warnings.push(warning);
+ }
+ }
+
+ let html = "";
+ html += Object.keys(warnings_by_row)
+ .map((row_number) => {
+ let message = warnings_by_row[row_number]
+ .map((w) => {
+ if (w.field) {
+ let label =
+ w.field.label +
+ (w.field.parent !== frm.doc.reference_doctype
+ ? ` (${w.field.parent})`
+ : "");
+ return `<li>${label}: ${w.message}</li>`;
+ }
+ return `<li>${w.message}</li>`;
+ })
+ .join("");
+ return `
+ <div class="warning" data-row="${row_number}">
+ <h5 class="text-uppercase">${__("Row {0}", [row_number])}</h5>
+ <div class="body"><ul>${message}</ul></div>
+ </div>
+ `;
+ })
+ .join("");
+
+ html += other_warnings
+ .map((warning) => {
+ let header = "";
+ if (warning.col) {
+ let column_number = `<span class="text-uppercase">${__(
+ "Column {0}",
+ [warning.col]
+ )}</span>`;
+ let column_header = columns[warning.col].header_title;
+ header = `${column_number} (${column_header})`;
+ }
+ return `
+ <div class="warning" data-col="${warning.col}">
+ <h5>${header}</h5>
+ <div class="body">${warning.message}</div>
+ </div>
+ `;
+ })
+ .join("");
+ frm.get_field("import_warnings").$wrapper.html(`
+ <div class="row">
+ <div class="col-sm-10 warnings">${html}</div>
+ </div>
+ `);
+ },
+
+ show_failed_logs(frm) {
+ frm.trigger("show_import_log");
+ },
+
+ show_import_log(frm) {
+ let import_log = JSON.parse(frm.doc.import_log || "[]");
+ let logs = import_log;
+ frm.toggle_display("import_log", false);
+ frm.toggle_display("import_log_section", logs.length > 0);
+
+ if (logs.length === 0) {
+ frm.get_field("import_log_preview").$wrapper.empty();
+ return;
+ }
+
+ let rows = logs
+ .map((log) => {
+ let html = "";
+ if (log.success) {
+ if (frm.doc.import_type === "Insert New Records") {
+ html = __(
+ "Successfully imported {0}", [
+ `<span class="underline">${frappe.utils.get_form_link(
+ frm.doc.reference_doctype,
+ log.docname,
+ true
+ )}<span>`,
+ ]
+ );
+ } else {
+ html = __(
+ "Successfully updated {0}", [
+ `<span class="underline">${frappe.utils.get_form_link(
+ frm.doc.reference_doctype,
+ log.docname,
+ true
+ )}<span>`,
+ ]
+ );
+ }
+ } else {
+ let messages = log.messages
+ .map(JSON.parse)
+ .map((m) => {
+ let title = m.title
+ ? `<strong>${m.title}</strong>`
+ : "";
+ let message = m.message
+ ? `<div>${m.message}</div>`
+ : "";
+ return title + message;
+ })
+ .join("");
+ let id = frappe.dom.get_unique_id();
+ html = `${messages}
+ <button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#${id}" aria-expanded="false" aria-controls="${id}" style="margin-top: 15px;">
+ ${__("Show Traceback")}
+ </button>
+ <div class="collapse" id="${id}" style="margin-top: 15px;">
+ <div class="well">
+ <pre>${log.exception}</pre>
+ </div>
+ </div>`;
+ }
+ let indicator_color = log.success ? "green" : "red";
+ let title = log.success ? __("Success") : __("Failure");
+
+ if (frm.doc.show_failed_logs && log.success) {
+ return "";
+ }
+
+ return `<tr>
+ <td>${log.row_indexes.join(", ")}</td>
+ <td>
+ <div class="indicator ${indicator_color}">${title}</div>
+ </td>
+ <td>
+ ${html}
+ </td>
+ </tr>`;
+ })
+ .join("");
+
+ if (!rows && frm.doc.show_failed_logs) {
+ rows = `<tr><td class="text-center text-muted" colspan=3>
+ ${__("No failed logs")}
+ </td></tr>`;
+ }
+
+ frm.get_field("import_log_preview").$wrapper.html(`
+ <table class="table table-bordered">
+ <tr class="text-muted">
+ <th width="10%">${__("Row Number")}</th>
+ <th width="10%">${__("Status")}</th>
+ <th width="80%">${__("Message")}</th>
+ </tr>
+ ${rows}
+ </table>
+ `);
+ },
+
+ show_missing_link_values(frm, missing_link_values) {
+ let can_be_created_automatically = missing_link_values.every(
+ (d) => d.has_one_mandatory_field
+ );
+
+ let html = missing_link_values
+ .map((d) => {
+ let doctype = d.doctype;
+ let values = d.missing_values;
+ return `
+ <h5>${doctype}</h5>
+ <ul>${values.map((v) => `<li>${v}</li>`).join("")}</ul>
+ `;
+ })
+ .join("");
+
+ if (can_be_created_automatically) {
+ // prettier-ignore
+ let message = __('There are some linked records which needs to be created before we can import your file. Do you want to create the following missing records automatically?');
+ frappe.confirm(message + html, () => {
+ frm.call("create_missing_link_values", {
+ missing_link_values,
+ }).then((r) => {
+ let records = r.message;
+ frappe.msgprint(__(
+ "Created {0} records successfully.", [
+ records.length,
+ ]
+ ));
+ });
+ });
+ } else {
+ frappe.msgprint(
+ // prettier-ignore
+ __('The following records needs to be created before we can import your file.') + html
+ );
+ }
+ },
+});
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
new file mode 100644
index 0000000..5e913cc
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
@@ -0,0 +1,227 @@
+{
+ "actions": [],
+ "autoname": "format:Bank Statement Import on {creation}",
+ "beta": 1,
+ "creation": "2019-08-04 14:16:08.318714",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "bank_account",
+ "bank",
+ "column_break_4",
+ "google_sheets_url",
+ "refresh_google_sheet",
+ "html_5",
+ "import_file",
+ "download_template",
+ "status",
+ "template_options",
+ "import_warnings_section",
+ "template_warnings",
+ "import_warnings",
+ "section_import_preview",
+ "import_preview",
+ "import_log_section",
+ "import_log",
+ "show_failed_logs",
+ "import_log_preview",
+ "reference_doctype",
+ "import_type",
+ "submit_after_import",
+ "mute_emails"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "fieldname": "bank_account",
+ "fieldtype": "Link",
+ "label": "Bank Account",
+ "options": "Bank Account",
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "depends_on": "eval:doc.bank_account",
+ "fetch_from": "bank_account.bank",
+ "fieldname": "bank",
+ "fieldtype": "Link",
+ "label": "Bank",
+ "options": "Bank",
+ "read_only": 1,
+ "set_only_once": 1
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "download_template",
+ "fieldtype": "Button",
+ "label": "Download Template"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "import_file",
+ "fieldtype": "Attach",
+ "in_list_view": 1,
+ "label": "Import File"
+ },
+ {
+ "fieldname": "import_preview",
+ "fieldtype": "HTML",
+ "label": "Import Preview"
+ },
+ {
+ "fieldname": "section_import_preview",
+ "fieldtype": "Section Break",
+ "label": "Preview"
+ },
+ {
+ "fieldname": "template_options",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Template Options",
+ "options": "JSON",
+ "read_only": 1
+ },
+ {
+ "fieldname": "import_log",
+ "fieldtype": "Code",
+ "label": "Import Log",
+ "options": "JSON"
+ },
+ {
+ "fieldname": "import_log_section",
+ "fieldtype": "Section Break",
+ "label": "Import Log"
+ },
+ {
+ "fieldname": "import_log_preview",
+ "fieldtype": "HTML",
+ "label": "Import Log Preview"
+ },
+ {
+ "default": "Pending",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Status",
+ "options": "Pending\nSuccess\nPartial Success\nError",
+ "read_only": 1
+ },
+ {
+ "fieldname": "template_warnings",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Template Warnings",
+ "options": "JSON"
+ },
+ {
+ "fieldname": "import_warnings_section",
+ "fieldtype": "Section Break",
+ "label": "Import File Errors and Warnings"
+ },
+ {
+ "fieldname": "import_warnings",
+ "fieldtype": "HTML",
+ "label": "Import Warnings"
+ },
+ {
+ "default": "0",
+ "fieldname": "show_failed_logs",
+ "fieldtype": "Check",
+ "label": "Show Failed Logs"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal && !doc.import_file",
+ "fieldname": "html_5",
+ "fieldtype": "HTML",
+ "options": "<h5 class=\"text-muted uppercase\">Or</h5>"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal && !doc.import_file\n",
+ "description": "Must be a publicly accessible Google Sheets URL",
+ "fieldname": "google_sheets_url",
+ "fieldtype": "Data",
+ "label": "Import from Google Sheets"
+ },
+ {
+ "depends_on": "eval:doc.google_sheets_url && !doc.__unsaved",
+ "fieldname": "refresh_google_sheet",
+ "fieldtype": "Button",
+ "label": "Refresh Google Sheet"
+ },
+ {
+ "default": "Bank Transaction",
+ "fieldname": "reference_doctype",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "Document Type",
+ "options": "DocType",
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "default": "Insert New Records",
+ "fieldname": "import_type",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "Import Type",
+ "options": "\nInsert New Records\nUpdate Existing Records",
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "submit_after_import",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Submit After Import",
+ "set_only_once": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "mute_emails",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Don't Send Emails",
+ "set_only_once": 1
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "hide_toolbar": 1,
+ "links": [],
+ "modified": "2021-02-10 19:29:59.027325",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Bank Statement Import",
+ "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/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
new file mode 100644
index 0000000..9f41b13
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
@@ -0,0 +1,205 @@
+# -*- 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
+import re
+
+import openpyxl
+from openpyxl.styles import Font
+from openpyxl.utils import get_column_letter
+from six import string_types
+
+import frappe
+from frappe.core.doctype.data_import.importer import Importer, ImportFile
+from frappe.utils.background_jobs import enqueue
+from frappe.utils.xlsxutils import handle_html, ILLEGAL_CHARACTERS_RE
+from frappe import _
+
+from frappe.core.doctype.data_import.data_import import DataImport
+
+class BankStatementImport(DataImport):
+ def __init__(self, *args, **kwargs):
+ super(BankStatementImport, self).__init__(*args, **kwargs)
+
+ def validate(self):
+ doc_before_save = self.get_doc_before_save()
+ if (
+ not (self.import_file or self.google_sheets_url)
+ or (doc_before_save and doc_before_save.import_file != self.import_file)
+ or (doc_before_save and doc_before_save.google_sheets_url != self.google_sheets_url)
+ ):
+
+ template_options_dict = {}
+ column_to_field_map = {}
+ bank = frappe.get_doc("Bank", self.bank)
+ for i in bank.bank_transaction_mapping:
+ column_to_field_map[i.file_field] = i.bank_transaction_field
+ template_options_dict["column_to_field_map"] = column_to_field_map
+ self.template_options = json.dumps(template_options_dict)
+
+ self.template_warnings = ""
+
+ self.validate_import_file()
+ self.validate_google_sheets_url()
+
+ def start_import(self):
+
+ from frappe.core.page.background_jobs.background_jobs import get_info
+ from frappe.utils.scheduler import is_scheduler_inactive
+
+ if is_scheduler_inactive() and not frappe.flags.in_test:
+ frappe.throw(
+ _("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")
+ )
+
+ enqueued_jobs = [d.get("job_name") for d in get_info()]
+
+ if self.name not in enqueued_jobs:
+ enqueue(
+ start_import,
+ queue="default",
+ timeout=6000,
+ event="data_import",
+ job_name=self.name,
+ data_import=self.name,
+ bank_account=self.bank_account,
+ import_file_path=self.import_file,
+ bank=self.bank,
+ template_options=self.template_options,
+ now=frappe.conf.developer_mode or frappe.flags.in_test,
+ )
+ return True
+
+ return False
+
+@frappe.whitelist()
+def get_preview_from_template(data_import, import_file=None, google_sheets_url=None):
+ return frappe.get_doc("Bank Statement Import", data_import).get_preview_from_template(
+ import_file, google_sheets_url
+ )
+
+@frappe.whitelist()
+def form_start_import(data_import):
+ return frappe.get_doc("Bank Statement Import", data_import).start_import()
+
+@frappe.whitelist()
+def download_errored_template(data_import_name):
+ data_import = frappe.get_doc("Bank Statement Import", data_import_name)
+ data_import.export_errored_rows()
+
+def start_import(data_import, bank_account, import_file_path, bank, template_options):
+ """This method runs in background job"""
+
+ update_mapping_db(bank, template_options)
+
+ data_import = frappe.get_doc("Bank Statement Import", data_import)
+
+ import_file = ImportFile("Bank Transaction", file = import_file_path, import_type="Insert New Records")
+ data = import_file.raw_data
+
+ add_bank_account(data, bank_account)
+ write_files(import_file, data)
+
+ try:
+ i = Importer(data_import.reference_doctype, data_import=data_import)
+ i.import_data()
+ except Exception:
+ frappe.db.rollback()
+ data_import.db_set("status", "Error")
+ frappe.log_error(title=data_import.name)
+ finally:
+ frappe.flags.in_import = False
+
+ frappe.publish_realtime("data_import_refresh", {"data_import": data_import.name})
+
+def update_mapping_db(bank, template_options):
+ bank = frappe.get_doc("Bank", bank)
+ for d in bank.bank_transaction_mapping:
+ d.delete()
+
+ for d in json.loads(template_options)["column_to_field_map"].items():
+ bank.append("bank_transaction_mapping", {"bank_transaction_field": d[1] ,"file_field": d[0]} )
+
+ bank.save()
+
+def add_bank_account(data, bank_account):
+ bank_account_loc = None
+ if "Bank Account" not in data[0]:
+ data[0].append("Bank Account")
+ else:
+ for loc, header in enumerate(data[0]):
+ if header == "Bank Account":
+ bank_account_loc = loc
+
+ for row in data[1:]:
+ if bank_account_loc:
+ row[bank_account_loc] = bank_account
+ else:
+ row.append(bank_account)
+
+def write_files(import_file, data):
+ full_file_path = import_file.file_doc.get_full_path()
+ parts = import_file.file_doc.get_extension()
+ extension = parts[1]
+ extension = extension.lstrip(".")
+
+ if extension == "csv":
+ with open(full_file_path, 'w', newline='') as file:
+ writer = csv.writer(file)
+ writer.writerows(data)
+ elif extension == "xlsx" or "xls":
+ write_xlsx(data, "trans", file_path = full_file_path)
+
+def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None):
+ # from xlsx utils with changes
+ column_widths = column_widths or []
+ if wb is None:
+ wb = openpyxl.Workbook(write_only=True)
+
+ ws = wb.create_sheet(sheet_name, 0)
+
+ for i, column_width in enumerate(column_widths):
+ if column_width:
+ ws.column_dimensions[get_column_letter(i + 1)].width = column_width
+
+ row1 = ws.row_dimensions[1]
+ row1.font = Font(name='Calibri', bold=True)
+
+ 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']):
+ value = handle_html(item)
+ else:
+ value = item
+
+ if isinstance(item, string_types) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
+ # Remove illegal characters from the string
+ value = re.sub(ILLEGAL_CHARACTERS_RE, '', value)
+
+ clean_row.append(value)
+
+ ws.append(clean_row)
+
+ wb.save(file_path)
+ return True
+
+@frappe.whitelist()
+def upload_bank_statement(**args):
+ args = frappe._dict(args)
+ bsi = frappe.new_doc("Bank Statement Import")
+
+ if args.company:
+ bsi.update({
+ "company": args.company,
+ })
+
+ if args.bank_account:
+ bsi.update({
+ "bank_account": args.bank_account
+ })
+
+ return bsi
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import_list.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import_list.js
new file mode 100644
index 0000000..6c75402
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import_list.js
@@ -0,0 +1,36 @@
+let imports_in_progress = [];
+
+frappe.listview_settings['Bank Statement Import'] = {
+ onload(listview) {
+ frappe.realtime.on('data_import_progress', data => {
+ if (!imports_in_progress.includes(data.data_import)) {
+ imports_in_progress.push(data.data_import);
+ }
+ });
+ frappe.realtime.on('data_import_refresh', data => {
+ imports_in_progress = imports_in_progress.filter(
+ d => d !== data.data_import
+ );
+ listview.refresh();
+ });
+ },
+ get_indicator: function(doc) {
+ var colors = {
+ 'Pending': 'orange',
+ 'Not Started': 'orange',
+ 'Partial Success': 'orange',
+ 'Success': 'green',
+ 'In Progress': 'orange',
+ 'Error': 'red'
+ };
+ let status = doc.status;
+ if (imports_in_progress.includes(doc.name)) {
+ status = 'In Progress';
+ }
+ if (status == 'Pending') {
+ status = 'Not Started';
+ }
+ return [__(status), colors[status], 'status,=,' + doc.status];
+ },
+ hide_name_column: true
+};
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
new file mode 100644
index 0000000..cd58314
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestBankStatementImport(unittest.TestCase):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.js b/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.js
deleted file mode 100644
index 46aa4f2..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2017, sathishpy@gmail.com and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Bank Statement Settings', {
- refresh: function(frm) {
-
- }
-});
diff --git a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.json b/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.json
deleted file mode 100644
index 53fbf7d..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.json
+++ /dev/null
@@ -1,272 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "beta": 0,
- "creation": "2017-11-13 13:38:10.863592",
- "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": "bank",
- "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": "Bank Account",
- "length": 0,
- "no_copy": 0,
- "options": "Bank",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "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,
- "default": "'%d/%m/%Y'",
- "fieldname": "date_format",
- "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": "Date Format",
- "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_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "statement_header_mapping",
- "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": "Statement Header Mapping",
- "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_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "header_items",
- "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": "Statement Headers",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Settings Item",
- "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_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "transaction_data_mapping",
- "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": "Transaction Data Mapping",
- "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_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mapped_items",
- "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": "Mapped Items",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Transaction Settings Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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-04-07 18:57:04.048423",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Settings",
- "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": "System Manager",
- "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": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.py b/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.py
deleted file mode 100644
index 6c4dd1b..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementSettings(Document):
- def autoname(self):
- self.name = self.bank + "-Statement-Settings"
diff --git a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.js b/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.js
deleted file mode 100644
index f2381c0..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Bank Statement Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Bank Statement Settings
- () => frappe.tests.make('Bank Statement Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.py b/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.py
deleted file mode 100644
index aa7fe83..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestBankStatementSettings(unittest.TestCase):
- pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.json b/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.json
deleted file mode 100644
index 7c93f26..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-01-08 00:16:42.762980",
- "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": "mapped_header",
- "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": "Mapped Header",
- "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": 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": "stmt_header",
- "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": "Bank Header",
- "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": 1,
- "max_attachments": 0,
- "modified": "2018-01-08 00:19:14.841134",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Settings Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.py b/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.py
deleted file mode 100644
index 9438e9a..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementSettingsItem(Document):
- pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.js b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.js
deleted file mode 100644
index 736ed35..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2017, sathishpy@gmail.com and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Bank Statement Transaction Entry', {
- setup: function(frm) {
- frm.events.account_filters(frm)
- frm.events.invoice_filter(frm)
- },
- refresh: function(frm) {
- frm.set_df_property("bank_account", "read_only", frm.doc.__islocal ? 0 : 1);
- frm.set_df_property("from_date", "read_only", frm.doc.__islocal ? 0 : 1);
- frm.set_df_property("to_date", "read_only", frm.doc.__islocal ? 0 : 1);
- },
- invoke_doc_function(frm, method) {
- frappe.call({
- doc: frm.doc,
- method: method,
- callback: function(r) {
- if(!r.exe) {
- frm.refresh_fields();
- }
- }
- });
- },
- account_filters: function(frm) {
- frm.fields_dict['bank_account'].get_query = function(doc, dt, dn) {
- return {
- filters:[
- ["Account", "account_type", "in", ["Bank"]]
- ]
- }
- };
- frm.fields_dict['receivable_account'].get_query = function(doc, dt, dn) {
- return {
- filters: {"account_type": "Receivable"}
- }
- };
- frm.fields_dict['payable_account'].get_query = function(doc, dt, dn) {
- return {
- filters: {"account_type": "Payable"}
- }
- };
- },
-
- invoice_filter: function(frm) {
- frm.set_query("invoice", "payment_invoice_items", function(doc, cdt, cdn) {
- let row = locals[cdt][cdn]
- if (row.party_type == "Customer") {
- return {
- filters:[[row.invoice_type, "customer", "in", [row.party]],
- [row.invoice_type, "status", "!=", "Cancelled" ],
- [row.invoice_type, "posting_date", "<", row.transaction_date ],
- [row.invoice_type, "outstanding_amount", ">", 0 ]]
- }
- } else if (row.party_type == "Supplier") {
- return {
- filters:[[row.invoice_type, "supplier", "in", [row.party]],
- [row.invoice_type, "status", "!=", "Cancelled" ],
- [row.invoice_type, "posting_date", "<", row.transaction_date ],
- [row.invoice_type, "outstanding_amount", ">", 0 ]]
- }
- }
- });
- },
-
- match_invoices: function(frm) {
- frm.events.invoke_doc_function(frm, "populate_matching_invoices");
- },
- create_payments: function(frm) {
- frm.events.invoke_doc_function(frm, "create_payment_entries");
- },
- submit_payments: function(frm) {
- frm.events.invoke_doc_function(frm, "submit_payment_entries");
- },
-});
-
-
-frappe.ui.form.on('Bank Statement Transaction Invoice Item', {
- party_type: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- if (row.party_type == "Customer") {
- row.invoice_type = "Sales Invoice";
- } else if (row.party_type == "Supplier") {
- row.invoice_type = "Purchase Invoice";
- } else if (row.party_type == "Account") {
- row.invoice_type = "Journal Entry";
- }
- refresh_field("invoice_type", row.name, "payment_invoice_items");
-
- },
- invoice_type: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- if (row.invoice_type == "Purchase Invoice") {
- row.party_type = "Supplier";
- } else if (row.invoice_type == "Sales Invoice") {
- row.party_type = "Customer";
- }
- refresh_field("party_type", row.name, "payment_invoice_items");
- }
-});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.json b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.json
deleted file mode 100644
index fb80169..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.json
+++ /dev/null
@@ -1,792 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "beta": 0,
- "creation": "2017-11-07 13:48:13.123185",
- "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": "bank_account",
- "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": "Bank Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "From 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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "To 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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bank_settings",
- "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": "Bank Statement Settings",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Settings",
- "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": "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bank",
- "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": "Bank",
- "length": 0,
- "no_copy": 0,
- "options": "Bank",
- "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": "receivable_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Receivable Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "payable_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payable Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "bank_statement",
- "fieldtype": "Attach",
- "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": "Bank Statement",
- "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": "",
- "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,
- "label": "Bank Transaction Entries",
- "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": "new_transaction_items",
- "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": "New Transactions",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Transaction Payment Item",
- "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,
- "depends_on": "eval:doc.new_transaction_items && doc.new_transaction_items.length",
- "fieldname": "section_break_9",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "match_invoices",
- "fieldtype": "Button",
- "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": "Match Transaction to Invoices",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_14",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "create_payments",
- "fieldtype": "Button",
- "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": "Create New Payment/Journal Entry",
- "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": "column_break_16",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "submit_payments",
- "fieldtype": "Button",
- "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": "Submit/Reconcile Payments",
- "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.new_transaction_items && doc.new_transaction_items.length",
- "fieldname": "section_break_18",
- "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": "Matching Invoices",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_invoice_items",
- "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": "Payment Invoice Items",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Transaction Invoice Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "reconciled_transactions",
- "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": "Reconciled Transactions",
- "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": "reconciled_transaction_items",
- "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": "Reconciled Transactions",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Transaction Payment Item",
- "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": "amended_from",
- "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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Bank Statement Transaction Entry",
- "permlevel": 0,
- "print_hide": 1,
- "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": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-14 18:04:44.170455",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Transaction Entry",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "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": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "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
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py
deleted file mode 100644
index 27dd8e4..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py
+++ /dev/null
@@ -1,443 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com 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 erpnext.accounts.utils import get_outstanding_invoices
-from frappe.utils import nowdate
-from datetime import datetime
-import csv, os, re, io
-import difflib
-import copy
-
-class BankStatementTransactionEntry(Document):
- def autoname(self):
- self.name = self.bank_account + "-" + self.from_date + "-" + self.to_date
- if self.bank:
- mapper_name = self.bank + "-Statement-Settings"
- if not frappe.db.exists("Bank Statement Settings", mapper_name):
- self.create_settings(self.bank)
- self.bank_settings = mapper_name
-
- def create_settings(self, bank):
- mapper = frappe.new_doc("Bank Statement Settings")
- mapper.bank = bank
- mapper.date_format = "%Y-%m-%d"
- mapper.bank_account = self.bank_account
- for header in ["Date", "Particulars", "Withdrawals", "Deposits", "Balance"]:
- header_item = mapper.append("header_items", {})
- header_item.mapped_header = header_item.stmt_header = header
- mapper.save()
-
- def on_update(self):
- if (not self.bank_statement):
- self.reconciled_transaction_items = self.new_transaction_items = []
- return
-
- if len(self.new_transaction_items + self.reconciled_transaction_items) == 0:
- self.populate_payment_entries()
- else:
- self.match_invoice_to_payment()
-
- def validate(self):
- if not self.new_transaction_items:
- self.populate_payment_entries()
-
- def get_statement_headers(self):
- if not self.bank_settings:
- frappe.throw(_("Bank Data mapper doesn't exist"))
- mapper_doc = frappe.get_doc("Bank Statement Settings", self.bank_settings)
- headers = {entry.mapped_header:entry.stmt_header for entry in mapper_doc.header_items}
- return headers
-
- def populate_payment_entries(self):
- if self.bank_statement is None: return
- file_url = self.bank_statement
- if (len(self.new_transaction_items + self.reconciled_transaction_items) > 0):
- frappe.throw(_("Transactions already retreived from the statement"))
-
- date_format = frappe.get_value("Bank Statement Settings", self.bank_settings, "date_format")
- if (date_format is None):
- date_format = '%Y-%m-%d'
- if self.bank_settings:
- mapped_items = frappe.get_doc("Bank Statement Settings", self.bank_settings).mapped_items
- statement_headers = self.get_statement_headers()
- transactions = get_transaction_entries(file_url, statement_headers)
- for entry in transactions:
- date = entry[statement_headers["Date"]].strip()
- #print("Processing entry DESC:{0}-W:{1}-D:{2}-DT:{3}".format(entry["Particulars"], entry["Withdrawals"], entry["Deposits"], entry["Date"]))
- if (not date): continue
- transaction_date = datetime.strptime(date, date_format).date()
- if (self.from_date and transaction_date < datetime.strptime(self.from_date, '%Y-%m-%d').date()): continue
- if (self.to_date and transaction_date > datetime.strptime(self.to_date, '%Y-%m-%d').date()): continue
- bank_entry = self.append('new_transaction_items', {})
- bank_entry.transaction_date = transaction_date
- bank_entry.description = entry[statement_headers["Particulars"]]
-
- mapped_item = next((entry for entry in mapped_items if entry.mapping_type == "Transaction" and frappe.safe_decode(entry.bank_data.lower()) in frappe.safe_decode(bank_entry.description.lower())), None)
- if (mapped_item is not None):
- bank_entry.party_type = mapped_item.mapped_data_type
- bank_entry.party = mapped_item.mapped_data
- else:
- bank_entry.party_type = "Supplier" if not entry[statement_headers["Deposits"]].strip() else "Customer"
- party_list = frappe.get_all(bank_entry.party_type, fields=["name"])
- parties = [party.name for party in party_list]
- matches = difflib.get_close_matches(frappe.safe_decode(bank_entry.description.lower()), parties, 1, 0.4)
- if len(matches) > 0: bank_entry.party = matches[0]
- bank_entry.amount = -float(entry[statement_headers["Withdrawals"]]) if not entry[statement_headers["Deposits"]].strip() else float(entry[statement_headers["Deposits"]])
- self.map_unknown_transactions()
- self.map_transactions_on_journal_entry()
-
- def map_transactions_on_journal_entry(self):
- for entry in self.new_transaction_items:
- vouchers = frappe.db.sql("""select name, posting_date from `tabJournal Entry`
- where posting_date='{0}' and total_credit={1} and cheque_no='{2}' and docstatus != 2
- """.format(entry.transaction_date, abs(entry.amount), frappe.safe_decode(entry.description)), as_dict=True)
- if (len(vouchers) == 1):
- entry.reference_name = vouchers[0].name
-
- def populate_matching_invoices(self):
- self.payment_invoice_items = []
- self.map_unknown_transactions()
- added_invoices = []
- for entry in self.new_transaction_items:
- if (not entry.party or entry.party_type == "Account"): continue
- account = self.receivable_account if entry.party_type == "Customer" else self.payable_account
- invoices = get_outstanding_invoices(entry.party_type, entry.party, account)
- transaction_date = datetime.strptime(entry.transaction_date, "%Y-%m-%d").date()
- outstanding_invoices = [invoice for invoice in invoices if invoice.posting_date <= transaction_date]
- amount = abs(entry.amount)
- matching_invoices = [invoice for invoice in outstanding_invoices if invoice.outstanding_amount == amount]
- sorted(outstanding_invoices, key=lambda k: k['posting_date'])
- for e in (matching_invoices + outstanding_invoices):
- added = next((inv for inv in added_invoices if inv == e.get('voucher_no')), None)
- if (added is not None): continue
- ent = self.append('payment_invoice_items', {})
- ent.transaction_date = entry.transaction_date
- ent.payment_description = frappe.safe_decode(entry.description)
- ent.party_type = entry.party_type
- ent.party = entry.party
- ent.invoice = e.get('voucher_no')
- added_invoices += [ent.invoice]
- ent.invoice_type = "Sales Invoice" if entry.party_type == "Customer" else "Purchase Invoice"
- ent.invoice_date = e.get('posting_date')
- ent.outstanding_amount = e.get('outstanding_amount')
- ent.allocated_amount = min(float(e.get('outstanding_amount')), amount)
- amount -= float(e.get('outstanding_amount'))
- if (amount <= 5): break
- self.match_invoice_to_payment()
- self.populate_matching_vouchers()
- self.map_transactions_on_journal_entry()
-
- def match_invoice_to_payment(self):
- added_payments = []
- for entry in self.new_transaction_items:
- if (not entry.party or entry.party_type == "Account"): continue
- entry.account = self.receivable_account if entry.party_type == "Customer" else self.payable_account
- amount = abs(entry.amount)
- payment, matching_invoices = None, []
- for inv_entry in self.payment_invoice_items:
- if (inv_entry.payment_description != frappe.safe_decode(entry.description) or inv_entry.transaction_date != entry.transaction_date): continue
- if (inv_entry.party != entry.party): continue
- matching_invoices += [inv_entry.invoice_type + "|" + inv_entry.invoice]
- payment = get_payments_matching_invoice(inv_entry.invoice, entry.amount, entry.transaction_date)
- doc = frappe.get_doc(inv_entry.invoice_type, inv_entry.invoice)
- inv_entry.invoice_date = doc.posting_date
- inv_entry.outstanding_amount = doc.outstanding_amount
- inv_entry.allocated_amount = min(float(doc.outstanding_amount), amount)
- amount -= inv_entry.allocated_amount
- if (amount < 0): break
-
- amount = abs(entry.amount)
- if (payment is None):
- order_doctype = "Sales Order" if entry.party_type=="Customer" else "Purchase Order"
- from erpnext.controllers.accounts_controller import get_advance_payment_entries
- payment_entries = get_advance_payment_entries(entry.party_type, entry.party, entry.account, order_doctype, against_all_orders=True)
- payment_entries += self.get_matching_payments(entry.party, amount, entry.transaction_date)
- payment = next((payment for payment in payment_entries if payment.amount == amount and payment not in added_payments), None)
- if (payment is None):
- print("Failed to find payments for {0}:{1}".format(entry.party, amount))
- continue
- added_payments += [payment]
- entry.reference_type = payment.reference_type
- entry.reference_name = payment.reference_name
- entry.mode_of_payment = "Wire Transfer"
- entry.outstanding_amount = min(amount, 0)
- if (entry.payment_reference is None):
- entry.payment_reference = frappe.safe_decode(entry.description)
- entry.invoices = ",".join(matching_invoices)
- #print("Matching payment is {0}:{1}".format(entry.reference_type, entry.reference_name))
-
- def get_matching_payments(self, party, amount, pay_date):
- query = """select 'Payment Entry' as reference_type, name as reference_name, paid_amount as amount
- from `tabPayment Entry` where party='{0}' and paid_amount={1} and posting_date='{2}' and docstatus != 2
- """.format(party, amount, pay_date)
- matching_payments = frappe.db.sql(query, as_dict=True)
- return matching_payments
-
- def map_unknown_transactions(self):
- for entry in self.new_transaction_items:
- if (entry.party): continue
- inv_type = "Sales Invoice" if (entry.amount > 0) else "Purchase Invoice"
- party_type = "customer" if (entry.amount > 0) else "supplier"
-
- query = """select posting_date, name, {0}, outstanding_amount
- from `tab{1}` where ROUND(outstanding_amount)={2} and posting_date < '{3}'
- """.format(party_type, inv_type, round(abs(entry.amount)), entry.transaction_date)
- invoices = frappe.db.sql(query, as_dict = True)
- if(len(invoices) > 0):
- entry.party = invoices[0].get(party_type)
-
- def populate_matching_vouchers(self):
- for entry in self.new_transaction_items:
- if (not entry.party or entry.reference_name): continue
- print("Finding matching voucher for {0}".format(frappe.safe_decode(entry.description)))
- amount = abs(entry.amount)
- invoices = []
- vouchers = get_matching_journal_entries(self.from_date, self.to_date, entry.party, self.bank_account, amount)
- if len(vouchers) == 0: continue
- for voucher in vouchers:
- added = next((entry.invoice for entry in self.payment_invoice_items if entry.invoice == voucher.voucher_no), None)
- if (added):
- print("Found voucher {0}".format(added))
- continue
- print("Adding voucher {0} {1} {2}".format(voucher.voucher_no, voucher.posting_date, voucher.debit))
- ent = self.append('payment_invoice_items', {})
- ent.invoice_date = voucher.posting_date
- ent.invoice_type = "Journal Entry"
- ent.invoice = voucher.voucher_no
- ent.payment_description = frappe.safe_decode(entry.description)
- ent.allocated_amount = max(voucher.debit, voucher.credit)
-
- invoices += [ent.invoice_type + "|" + ent.invoice]
- entry.reference_type = "Journal Entry"
- entry.mode_of_payment = "Wire Transfer"
- entry.reference_name = ent.invoice
- #entry.account = entry.party
- entry.invoices = ",".join(invoices)
- break
-
-
- def create_payment_entries(self):
- for payment_entry in self.new_transaction_items:
- if (not payment_entry.party): continue
- if (payment_entry.reference_name): continue
- print("Creating payment entry for {0}".format(frappe.safe_decode(payment_entry.description)))
- if (payment_entry.party_type == "Account"):
- payment = self.create_journal_entry(payment_entry)
- invoices = [payment.doctype + "|" + payment.name]
- payment_entry.invoices = ",".join(invoices)
- else:
- payment = self.create_payment_entry(payment_entry)
- invoices = [entry.reference_doctype + "|" + entry.reference_name for entry in payment.references if entry is not None]
- payment_entry.invoices = ",".join(invoices)
- payment_entry.mode_of_payment = payment.mode_of_payment
- payment_entry.account = self.receivable_account if payment_entry.party_type == "Customer" else self.payable_account
- payment_entry.reference_name = payment.name
- payment_entry.reference_type = payment.doctype
- frappe.msgprint(_("Successfully created payment entries"))
-
- def create_payment_entry(self, pe):
- payment = frappe.new_doc("Payment Entry")
- payment.posting_date = pe.transaction_date
- payment.payment_type = "Receive" if pe.party_type == "Customer" else "Pay"
- payment.mode_of_payment = "Wire Transfer"
- payment.party_type = pe.party_type
- payment.party = pe.party
- payment.paid_to = self.bank_account if pe.party_type == "Customer" else self.payable_account
- payment.paid_from = self.receivable_account if pe.party_type == "Customer" else self.bank_account
- payment.paid_amount = payment.received_amount = abs(pe.amount)
- payment.reference_no = pe.description
- payment.reference_date = pe.transaction_date
- payment.save()
- for inv_entry in self.payment_invoice_items:
- if (pe.description != inv_entry.payment_description or pe.transaction_date != inv_entry.transaction_date): continue
- if (pe.party != inv_entry.party): continue
- reference = payment.append("references", {})
- reference.reference_doctype = inv_entry.invoice_type
- reference.reference_name = inv_entry.invoice
- reference.allocated_amount = inv_entry.allocated_amount
- print ("Adding invoice {0} {1}".format(reference.reference_name, reference.allocated_amount))
- payment.setup_party_account_field()
- payment.set_missing_values()
- #payment.set_exchange_rate()
- #payment.set_amounts()
- #print("Created payment entry {0}".format(payment.as_dict()))
- payment.save()
- return payment
-
- def create_journal_entry(self, pe):
- je = frappe.new_doc("Journal Entry")
- je.is_opening = "No"
- je.voucher_type = "Bank Entry"
- je.cheque_no = pe.description
- je.cheque_date = pe.transaction_date
- je.remark = pe.description
- je.posting_date = pe.transaction_date
- if (pe.amount < 0):
- je.append("accounts", {"account": pe.party, "debit_in_account_currency": abs(pe.amount)})
- je.append("accounts", {"account": self.bank_account, "credit_in_account_currency": abs(pe.amount)})
- else:
- je.append("accounts", {"account": pe.party, "credit_in_account_currency": pe.amount})
- je.append("accounts", {"account": self.bank_account, "debit_in_account_currency": pe.amount})
- je.save()
- return je
-
- def update_payment_entry(self, payment):
- lst = []
- invoices = payment.invoices.strip().split(',')
- if (len(invoices) == 0): return
- amount = float(abs(payment.amount))
- for invoice_entry in invoices:
- if (not invoice_entry.strip()): continue
- invs = invoice_entry.split('|')
- invoice_type, invoice = invs[0], invs[1]
- outstanding_amount = frappe.get_value(invoice_type, invoice, 'outstanding_amount')
-
- lst.append(frappe._dict({
- 'voucher_type': payment.reference_type,
- 'voucher_no' : payment.reference_name,
- 'against_voucher_type' : invoice_type,
- 'against_voucher' : invoice,
- 'account' : payment.account,
- 'party_type': payment.party_type,
- 'party': frappe.get_value("Payment Entry", payment.reference_name, "party"),
- 'unadjusted_amount' : float(amount),
- 'allocated_amount' : min(outstanding_amount, amount)
- }))
- amount -= outstanding_amount
- if lst:
- from erpnext.accounts.utils import reconcile_against_document
- try:
- reconcile_against_document(lst)
- except:
- frappe.throw(_("Exception occurred while reconciling {0}").format(payment.reference_name))
-
- def submit_payment_entries(self):
- for payment in self.new_transaction_items:
- if payment.reference_name is None: continue
- doc = frappe.get_doc(payment.reference_type, payment.reference_name)
- if doc.docstatus == 1:
- if (payment.reference_type == "Journal Entry"): continue
- if doc.unallocated_amount == 0: continue
- print("Reconciling payment {0}".format(payment.reference_name))
- self.update_payment_entry(payment)
- else:
- print("Submitting payment {0}".format(payment.reference_name))
- if (payment.reference_type == "Payment Entry"):
- if (payment.payment_reference):
- doc.reference_no = payment.payment_reference
- doc.mode_of_payment = payment.mode_of_payment
- doc.save()
- doc.submit()
- self.move_reconciled_entries()
- self.populate_matching_invoices()
-
- def move_reconciled_entries(self):
- idx = 0
- while idx < len(self.new_transaction_items):
- entry = self.new_transaction_items[idx]
- try:
- print("Checking transaction {0}: {2} in {1} entries".format(idx, len(self.new_transaction_items), frappe.safe_decode(entry.description)))
- except UnicodeEncodeError:
- pass
- idx += 1
- if entry.reference_name is None: continue
- doc = frappe.get_doc(entry.reference_type, entry.reference_name)
- if doc.docstatus == 1 and (entry.reference_type == "Journal Entry" or doc.unallocated_amount == 0):
- self.remove(entry)
- rc_entry = self.append('reconciled_transaction_items', {})
- dentry = entry.as_dict()
- dentry.pop('idx', None)
- rc_entry.update(dentry)
- idx -= 1
-
-
-def get_matching_journal_entries(from_date, to_date, account, against, amount):
- query = """select voucher_no, posting_date, account, against, debit_in_account_currency as debit, credit_in_account_currency as credit
- from `tabGL Entry`
- where posting_date between '{0}' and '{1}' and account = '{2}' and against = '{3}' and debit = '{4}'
- """.format(from_date, to_date, account, against, amount)
- jv_entries = frappe.db.sql(query, as_dict=True)
- #print("voucher query:{0}\n Returned {1} entries".format(query, len(jv_entries)))
- return jv_entries
-
-def get_payments_matching_invoice(invoice, amount, pay_date):
- query = """select pe.name as reference_name, per.reference_doctype as reference_type, per.outstanding_amount, per.allocated_amount
- from `tabPayment Entry Reference` as per JOIN `tabPayment Entry` as pe on pe.name = per.parent
- where per.reference_name='{0}' and (posting_date='{1}' or reference_date='{1}') and pe.docstatus != 2
- """.format(invoice, pay_date)
- payments = frappe.db.sql(query, as_dict=True)
- if (len(payments) == 0): return
- payment = next((payment for payment in payments if payment.allocated_amount == amount), payments[0])
- #Hack: Update the reference type which is set to invoice type
- payment.reference_type = "Payment Entry"
- return payment
-
-def is_headers_present(headers, row):
- for header in headers:
- if header not in row:
- return False
- return True
-
-def get_header_index(headers, row):
- header_index = {}
- for header in headers:
- if header in row:
- header_index[header] = row.index(header)
- return header_index
-
-def get_transaction_info(headers, header_index, row):
- transaction = {}
- for header in headers:
- transaction[header] = row[header_index[header]]
- if (transaction[header] == None):
- transaction[header] = ""
- return transaction
-
-def get_transaction_entries(file_url, headers):
- header_index = {}
- rows, transactions = [], []
-
- if (file_url.lower().endswith("xlsx")):
- from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
- rows = read_xlsx_file_from_attached_file(file_url=file_url)
- elif (file_url.lower().endswith("csv")):
- from frappe.utils.csvutils import read_csv_content
- _file = frappe.get_doc("File", {"file_url": file_url})
- filepath = _file.get_full_path()
- with open(filepath,'rb') as csvfile:
- rows = read_csv_content(csvfile.read())
- elif (file_url.lower().endswith("xls")):
- filename = file_url.split("/")[-1]
- rows = get_rows_from_xls_file(filename)
- else:
- frappe.throw(_("Only .csv and .xlsx files are supported currently"))
-
- stmt_headers = headers.values()
- for row in rows:
- if len(row) == 0 or row[0] == None or not row[0]: continue
- #print("Processing row {0}".format(row))
- if header_index:
- transaction = get_transaction_info(stmt_headers, header_index, row)
- transactions.append(transaction)
- elif is_headers_present(stmt_headers, row):
- header_index = get_header_index(stmt_headers, row)
- return transactions
-
-def get_rows_from_xls_file(filename):
- _file = frappe.get_doc("File", {"file_name": filename})
- filepath = _file.get_full_path()
- import xlrd
- book = xlrd.open_workbook(filepath)
- sheets = book.sheets()
- rows = []
- for row in range(1, sheets[0].nrows):
- row_values = []
- for col in range(1, sheets[0].ncols):
- row_values.append(sheets[0].cell_value(row, col))
- rows.append(row_values)
- return rows
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.js b/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.js
deleted file mode 100644
index 46d570f..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Bank Statement Transaction Entry", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Bank Statement Transaction Entry
- () => frappe.tests.make('Bank Statement Transaction Entry', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.py b/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.py
deleted file mode 100644
index 4589483..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestBankStatementTransactionEntry(unittest.TestCase):
- pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.json b/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.json
deleted file mode 100644
index d96c94d..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.json
+++ /dev/null
@@ -1,365 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-11-07 13:58:53.827058",
- "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": "transaction_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": "Transaction 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": 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": 4,
- "fieldname": "payment_description",
- "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": "Payment 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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "party_type",
- "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": "Party Type",
- "length": 0,
- "no_copy": 0,
- "options": "Customer\nSupplier\nAccount",
- "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": "party",
- "fieldtype": "Dynamic 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": "Party",
- "length": 0,
- "no_copy": 0,
- "options": "party_type",
- "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": "column_break_4",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "invoice_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Invoice Date",
- "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": 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": "invoice_type",
- "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": "Invoice Type",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Invoice\nPurchase Invoice\nJournal Entry",
- "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": 2,
- "fieldname": "invoice",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "invoice",
- "length": 0,
- "no_copy": 0,
- "options": "invoice_type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "fieldname": "outstanding_amount",
- "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": "Outstanding Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "fieldname": "allocated_amount",
- "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": "Allocated Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "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-09-14 19:03:30.949831",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Transaction Invoice Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.py b/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.py
deleted file mode 100644
index cb1b158..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementTransactionInvoiceItem(Document):
- pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_payment_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.json b/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.json
deleted file mode 100644
index 177dccd..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.json
+++ /dev/null
@@ -1,494 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-11-07 14:03:05.651413",
- "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": 1,
- "fieldname": "transaction_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Transaction Date",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 4,
- "fieldname": "description",
- "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": "Description",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "fieldname": "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": "Amount",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "fieldname": "party_type",
- "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": "Party Type",
- "length": 0,
- "no_copy": 0,
- "options": "Customer\nSupplier\nAccount",
- "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": 2,
- "fieldname": "party",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Party",
- "length": 0,
- "no_copy": 0,
- "options": "party_type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference_type",
- "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": "Reference Type",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Entry\nJournal Entry",
- "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": "account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mode_of_payment",
- "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": "Mode of Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Mode of Payment",
- "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": "outstanding_amount",
- "fieldtype": "Currency",
- "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": "outstanding_amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "reference_name",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Reference Name",
- "length": 0,
- "no_copy": 0,
- "options": "reference_type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "payment_reference",
- "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": "Payment Reference",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "invoices",
- "fieldtype": "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": "Invoices",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-11-15 19:18:52.876221",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Transaction Payment Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.py b/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.py
deleted file mode 100644
index 9840c0d..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementTransactionPaymentItem(Document):
- pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_settings/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.js b/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.js
deleted file mode 100644
index 46aa4f2..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2017, sathishpy@gmail.com and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Bank Statement Settings', {
- refresh: function(frm) {
-
- }
-});
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.json b/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.json
deleted file mode 100644
index 474bb90..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.json
+++ /dev/null
@@ -1,266 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "beta": 0,
- "creation": "2017-11-13 13:38:10.863592",
- "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": "bank_account",
- "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": "Bank Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "'%d/%m/%Y'",
- "fieldname": "date_format",
- "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": "Date Format",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "statement_header_mapping",
- "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": "Statement Header Mapping",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "header_items",
- "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": "Statement Headers",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Settings Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "transaction_data_mapping",
- "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": "Transaction Data Mapping",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mapped_items",
- "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": "Mapped Items",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Statement Transaction Settings Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 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": "2018-01-12 10:34:32.840487",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Settings",
- "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": "System Manager",
- "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": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.py b/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.py
deleted file mode 100644
index de9a85f..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementSettings(Document):
- def autoname(self):
- self.name = self.bank_account + "-Mappings"
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.js b/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.js
deleted file mode 100644
index f2381c0..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Bank Statement Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Bank Statement Settings
- () => frappe.tests.make('Bank Statement Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.py b/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.py
deleted file mode 100644
index aa7fe83..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestBankStatementSettings(unittest.TestCase):
- pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_settings_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.json b/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.json
deleted file mode 100644
index 47c3209..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.json
+++ /dev/null
@@ -1,166 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-11-13 13:42:00.335432",
- "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,
- "default": "Transaction",
- "fieldname": "mapping_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Mapping Type",
- "length": 0,
- "no_copy": 0,
- "options": "Transaction",
- "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": "bank_data",
- "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": "Bank Data",
- "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,
- "default": "Account",
- "fieldname": "mapped_data_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Mapped Data Type",
- "length": 0,
- "no_copy": 0,
- "options": "Account\nCustomer\nSupplier\nAccount",
- "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": "mapped_data",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Mapped Data",
- "length": 0,
- "no_copy": 0,
- "options": "mapped_data_type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "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-01-08 00:13:49.973501",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Transaction Settings Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.py b/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.py
deleted file mode 100644
index bf0a590..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementTransactionSettingsItem(Document):
- pass
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.js b/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
index 8b1bab1..3758b52 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
@@ -1,32 +1,70 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Bank Transaction', {
+frappe.ui.form.on("Bank Transaction", {
onload(frm) {
- frm.set_query('payment_document', 'payment_entries', function() {
+ frm.set_query("payment_document", "payment_entries", function () {
return {
- "filters": {
- "name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
- }
+ filters: {
+ name: [
+ "in",
+ [
+ "Payment Entry",
+ "Journal Entry",
+ "Sales Invoice",
+ "Purchase Invoice",
+ "Expense Claim",
+ ],
+ ],
+ },
};
});
- }
+ },
+ bank_account: function (frm) {
+ set_bank_statement_filter(frm);
+ },
+
+ setup: function (frm) {
+ frm.set_query("party_type", function () {
+ return {
+ filters: {
+ name: ["in", Object.keys(frappe.boot.party_account_types)],
+ },
+ };
+ });
+ },
});
-frappe.ui.form.on('Bank Transaction Payments', {
- payment_entries_remove: function(frm, cdt, cdn) {
+frappe.ui.form.on("Bank Transaction Payments", {
+ payment_entries_remove: function (frm, cdt, cdn) {
update_clearance_date(frm, cdt, cdn);
- }
+ },
});
const update_clearance_date = (frm, cdt, cdn) => {
if (frm.doc.docstatus === 1) {
- frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment',
- {doctype: cdt, docname: cdn})
- .then(e => {
+ frappe
+ .xcall(
+ "erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment",
+ { doctype: cdt, docname: cdn }
+ )
+ .then((e) => {
if (e == "success") {
- frappe.show_alert({message:__("Document {0} successfully uncleared", [e]), indicator:'green'});
+ frappe.show_alert({
+ message: __("Document {0} successfully uncleared", [e]),
+ indicator: "green",
+ });
}
});
}
-};
\ No newline at end of file
+};
+
+function set_bank_statement_filter(frm) {
+ frm.set_query("bank_statement", function () {
+ return {
+ filters: {
+ bank_account: frm.doc.bank_account,
+ },
+ };
+ });
+}
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
index 39937bb..69ee497 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
@@ -1,833 +1,245 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
"allow_import": 1,
- "allow_rename": 0,
"autoname": "naming_series:",
- "beta": 0,
"creation": "2018-10-22 18:19:02.784533",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "date",
+ "column_break_2",
+ "status",
+ "bank_account",
+ "company",
+ "section_break_4",
+ "deposit",
+ "withdrawal",
+ "column_break_7",
+ "currency",
+ "section_break_10",
+ "description",
+ "section_break_14",
+ "reference_number",
+ "transaction_id",
+ "payment_entries",
+ "section_break_18",
+ "allocated_amount",
+ "amended_from",
+ "column_break_17",
+ "unallocated_amount",
+ "party_section",
+ "party_type",
+ "party"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "ACC-BTN-.YYYY.-",
- "fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
"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": "Series",
- "length": 0,
"no_copy": 1,
"options": "ACC-BTN-.YYYY.-",
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "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": 1,
- "translatable": 0,
- "unique": 0
+ "set_only_once": 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": "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": "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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Date"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_2",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "Pending",
- "fetch_if_empty": 0,
"fieldname": "status",
"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": 1,
"label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "\nPending\nSettled\nUnreconciled\nReconciled",
- "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
+ "options": "\nPending\nSettled\nUnreconciled\nReconciled"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "bank_account",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Bank Account",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Bank Account"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
"fetch_from": "bank_account.company",
- "fetch_if_empty": 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": 0,
"in_standard_filter": 1,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "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
+ "read_only": 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": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "debit",
- "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": "Debit",
- "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": "credit",
- "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": "Credit",
- "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": "column_break_7",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "currency",
"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": "Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "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
+ "options": "Currency"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_10",
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "description",
"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": "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
+ "label": "Description"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_14",
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "allow_on_submit": 1,
"fieldname": "reference_number",
"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": "Reference 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Reference Number"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "transaction_id",
"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": "Transaction ID",
- "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": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
"allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "payment_entries",
"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": "Payment Entries",
- "length": 0,
- "no_copy": 0,
- "options": "Bank Transaction Payments",
- "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
+ "options": "Bank Transaction Payments"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_18",
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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": 0,
- "in_standard_filter": 0,
- "label": "Allocated Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Allocated Amount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "amended_from",
"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": "Amended From",
- "length": 0,
"no_copy": 1,
"options": "Bank Transaction",
- "permlevel": 0,
"print_hide": 1,
- "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
+ "read_only": 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": "column_break_17",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
"fieldname": "unallocated_amount",
"fieldtype": "Currency",
- "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": "Unallocated Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Unallocated Amount"
+ },
+ {
+ "fieldname": "party_section",
+ "fieldtype": "Section Break",
+ "label": "Payment From / To"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "party_type",
+ "fieldtype": "Link",
+ "label": "Party Type",
+ "options": "DocType"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "party",
+ "fieldtype": "Dynamic Link",
+ "label": "Party",
+ "options": "party_type"
+ },
+ {
+ "fieldname": "deposit",
+ "oldfieldname": "debit",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Deposit"
+ },
+ {
+ "fieldname": "withdrawal",
+ "oldfieldname": "credit",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Withdrawal"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
"is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-11 05:27:55.244721",
+ "links": [],
+ "modified": "2020-12-30 19:40:54.221070",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
"cancel": 1,
"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": 1,
"write": 1
},
{
- "amend": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
- "set_user_permissions": 0,
"share": 1,
"submit": 1,
"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": "Accounts User",
- "set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "date",
"sort_order": "DESC",
"title_field": "bank_account",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index 0e45db3..5246baa 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -11,7 +11,7 @@
class BankTransaction(StatusUpdater):
def after_insert(self):
- self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
+ self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit))
def on_submit(self):
self.clear_linked_payment_entries()
@@ -30,13 +30,13 @@
if allocated_amount:
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
- frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount))
+ frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit)) - flt(allocated_amount))
else:
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
- frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)))
+ frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit)))
- amount = self.debit or self.credit
+ amount = self.deposit or self.withdrawal
if amount == self.allocated_amount:
frappe.db.set_value(self.doctype, self.name, "status", "Reconciled")
@@ -44,18 +44,11 @@
def clear_linked_payment_entries(self):
for payment_entry in self.payment_entries:
- allocated_amount = get_total_allocated_amount(payment_entry)
- paid_amount = get_paid_amount(payment_entry, self.currency)
+ if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
+ self.clear_simple_entry(payment_entry)
- if paid_amount and allocated_amount:
- if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
- frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).").format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount)))
- else:
- if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
- self.clear_simple_entry(payment_entry)
-
- elif payment_entry.payment_document == "Sales Invoice":
- self.clear_sales_invoice(payment_entry)
+ elif payment_entry.payment_document == "Sales Invoice":
+ self.clear_sales_invoice(payment_entry)
def clear_simple_entry(self, payment_entry):
frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date)
@@ -112,3 +105,4 @@
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
return doc.payment_entry
+
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index 2754633..3b14e4e 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -5,17 +5,20 @@
import frappe
import unittest
+import json
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
-from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
+from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import reconcile_vouchers, get_linked_payments
+from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
test_dependencies = ["Item", "Cost Center"]
class TestBankTransaction(unittest.TestCase):
def setUp(self):
+ make_pos_profile()
add_transactions()
- add_payments()
+ add_vouchers()
def tearDown(self):
for bt in frappe.get_all("Bank Transaction"):
@@ -27,20 +30,27 @@
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
frappe.db.sql("""delete from `tabPayment Entry`""")
+ # Delete POS Profile
+ frappe.db.sql("delete from `tabPOS Profile`")
+
frappe.flags.test_bank_transactions_created = False
frappe.flags.test_payments_created = False
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
def test_linked_payments(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"))
- linked_payments = get_linked_payments(bank_transaction.name)
- self.assertTrue(linked_payments[0].party == "Conrad Electronic")
+ linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
+ self.assertTrue(linked_payments[0][6] == "Conrad Electronic")
# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
def test_reconcile(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
- reconcile(bank_transaction.name, "Payment Entry", payment.name)
+ vouchers = json.dumps([{
+ "payment_doctype":"Payment Entry",
+ "payment_name":payment.name,
+ "amount":bank_transaction.unallocated_amount}])
+ reconcile_vouchers(bank_transaction.name, vouchers)
unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount")
self.assertTrue(unallocated_amount == 0)
@@ -48,45 +58,40 @@
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
self.assertTrue(clearance_date is not None)
- # Check if ERPNext can correctly fetch a linked payment based on the party
- def test_linked_payments_based_on_party(self):
- bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"))
- linked_payments = get_linked_payments(bank_transaction.name)
- self.assertTrue(len(linked_payments)==1)
-
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
def test_debit_credit_output(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
- linked_payments = get_linked_payments(bank_transaction.name)
- self.assertTrue(linked_payments[0].payment_type == "Pay")
+ linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
+ print(linked_payments)
+ self.assertTrue(linked_payments[0][3])
# Check error if already reconciled
def test_already_reconciled(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
- reconcile(bank_transaction.name, "Payment Entry", payment.name)
+ vouchers = json.dumps([{
+ "payment_doctype":"Payment Entry",
+ "payment_name":payment.name,
+ "amount":bank_transaction.unallocated_amount}])
+ reconcile_vouchers(bank_transaction.name, vouchers)
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
- self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
-
- # Raise an error if creditor transaction vs creditor payment
- def test_invalid_creditor_reconcilation(self):
- bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
- payment = frappe.get_doc("Payment Entry", dict(party="Conrad Electronic", paid_amount=690))
- self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
-
- # Raise an error if debitor transaction vs debitor payment
- def test_invalid_debitor_reconcilation(self):
- bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
- payment = frappe.get_doc("Payment Entry", dict(party="Fayva", paid_amount=109080))
- self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
+ vouchers = json.dumps([{
+ "payment_doctype":"Payment Entry",
+ "payment_name":payment.name,
+ "amount":bank_transaction.unallocated_amount}])
+ self.assertRaises(frappe.ValidationError, reconcile_vouchers, bank_transaction_name=bank_transaction.name, vouchers=vouchers)
# Raise an error if debitor transaction vs debitor payment
def test_clear_sales_invoice(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"]))
- reconcile(bank_transaction.name, "Sales Invoice", payment.name)
+ vouchers = json.dumps([{
+ "payment_doctype":"Sales Invoice",
+ "payment_name":payment.name,
+ "amount":bank_transaction.unallocated_amount}])
+ reconcile_vouchers(bank_transaction.name, vouchers=vouchers)
self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
@@ -121,7 +126,7 @@
"doctype": "Bank Transaction",
"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
"date": "2018-10-23",
- "debit": 1200,
+ "deposit": 1200,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
@@ -131,7 +136,7 @@
"doctype": "Bank Transaction",
"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G",
"date": "2018-10-23",
- "debit": 1700,
+ "deposit": 1700,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
@@ -141,7 +146,7 @@
"doctype": "Bank Transaction",
"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic",
"date": "2018-10-26",
- "debit": 690,
+ "withdrawal": 690,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
@@ -151,7 +156,7 @@
"doctype": "Bank Transaction",
"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07",
"date": "2018-10-27",
- "debit": 3900,
+ "deposit": 3900,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
@@ -161,7 +166,7 @@
"doctype": "Bank Transaction",
"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio",
"date": "2018-10-27",
- "credit": 109080,
+ "withdrawal": 109080,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
@@ -169,7 +174,7 @@
frappe.flags.test_bank_transactions_created = True
-def add_payments():
+def add_vouchers():
if frappe.flags.test_payments_created:
return
@@ -187,6 +192,7 @@
pass
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
+
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Conrad Oct 18"
pe.reference_date = "2018-10-24"
@@ -237,10 +243,15 @@
except frappe.DuplicateEntryError:
pass
- pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900)
+ pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save =1)
+ pi.cash_bank_account = "_Test Bank - _TC"
+ pi.insert()
+ pi.submit()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
+ pe.paid_amount = 690
+ pe.received_amount = 690
pe.insert()
pe.submit()
@@ -290,4 +301,4 @@
si.save()
si.submit()
- frappe.flags.test_payments_created = True
\ No newline at end of file
+ frappe.flags.test_payments_created = True
diff --git a/erpnext/accounts/doctype/budget/budget.js b/erpnext/accounts/doctype/budget/budget.js
index cadf1e7..e162e32 100644
--- a/erpnext/accounts/doctype/budget/budget.js
+++ b/erpnext/accounts/doctype/budget/budget.js
@@ -1,24 +1,9 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Budget', {
onload: function(frm) {
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- }
- })
-
- frm.set_query("project", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- }
- })
-
frm.set_query("account", "accounts", function() {
return {
filters: {
@@ -26,16 +11,18 @@
report_type: "Profit and Loss",
is_group: 0
}
- }
- })
-
+ };
+ });
+
frm.set_query("monthly_distribution", function() {
return {
filters: {
fiscal_year: frm.doc.fiscal_year
}
- }
- })
+ };
+ });
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/accounts/doctype/budget/budget.json b/erpnext/accounts/doctype/budget/budget.json
index 50ad2e5..fc4dd20 100644
--- a/erpnext/accounts/doctype/budget/budget.json
+++ b/erpnext/accounts/doctype/budget/budget.json
@@ -1,814 +1,224 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-05-16 11:42:29.632528",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
+ "actions": [],
+ "allow_import": 1,
+ "creation": "2016-05-16 11:42:29.632528",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "budget_against",
+ "company",
+ "cost_center",
+ "project",
+ "fiscal_year",
+ "column_break_3",
+ "monthly_distribution",
+ "amended_from",
+ "section_break_6",
+ "applicable_on_material_request",
+ "action_if_annual_budget_exceeded_on_mr",
+ "action_if_accumulated_monthly_budget_exceeded_on_mr",
+ "column_break_13",
+ "applicable_on_purchase_order",
+ "action_if_annual_budget_exceeded_on_po",
+ "action_if_accumulated_monthly_budget_exceeded_on_po",
+ "section_break_16",
+ "applicable_on_booking_actual_expenses",
+ "action_if_annual_budget_exceeded",
+ "action_if_accumulated_monthly_budget_exceeded",
+ "section_break_21",
+ "accounts"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Cost Center",
- "fetch_if_empty": 0,
- "fieldname": "budget_against",
- "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": 1,
- "label": "Budget Against",
- "length": 0,
- "no_copy": 0,
- "options": "\nCost Center\nProject",
- "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
- },
+ "default": "Cost Center",
+ "fieldname": "budget_against",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Budget Against",
+ "options": "\nCost Center\nProject",
+ "reqd": 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": "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": 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,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.budget_against == 'Cost Center'",
- "fetch_if_empty": 0,
- "fieldname": "cost_center",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Cost Center",
- "length": 0,
- "no_copy": 0,
- "options": "Cost Center",
- "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
- },
+ "depends_on": "eval:doc.budget_against == 'Cost Center'",
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.budget_against == 'Project'",
- "fetch_if_empty": 0,
- "fieldname": "project",
- "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": 1,
- "label": "Project",
- "length": 0,
- "no_copy": 0,
- "options": "Project",
- "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
- },
+ "depends_on": "eval:doc.budget_against == 'Project'",
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Project",
+ "options": "Project"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "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": 1,
- "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
- },
+ "fieldname": "fiscal_year",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Fiscal Year",
+ "options": "Fiscal Year",
+ "reqd": 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": "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded_on_po || doc.action_if_accumulated_monthly_budget_exceeded_on_mr || doc.action_if_accumulated_monthly_budget_exceeded_on_actual)",
- "fetch_if_empty": 0,
- "fieldname": "monthly_distribution",
- "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": "Monthly Distribution",
- "length": 0,
- "no_copy": 0,
- "options": "Monthly Distribution",
- "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
- },
+ "depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded_on_po || doc.action_if_accumulated_monthly_budget_exceeded_on_mr || doc.action_if_accumulated_monthly_budget_exceeded_on_actual)",
+ "fieldname": "monthly_distribution",
+ "fieldtype": "Link",
+ "label": "Monthly Distribution",
+ "options": "Monthly Distribution"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Budget",
- "permlevel": 0,
- "print_hide": 1,
- "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": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Budget",
+ "print_hide": 1,
+ "read_only": 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": "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,
- "label": "Control Action",
- "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",
+ "label": "Control Action"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "applicable_on_material_request",
- "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": "Applicable on Material Request",
- "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": "applicable_on_material_request",
+ "fieldtype": "Check",
+ "label": "Applicable on Material Request"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Stop",
- "depends_on": "eval:doc.applicable_on_material_request == 1",
- "fetch_if_empty": 0,
- "fieldname": "action_if_annual_budget_exceeded_on_mr",
- "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": "Action if Annual Budget Exceeded on MR",
- "length": 0,
- "no_copy": 0,
- "options": "\nStop\nWarn\nIgnore",
- "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_on_submit": 1,
+ "default": "Stop",
+ "depends_on": "eval:doc.applicable_on_material_request == 1",
+ "fieldname": "action_if_annual_budget_exceeded_on_mr",
+ "fieldtype": "Select",
+ "label": "Action if Annual Budget Exceeded on MR",
+ "options": "\nStop\nWarn\nIgnore"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Warn",
- "depends_on": "eval:doc.applicable_on_material_request == 1",
- "fetch_if_empty": 0,
- "fieldname": "action_if_accumulated_monthly_budget_exceeded_on_mr",
- "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": "Action if Accumulated Monthly Budget Exceeded on MR",
- "length": 0,
- "no_copy": 0,
- "options": "\nStop\nWarn\nIgnore",
- "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_on_submit": 1,
+ "default": "Warn",
+ "depends_on": "eval:doc.applicable_on_material_request == 1",
+ "fieldname": "action_if_accumulated_monthly_budget_exceeded_on_mr",
+ "fieldtype": "Select",
+ "label": "Action if Accumulated Monthly Budget Exceeded on MR",
+ "options": "\nStop\nWarn\nIgnore"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_13",
- "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_13",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "applicable_on_purchase_order",
- "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": "Applicable on Purchase Order",
- "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": "applicable_on_purchase_order",
+ "fieldtype": "Check",
+ "label": "Applicable on Purchase Order"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Stop",
- "depends_on": "eval:doc.applicable_on_purchase_order == 1",
- "fetch_if_empty": 0,
- "fieldname": "action_if_annual_budget_exceeded_on_po",
- "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": "Action if Annual Budget Exceeded on PO",
- "length": 0,
- "no_copy": 0,
- "options": "\nStop\nWarn\nIgnore",
- "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_on_submit": 1,
+ "default": "Stop",
+ "depends_on": "eval:doc.applicable_on_purchase_order == 1",
+ "fieldname": "action_if_annual_budget_exceeded_on_po",
+ "fieldtype": "Select",
+ "label": "Action if Annual Budget Exceeded on PO",
+ "options": "\nStop\nWarn\nIgnore"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Warn",
- "depends_on": "eval:doc.applicable_on_purchase_order == 1",
- "fetch_if_empty": 0,
- "fieldname": "action_if_accumulated_monthly_budget_exceeded_on_po",
- "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": "Action if Accumulated Monthly Budget Exceeded on PO",
- "length": 0,
- "no_copy": 0,
- "options": "\nStop\nWarn\nIgnore",
- "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_on_submit": 1,
+ "default": "Warn",
+ "depends_on": "eval:doc.applicable_on_purchase_order == 1",
+ "fieldname": "action_if_accumulated_monthly_budget_exceeded_on_po",
+ "fieldtype": "Select",
+ "label": "Action if Accumulated Monthly Budget Exceeded on PO",
+ "options": "\nStop\nWarn\nIgnore"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_16",
- "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_16",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "applicable_on_booking_actual_expenses",
- "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": "Applicable on booking actual expenses",
- "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": "applicable_on_booking_actual_expenses",
+ "fieldtype": "Check",
+ "label": "Applicable on booking actual expenses"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Stop",
- "depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
- "fetch_if_empty": 0,
- "fieldname": "action_if_annual_budget_exceeded",
- "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": "Action if Annual Budget Exceeded on Actual",
- "length": 0,
- "no_copy": 0,
- "options": "\nStop\nWarn\nIgnore",
- "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_on_submit": 1,
+ "default": "Stop",
+ "depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
+ "fieldname": "action_if_annual_budget_exceeded",
+ "fieldtype": "Select",
+ "label": "Action if Annual Budget Exceeded on Actual",
+ "options": "\nStop\nWarn\nIgnore"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Warn",
- "depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
- "fetch_if_empty": 0,
- "fieldname": "action_if_accumulated_monthly_budget_exceeded",
- "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": "Action if Accumulated Monthly Budget Exceeded on Actual",
- "length": 0,
- "no_copy": 0,
- "options": "\nStop\nWarn\nIgnore",
- "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_on_submit": 1,
+ "default": "Warn",
+ "depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
+ "fieldname": "action_if_accumulated_monthly_budget_exceeded",
+ "fieldtype": "Select",
+ "label": "Action if Accumulated Monthly Budget Exceeded on Actual",
+ "options": "\nStop\nWarn\nIgnore"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_21",
- "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_21",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "accounts",
- "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": "Budget Accounts",
- "length": 0,
- "no_copy": 0,
- "options": "Budget Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Budget Accounts",
+ "options": "Budget Account",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-22 12:06:02.323099",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Budget",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-10-06 15:13:54.055854",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Budget",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "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
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 61c48c7..c5ec23c 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -122,8 +122,10 @@
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
+ project = frappe.get_value("Project", {"project_name": "_Test Project"})
+
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
+ "_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project=project, posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@@ -147,8 +149,11 @@
budget = make_budget(budget_against="Project")
+ project = frappe.get_value("Project", {"project_name": "_Test Project"})
+
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Bank - _TC", 250000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
+ "_Test Bank - _TC", 250000, "_Test Cost Center - _TC",
+ project=project, posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@@ -158,8 +163,11 @@
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
+ month = now_datetime().month
+ if month > 9:
+ month = 9
- for i in range(now_datetime().month):
+ for i in range(month+1):
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
@@ -177,10 +185,15 @@
set_total_expense_zero(nowdate(), "project")
budget = make_budget(budget_against="Project")
+ month = now_datetime().month
+ if month > 9:
+ month = 9
- for i in range(now_datetime().month):
+ project = frappe.get_value("Project", {"project_name": "_Test Project"})
+ for i in range(month + 1):
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
+ "_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True,
+ project=project)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
@@ -283,7 +296,7 @@
budget = frappe.new_doc("Budget")
if budget_against == "Project":
- budget.project = "_Test Project"
+ budget.project = frappe.get_value("Project", {"project_name": "_Test Project"})
else:
budget.cost_center =cost_center or "_Test Cost Center - _TC"
diff --git a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py
index 6de62ee..7ad1d3a 100644
--- a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py
+++ b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py
@@ -23,13 +23,13 @@
where posting_date=%s and posting_time>=%s and posting_time<=%s and owner=%s
""", (self.date, self.from_time, self.time, self.user))
self.outstanding_amount = flt(values[0][0] if values else 0)
-
+
def make_calculations(self):
total = 0.00
for i in self.payments:
total += flt(i.amount)
- self.net_amount = total + self.outstanding_amount + self.expense - self.custody + self.returns
+ self.net_amount = total + self.outstanding_amount + flt(self.expense) - flt(self.custody) + flt(self.returns)
def validate_time(self):
if self.from_time >= self.time:
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 2235298..f795dfa 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
@@ -94,8 +94,7 @@
callback: function(r) {
if(r.message===false) {
frm.set_value("company", "");
- frappe.throw(__(`Transactions against the company already exist!
- Chart Of accounts can be imported for company with no transactions`));
+ frappe.throw(__("Transactions against the Company already exist! Chart of Accounts can only be imported for a Company with no transactions."));
} else {
frm.trigger("refresh");
}
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 e1b331b..03c3eb0 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
@@ -22,9 +22,10 @@
'allow_account_creation_against_child_company'])
if parent_company and (not allow_account_creation_against_child_company):
- frappe.throw(_("""{0} is a child company. Please import accounts against parent company
- or enable {1} in company master""").format(frappe.bold(company),
- frappe.bold('Allow Account Creation Against Child Company')), title='Wrong Company')
+ msg = _("{} is a child company. ").format(frappe.bold(company))
+ msg += _("Please import accounts against parent company or enable {} in company master.").format(
+ frappe.bold('Allow Account Creation Against Child Company'))
+ frappe.throw(msg, title=_('Wrong Company'))
if frappe.db.get_all('GL Entry', {"company": company}, "name", limit=1):
return False
@@ -74,7 +75,9 @@
if as_dict:
data.append({frappe.scrub(header): row[index] for index, header in enumerate(headers)})
else:
- if not row[1]: row[1] = row[0]
+ if not row[1]:
+ row[1] = row[0]
+ row[3] = row[2]
data.append(row)
# convert csv data
@@ -96,7 +99,9 @@
if as_dict:
data.append({frappe.scrub(header): row[index] for index, header in enumerate(headers)})
else:
- if not row[1]: row[1] = row[0]
+ if not row[1]:
+ row[1] = row[0]
+ row[3] = row[2]
data.append(row)
return data
@@ -147,7 +152,13 @@
from frappe import _
for row in data:
- account_name, parent_account = row[0:2]
+ account_name, parent_account, account_number, parent_account_number = row[0:4]
+ if account_number:
+ account_name = "{} - {}".format(account_number, account_name)
+ if parent_account_number:
+ parent_account_number = cstr(parent_account_number).strip()
+ parent_account = "{} - {}".format(parent_account_number, parent_account)
+
if parent_account == account_name == child:
return [parent_account]
elif account_name == child:
@@ -159,20 +170,23 @@
charts_map, paths = {}, []
- line_no = 3
+ line_no = 2
error_messages = []
for i in data:
- account_name, dummy, account_number, is_group, account_type, root_type = i
+ account_name, parent_account, account_number, parent_account_number, is_group, account_type, root_type = i
if not account_name:
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
+ if account_number:
+ account_number = cstr(account_number).strip()
+ account_name = "{} - {}".format(account_number, account_name)
+
charts_map[account_name] = {}
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
- if account_number: charts_map[account_name]["account_number"] = account_number
path = return_parent(data, account_name)[::-1]
paths.append(path) # List of path is created
line_no += 1
@@ -195,7 +209,7 @@
reader = csv.reader(f)
from frappe.utils.xlsxutils import make_xlsx
- xlsx_file = make_xlsx(reader, "Chart Of Accounts Importer Template")
+ xlsx_file = make_xlsx(reader, "Chart of Accounts Importer Template")
f.close()
os.remove(filename)
@@ -221,7 +235,7 @@
def get_template(template_type):
- fields = ["Account Name", "Parent Account", "Account Number", "Is Group", "Account Type", "Root Type"]
+ fields = ["Account Name", "Parent Account", "Account Number", "Parent Account Number", "Is Group", "Account Type", "Root Type"]
writer = UnicodeWriter()
writer.writerow(fields)
@@ -241,23 +255,23 @@
def get_sample_template(writer):
template = [
- ["Application Of Funds(Assets)", "", "", 1, "", "Asset"],
- ["Sources Of Funds(Liabilities)", "", "", 1, "", "Liability"],
- ["Equity", "", "", 1, "", "Equity"],
- ["Expenses", "", "", 1, "", "Expense"],
- ["Income", "", "", 1, "", "Income"],
- ["Bank Accounts", "Application Of Funds(Assets)", "", 1, "Bank", "Asset"],
- ["Cash In Hand", "Application Of Funds(Assets)", "", 1, "Cash", "Asset"],
- ["Stock Assets", "Application Of Funds(Assets)", "", 1, "Stock", "Asset"],
- ["Cost Of Goods Sold", "Expenses", "", 0, "Cost of Goods Sold", "Expense"],
- ["Asset Depreciation", "Expenses", "", 0, "Depreciation", "Expense"],
- ["Fixed Assets", "Application Of Funds(Assets)", "", 0, "Fixed Asset", "Asset"],
- ["Accounts Payable", "Sources Of Funds(Liabilities)", "", 0, "Payable", "Liability"],
- ["Accounts Receivable", "Application Of Funds(Assets)", "", 1, "Receivable", "Asset"],
- ["Stock Expenses", "Expenses", "", 0, "Stock Adjustment", "Expense"],
- ["Sample Bank", "Bank Accounts", "", 0, "Bank", "Asset"],
- ["Cash", "Cash In Hand", "", 0, "Cash", "Asset"],
- ["Stores", "Stock Assets", "", 0, "Stock", "Asset"],
+ ["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"],
+ ["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"],
+ ["Equity", "", "", "", 1, "", "Equity"],
+ ["Expenses", "", "", "", 1, "", "Expense"],
+ ["Income", "", "", "", 1, "", "Income"],
+ ["Bank Accounts", "Application Of Funds(Assets)", "", "", 1, "Bank", "Asset"],
+ ["Cash In Hand", "Application Of Funds(Assets)", "", "", 1, "Cash", "Asset"],
+ ["Stock Assets", "Application Of Funds(Assets)", "", "", 1, "Stock", "Asset"],
+ ["Cost Of Goods Sold", "Expenses", "", "", 0, "Cost of Goods Sold", "Expense"],
+ ["Asset Depreciation", "Expenses", "", "", 0, "Depreciation", "Expense"],
+ ["Fixed Assets", "Application Of Funds(Assets)", "", "", 0, "Fixed Asset", "Asset"],
+ ["Accounts Payable", "Sources Of Funds(Liabilities)", "", "", 0, "Payable", "Liability"],
+ ["Accounts Receivable", "Application Of Funds(Assets)", "", "", 1, "Receivable", "Asset"],
+ ["Stock Expenses", "Expenses", "", "", 0, "Stock Adjustment", "Expense"],
+ ["Sample Bank", "Bank Accounts", "", "", 0, "Bank", "Asset"],
+ ["Cash", "Cash In Hand", "", "", 0, "Cash", "Asset"],
+ ["Stores", "Stock Assets", "", "", 0, "Stock", "Asset"],
]
for row in template:
diff --git a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
index 340b9dd..622bd33 100644
--- a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
+++ b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
@@ -28,22 +28,22 @@
"item_group": "_Test Item Group",
"item_name": "_Test Tesla Car",
"apply_warehouse_wise_reorder_level": 0,
- "warehouse":"Stores - TCP1",
+ "warehouse":"Stores - _TC",
"gst_hsn_code": "999800",
"valuation_rate": 5000,
"standard_rate":5000,
"item_defaults": [{
- "company": "_Test Company with perpetual inventory",
- "default_warehouse": "Stores - TCP1",
+ "company": "_Test Company",
+ "default_warehouse": "Stores - _TC",
"default_price_list":"_Test Price List",
- "expense_account": "Cost of Goods Sold - TCP1",
- "buying_cost_center": "Main - TCP1",
- "selling_cost_center": "Main - TCP1",
- "income_account": "Sales - TCP1"
+ "expense_account": "Cost of Goods Sold - _TC",
+ "buying_cost_center": "Main - _TC",
+ "selling_cost_center": "Main - _TC",
+ "income_account": "Sales - _TC"
}],
"show_in_website": 1,
"route":"-test-tesla-car",
- "website_warehouse": "Stores - TCP1"
+ "website_warehouse": "Stores - _TC"
})
item.insert()
# create test item price
@@ -65,12 +65,12 @@
"items": [{
"item_code": "_Test Tesla Car"
}],
- "warehouse":"Stores - TCP1",
+ "warehouse":"Stores - _TC",
"coupon_code_based":1,
"selling": 1,
"rate_or_discount": "Discount Percentage",
"discount_percentage": 30,
- "company": "_Test Company with perpetual inventory",
+ "company": "_Test Company",
"currency":"INR",
"for_price_list":"_Test Price List"
})
@@ -85,7 +85,7 @@
})
sales_partner.insert()
# create test item coupon code
- if not frappe.db.exists("Coupon Code","SAVE30"):
+ if not frappe.db.exists("Coupon Code", "SAVE30"):
coupon_code = frappe.get_doc({
"doctype": "Coupon Code",
"coupon_name":"SAVE30",
@@ -102,35 +102,27 @@
test_create_test_data()
def tearDown(self):
- frappe.set_user("Administrator")
+ frappe.set_user("Administrator")
- def test_1_check_coupon_code_used_before_so(self):
- coupon_code = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
- # reset used coupon code count
- coupon_code.used=0
- coupon_code.save()
- # check no coupon code is used before sales order is made
- self.assertEqual(coupon_code.get("used"),0)
+ def test_sales_order_with_coupon_code(self):
+ frappe.db.set_value("Coupon Code", "SAVE30", "used", 0)
- def test_2_sales_order_with_coupon_code(self):
- so = make_sales_order(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1',
- customer="_Test Customer", selling_price_list="_Test Price List", item_code="_Test Tesla Car", rate=5000,qty=1,
+ so = make_sales_order(company='_Test Company', warehouse='Stores - _TC',
+ customer="_Test Customer", selling_price_list="_Test Price List",
+ item_code="_Test Tesla Car", rate=5000, qty=1,
do_not_submit=True)
- so = frappe.get_doc('Sales Order', so.name)
- # check item price before coupon code is applied
self.assertEqual(so.items[0].rate, 5000)
+
so.coupon_code='SAVE30'
so.sales_partner='_Test Coupon Partner'
so.save()
+
# check item price after coupon code is applied
self.assertEqual(so.items[0].rate, 3500)
- so.submit()
- def test_3_check_coupon_code_used_after_so(self):
- doc = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
- # check no coupon code is used before sales order is made
- self.assertEqual(doc.get("used"),1)
+ so.submit()
+ self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1)
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.js b/erpnext/accounts/doctype/fiscal_year/fiscal_year.js
index 152e17d..bc77dac 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.js
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.js
@@ -9,11 +9,7 @@
}
},
refresh: function (frm) {
- let doc = frm.doc;
- frm.toggle_enable('year_start_date', doc.__islocal);
- frm.toggle_enable('year_end_date', doc.__islocal);
-
- if (!doc.__islocal && (doc.name != frappe.sys_defaults.fiscal_year)) {
+ if (!frm.doc.__islocal && (frm.doc.name != frappe.sys_defaults.fiscal_year)) {
frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm));
frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
} else {
@@ -24,8 +20,10 @@
return frm.call('set_as_default');
},
year_start_date: function(frm) {
- let year_end_date =
- frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
- frm.set_value("year_end_date", year_end_date);
+ if (!frm.doc.is_short_year) {
+ let year_end_date =
+ frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
+ frm.set_value("year_end_date", year_end_date);
+ }
},
});
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
index 4ca9f6b..5ab91f2 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
@@ -1,347 +1,126 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "field:year",
- "beta": 0,
- "creation": "2013-01-22 16:50:25",
- "custom": 0,
- "description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "field:year",
+ "creation": "2013-01-22 16:50:25",
+ "description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "year",
+ "disabled",
+ "is_short_year",
+ "year_start_date",
+ "year_end_date",
+ "companies",
+ "auto_created"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "For e.g. 2012, 2012-13",
- "fieldname": "year",
- "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": "Year Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "year",
- "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": 0
- },
+ "description": "For e.g. 2012, 2012-13",
+ "fieldname": "year",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Year Name",
+ "oldfieldname": "year",
+ "oldfieldtype": "Data",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "disabled",
- "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": "Disabled",
- "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": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "year_start_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Year Start Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "year_start_date",
- "oldfieldtype": "Date",
- "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": 0
- },
+ "fieldname": "year_start_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Year Start Date",
+ "no_copy": 1,
+ "oldfieldname": "year_start_date",
+ "oldfieldtype": "Date",
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "year_end_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Year End Date",
- "length": 0,
- "no_copy": 1,
- "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": 0
- },
+ "fieldname": "year_end_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Year End Date",
+ "no_copy": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "companies",
- "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": "Companies",
- "length": 0,
- "no_copy": 0,
- "options": "Fiscal Year 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
- },
+ "fieldname": "companies",
+ "fieldtype": "Table",
+ "label": "Companies",
+ "options": "Fiscal Year Company"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "auto_created",
- "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": "Auto Created",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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
+ "default": "0",
+ "fieldname": "auto_created",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Auto Created",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "description": "Less than 12 months.",
+ "fieldname": "is_short_year",
+ "fieldtype": "Check",
+ "label": "Is Short Year",
+ "set_only_once": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-calendar",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-04-25 14:21:41.273354",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Fiscal Year",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-calendar",
+ "idx": 1,
+ "links": [],
+ "modified": "2020-11-05 12:16:53.081573",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Fiscal Year",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "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,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "read": 1,
+ "role": "Sales User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "read": 1,
+ "role": "Purchase User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "read": 1,
+ "role": "Accounts User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "read": 1,
+ "role": "Stock User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "read": 1,
+ "role": "Employee"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_field": "name",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "name",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py
index d80bc7f..da6a3fd 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py
@@ -36,6 +36,11 @@
frappe.throw(_("Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."))
def validate_dates(self):
+ if self.is_short_year:
+ # Fiscal Year can be shorter than one year, in some jurisdictions
+ # under certain circumstances. For example, in the USA and Germany.
+ return
+
if getdate(self.year_start_date) > getdate(self.year_end_date):
frappe.throw(_("Fiscal Year Start Date should be one year earlier than Fiscal Year End Date"),
FiscalYearIncorrectDate)
@@ -116,12 +121,8 @@
pass
def get_from_and_to_date(fiscal_year):
- from_and_to_date_tuple = frappe.db.sql("""select year_start_date, year_end_date
- from `tabFiscal Year` where name=%s""", (fiscal_year))[0]
-
- from_and_to_date = {
- "from_date": from_and_to_date_tuple[0],
- "to_date": from_and_to_date_tuple[1]
- }
-
- return from_and_to_date
+ fields = [
+ "year_start_date as from_date",
+ "year_end_date as to_date"
+ ]
+ return frappe.db.get_value("Fiscal Year", fiscal_year, fields, as_dict=1)
diff --git a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py
index f7b7782..cec4f44 100644
--- a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py
+++ b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py
@@ -11,6 +11,7 @@
test_ignore = ["Company"]
class TestFiscalYear(unittest.TestCase):
+
def test_extra_year(self):
if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"):
frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000")
diff --git a/erpnext/accounts/doctype/fiscal_year/test_records.json b/erpnext/accounts/doctype/fiscal_year/test_records.json
index d5723ca..4405253 100644
--- a/erpnext/accounts/doctype/fiscal_year/test_records.json
+++ b/erpnext/accounts/doctype/fiscal_year/test_records.json
@@ -1,6 +1,13 @@
[
{
"doctype": "Fiscal Year",
+ "year": "_Test Short Fiscal Year 2011",
+ "is_short_year": 1,
+ "year_end_date": "2011-04-01",
+ "year_start_date": "2011-12-31"
+ },
+ {
+ "doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2012",
"year_end_date": "2012-12-31",
"year_start_date": "2012-01-01"
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index def9ed6..ce76d0a 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -11,8 +11,10 @@
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_fiscal_year
-from erpnext.exceptions import InvalidAccountCurrency
+from erpnext.exceptions import InvalidAccountCurrency, InvalidAccountDimensionError, MandatoryAccountDimensionError
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
+from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import get_dimension_filter_map
+from six import iteritems
exclude_from_linked_with = True
class GLEntry(Document):
@@ -25,27 +27,30 @@
def validate(self):
self.flags.ignore_submit_comment = True
- self.check_mandatory()
self.validate_and_set_fiscal_year()
self.pl_must_have_cost_center()
- self.validate_cost_center()
- self.check_pl_account()
- self.validate_party()
- self.validate_currency()
+ if not self.flags.from_repost:
+ self.check_mandatory()
+ self.validate_cost_center()
+ self.check_pl_account()
+ self.validate_party()
+ self.validate_currency()
- def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
- self.validate_account_details(adv_adj)
- self.validate_dimensions_for_pl_and_bs()
+ def on_update(self):
+ adv_adj = self.flags.adv_adj
+ if not self.flags.from_repost:
+ self.validate_account_details(adv_adj)
+ self.validate_dimensions_for_pl_and_bs()
+ self.validate_allowed_dimensions()
+ validate_balance_type(self.account, adv_adj)
+ validate_frozen_account(self.account, adv_adj)
- validate_frozen_account(self.account, adv_adj)
- validate_balance_type(self.account, adv_adj)
-
- # Update outstanding amt on against voucher
- if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
- and self.against_voucher and update_outstanding == 'Yes':
- update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
- self.against_voucher)
+ # 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'):
+ update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
+ self.against_voucher)
def check_mandatory(self):
mandatory = ['account','voucher_type','voucher_no','company']
@@ -53,7 +58,7 @@
if not self.get(k):
frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
- account_type = frappe.db.get_value("Account", self.account, "account_type")
+ account_type = frappe.get_cached_value("Account", self.account, "account_type")
if not (self.party_type and self.party):
if account_type == "Receivable":
frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}")
@@ -68,17 +73,15 @@
.format(self.voucher_type, self.voucher_no, self.account))
def pl_must_have_cost_center(self):
- if frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss":
+ if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.")
.format(self.voucher_type, self.voucher_no, self.account))
def validate_dimensions_for_pl_and_bs(self):
-
account_type = frappe.db.get_value("Account", self.account, "report_type")
for dimension in get_checks_for_pl_and_bs_accounts():
-
if account_type == "Profit and Loss" \
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
if not self.get(dimension.fieldname):
@@ -91,6 +94,25 @@
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
.format(dimension.label, self.account))
+ def validate_allowed_dimensions(self):
+ dimension_filter_map = get_dimension_filter_map()
+ for key, value in iteritems(dimension_filter_map):
+ dimension = key[0]
+ account = key[1]
+
+ if self.account == account:
+ if value['is_mandatory'] and not self.get(dimension):
+ frappe.throw(_("{0} is mandatory for account {1}").format(
+ frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), MandatoryAccountDimensionError)
+
+ if value['allow_or_restrict'] == 'Allow':
+ if self.get(dimension) and self.get(dimension) not in value['allowed_dimensions']:
+ frappe.throw(_("Invalid value {0} for {1} against account {2}").format(
+ frappe.bold(self.get(dimension)), frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), InvalidAccountDimensionError)
+ else:
+ if self.get(dimension) and self.get(dimension) in value['allowed_dimensions']:
+ frappe.throw(_("Invalid value {0} for {1} against account {2}").format(
+ frappe.bold(self.get(dimension)), frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), InvalidAccountDimensionError)
def check_pl_account(self):
if self.is_opening=='Yes' and \
@@ -106,8 +128,8 @@
from tabAccount where name=%s""", self.account, as_dict=1)[0]
if ret.is_group==1:
- frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in
- transactions''').format(self.voucher_type, self.voucher_no, self.account))
+ frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in transactions''')
+ .format(self.voucher_type, self.voucher_no, self.account))
if ret.docstatus==2:
frappe.throw(_("{0} {1}: Account {2} is inactive")
@@ -118,26 +140,18 @@
.format(self.voucher_type, self.voucher_no, self.account, self.company))
def validate_cost_center(self):
- if not hasattr(self, "cost_center_company"):
- self.cost_center_company = {}
+ if not self.cost_center: return
- def _get_cost_center_company():
- if not self.cost_center_company.get(self.cost_center):
- self.cost_center_company[self.cost_center] = frappe.db.get_value(
- "Cost Center", self.cost_center, "company")
+ is_group, company = frappe.get_cached_value('Cost Center',
+ self.cost_center, ['is_group', 'company'])
- return self.cost_center_company[self.cost_center]
-
- def _check_is_group():
- return cint(frappe.get_cached_value('Cost Center', self.cost_center, 'is_group'))
-
- if self.cost_center and _get_cost_center_company() != self.company:
+ if company != self.company:
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
- if self.cost_center and _check_is_group():
- frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
- be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
+ if (self.voucher_type != 'Period Closing Voucher' and is_group):
+ frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot be used in transactions""").format(
+ self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
def validate_party(self):
validate_party_frozen_disabled(self.party_type, self.party)
@@ -147,7 +161,7 @@
account_currency = get_account_currency(self.account)
if not self.account_currency:
- self.account_currency = company_currency
+ self.account_currency = account_currency or company_currency
if account_currency != self.account_currency:
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
@@ -161,7 +175,6 @@
if not self.fiscal_year:
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
-
def validate_balance_type(account, adv_adj=False):
if not adv_adj and account:
balance_must_be = frappe.db.get_value("Account", account, "balance_must_be")
@@ -227,7 +240,7 @@
def validate_frozen_account(account, adv_adj=None):
- frozen_account = frappe.db.get_value("Account", account, "freeze_account")
+ frozen_account = frappe.get_cached_value("Account", account, "freeze_account")
if frozen_account == 'Yes' and not adv_adj:
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,
'frozen_accounts_modifier')
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
index 8083b21..af8940c 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
@@ -137,11 +137,12 @@
"cost_center": erpnext.get_default_cost_center(self.company)
})
- je.append("accounts", {
- "account": self.bank_charges_account,
- "debit_in_account_currency": flt(self.bank_charges),
- "cost_center": erpnext.get_default_cost_center(self.company)
- })
+ if self.bank_charges:
+ je.append("accounts", {
+ "account": self.bank_charges_account,
+ "debit_in_account_currency": flt(self.bank_charges),
+ "cost_center": erpnext.get_default_cost_center(self.company)
+ })
je.append("accounts", {
"account": self.short_term_loan,
diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py
index 3d74d9a..919dd0c 100644
--- a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py
+++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py
@@ -80,6 +80,7 @@
short_term_loan=self.short_term_loan,
bank_charges_account=self.bank_charges_account,
bank_account=self.bank_account,
+ bank_charges=100
)
je = inv_disc.create_disbursement_entry()
@@ -289,6 +290,7 @@
inv_disc.bank_account=args.bank_account
inv_disc.loan_start_date = args.start or nowdate()
inv_disc.loan_period = args.period or 30
+ inv_disc.bank_charges = flt(args.bank_charges)
for d in invoices:
inv_disc.append("invoices", {
diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template.json b/erpnext/accounts/doctype/item_tax_template/item_tax_template.json
index 8915f79..77c9e95 100644
--- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.json
+++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.json
@@ -1,7 +1,7 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
- "autoname": "field:title",
"creation": "2018-11-22 22:45:00.370913",
"doctype": "DocType",
"document_type": "Setup",
@@ -20,8 +20,7 @@
"in_list_view": 1,
"label": "Title",
"no_copy": 1,
- "reqd": 1,
- "unique": 1
+ "reqd": 1
},
{
"fieldname": "taxes",
@@ -33,12 +32,14 @@
{
"fieldname": "company",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
}
],
- "modified": "2020-09-18 17:26:09.703215",
+ "links": [],
+ "modified": "2021-03-08 19:50:21.416513",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Item Tax Template",
@@ -81,5 +82,6 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
+ "title_field": "title",
"track_changes": 1
}
\ No newline at end of file
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 e77481d..d9155cb 100644
--- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.py
+++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.py
@@ -11,6 +11,11 @@
def validate(self):
self.validate_tax_accounts()
+ def autoname(self):
+ if self.company and self.title:
+ abbr = frappe.get_cached_value('Company', self.company, 'abbr')
+ self.name = '{0} - {1}'.format(self.title, abbr)
+
def validate_tax_accounts(self):
"""Check whether Tax Rate is not entered twice for same Tax Type"""
check_list = []
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 acc308e..3d80a97 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
@@ -20,7 +20,8 @@
'items': ['Purchase Invoice', 'Purchase Order', 'Purchase Receipt']
},
{
- 'items': ['Item']
+ 'label': _('Stock'),
+ 'items': ['Item Groups', 'Item']
}
]
}
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 409c15f..37b03f3 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -120,6 +120,8 @@
}
}
});
+
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
voucher_type: function(frm){
@@ -197,6 +199,7 @@
this.load_defaults();
this.setup_queries();
this.setup_balance_formatter();
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
onload_post_render: function() {
@@ -210,7 +213,7 @@
$.each(this.frm.doc.accounts || [], function(i, jvd) {
frappe.model.set_default_values(jvd);
});
- var posting_date = this.frm.posting_date;
+ var posting_date = this.frm.doc.posting_date;
if(!this.frm.doc.amended_from) this.frm.set_value('posting_date', posting_date || frappe.datetime.get_today());
}
},
@@ -222,15 +225,6 @@
return erpnext.journal_entry.account_query(me.frm);
});
- me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) {
- return {
- filters: {
- company: me.frm.doc.company,
- is_group: 0
- }
- };
- });
-
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
@@ -406,6 +400,8 @@
}
}
cur_frm.cscript.update_totals(doc);
+
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
},
});
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 4573c50..b7bbb74 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-03-25 10:53:52",
@@ -503,7 +504,7 @@
"idx": 176,
"is_submittable": 1,
"links": [],
- "modified": "2020-06-02 18:15:46.955697",
+ "modified": "2020-10-30 13:56:01.121995",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 34c262e..3419bb6 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -6,14 +6,18 @@
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, nowdate, cint, get_link_to_form
from frappe import msgprint, _, scrub
from erpnext.controllers.accounts_controller import AccountsController
-from erpnext.accounts.utils import get_balance_on, get_account_currency
+from erpnext.accounts.utils import get_balance_on, get_stock_accounts, get_stock_and_account_balance, \
+ get_account_currency, check_if_stock_and_account_balance_synced
from erpnext.accounts.party import get_party_account
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
-from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
+from erpnext.accounts.doctype.invoice_discounting.invoice_discounting \
+ import get_party_account_based_on_invoice_discounting
from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts
from six import string_types, iteritems
+class StockAccountInvalidTransaction(frappe.ValidationError): pass
+
class JournalEntry(AccountsController):
def __init__(self, *args, **kwargs):
super(JournalEntry, self).__init__(*args, **kwargs)
@@ -22,14 +26,19 @@
return self.voucher_type
def validate(self):
+ if self.voucher_type == 'Opening Entry':
+ self.is_opening = 'Yes'
+
if not self.is_opening:
self.is_opening='No'
+
self.clearance_date = None
self.validate_party()
self.validate_entries_for_advance()
self.validate_multi_currency()
self.set_amounts_in_company_currency()
+ self.validate_debit_credit_amount()
self.validate_total_debit_and_credit()
self.validate_against_jv()
self.validate_reference_doc()
@@ -41,6 +50,7 @@
self.validate_empty_accounts_table()
self.set_account_and_party_balance()
self.validate_inter_company_accounts()
+ self.validate_stock_accounts()
if not self.title:
self.title = self.get_title()
@@ -52,6 +62,8 @@
self.update_expense_claim()
self.update_inter_company_jv()
self.update_invoice_discounting()
+ check_if_stock_and_account_balance_synced(self.posting_date,
+ self.company, self.doctype, self.name)
def on_cancel(self):
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
@@ -91,6 +103,16 @@
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
+ def validate_stock_accounts(self):
+ stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
+ for account in stock_accounts:
+ account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
+ self.posting_date, self.company)
+
+ if account_bal == stock_bal:
+ frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
+ .format(account), StockAccountInvalidTransaction)
+
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,\
@@ -207,11 +229,11 @@
if d.reference_type=="Journal Entry":
account_root_type = frappe.db.get_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0:
- frappe.throw(_("For {0}, only credit accounts can be linked against another debit entry")
- .format(d.account))
+ frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets credited")
+ .format(d.idx, d.account))
elif account_root_type == "Liability" and flt(d.credit) > 0:
- frappe.throw(_("For {0}, only debit accounts can be linked against another credit entry")
- .format(d.account))
+ frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets debited")
+ .format(d.idx, d.account))
if d.reference_name == self.name:
frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column"))
@@ -335,8 +357,7 @@
currency=account_currency)
if flt(voucher_total) < (flt(order.advance_paid) + total):
- frappe.throw(_("Advance paid against {0} {1} cannot be greater \
- than Grand Total {2}").format(reference_type, reference_name, formatted_voucher_total))
+ frappe.throw(_("Advance paid against {0} {1} cannot be greater than Grand Total {2}").format(reference_type, reference_name, formatted_voucher_total))
def validate_invoices(self):
"""Validate totals and docstatus for invoices"""
@@ -365,6 +386,11 @@
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited)))
+ def validate_debit_credit_amount(self):
+ for d in self.get('accounts'):
+ if not flt(d.debit) and not flt(d.credit):
+ frappe.throw(_("Row {0}: Both Debit and Credit values cannot be zero").format(d.idx))
+
def validate_total_debit_and_credit(self):
self.set_total_debit_credit()
if self.difference:
@@ -1051,4 +1077,4 @@
},
}, target_doc)
- return doclist
\ No newline at end of file
+ return doclist
diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
index 53c0758..5f003e0 100644
--- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
@@ -6,7 +6,7 @@
from frappe.utils import flt, nowdate
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.exceptions import InvalidAccountCurrency
-from erpnext.accounts.general_ledger import StockAccountInvalidTransaction
+from erpnext.accounts.doctype.journal_entry.journal_entry import StockAccountInvalidTransaction
class TestJournalEntry(unittest.TestCase):
def test_journal_entry_with_against_jv(self):
@@ -75,54 +75,46 @@
elif test_voucher.doctype in ["Sales Order", "Purchase Order"]:
# if test_voucher is a Sales Order/Purchase Order, test error on cancellation of test_voucher
+ frappe.db.set_value("Accounts Settings", "Accounts Settings",
+ "unlink_advance_payment_on_cancelation_of_order", 0)
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
self.assertRaises(frappe.LinkExistsError, submitted_voucher.cancel)
def test_jv_against_stock_account(self):
- from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
- set_perpetual_inventory()
+ company = "_Test Company with perpetual inventory"
+ stock_account = get_inventory_account(company)
- jv = frappe.copy_doc({
- "cheque_date": nowdate(),
- "cheque_no": "33",
- "company": "_Test Company with perpetual inventory",
- "doctype": "Journal Entry",
- "accounts": [
- {
- "account": "Debtors - TCP1",
- "party_type": "Customer",
- "party": "_Test Customer",
- "credit_in_account_currency": 400.0,
- "debit_in_account_currency": 0.0,
- "doctype": "Journal Entry Account",
- "parentfield": "accounts",
- "cost_center": "Main - TCP1"
- },
- {
- "account": "_Test Bank - TCP1",
- "credit_in_account_currency": 0.0,
- "debit_in_account_currency": 400.0,
- "doctype": "Journal Entry Account",
- "parentfield": "accounts",
- "cost_center": "Main - TCP1"
- }
- ],
- "naming_series": "_T-Journal Entry-",
- "posting_date": nowdate(),
- "user_remark": "test",
- "voucher_type": "Bank Entry"
- })
+ from erpnext.accounts.utils import get_stock_and_account_balance
+ account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(stock_account, nowdate(), company)
+ diff = flt(account_bal) - flt(stock_bal)
- jv.get("accounts")[0].update({
- "account": get_inventory_account('_Test Company with perpetual inventory'),
- "company": "_Test Company with perpetual inventory",
- "party_type": None,
- "party": None
+ if not diff:
+ diff = 100
+
+ jv = frappe.new_doc("Journal Entry")
+ jv.company = company
+ jv.posting_date = nowdate()
+ jv.append("accounts", {
+ "account": stock_account,
+ "cost_center": "Main - TCP1",
+ "debit_in_account_currency": 0 if diff > 0 else abs(diff),
+ "credit_in_account_currency": diff if diff > 0 else 0
})
+
+ jv.append("accounts", {
+ "account": "Stock Adjustment - TCP1",
+ "cost_center": "Main - TCP1",
+ "debit_in_account_currency": diff if diff > 0 else 0,
+ "credit_in_account_currency": 0 if diff > 0 else abs(diff)
+ })
+ jv.insert()
- self.assertRaises(StockAccountInvalidTransaction, jv.submit)
- jv.cancel()
- set_perpetual_inventory(0)
+ if account_bal == stock_bal:
+ self.assertRaises(StockAccountInvalidTransaction, jv.submit)
+ frappe.db.rollback()
+ else:
+ jv.submit()
+ jv.cancel()
def test_multi_currency(self):
jv = make_journal_entry("_Test Bank USD - _TC",
@@ -168,7 +160,7 @@
self.assertFalse(gle)
def test_reverse_journal_entry(self):
- from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
+ from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
jv = make_journal_entry("_Test Bank USD - _TC",
"Sales - _TC", 100, exchange_rate=50, save=False)
@@ -307,15 +299,20 @@
def test_jv_with_project(self):
from erpnext.projects.doctype.project.test_project import make_project
- project = make_project({
- 'project_name': 'Journal Entry Project',
- 'project_template_name': 'Test Project Template',
- 'start_date': '2020-01-01'
- })
+
+ if not frappe.db.exists("Project", {"project_name": "Journal Entry Project"}):
+ project = make_project({
+ 'project_name': 'Journal Entry Project',
+ 'project_template_name': 'Test Project Template',
+ 'start_date': '2020-01-01'
+ })
+ project_name = project.name
+ else:
+ project_name = frappe.get_value("Project", {"project_name": "_Test Project"})
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False)
for d in jv.accounts:
- d.project = project.project_name
+ d.project = project_name
jv.voucher_type = "Bank Entry"
jv.multi_currency = 0
jv.cheque_no = "112233"
@@ -325,10 +322,10 @@
expected_values = {
"_Test Cash - _TC": {
- "project": project.project_name
+ "project": project_name
},
"_Test Bank - _TC": {
- "project": project.project_name
+ "project": project_name
}
}
diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.js b/erpnext/accounts/doctype/loyalty_program/loyalty_program.js
index 524a671..f90f867 100644
--- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.js
+++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.js
@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Loyalty Program', {
setup: function(frm) {
var help_content =
@@ -46,20 +48,17 @@
};
});
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- };
- });
-
frm.set_value("company", frappe.defaults.get_user_default("Company"));
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) {
frappe.throw(__("Please select the Multiple Tier Program type for more than one collection rules."));
}
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}
});
diff --git a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
index ee73cca..3199488 100644
--- a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
+++ b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
@@ -8,12 +8,10 @@
from frappe.utils import today, cint, flt, getdate
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
from erpnext.accounts.party import get_dashboard_info
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestLoyaltyProgram(unittest.TestCase):
@classmethod
def setUpClass(self):
- set_perpetual_inventory(0)
# create relevant item, customer, loyalty program, etc
create_records()
@@ -195,88 +193,91 @@
def create_records():
# create a new loyalty Account
- if frappe.db.exists("Account", "Loyalty - _TC"):
- return
-
- frappe.get_doc({
- "doctype": "Account",
- "account_name": "Loyalty",
- "parent_account": "Direct Expenses - _TC",
- "company": "_Test Company",
- "is_group": 0,
- "account_type": "Expense Account",
- }).insert()
+ if not frappe.db.exists("Account", "Loyalty - _TC"):
+ frappe.get_doc({
+ "doctype": "Account",
+ "account_name": "Loyalty",
+ "parent_account": "Direct Expenses - _TC",
+ "company": "_Test Company",
+ "is_group": 0,
+ "account_type": "Expense Account",
+ }).insert()
# create a new loyalty program Single tier
- frappe.get_doc({
- "doctype": "Loyalty Program",
- "loyalty_program_name": "Test Single Loyalty",
- "auto_opt_in": 1,
- "from_date": today(),
- "loyalty_program_type": "Single Tier Program",
- "conversion_factor": 1,
- "expiry_duration": 10,
- "company": "_Test Company",
- "cost_center": "Main - _TC",
- "expense_account": "Loyalty - _TC",
- "collection_rules": [{
- 'tier_name': 'Silver',
- 'collection_factor': 1000,
- 'min_spent': 1000
- }]
- }).insert()
-
- # create a new customer
- frappe.get_doc({
- "customer_group": "_Test Customer Group",
- "customer_name": "Test Loyalty Customer",
- "customer_type": "Individual",
- "doctype": "Customer",
- "territory": "_Test Territory"
- }).insert()
-
- # create a new loyalty program Multiple tier
- frappe.get_doc({
- "doctype": "Loyalty Program",
- "loyalty_program_name": "Test Multiple Loyalty",
- "auto_opt_in": 1,
- "from_date": today(),
- "loyalty_program_type": "Multiple Tier Program",
- "conversion_factor": 1,
- "expiry_duration": 10,
- "company": "_Test Company",
- "cost_center": "Main - _TC",
- "expense_account": "Loyalty - _TC",
- "collection_rules": [
- {
+ if not frappe.db.exists("Loyalty Program","Test Single Loyalty"):
+ frappe.get_doc({
+ "doctype": "Loyalty Program",
+ "loyalty_program_name": "Test Single Loyalty",
+ "auto_opt_in": 1,
+ "from_date": today(),
+ "loyalty_program_type": "Single Tier Program",
+ "conversion_factor": 1,
+ "expiry_duration": 10,
+ "company": "_Test Company",
+ "cost_center": "Main - _TC",
+ "expense_account": "Loyalty - _TC",
+ "collection_rules": [{
'tier_name': 'Silver',
'collection_factor': 1000,
- 'min_spent': 10000
- },
- {
- 'tier_name': 'Gold',
- 'collection_factor': 1000,
- 'min_spent': 19000
- }
- ]
- }).insert()
+ 'min_spent': 1000
+ }]
+ }).insert()
+
+ # create a new customer
+ if not frappe.db.exists("Customer","Test Loyalty Customer"):
+ frappe.get_doc({
+ "customer_group": "_Test Customer Group",
+ "customer_name": "Test Loyalty Customer",
+ "customer_type": "Individual",
+ "doctype": "Customer",
+ "territory": "_Test Territory"
+ }).insert()
+
+ # create a new loyalty program Multiple tier
+ if not frappe.db.exists("Loyalty Program","Test Multiple Loyalty"):
+ frappe.get_doc({
+ "doctype": "Loyalty Program",
+ "loyalty_program_name": "Test Multiple Loyalty",
+ "auto_opt_in": 1,
+ "from_date": today(),
+ "loyalty_program_type": "Multiple Tier Program",
+ "conversion_factor": 1,
+ "expiry_duration": 10,
+ "company": "_Test Company",
+ "cost_center": "Main - _TC",
+ "expense_account": "Loyalty - _TC",
+ "collection_rules": [
+ {
+ 'tier_name': 'Silver',
+ 'collection_factor': 1000,
+ 'min_spent': 10000
+ },
+ {
+ 'tier_name': 'Gold',
+ 'collection_factor': 1000,
+ 'min_spent': 19000
+ }
+ ]
+ }).insert()
# create an item
- item = frappe.get_doc({
- "doctype": "Item",
- "item_code": "Loyal Item",
- "item_name": "Loyal Item",
- "item_group": "All Item Groups",
- "company": "_Test Company",
- "is_stock_item": 1,
- "opening_stock": 100,
- "valuation_rate": 10000,
- }).insert()
+ if not frappe.db.exists("Item", "Loyal Item"):
+ frappe.get_doc({
+ "doctype": "Item",
+ "item_code": "Loyal Item",
+ "item_name": "Loyal Item",
+ "item_group": "All Item Groups",
+ "company": "_Test Company",
+ "is_stock_item": 1,
+ "opening_stock": 100,
+ "valuation_rate": 10000,
+ }).insert()
# create item price
- frappe.get_doc({
- "doctype": "Item Price",
- "price_list": "Standard Selling",
- "item_code": item.item_code,
- "price_list_rate": 10000
- }).insert()
+ if not frappe.db.exists("Item Price", {"price_list": "Standard Selling", "item_code": "Loyal Item"}):
+ frappe.get_doc({
+ "doctype": "Item Price",
+ "price_list": "Standard Selling",
+ "item_code": "Loyal Item",
+ "price_list_rate": 10000
+ }).insert()
diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
index d3040c8..7a06d35 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
@@ -1,13 +1,17 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-cur_frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
- return{
- filters: [
- ['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
- ['Account', 'is_group', '=', 0],
- ['Account', 'company', '=', d.company]
- ]
- }
-});
+frappe.ui.form.on('Mode of Payment', {
+ setup: function(frm) {
+ frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
+ let d = locals[cdt][cdn];
+ return {
+ filters: [
+ ['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
+ ['Account', 'is_group', '=', 0],
+ ['Account', 'company', '=', d.company]
+ ]
+ };
+ });
+ },
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
index 50fc3bb..51fc3f7 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:mode_of_payment",
@@ -28,7 +29,7 @@
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Type",
- "options": "Cash\nBank\nGeneral"
+ "options": "Cash\nBank\nGeneral\nPhone"
},
{
"fieldname": "accounts",
@@ -45,7 +46,9 @@
],
"icon": "fa fa-credit-card",
"idx": 1,
- "modified": "2020-09-18 17:26:09.703215",
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-09-18 17:57:23.835236",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Mode of Payment",
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 d54a47e..3247369 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py
@@ -12,7 +12,7 @@
self.validate_accounts()
self.validate_repeating_companies()
self.validate_pos_mode_of_payment()
-
+
def validate_repeating_companies(self):
"""Error when Same Company is entered multiple times in accounts"""
accounts_list = []
@@ -31,10 +31,10 @@
def validate_pos_mode_of_payment(self):
if not self.enabled:
- pos_profiles = frappe.db.sql("""SELECT sip.parent FROM `tabSales Invoice Payment` sip
+ pos_profiles = frappe.db.sql("""SELECT sip.parent FROM `tabSales Invoice Payment` sip
WHERE sip.parenttype = 'POS Profile' and sip.mode_of_payment = %s""", (self.name))
pos_profiles = list(map(lambda x: x[0], pos_profiles))
-
+
if pos_profiles:
message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \
Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode."
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
index 699eb08..b2e8626 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
@@ -6,7 +6,7 @@
frm.set_query('party_type', 'invoices', function(doc, cdt, cdn) {
return {
filters: {
- 'name': ['in', 'Customer,Supplier']
+ 'name': ['in', 'Customer, Supplier']
}
};
});
@@ -14,29 +14,48 @@
if (frm.doc.company) {
frm.trigger('setup_company_filters');
}
+
+ frappe.realtime.on('opening_invoice_creation_progress', data => {
+ if (!frm.doc.import_in_progress) {
+ frm.dashboard.reset();
+ frm.doc.import_in_progress = true;
+ }
+ if (data.user != frappe.session.user) return;
+ if (data.count == data.total) {
+ setTimeout((title) => {
+ frm.doc.import_in_progress = false;
+ frm.clear_table("invoices");
+ frm.refresh_fields();
+ frm.page.clear_indicator();
+ frm.dashboard.hide_progress(title);
+ frappe.msgprint(__("Opening {0} Invoice created", [frm.doc.invoice_type]));
+ }, 1500, data.title);
+ return;
+ }
+
+ frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
+ frm.page.set_indicator(__('In Progress'), 'orange');
+ });
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
frm.disable_save();
- frm.trigger("make_dashboard");
+ !frm.doc.import_in_progress && frm.trigger("make_dashboard");
frm.page.set_primary_action(__('Create Invoices'), () => {
let btn_primary = frm.page.btn_primary.get(0);
return frm.call({
doc: frm.doc,
- freeze: true,
btn: $(btn_primary),
method: "make_invoices",
- freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type]),
- callback: (r) => {
- if(!r.exc){
- frappe.msgprint(__("Opening {0} Invoice created", [frm.doc.invoice_type]));
- frm.clear_table("invoices");
- frm.refresh_fields();
- frm.reload_doc();
- }
- }
+ freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type])
});
});
+
+ if (frm.doc.create_missing_party) {
+ frm.set_df_property("party", "fieldtype", "Data", frm.doc.name, "invoices");
+ }
},
setup_company_filters: function(frm) {
@@ -83,6 +102,7 @@
}
})
}
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
invoice_type: function(frm) {
@@ -101,7 +121,8 @@
frappe.render_template('opening_invoice_creation_tool_dashboard', {
data: opening_invoices_summary,
max_count: max_count
- })
+ }),
+ __("Opening Invoices Summary")
);
section.on('click', '.invoice-link', function() {
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 a53417e..e6449b7 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
@@ -4,9 +4,12 @@
from __future__ import unicode_literals
import frappe
+import traceback
+from json import dumps
from frappe import _, scrub
from frappe.utils import flt, nowdate
from frappe.model.document import Document
+from frappe.utils.background_jobs import enqueue
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
@@ -62,66 +65,47 @@
return invoices_summary, max_count
- def make_invoices(self):
- names = []
- mandatory_error_msg = _("Row {0}: {1} is required to create the Opening {2} Invoices")
+ def validate_company(self):
if not self.company:
frappe.throw(_("Please select the Company"))
- company_details = frappe.get_cached_value('Company', self.company,
- ["default_currency", "default_letter_head"], as_dict=1) or {}
+ def set_missing_values(self, row):
+ row.qty = row.qty or 1.0
+ row.temporary_opening_account = row.temporary_opening_account or get_temporary_opening_account(self.company)
+ row.party_type = "Customer" if self.invoice_type == "Sales" else "Supplier"
+ row.item_name = row.item_name or _("Opening Invoice Item")
+ row.posting_date = row.posting_date or nowdate()
+ row.due_date = row.due_date or nowdate()
+ def validate_mandatory_invoice_fields(self, row):
+ if not frappe.db.exists(row.party_type, row.party):
+ if self.create_missing_party:
+ self.add_party(row.party_type, row.party)
+ else:
+ frappe.throw(_("Row #{}: {} {} does not exist.").format(row.idx, frappe.bold(row.party_type), frappe.bold(row.party)))
+
+ mandatory_error_msg = _("Row #{0}: {1} is required to create the Opening {2} Invoices")
+ for d in ("Party", "Outstanding Amount", "Temporary Opening Account"):
+ if not row.get(scrub(d)):
+ frappe.throw(mandatory_error_msg.format(row.idx, d, self.invoice_type))
+
+ def get_invoices(self):
+ invoices = []
for row in self.invoices:
- if not row.qty:
- row.qty = 1.0
-
- # always mandatory fields for the invoices
- if not row.temporary_opening_account:
- row.temporary_opening_account = get_temporary_opening_account(self.company)
- row.party_type = "Customer" if self.invoice_type == "Sales" else "Supplier"
-
- # Allow to create invoice even if no party present in customer or supplier.
- if not frappe.db.exists(row.party_type, row.party):
- if self.create_missing_party:
- self.add_party(row.party_type, row.party)
- else:
- frappe.throw(_("{0} {1} does not exist.").format(frappe.bold(row.party_type), frappe.bold(row.party)))
-
- if not row.item_name:
- row.item_name = _("Opening Invoice Item")
- if not row.posting_date:
- row.posting_date = nowdate()
- if not row.due_date:
- row.due_date = nowdate()
-
- for d in ("Party", "Outstanding Amount", "Temporary Opening Account"):
- if not row.get(scrub(d)):
- frappe.throw(mandatory_error_msg.format(row.idx, _(d), self.invoice_type))
-
- args = self.get_invoice_dict(row=row)
- if not args:
+ if not row:
continue
-
+ self.set_missing_values(row)
+ self.validate_mandatory_invoice_fields(row)
+ invoice = self.get_invoice_dict(row)
+ company_details = frappe.get_cached_value('Company', self.company, ["default_currency", "default_letter_head"], as_dict=1) or {}
if company_details:
- args.update({
+ invoice.update({
"currency": company_details.get("default_currency"),
"letter_head": company_details.get("default_letter_head")
})
+ invoices.append(invoice)
- doc = frappe.get_doc(args).insert()
- doc.submit()
- names.append(doc.name)
-
- if len(self.invoices) > 5:
- frappe.publish_realtime(
- "progress", dict(
- progress=[row.idx, len(self.invoices)],
- title=_('Creating {0}').format(doc.doctype)
- ),
- user=frappe.session.user
- )
-
- return names
+ return invoices
def add_party(self, party_type, party):
party_doc = frappe.new_doc(party_type)
@@ -140,14 +124,12 @@
def get_invoice_dict(self, row=None):
def get_item_dict():
- default_uom = frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos")
- cost_center = row.get('cost_center') or frappe.get_cached_value('Company',
- self.company, "cost_center")
-
+ cost_center = row.get('cost_center') or frappe.get_cached_value('Company', self.company, "cost_center")
if not cost_center:
- frappe.throw(
- _("Please set the Default Cost Center in {0} company.").format(frappe.bold(self.company))
- )
+ frappe.throw(_("Please set the Default Cost Center in {0} company.").format(frappe.bold(self.company)))
+
+ income_expense_account_field = "income_account" if row.party_type == "Customer" else "expense_account"
+ default_uom = frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos")
rate = flt(row.outstanding_amount) / flt(row.qty)
return frappe._dict({
@@ -161,18 +143,9 @@
"cost_center": cost_center
})
- if not row:
- return None
-
- party_type = "Customer"
- income_expense_account_field = "income_account"
- if self.invoice_type == "Purchase":
- party_type = "Supplier"
- income_expense_account_field = "expense_account"
-
item = get_item_dict()
- args = frappe._dict({
+ invoice = frappe._dict({
"items": [item],
"is_opening": "Yes",
"set_posting_time": 1,
@@ -180,21 +153,78 @@
"cost_center": self.cost_center,
"due_date": row.due_date,
"posting_date": row.posting_date,
- frappe.scrub(party_type): row.party,
- "doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice"
+ frappe.scrub(row.party_type): row.party,
+ "is_pos": 0,
+ "doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice",
+ "update_stock": 0
})
accounting_dimension = get_accounting_dimensions()
-
for dimension in accounting_dimension:
- args.update({
+ invoice.update({
dimension: item.get(dimension)
})
- if self.invoice_type == "Sales":
- args["is_pos"] = 0
+ return invoice
- return args
+ def make_invoices(self):
+ self.validate_company()
+ invoices = self.get_invoices()
+ if len(invoices) < 50:
+ return start_import(invoices)
+ else:
+ from frappe.core.page.background_jobs.background_jobs import get_info
+ from frappe.utils.scheduler import is_scheduler_inactive
+
+ if is_scheduler_inactive() and not frappe.flags.in_test:
+ frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive"))
+
+ enqueued_jobs = [d.get("job_name") for d in get_info()]
+ if self.name not in enqueued_jobs:
+ enqueue(
+ start_import,
+ queue="default",
+ timeout=6000,
+ event="opening_invoice_creation",
+ job_name=self.name,
+ invoices=invoices,
+ now=frappe.conf.developer_mode or frappe.flags.in_test
+ )
+
+def start_import(invoices):
+ errors = 0
+ names = []
+ for idx, d in enumerate(invoices):
+ try:
+ publish(idx, len(invoices), d.doctype)
+ doc = frappe.get_doc(d)
+ doc.flags.ignore_mandatory = True
+ doc.insert()
+ doc.submit()
+ frappe.db.commit()
+ names.append(doc.name)
+ except Exception:
+ errors += 1
+ frappe.db.rollback()
+ message = "\n".join(["Data:", dumps(d, default=str, indent=4), "--" * 50, "\nException:", traceback.format_exc()])
+ frappe.log_error(title="Error while creating Opening Invoice", message=message)
+ frappe.db.commit()
+ if errors:
+ frappe.msgprint(_("You had {} errors while creating opening invoices. Check {} for more details")
+ .format(errors, "<a href='/app/List/Error Log' class='variant-click'>Error Log</a>"), indicator="red", title=_("Error Occured"))
+ return names
+
+def publish(index, total, doctype):
+ if total < 5: return
+ frappe.publish_realtime(
+ "opening_invoice_creation_progress",
+ dict(
+ title=_("Opening Invoice Creation In Progress"),
+ message=_('Creating {} out of {} {}').format(index + 1, total, doctype),
+ user=frappe.session.user,
+ count=index+1,
+ total=total
+ ))
@frappe.whitelist()
def get_temporary_opening_account(company=None):
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool_dashboard.html b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool_dashboard.html
index 5b136d4..afbcfa5 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool_dashboard.html
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool_dashboard.html
@@ -1,4 +1,3 @@
-<h5 style="margin-top: 0px;">{{ __("Opening Invoices Summary") }}</h5>
{% $.each(data, (company, summary) => { %}
<h6 style="margin: 15px 0px -10px 0px;"><a class="company-link"> {{ company }}</a></h6>
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 3bfc10d..8d6de2d 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
@@ -6,26 +6,45 @@
import frappe
import unittest
-test_dependencies = ["Customer", "Supplier"]
+from frappe.cache_manager import clear_doctype_cache
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import get_temporary_opening_account
+test_dependencies = ["Customer", "Supplier"]
+
class TestOpeningInvoiceCreationTool(unittest.TestCase):
- def make_invoices(self, invoice_type="Sales"):
+ def setUp(self):
+ if not frappe.db.exists("Company", "_Test Opening Invoice Company"):
+ make_company()
+
+ def make_invoices(self, invoice_type="Sales", company=None, party_1=None, party_2=None):
doc = frappe.get_single("Opening Invoice Creation Tool")
- args = get_opening_invoice_creation_dict(invoice_type=invoice_type)
+ args = get_opening_invoice_creation_dict(invoice_type=invoice_type, company=company,
+ party_1=party_1, party_2=party_2)
doc.update(args)
return doc.make_invoices()
def test_opening_sales_invoice_creation(self):
- invoices = self.make_invoices()
+ property_setter = make_property_setter("Sales Invoice", "update_stock", "default", 1, "Check")
+ try:
+ invoices = self.make_invoices(company="_Test Opening Invoice Company")
- self.assertEqual(len(invoices), 2)
- expected_value = {
- "keys": ["customer", "outstanding_amount", "status"],
- 0: ["_Test Customer", 300, "Overdue"],
- 1: ["_Test Customer 1", 250, "Overdue"],
- }
- self.check_expected_values(invoices, expected_value)
+ self.assertEqual(len(invoices), 2)
+ expected_value = {
+ "keys": ["customer", "outstanding_amount", "status"],
+ 0: ["_Test Customer", 300, "Overdue"],
+ 1: ["_Test Customer 1", 250, "Overdue"],
+ }
+ self.check_expected_values(invoices, expected_value)
+
+ si = frappe.get_doc("Sales Invoice", invoices[0])
+
+ # Check if update stock is not enabled
+ self.assertEqual(si.update_stock, 0)
+
+ finally:
+ property_setter.delete()
+ clear_doctype_cache("Sales Invoice")
def check_expected_values(self, invoices, expected_value, invoice_type="Sales"):
doctype = "Sales Invoice" if invoice_type == "Sales" else "Purchase Invoice"
@@ -36,7 +55,7 @@
self.assertEqual(si.get(field, ""), expected_value[invoice_idx][field_idx])
def test_opening_purchase_invoice_creation(self):
- invoices = self.make_invoices(invoice_type="Purchase")
+ invoices = self.make_invoices(invoice_type="Purchase", company="_Test Opening Invoice Company")
self.assertEqual(len(invoices), 2)
expected_value = {
@@ -44,7 +63,33 @@
0: ["_Test Supplier", 300, "Overdue"],
1: ["_Test Supplier 1", 250, "Overdue"],
}
- self.check_expected_values(invoices, expected_value, invoice_type="Purchase", )
+ self.check_expected_values(invoices, expected_value, "Purchase")
+
+ def test_opening_sales_invoice_creation_with_missing_debit_account(self):
+ company = "_Test Opening Invoice Company"
+ party_1, party_2 = make_customer("Customer A"), make_customer("Customer B")
+
+ old_default_receivable_account = frappe.db.get_value("Company", company, "default_receivable_account")
+ frappe.db.set_value("Company", company, "default_receivable_account", "")
+
+ if not frappe.db.exists("Cost Center", "_Test Opening Invoice Company - _TOIC"):
+ cc = frappe.get_doc({"doctype": "Cost Center", "cost_center_name": "_Test Opening Invoice Company",
+ "is_group": 1, "company": "_Test Opening Invoice Company"})
+ cc.insert(ignore_mandatory=True)
+ cc2 = frappe.get_doc({"doctype": "Cost Center", "cost_center_name": "Main", "is_group": 0,
+ "company": "_Test Opening Invoice Company", "parent_cost_center": cc.name})
+ cc2.insert()
+
+ frappe.db.set_value("Company", company, "cost_center", "Main - _TOIC")
+
+ self.make_invoices(company="_Test Opening Invoice Company", party_1=party_1, party_2=party_2)
+
+ # Check if missing debit account error raised
+ error_log = frappe.db.exists("Error Log", {"error": ["like", "%erpnext.controllers.accounts_controller.AccountMissingError%"]})
+ self.assertTrue(error_log)
+
+ # teardown
+ frappe.db.set_value("Company", company, "default_receivable_account", old_default_receivable_account)
def get_opening_invoice_creation_dict(**args):
party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier"
@@ -57,7 +102,7 @@
{
"qty": 1.0,
"outstanding_amount": 300,
- "party": "_Test {0}".format(party),
+ "party": args.get("party_1") or "_Test {0}".format(party),
"item_name": "Opening Item",
"due_date": "2016-09-10",
"posting_date": "2016-09-05",
@@ -66,7 +111,7 @@
{
"qty": 2.0,
"outstanding_amount": 250,
- "party": "_Test {0} 1".format(party),
+ "party": args.get("party_2") or "_Test {0} 1".format(party),
"item_name": "Opening Item",
"due_date": "2016-09-10",
"posting_date": "2016-09-05",
@@ -76,4 +121,31 @@
})
invoice_dict.update(args)
- return invoice_dict
\ No newline at end of file
+ return invoice_dict
+
+def make_company():
+ if frappe.db.exists("Company", "_Test Opening Invoice Company"):
+ return frappe.get_doc("Company", "_Test Opening Invoice Company")
+
+ company = frappe.new_doc("Company")
+ company.company_name = "_Test Opening Invoice Company"
+ company.abbr = "_TOIC"
+ company.default_currency = "INR"
+ company.country = "India"
+ company.insert()
+ return company
+
+def make_customer(customer=None):
+ customer_name = customer or "Opening Customer"
+ customer = frappe.get_doc({
+ "doctype": "Customer",
+ "customer_name": customer_name,
+ "customer_group": "All Customer Groups",
+ "customer_type": "Company",
+ "territory": "All Territories"
+ })
+ if not frappe.db.exists("Customer", customer_name):
+ customer.insert(ignore_permissions=True)
+ return customer.name
+ else:
+ return frappe.db.exists("Customer", customer_name)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index e117471..b5f6a40 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -1,6 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
{% include "erpnext/public/js/controllers/accounts.js" %}
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Payment Entry', {
onload: function(frm) {
@@ -8,6 +9,8 @@
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
setup: function(frm) {
@@ -88,24 +91,17 @@
}
});
- frm.set_query("cost_center", "deductions", function() {
- return {
- filters: {
- "is_group": 0,
- "company": frm.doc.company
- }
- }
- });
-
frm.set_query("reference_doctype", "references", function() {
- if (frm.doc.party_type=="Customer") {
+ if (frm.doc.party_type == "Customer") {
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
- } else if (frm.doc.party_type=="Supplier") {
+ } else if (frm.doc.party_type == "Supplier") {
var doctypes = ["Purchase Order", "Purchase Invoice", "Journal Entry"];
- } else if (frm.doc.party_type=="Employee") {
+ } else if (frm.doc.party_type == "Employee") {
var doctypes = ["Expense Claim", "Journal Entry"];
- } else if (frm.doc.party_type=="Student") {
+ } else if (frm.doc.party_type == "Student") {
var doctypes = ["Fees"];
+ } else if (frm.doc.party_type == "Donor") {
+ var doctypes = ["Donation"];
} else {
var doctypes = ["Journal Entry"];
}
@@ -134,7 +130,7 @@
const child = locals[cdt][cdn];
const filters = {"docstatus": 1, "company": doc.company};
const party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice',
- 'Purchase Order', 'Expense Claim', 'Fees', 'Dunning'];
+ 'Purchase Order', 'Expense Claim', 'Fees', 'Dunning', 'Donation'];
if (in_list(party_type_doctypes, child.reference_doctype)) {
filters[doc.party_type.toLowerCase()] = doc.party;
@@ -167,6 +163,7 @@
company: function(frm) {
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
contact_person: function(frm) {
@@ -286,7 +283,7 @@
let party_types = Object.keys(frappe.boot.party_account_types);
if(frm.doc.party_type && !party_types.includes(frm.doc.party_type)){
frm.set_value("party_type", "");
- frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
+ frappe.throw(__("Party can only be one of {0}", [party_types.join(", ")]));
}
frm.set_query("party", function() {
@@ -401,6 +398,8 @@
set_account_currency_and_balance: function(frm, account, currency_field,
balance_field, callback_function) {
+
+ var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
if (frm.doc.posting_date && account) {
frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
@@ -427,6 +426,14 @@
if(!frm.doc.paid_amount && frm.doc.received_amount)
frm.events.received_amount(frm);
+
+ if (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency
+ && frm.doc.paid_amount != frm.doc.received_amount) {
+ if (company_currency != frm.doc.paid_from_account_currency &&
+ frm.doc.payment_type == "Pay") {
+ frm.doc.paid_amount = frm.doc.received_amount;
+ }
+ }
}
},
() => {
@@ -598,12 +605,22 @@
{fieldtype:"Column Break"},
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
{fieldtype:"Section Break"},
+ {fieldtype:"Link", label:__("Cost Center"), fieldname:"cost_center", options:"Cost Center",
+ "get_query": function() {
+ return {
+ "filters": {"company": frm.doc.company}
+ }
+ }
+ },
+ {fieldtype:"Column Break"},
+ {fieldtype:"Section Break"},
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
];
frappe.prompt(fields, function(filters){
frappe.flags.allocate_payment_amount = true;
frm.events.validate_filters_data(frm, filters);
+ frm.doc.cost_center = filters.cost_center;
frm.events.get_outstanding_documents(frm, filters);
}, __("Filters"), __("Get Outstanding Documents"));
},
@@ -700,7 +717,8 @@
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") ||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee") ||
- (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
+ (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") ||
+ (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Donor")
) {
if(total_positive_outstanding > total_negative_outstanding)
if (!frm.doc.paid_amount)
@@ -743,7 +761,8 @@
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") ||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee") ||
- (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
+ (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") ||
+ (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Donor")
) {
if(total_positive_outstanding_including_order > paid_amount) {
var remaining_outstanding = total_positive_outstanding_including_order - paid_amount;
@@ -900,6 +919,12 @@
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Expense Claim or Journal Entry", [row.idx]));
return false;
}
+
+ if (frm.doc.party_type == "Donor" && row.reference_doctype != "Donation") {
+ frappe.model.set_value(row.doctype, row.name, "reference_doctype", null);
+ frappe.msgprint(__("Row #{0}: Reference Document Type must be Donation", [row.idx]));
+ return false;
+ }
}
if (row) {
@@ -1051,11 +1076,6 @@
frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
frm.set_value("party_balance", r.message.party_balance);
- },
- () => {
- if(frm.doc.payment_type != "Internal") {
- frm.clear_table("references");
- }
}
]);
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index 72149a6..328584a 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2016-06-01 14:38:51.012597",
@@ -535,7 +536,8 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Title",
- "print_hide": 1
+ "print_hide": 1,
+ "read_only": 1
},
{
"depends_on": "party",
@@ -587,7 +589,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-09-02 13:39:43.383705",
+ "modified": "2021-03-08 13:05:16.958866",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
@@ -631,4 +633,4 @@
"sort_order": "DESC",
"title_field": "title",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 11ab020..8acd92c 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -72,6 +72,7 @@
self.update_outstanding_amounts()
self.update_advance_paid()
self.update_expense_claim()
+ self.update_donation()
self.update_payment_schedule()
self.set_status()
@@ -82,6 +83,7 @@
self.update_outstanding_amounts()
self.update_advance_paid()
self.update_expense_claim()
+ self.update_donation(cancel=1)
self.delink_advance_entry_references()
self.update_payment_schedule(cancel=1)
self.set_payment_req_status()
@@ -202,17 +204,32 @@
# if account_type not in account_types:
# frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
- def set_exchange_rate(self):
+ def set_exchange_rate(self, ref_doc=None):
+ self.set_source_exchange_rate(ref_doc)
+ self.set_target_exchange_rate(ref_doc)
+
+ def set_source_exchange_rate(self, ref_doc=None):
if self.paid_from and not self.source_exchange_rate:
if self.paid_from_account_currency == self.company_currency:
self.source_exchange_rate = 1
else:
- self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
- self.company_currency, self.posting_date)
+ if ref_doc:
+ if self.paid_from_account_currency == ref_doc.currency:
+ self.source_exchange_rate = ref_doc.get("exchange_rate")
+ if not self.source_exchange_rate:
+ self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
+ self.company_currency, self.posting_date)
+
+ def set_target_exchange_rate(self, ref_doc=None):
if self.paid_to and not self.target_exchange_rate:
- self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
- self.company_currency, self.posting_date)
+ if ref_doc:
+ if self.paid_to_account_currency == ref_doc.currency:
+ self.target_exchange_rate = ref_doc.get("exchange_rate")
+
+ if not self.target_exchange_rate:
+ self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
+ self.company_currency, self.posting_date)
def validate_mandatory(self):
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
@@ -227,9 +244,11 @@
elif self.party_type == "Supplier":
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
elif self.party_type == "Employee":
- valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance")
+ valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance", "Gratuity")
elif self.party_type == "Shareholder":
valid_reference_doctypes = ("Journal Entry")
+ elif self.party_type == "Donor":
+ valid_reference_doctypes = ("Donation")
for d in self.get("references"):
if not d.allocated_amount:
@@ -282,9 +301,10 @@
no_oustanding_refs.setdefault(d.reference_doctype, []).append(d)
for k, v in no_oustanding_refs.items():
- frappe.msgprint(_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.<br><br>\
- If this is undesirable please cancel the corresponding Payment Entry.")
- .format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount")),
+ frappe.msgprint(
+ _("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.")
+ .format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount"))
+ + "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."),
title=_("Warning"), indicator="orange")
@@ -439,6 +459,10 @@
.format(total_negative_outstanding), InvalidPaymentEntry)
def set_title(self):
+ if frappe.flags.in_import and self.title:
+ # do not set title dynamically if title exists during data import.
+ return
+
if self.payment_type in ("Receive", "Pay"):
self.title = self.party
else:
@@ -588,7 +612,7 @@
if self.payment_type in ("Receive", "Pay") and self.party:
for d in self.get("references"):
if d.allocated_amount \
- and d.reference_doctype in ("Sales Order", "Purchase Order", "Employee Advance"):
+ and d.reference_doctype in ("Sales Order", "Purchase Order", "Employee Advance", "Gratuity"):
frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
def update_expense_claim(self):
@@ -598,6 +622,13 @@
doc = frappe.get_doc("Expense Claim", d.reference_name)
update_reimbursed_amount(doc, self.name)
+ def update_donation(self, cancel=0):
+ if self.payment_type == "Receive" and self.party_type == "Donor" and self.party:
+ for d in self.get("references"):
+ if d.reference_doctype=="Donation" and d.reference_name:
+ is_paid = 0 if cancel else 1
+ frappe.db.set_value("Donation", d.reference_name, "paid", is_paid)
+
def on_recurring(self, reference_doc, auto_repeat_doc):
self.reference_no = reference_doc.name
self.reference_date = nowdate()
@@ -897,6 +928,9 @@
total_amount = ref_doc.get("grand_total")
exchange_rate = 1
outstanding_amount = ref_doc.get("outstanding_amount")
+ elif reference_doctype == "Donation":
+ total_amount = ref_doc.get("amount")
+ exchange_rate = 1
elif reference_doctype == "Dunning":
total_amount = ref_doc.get("dunning_amount")
exchange_rate = 1
@@ -909,22 +943,26 @@
exchange_rate = 1
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
elif reference_doctype != "Journal Entry":
- if party_account_currency == company_currency:
- if ref_doc.doctype == "Expense Claim":
+ if ref_doc.doctype == "Expense Claim":
total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
- elif ref_doc.doctype == "Employee Advance":
- total_amount = ref_doc.advance_amount
- else:
+ elif ref_doc.doctype == "Employee Advance":
+ total_amount = ref_doc.advance_amount
+ exchange_rate = ref_doc.get("exchange_rate")
+ if party_account_currency != ref_doc.currency:
+ total_amount = flt(total_amount) * flt(exchange_rate)
+ elif ref_doc.doctype == "Gratuity":
+ total_amount = ref_doc.amount
+ if not total_amount:
+ if party_account_currency == company_currency:
total_amount = ref_doc.base_grand_total
- exchange_rate = 1
- else:
- total_amount = ref_doc.grand_total
-
+ exchange_rate = 1
+ else:
+ total_amount = ref_doc.grand_total
+ if not exchange_rate:
# Get the exchange rate from the original ref doc
- # or get it based on the posting date of the ref doc
+ # or get it based on the posting date of the ref doc.
exchange_rate = ref_doc.get("conversion_rate") or \
get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
-
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
outstanding_amount = ref_doc.get("outstanding_amount")
bill_no = ref_doc.get("bill_no")
@@ -932,11 +970,17 @@
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) + flt(ref_doc.get("total_taxes_and_charges"))\
- flt(ref_doc.get("total_amount_reimbursed")) - flt(ref_doc.get("total_advance_amount"))
elif reference_doctype == "Employee Advance":
- outstanding_amount = ref_doc.advance_amount - flt(ref_doc.paid_amount)
+ outstanding_amount = (flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount))
+ if party_account_currency != ref_doc.currency:
+ outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
+ if party_account_currency == company_currency:
+ exchange_rate = 1
+ elif reference_doctype == "Gratuity":
+ outstanding_amount = ref_doc.amount - flt(ref_doc.paid_amount)
else:
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
else:
- # Get the exchange rate based on the posting date of the ref doc
+ # Get the exchange rate based on the posting date of the ref doc.
exchange_rate = get_exchange_rate(party_account_currency,
company_currency, ref_doc.posting_date)
@@ -948,102 +992,104 @@
"bill_no": bill_no
})
+def get_amounts_based_on_reference_doctype(reference_doctype, ref_doc, party_account_currency, company_currency, reference_name):
+ total_amount, outstanding_amount, exchange_rate = None
+ if reference_doctype == "Fees":
+ total_amount = ref_doc.get("grand_total")
+ exchange_rate = 1
+ outstanding_amount = ref_doc.get("outstanding_amount")
+ elif reference_doctype == "Dunning":
+ total_amount = ref_doc.get("dunning_amount")
+ exchange_rate = 1
+ outstanding_amount = ref_doc.get("dunning_amount")
+ elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
+ total_amount = ref_doc.get("total_amount")
+ if ref_doc.multi_currency:
+ exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
+ else:
+ exchange_rate = 1
+ outstanding_amount = get_outstanding_on_journal_entry(reference_name)
+
+ return total_amount, outstanding_amount, exchange_rate
+
+def get_amounts_based_on_ref_doc(reference_doctype, ref_doc, party_account_currency, company_currency):
+ total_amount, outstanding_amount, exchange_rate = None
+ if ref_doc.doctype == "Expense Claim":
+ total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
+ elif ref_doc.doctype == "Employee Advance":
+ total_amount, exchange_rate = get_total_amount_exchange_rate_for_employee_advance(party_account_currency, ref_doc)
+
+ if not total_amount:
+ total_amount, exchange_rate = get_total_amount_exchange_rate_base_on_currency(
+ party_account_currency, company_currency, ref_doc)
+
+ if not exchange_rate:
+ # Get the exchange rate from the original ref doc
+ # or get it based on the posting date of the ref doc
+ exchange_rate = ref_doc.get("conversion_rate") or \
+ get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
+
+ outstanding_amount, exchange_rate, bill_no = get_bill_no_and_update_amounts(
+ reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency)
+
+ return total_amount, outstanding_amount, exchange_rate, bill_no
+
+def get_total_amount_exchange_rate_for_employee_advance(party_account_currency, ref_doc):
+ total_amount = ref_doc.advance_amount
+ exchange_rate = ref_doc.get("exchange_rate")
+ if party_account_currency != ref_doc.currency:
+ total_amount = flt(total_amount) * flt(exchange_rate)
+
+ return total_amount, exchange_rate
+
+def get_total_amount_exchange_rate_base_on_currency(party_account_currency, company_currency, ref_doc):
+ exchange_rate = None
+ if party_account_currency == company_currency:
+ total_amount = ref_doc.base_grand_total
+ exchange_rate = 1
+ else:
+ total_amount = ref_doc.grand_total
+
+ return total_amount, exchange_rate
+
+def get_bill_no_and_update_amounts(reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency):
+ outstanding_amount, bill_no = None
+ if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
+ outstanding_amount = ref_doc.get("outstanding_amount")
+ bill_no = ref_doc.get("bill_no")
+ elif reference_doctype == "Expense Claim":
+ outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) + flt(ref_doc.get("total_taxes_and_charges"))\
+ - flt(ref_doc.get("total_amount_reimbursed")) - flt(ref_doc.get("total_advance_amount"))
+ elif reference_doctype == "Employee Advance":
+ outstanding_amount = (flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount))
+ if party_account_currency != ref_doc.currency:
+ outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
+ if party_account_currency == company_currency:
+ exchange_rate = 1
+ else:
+ outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
+
+ return outstanding_amount, exchange_rate, bill_no
+
@frappe.whitelist()
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
+ reference_doc = None
doc = frappe.get_doc(dt, dn)
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
- if dt in ("Sales Invoice", "Sales Order", "Dunning"):
- party_type = "Customer"
- elif dt in ("Purchase Invoice", "Purchase Order"):
- party_type = "Supplier"
- elif dt in ("Expense Claim", "Employee Advance"):
- party_type = "Employee"
- elif dt in ("Fees"):
- party_type = "Student"
-
- # party account
- if dt == "Sales Invoice":
- party_account = get_party_account_based_on_invoice_discounting(dn) or doc.debit_to
- elif dt == "Purchase Invoice":
- party_account = doc.credit_to
- elif dt == "Fees":
- party_account = doc.receivable_account
- elif dt == "Employee Advance":
- party_account = doc.advance_account
- elif dt == "Expense Claim":
- party_account = doc.payable_account
- else:
- party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
-
- if dt not in ("Sales Invoice", "Purchase Invoice"):
- party_account_currency = get_account_currency(party_account)
- else:
- party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
-
- # payment type
- if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)) \
- or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
- payment_type = "Receive"
- else:
- payment_type = "Pay"
-
- # amounts
- grand_total = outstanding_amount = 0
- if party_amount:
- grand_total = outstanding_amount = party_amount
- elif dt in ("Sales Invoice", "Purchase Invoice"):
- if party_account_currency == doc.company_currency:
- grand_total = doc.base_rounded_total or doc.base_grand_total
- else:
- grand_total = doc.rounded_total or doc.grand_total
- outstanding_amount = doc.outstanding_amount
- elif dt in ("Expense Claim"):
- grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
- outstanding_amount = doc.grand_total \
- - doc.total_amount_reimbursed
- elif dt == "Employee Advance":
- grand_total = doc.advance_amount
- outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
- elif dt == "Fees":
- grand_total = doc.grand_total
- outstanding_amount = doc.outstanding_amount
- elif dt == "Dunning":
- grand_total = doc.grand_total
- outstanding_amount = doc.grand_total
- else:
- if party_account_currency == doc.company_currency:
- grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
- else:
- grand_total = flt(doc.get("rounded_total") or doc.grand_total)
- outstanding_amount = grand_total - flt(doc.advance_paid)
+ party_type = set_party_type(dt)
+ party_account = set_party_account(dt, dn, doc, party_type)
+ party_account_currency = set_party_account_currency(dt, party_account, doc)
+ payment_type = set_payment_type(dt, doc)
+ grand_total, outstanding_amount = set_grand_total_and_outstanding_amount(party_amount, dt, party_account_currency, doc)
# bank or cash
- bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
- account=bank_account)
+ bank = get_bank_cash_account(doc, bank_account)
- if not bank:
- bank = get_default_bank_cash_account(doc.company, "Cash", mode_of_payment=doc.get("mode_of_payment"),
- account=bank_account)
-
- paid_amount = received_amount = 0
- if party_account_currency == bank.account_currency:
- paid_amount = received_amount = abs(outstanding_amount)
- elif payment_type == "Receive":
- paid_amount = abs(outstanding_amount)
- if bank_amount:
- received_amount = bank_amount
- else:
- received_amount = paid_amount * doc.get('conversion_rate', 1)
- else:
- received_amount = abs(outstanding_amount)
- if bank_amount:
- paid_amount = bank_amount
- else:
- # if party account currency and bank currency is different then populate paid amount as well
- paid_amount = received_amount * doc.get('conversion_rate', 1)
+ paid_amount, received_amount = set_paid_amount_and_received_amount(
+ dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc)
pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type
@@ -1115,10 +1161,130 @@
pe.setup_party_account_field()
pe.set_missing_values()
if party_account and bank:
- pe.set_exchange_rate()
+ if dt == "Employee Advance":
+ reference_doc = doc
+ pe.set_exchange_rate(ref_doc=reference_doc)
pe.set_amounts()
return pe
+def get_bank_cash_account(doc, bank_account):
+ bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
+ account=bank_account)
+
+ if not bank:
+ bank = get_default_bank_cash_account(doc.company, "Cash", mode_of_payment=doc.get("mode_of_payment"),
+ account=bank_account)
+
+ return bank
+
+def set_party_type(dt):
+ if dt in ("Sales Invoice", "Sales Order", "Dunning"):
+ party_type = "Customer"
+ elif dt in ("Purchase Invoice", "Purchase Order"):
+ party_type = "Supplier"
+ elif dt in ("Expense Claim", "Employee Advance", "Gratuity"):
+ party_type = "Employee"
+ elif dt == "Fees":
+ party_type = "Student"
+ elif dt == "Donation":
+ party_type = "Donor"
+ return party_type
+
+def set_party_account(dt, dn, doc, party_type):
+ if dt == "Sales Invoice":
+ party_account = get_party_account_based_on_invoice_discounting(dn) or doc.debit_to
+ elif dt == "Purchase Invoice":
+ party_account = doc.credit_to
+ elif dt == "Fees":
+ party_account = doc.receivable_account
+ elif dt == "Employee Advance":
+ party_account = doc.advance_account
+ elif dt == "Expense Claim":
+ party_account = doc.payable_account
+ elif dt == "Gratuity":
+ party_account = doc.payable_account
+ else:
+ party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
+ return party_account
+
+def set_party_account_currency(dt, party_account, doc):
+ if dt not in ("Sales Invoice", "Purchase Invoice"):
+ party_account_currency = get_account_currency(party_account)
+ else:
+ party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
+ return party_account_currency
+
+def set_payment_type(dt, doc):
+ if (dt in ("Sales Order", "Donation") or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)) \
+ or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
+ payment_type = "Receive"
+ else:
+ payment_type = "Pay"
+ return payment_type
+
+def set_grand_total_and_outstanding_amount(party_amount, dt, party_account_currency, doc):
+ grand_total = outstanding_amount = 0
+ if party_amount:
+ grand_total = outstanding_amount = party_amount
+ elif dt in ("Sales Invoice", "Purchase Invoice"):
+ if party_account_currency == doc.company_currency:
+ grand_total = doc.base_rounded_total or doc.base_grand_total
+ else:
+ grand_total = doc.rounded_total or doc.grand_total
+ outstanding_amount = doc.outstanding_amount
+ elif dt in ("Expense Claim"):
+ grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
+ outstanding_amount = doc.grand_total \
+ - doc.total_amount_reimbursed
+ elif dt == "Employee Advance":
+ grand_total = flt(doc.advance_amount)
+ outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
+ if party_account_currency != doc.currency:
+ grand_total = flt(doc.advance_amount) * flt(doc.exchange_rate)
+ outstanding_amount = (flt(doc.advance_amount) - flt(doc.paid_amount)) * flt(doc.exchange_rate)
+ elif dt == "Fees":
+ grand_total = doc.grand_total
+ outstanding_amount = doc.outstanding_amount
+ elif dt == "Dunning":
+ grand_total = doc.grand_total
+ outstanding_amount = doc.grand_total
+ elif dt == "Donation":
+ grand_total = doc.amount
+ outstanding_amount = doc.amount
+ elif dt == "Gratuity":
+ grand_total = doc.amount
+ outstanding_amount = flt(doc.amount) - flt(doc.paid_amount)
+ else:
+ if party_account_currency == doc.company_currency:
+ grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
+ else:
+ grand_total = flt(doc.get("rounded_total") or doc.grand_total)
+ outstanding_amount = grand_total - flt(doc.advance_paid)
+ return grand_total, outstanding_amount
+
+def set_paid_amount_and_received_amount(dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc):
+ paid_amount = received_amount = 0
+ if party_account_currency == bank.account_currency:
+ paid_amount = received_amount = abs(outstanding_amount)
+ elif payment_type == "Receive":
+ paid_amount = abs(outstanding_amount)
+ if bank_amount:
+ received_amount = bank_amount
+ else:
+ received_amount = paid_amount * doc.get('conversion_rate', 1)
+ if dt == "Employee Advance":
+ received_amount = paid_amount * doc.get('exchange_rate', 1)
+ else:
+ received_amount = abs(outstanding_amount)
+ if bank_amount:
+ paid_amount = bank_amount
+ else:
+ # if party account currency and bank currency is different then populate paid amount as well
+ paid_amount = received_amount * doc.get('conversion_rate', 1)
+ if dt == "Employee Advance":
+ paid_amount = received_amount * doc.get('exchange_rate', 1)
+ return paid_amount, received_amount
+
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
references = []
for payment_term in payment_schedule:
@@ -1192,4 +1358,4 @@
}, target_doc, set_missing_values)
- return doclist
\ No newline at end of file
+ return doclist
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry_list.js b/erpnext/accounts/doctype/payment_entry/payment_entry_list.js
index 7ea60bb..e6d83b9 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry_list.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry_list.js
@@ -1,12 +1,14 @@
frappe.listview_settings['Payment Entry'] = {
onload: function(listview) {
- listview.page.fields_dict.party_type.get_query = function() {
- return {
- "filters": {
- "name": ["in", Object.keys(frappe.boot.party_account_types)],
- }
+ if (listview.page.fields_dict.party_type) {
+ listview.page.fields_dict.party_type.get_query = function() {
+ return {
+ "filters": {
+ "name": ["in", Object.keys(frappe.boot.party_account_types)],
+ }
+ };
};
- };
+ }
}
};
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json
index 8dc2628..12e6f5e 100644
--- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json
+++ b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json
@@ -1,313 +1,98 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2015-12-23 21:31:52.699821",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
+ "actions": [],
+ "creation": "2015-12-23 21:31:52.699821",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "field_order": [
+ "payment_gateway",
+ "payment_channel",
+ "is_default",
+ "column_break_4",
+ "payment_account",
+ "currency",
+ "payment_request_message",
+ "message",
+ "message_examples"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_gateway",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
+ "fieldname": "payment_gateway",
+ "fieldtype": "Link",
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Payment Gateway",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Gateway",
- "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
- },
+ "label": "Payment Gateway",
+ "options": "Payment Gateway",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_default",
- "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": "Is Default",
- "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": "is_default",
+ "fieldtype": "Check",
+ "label": "Is Default"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "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_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
+ "fieldname": "payment_account",
+ "fieldtype": "Link",
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Payment Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "label": "Payment Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "payment_account.account_currency",
"fieldname": "currency",
- "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": "Currency",
- "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
- },
+ "fieldtype": "Read Only",
+ "label": "Currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_request_message",
- "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": "",
- "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
- },
+ "depends_on": "eval: doc.payment_channel !== \"Phone\"",
+ "fieldname": "payment_request_message",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Please click on the link below to make your payment",
- "fieldname": "message",
- "fieldtype": "Small 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": "Default Payment Request Message",
- "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": "Please click on the link below to make your payment",
+ "fieldname": "message",
+ "fieldtype": "Small Text",
+ "label": "Default Payment Request Message"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "message_examples",
- "fieldtype": "HTML",
- "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": "Message Examples",
- "length": 0,
- "no_copy": 0,
- "options": "<pre><h5>Message Example</h5>\n\n<p> Thank You for being a part of {{ doc.company }}! We hope you are enjoying the service.</p>\n\n<p> Please find enclosed the E Bill statement. The outstanding amount is {{ doc.grand_total }}.</p>\n\n<p> We don't want you to be spending time running around in order to pay for your Bill.<br>After all, life is beautiful and the time you have in hand should be spent to enjoy it!<br>So here are our little ways to help you get more time for life! </p>\n\n<a href=\"{{ payment_url }}\"> click here to pay </a>\n\n</pre>\n",
- "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": "message_examples",
+ "fieldtype": "HTML",
+ "label": "Message Examples",
+ "options": "<pre><h5>Message Example</h5>\n\n<p> Thank You for being a part of {{ doc.company }}! We hope you are enjoying the service.</p>\n\n<p> Please find enclosed the E Bill statement. The outstanding amount is {{ doc.grand_total }}.</p>\n\n<p> We don't want you to be spending time running around in order to pay for your Bill.<br>After all, life is beautiful and the time you have in hand should be spent to enjoy it!<br>So here are our little ways to help you get more time for life! </p>\n\n<a href=\"{{ payment_url }}\"> click here to pay </a>\n\n</pre>\n"
+ },
+ {
+ "default": "Email",
+ "fieldname": "payment_channel",
+ "fieldtype": "Select",
+ "label": "Payment Channel",
+ "options": "\nEmail\nPhone"
}
- ],
- "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-05-16 22:43:34.970491",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Payment Gateway Account",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-09-20 13:30:27.722852",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Payment Gateway Account",
+ "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": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
}
- ],
- "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
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 355fe96..6b07197 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -37,6 +37,11 @@
erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.extend({
onload: function() {
var me = this;
+
+ this.frm.set_query("party", function() {
+ check_mandatory(me.frm);
+ });
+
this.frm.set_query("party_type", function() {
return {
"filters": {
@@ -46,37 +51,39 @@
});
this.frm.set_query('receivable_payable_account', function() {
- if(!me.frm.doc.company || !me.frm.doc.party_type) {
- frappe.msgprint(__("Please select Company and Party Type first"));
- } else {
- return{
- filters: {
- "company": me.frm.doc.company,
- "is_group": 0,
- "account_type": frappe.boot.party_account_types[me.frm.doc.party_type]
- }
- };
- }
-
+ check_mandatory(me.frm);
+ return {
+ filters: {
+ "company": me.frm.doc.company,
+ "is_group": 0,
+ "account_type": frappe.boot.party_account_types[me.frm.doc.party_type]
+ }
+ };
});
this.frm.set_query('bank_cash_account', function() {
- if(!me.frm.doc.company) {
- frappe.msgprint(__("Please select Company first"));
- } else {
- return{
- filters:[
- ['Account', 'company', '=', me.frm.doc.company],
- ['Account', 'is_group', '=', 0],
- ['Account', 'account_type', 'in', ['Bank', 'Cash']]
- ]
- };
- }
+ check_mandatory(me.frm, true);
+ return {
+ filters:[
+ ['Account', 'company', '=', me.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: function() {
@@ -90,7 +97,7 @@
party: function() {
var me = this
- if(!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
+ if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
return frappe.call({
method: "erpnext.accounts.party.get_party_account",
args: {
@@ -99,7 +106,7 @@
party: me.frm.doc.party
},
callback: function(r) {
- if(!r.exc && r.message) {
+ if (!r.exc && r.message) {
me.frm.set_value("receivable_payable_account", r.message);
}
}
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 2f8b634..f7a15c0 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -88,18 +88,19 @@
voucher_type = ('Sales Invoice'
if self.party_type == 'Customer' else "Purchase Invoice")
- return frappe.db.sql(""" SELECT `tab{doc}`.name as reference_name, %(voucher_type)s as reference_type,
- (sum(`tabGL Entry`.{dr_or_cr}) - sum(`tabGL Entry`.{reconciled_dr_or_cr})) as amount,
+ return frappe.db.sql(""" SELECT doc.name as reference_name, %(voucher_type)s as reference_type,
+ (sum(gl.{dr_or_cr}) - sum(gl.{reconciled_dr_or_cr})) as amount,
account_currency as currency
- FROM `tab{doc}`, `tabGL Entry`
+ FROM `tab{doc}` doc, `tabGL Entry` gl
WHERE
- (`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
- and `tab{doc}`.{party_type_field} = %(party)s
- and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
- and `tabGL Entry`.against_voucher_type = %(voucher_type)s
- and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
- and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
- GROUP BY `tab{doc}`.name
+ (doc.name = gl.against_voucher or doc.name = gl.voucher_no)
+ and doc.{party_type_field} = %(party)s
+ and doc.is_return = 1 and ifnull(doc.return_against, "") = ""
+ and gl.against_voucher_type = %(voucher_type)s
+ and doc.docstatus = 1 and gl.party = %(party)s
+ and gl.party_type = %(party_type)s and gl.account = %(account)s
+ and gl.is_cancelled = 0
+ GROUP BY doc.name
Having
amount > 0
""".format(
@@ -112,7 +113,7 @@
'party_type': self.party_type,
'voucher_type': voucher_type,
'account': self.receivable_payable_account
- }, as_dict=1)
+ }, as_dict=1, debug=1)
def add_payment_entries(self, entries):
self.set('payments', [])
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js
index e1e4314..901ef19 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request.js
@@ -25,7 +25,7 @@
})
frappe.ui.form.on("Payment Request", "refresh", function(frm) {
- if(frm.doc.payment_request_type == 'Inward' &&
+ if(frm.doc.payment_request_type == 'Inward' && frm.doc.payment_channel !== "Phone" &&
!in_list(["Initiated", "Paid"], frm.doc.status) && !frm.doc.__islocal && frm.doc.docstatus==1){
frm.add_custom_button(__('Resend Payment Email'), function(){
frappe.call({
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json
index 8eadfd0..2ee356a 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.json
+++ b/erpnext/accounts/doctype/payment_request/payment_request.json
@@ -48,6 +48,7 @@
"section_break_7",
"payment_gateway",
"payment_account",
+ "payment_channel",
"payment_order",
"amended_from"
],
@@ -230,6 +231,7 @@
"label": "Recipient Message And Payment Details"
},
{
+ "depends_on": "eval: doc.payment_channel != \"Phone\"",
"fieldname": "print_format",
"fieldtype": "Select",
"label": "Print Format"
@@ -241,6 +243,7 @@
"label": "To"
},
{
+ "depends_on": "eval: doc.payment_channel != \"Phone\"",
"fieldname": "subject",
"fieldtype": "Data",
"in_global_search": 1,
@@ -277,16 +280,18 @@
"read_only": 1
},
{
- "depends_on": "eval: doc.payment_request_type == 'Inward'",
+ "depends_on": "eval: doc.payment_request_type == 'Inward' || doc.payment_channel != \"Phone\"",
"fieldname": "section_break_10",
"fieldtype": "Section Break"
},
{
+ "depends_on": "eval: doc.payment_channel != \"Phone\"",
"fieldname": "message",
"fieldtype": "Text",
"label": "Message"
},
{
+ "depends_on": "eval: doc.payment_channel != \"Phone\"",
"fieldname": "message_examples",
"fieldtype": "HTML",
"label": "Message Examples",
@@ -347,12 +352,21 @@
"options": "Payment Request",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fetch_from": "payment_gateway_account.payment_channel",
+ "fieldname": "payment_channel",
+ "fieldtype": "Select",
+ "label": "Payment Channel",
+ "options": "\nEmail\nPhone",
+ "read_only": 1
}
],
"in_create": 1,
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-07-17 14:06:42.185763",
+ "modified": "2020-09-18 12:24:14.178853",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index e93ec95..53ac996 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -3,6 +3,7 @@
# 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
@@ -36,7 +37,7 @@
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if (hasattr(ref_doc, "order_type") \
and getattr(ref_doc, "order_type") != "Shopping Cart"):
- ref_amount = get_amount(ref_doc)
+ ref_amount = get_amount(ref_doc, self.payment_account)
if existing_payment_request_amount + flt(self.grand_total)> ref_amount:
frappe.throw(_("Total Payment Request amount cannot be greater than {0} amount")
@@ -76,11 +77,44 @@
or self.flags.mute_email:
send_mail = False
- if send_mail:
+ if send_mail and self.payment_channel != "Phone":
self.set_payment_request_url()
self.send_email()
self.make_communication_entry()
+ elif self.payment_channel == "Phone":
+ self.request_phone_payment()
+
+ def request_phone_payment(self):
+ controller = get_payment_gateway_controller(self.payment_gateway)
+ request_amount = self.get_request_amount()
+
+ payment_record = dict(
+ reference_doctype="Payment Request",
+ reference_docname=self.name,
+ payment_reference=self.reference_name,
+ request_amount=request_amount,
+ sender=self.email_to,
+ currency=self.currency,
+ payment_gateway=self.payment_gateway
+ )
+
+ controller.validate_transaction_currency(self.currency)
+ controller.request_for_payment(**payment_record)
+
+ def get_request_amount(self):
+ data_of_completed_requests = frappe.get_all("Integration Request", filters={
+ 'reference_doctype': self.doctype,
+ 'reference_docname': self.name,
+ 'status': 'Completed'
+ }, pluck="data")
+
+ if not data_of_completed_requests:
+ return self.grand_total
+
+ request_amounts = sum([json.loads(d).get('request_amount') for d in data_of_completed_requests])
+ return request_amounts
+
def on_cancel(self):
self.check_if_payment_entry_exists()
self.set_as_cancelled()
@@ -105,13 +139,14 @@
return False
def set_payment_request_url(self):
- if self.payment_account:
+ if self.payment_account and self.payment_channel != "Phone":
self.payment_url = self.get_payment_url()
if self.payment_url:
self.db_set('payment_url', self.payment_url)
- if self.payment_url or not self.payment_gateway_account:
+ if self.payment_url or not self.payment_gateway_account \
+ or (self.payment_gateway_account and self.payment_channel == "Phone"):
self.db_set('status', 'Initiated')
def get_payment_url(self):
@@ -140,10 +175,14 @@
})
def set_as_paid(self):
- payment_entry = self.create_payment_entry()
- self.make_invoice()
+ if self.payment_channel == "Phone":
+ self.db_set("status", "Paid")
- return payment_entry
+ else:
+ payment_entry = self.create_payment_entry()
+ self.make_invoice()
+
+ return payment_entry
def create_payment_entry(self, submit=True):
"""create entry"""
@@ -151,7 +190,7 @@
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
- if self.reference_doctype == "Sales Invoice":
+ if self.reference_doctype in ["Sales Invoice", "POS Invoice"]:
party_account = ref_doc.debit_to
elif self.reference_doctype == "Purchase Invoice":
party_account = ref_doc.credit_to
@@ -166,8 +205,8 @@
else:
party_amount = self.grand_total
- payment_entry = get_payment_entry(self.reference_doctype, self.reference_name,
- party_amount=party_amount, bank_account=self.payment_account, bank_amount=bank_amount)
+ payment_entry = get_payment_entry(self.reference_doctype, self.reference_name, party_amount=party_amount,
+ bank_account=self.payment_account, bank_amount=bank_amount)
payment_entry.update({
"reference_no": self.name,
@@ -255,7 +294,7 @@
# if shopping cart enabled and in session
if (shopping_cart_settings.enabled and hasattr(frappe.local, "session")
- and frappe.local.session.user != "Guest"):
+ and frappe.local.session.user != "Guest") and self.payment_channel != "Phone":
success_url = shopping_cart_settings.payment_success_url
if success_url:
@@ -280,7 +319,9 @@
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.dt, args.dn)
- grand_total = get_amount(ref_doc)
+ gateway_account = get_gateway_details(args) or frappe._dict()
+
+ grand_total = get_amount(ref_doc, gateway_account.get("payment_account"))
if args.loyalty_points and args.dt == "Sales Order":
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
loyalty_amount = validate_loyalty_points(ref_doc, int(args.loyalty_points))
@@ -288,8 +329,6 @@
frappe.db.set_value("Sales Order", args.dn, "loyalty_amount", loyalty_amount, update_modified=False)
grand_total = grand_total - loyalty_amount
- gateway_account = get_gateway_details(args) or frappe._dict()
-
bank_account = (get_party_bank_account(args.get('party_type'), args.get('party'))
if args.get('party_type') else '')
@@ -314,9 +353,11 @@
"payment_gateway_account": gateway_account.get("name"),
"payment_gateway": gateway_account.get("payment_gateway"),
"payment_account": gateway_account.get("payment_account"),
+ "payment_channel": gateway_account.get("payment_channel"),
"payment_request_type": args.get("payment_request_type"),
"currency": ref_doc.currency,
"grand_total": grand_total,
+ "mode_of_payment": args.mode_of_payment,
"email_to": args.recipient_id or ref_doc.owner,
"subject": _("Payment Request for {0}").format(args.dn),
"message": gateway_account.get("message") or get_dummy_message(ref_doc),
@@ -330,8 +371,8 @@
if args.order_type == "Shopping Cart" or args.mute_email:
pr.flags.mute_email = True
+ pr.insert(ignore_permissions=True)
if args.submit_doc:
- pr.insert(ignore_permissions=True)
pr.submit()
if args.order_type == "Shopping Cart":
@@ -344,7 +385,7 @@
return pr.as_dict()
-def get_amount(ref_doc):
+def get_amount(ref_doc, payment_account=None):
"""get amount based on doctype"""
dt = ref_doc.doctype
if dt in ["Sales Order", "Purchase Order"]:
@@ -356,6 +397,12 @@
else:
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
+ elif dt == "POS Invoice":
+ for pay in ref_doc.payments:
+ if pay.type == "Phone" and pay.account == payment_account:
+ grand_total = pay.amount
+ break
+
elif dt == "Fees":
grand_total = ref_doc.outstanding_amount
@@ -366,6 +413,10 @@
frappe.throw(_("Payment Entry is already created"))
def get_existing_payment_request_amount(ref_dt, ref_dn):
+ """
+ Get the existing payment request which are unpaid or partially paid for payment channel other than Phone
+ and get the summation of existing paid payment request for Phone payment channel.
+ """
existing_payment_request_amount = frappe.db.sql("""
select sum(grand_total)
from `tabPayment Request`
@@ -373,14 +424,16 @@
reference_doctype = %s
and reference_name = %s
and docstatus = 1
- and status != 'Paid'
+ and (status != 'Paid'
+ or (payment_channel = 'Phone'
+ and status = 'Paid'))
""", (ref_dt, ref_dn))
return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0
def get_gateway_details(args):
"""return gateway and payment account of default payment gateway"""
- if args.get("payment_gateway"):
- return get_payment_gateway_account(args.get("payment_gateway"))
+ if args.get("payment_gateway_account"):
+ return get_payment_gateway_account(args.get("payment_gateway_account"))
if args.order_type == "Shopping Cart":
payment_gateway_account = frappe.get_doc("Shopping Cart Settings").payment_gateway_account
diff --git a/erpnext/accounts/doctype/payment_request/payment_request_list.js b/erpnext/accounts/doctype/payment_request/payment_request_list.js
index 72833d2..85d729c 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request_list.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request_list.js
@@ -2,7 +2,7 @@
add_fields: ["status"],
get_indicator: function(doc) {
if(doc.status == "Draft") {
- return [__("Draft"), "darkgrey", "status,=,Draft"];
+ return [__("Draft"), "gray", "status,=,Draft"];
}
if(doc.status == "Requested") {
return [__("Requested"), "green", "status,=,Requested"];
@@ -19,5 +19,5 @@
else if(doc.status == "Cancelled") {
return [__("Cancelled"), "red", "status,=,Cancelled"];
}
- }
+ }
}
diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py
index 8a10e2c..5eba62c 100644
--- a/erpnext/accounts/doctype/payment_request/test_payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py
@@ -45,7 +45,8 @@
def test_payment_request_linkings(self):
so_inr = make_sales_order(currency="INR")
- pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com")
+ pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
+ payment_gateway_account="_Test Gateway - INR")
self.assertEqual(pr.reference_doctype, "Sales Order")
self.assertEqual(pr.reference_name, so_inr.name)
@@ -54,7 +55,8 @@
conversion_rate = get_exchange_rate("USD", "INR")
si_usd = create_sales_invoice(currency="USD", conversion_rate=conversion_rate)
- pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com")
+ pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
+ payment_gateway_account="_Test Gateway - USD")
self.assertEqual(pr.reference_doctype, "Sales Invoice")
self.assertEqual(pr.reference_name, si_usd.name)
@@ -68,7 +70,7 @@
so_inr = make_sales_order(currency="INR")
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
- mute_email=1, submit_doc=1, return_doc=1)
+ mute_email=1, payment_gateway_account="_Test Gateway - INR", submit_doc=1, return_doc=1)
pe = pr.set_as_paid()
so_inr = frappe.get_doc("Sales Order", so_inr.name)
@@ -79,7 +81,7 @@
currency="USD", conversion_rate=50)
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
- mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
+ mute_email=1, payment_gateway_account="_Test Gateway - USD", submit_doc=1, return_doc=1)
pe = pr.set_as_paid()
@@ -106,7 +108,7 @@
currency="USD", conversion_rate=50)
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
- mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
+ mute_email=1, payment_gateway_account="_Test Gateway - USD", submit_doc=1, return_doc=1)
pe = pr.create_payment_entry()
pr.load_from_db()
diff --git a/erpnext/accounts/doctype/payment_term/payment_term.json b/erpnext/accounts/doctype/payment_term/payment_term.json
index 723d3bd..e77c244 100644
--- a/erpnext/accounts/doctype/payment_term/payment_term.json
+++ b/erpnext/accounts/doctype/payment_term/payment_term.json
@@ -45,6 +45,7 @@
"unique": 0
},
{
+ "description": "Provide the invoice portion in percent",
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
@@ -170,6 +171,7 @@
"unique": 0
},
{
+ "description": "Give number of days according to prior selection",
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
@@ -305,7 +307,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-03-08 10:47:32.830478",
+ "modified": "2020-10-14 10:47:32.830478",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Term",
@@ -381,4 +383,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
-}
\ No newline at end of file
+}
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 7dd5b01..a74fa06 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -8,7 +8,7 @@
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (get_accounting_dimensions,
- get_dimension_filters)
+ get_dimensions)
class PeriodClosingVoucher(AccountsController):
def validate(self):
@@ -58,7 +58,7 @@
for dimension in accounting_dimensions:
dimension_fields.append('t1.{0}'.format(dimension))
- dimension_filters, default_dimensions = get_dimension_filters()
+ dimension_filters, default_dimensions = get_dimensions()
pl_accounts = self.get_pl_balances(dimension_fields)
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 9336fc3..9ea616f 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -3,6 +3,7 @@
frappe.ui.form.on('POS Closing Entry', {
onload: function(frm) {
+ frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
frm.set_query("pos_profile", function(doc) {
return {
filters: { 'user': doc.user }
@@ -20,7 +21,7 @@
return { filters: { 'status': 'Open', 'docstatus': 1 } };
});
- if (frm.doc.docstatus === 0) frm.set_value("period_end_date", frappe.datetime.now_datetime());
+ if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
if (frm.doc.docstatus === 1) set_html_data(frm);
},
@@ -51,6 +52,7 @@
args: {
start: frappe.datetime.get_datetime_as_string(frm.doc.period_start_date),
end: frappe.datetime.get_datetime_as_string(frm.doc.period_end_date),
+ pos_profile: frm.doc.pos_profile,
user: frm.doc.user
},
callback: (r) => {
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 32bca3b..a9b91e0 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
@@ -6,11 +6,13 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
+ "period_details_section",
"period_start_date",
"period_end_date",
"column_break_3",
"posting_date",
"pos_opening_entry",
+ "status",
"section_break_5",
"company",
"column_break_7",
@@ -64,7 +66,8 @@
},
{
"fieldname": "section_break_5",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "User Details"
},
{
"fieldname": "company",
@@ -120,7 +123,7 @@
"collapsible_depends_on": "eval:doc.docstatus==0",
"fieldname": "section_break_13",
"fieldtype": "Section Break",
- "label": "Details"
+ "label": "Totals"
},
{
"default": "0",
@@ -184,11 +187,32 @@
"label": "POS Opening Entry",
"options": "POS Opening Entry",
"reqd": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Status",
+ "options": "Draft\nSubmitted\nQueued\nCancelled",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "period_details_section",
+ "fieldtype": "Section Break",
+ "label": "Period Details"
}
],
"is_submittable": 1,
- "links": [],
- "modified": "2020-05-29 15:03:22.226113",
+ "links": [
+ {
+ "link_doctype": "POS Invoice Merge Log",
+ "link_fieldname": "pos_closing_entry"
+ }
+ ],
+ "modified": "2021-02-01 13:47:20.722104",
"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 9899219..f5224a2 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
@@ -6,39 +6,84 @@
import frappe
import json
from frappe import _
-from frappe.model.document import Document
-from frappe.utils import getdate, get_datetime, flt
-from collections import defaultdict
+from frappe.utils import get_datetime, flt
+from erpnext.controllers.status_updater import StatusUpdater
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
-from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
+from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices, unconsolidate_pos_invoices
-class POSClosingEntry(Document):
+class POSClosingEntry(StatusUpdater):
def validate(self):
- user = frappe.get_all('POS Closing Entry',
- filters = { 'user': self.user, 'docstatus': 1 },
- or_filters = {
- 'period_start_date': ('between', [self.period_start_date, self.period_end_date]),
- 'period_end_date': ('between', [self.period_start_date, self.period_end_date])
- })
-
- if user:
- frappe.throw(_("POS Closing Entry {} against {} between selected period"
- .format(frappe.bold("already exists"), frappe.bold(self.user))), title=_("Invalid Period"))
-
if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open":
frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry"))
- def on_submit(self):
- merge_pos_invoices(self.pos_transactions)
- opening_entry = frappe.get_doc("POS Opening Entry", self.pos_opening_entry)
- opening_entry.pos_closing_entry = self.name
- opening_entry.set_status()
- opening_entry.save()
+ self.validate_pos_closing()
+ self.validate_pos_invoices()
+
+ def validate_pos_closing(self):
+ user = frappe.db.sql("""
+ SELECT name FROM `tabPOS Closing Entry`
+ WHERE
+ user = %(user)s AND docstatus = 1 AND pos_profile = %(profile)s AND
+ (period_start_date between %(start)s and %(end)s OR period_end_date between %(start)s and %(end)s)
+ """, {
+ 'user': self.user,
+ 'profile': self.pos_profile,
+ 'start': self.period_start_date,
+ 'end': self.period_end_date
+ })
+
+ if user:
+ bold_already_exists = frappe.bold(_("already exists"))
+ bold_user = frappe.bold(self.user)
+ frappe.throw(_("POS Closing Entry {} against {} between selected period")
+ .format(bold_already_exists, bold_user), title=_("Invalid Period"))
+
+ def validate_pos_invoices(self):
+ invalid_rows = []
+ for d in self.pos_transactions:
+ invalid_row = {'idx': d.idx}
+ pos_invoice = frappe.db.get_values("POS Invoice", d.pos_invoice,
+ ["consolidated_invoice", "pos_profile", "docstatus", "owner"], as_dict=1)[0]
+ if pos_invoice.consolidated_invoice:
+ invalid_row.setdefault('msg', []).append(_('POS Invoice is {}').format(frappe.bold("already consolidated")))
+ invalid_rows.append(invalid_row)
+ continue
+ if pos_invoice.pos_profile != self.pos_profile:
+ invalid_row.setdefault('msg', []).append(_("POS Profile doesn't matches {}").format(frappe.bold(self.pos_profile)))
+ if pos_invoice.docstatus != 1:
+ invalid_row.setdefault('msg', []).append(_('POS Invoice is not {}').format(frappe.bold("submitted")))
+ if pos_invoice.owner != self.user:
+ invalid_row.setdefault('msg', []).append(_("POS Invoice isn't created by user {}").format(frappe.bold(self.owner)))
+
+ if invalid_row.get('msg'):
+ invalid_rows.append(invalid_row)
+
+ if not invalid_rows:
+ return
+
+ error_list = []
+ for row in invalid_rows:
+ for msg in row.get('msg'):
+ error_list.append(_("Row #{}: {}").format(row.get('idx'), msg))
+
+ frappe.throw(error_list, title=_("Invalid POS Invoices"), as_list=True)
def get_payment_reconciliation_details(self):
currency = frappe.get_cached_value('Company', self.company, "default_currency")
return frappe.render_template("erpnext/accounts/doctype/pos_closing_entry/closing_voucher_details.html",
{"data": self, "currency": currency})
+
+ def on_submit(self):
+ consolidate_pos_invoices(closing_entry=self)
+
+ def on_cancel(self):
+ unconsolidate_pos_invoices(closing_entry=self)
+
+ def update_opening_entry(self, for_cancel=False):
+ opening_entry = frappe.get_doc("POS Opening Entry", self.pos_opening_entry)
+ opening_entry.pos_closing_entry = self.name if not for_cancel else None
+ opening_entry.set_status()
+ opening_entry.save()
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
@@ -47,16 +92,15 @@
return [c['user'] for c in cashiers_list]
@frappe.whitelist()
-def get_pos_invoices(start, end, user):
+def get_pos_invoices(start, end, pos_profile, user):
data = frappe.db.sql("""
select
name, timestamp(posting_date, posting_time) as "timestamp"
from
`tabPOS Invoice`
where
- owner = %s and docstatus = 1 and
- (consolidated_invoice is NULL or consolidated_invoice = '')
- """, (user), as_dict=1)
+ owner = %s and docstatus = 1 and pos_profile = %s and ifnull(consolidated_invoice,'') = ''
+ """, (user, pos_profile), as_dict=1)
data = list(filter(lambda d: get_datetime(start) <= get_datetime(d.timestamp) <= get_datetime(end), data))
# need to get taxes and payments so can't avoid get_doc
@@ -76,7 +120,8 @@
closing_entry.net_total = 0
closing_entry.total_quantity = 0
- invoices = get_pos_invoices(closing_entry.period_start_date, closing_entry.period_end_date, closing_entry.user)
+ invoices = get_pos_invoices(closing_entry.period_start_date, closing_entry.period_end_date,
+ closing_entry.pos_profile, closing_entry.user)
pos_transactions = []
taxes = []
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js
new file mode 100644
index 0000000..20fd610
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+// render
+frappe.listview_settings['POS Closing Entry'] = {
+ get_indicator: function(doc) {
+ var status_color = {
+ "Draft": "red",
+ "Submitted": "blue",
+ "Queued": "orange",
+ "Cancelled": "red"
+
+ };
+ return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
+ }
+};
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 aa6a388..b596c0c 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
@@ -5,15 +5,23 @@
import frappe
import unittest
from frappe.utils import nowdate
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import make_closing_entry_from_opening
from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
class TestPOSClosingEntry(unittest.TestCase):
+ def setUp(self):
+ # Make stock available for POS Sales
+ make_stock_entry(target="_Test Warehouse - _TC", qty=2, basic_rate=100)
+
+ def tearDown(self):
+ frappe.set_user("Administrator")
+ frappe.db.sql("delete from `tabPOS Profile`")
+
def test_pos_closing_entry(self):
test_user, pos_profile = init_user_and_profile()
-
opening_entry = create_opening_entry(pos_profile, test_user.name)
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
@@ -42,10 +50,48 @@
self.assertEqual(pcv_doc.total_quantity, 2)
self.assertEqual(pcv_doc.net_total, 6700)
- frappe.set_user("Administrator")
- frappe.db.sql("delete from `tabPOS Profile`")
+ def test_cancelling_of_pos_closing_entry(self):
+ test_user, pos_profile = init_user_and_profile()
+ opening_entry = create_opening_entry(pos_profile, test_user.name)
-def init_user_and_profile():
+ pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
+ pos_inv1.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3500
+ })
+ pos_inv1.submit()
+
+ pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
+ pos_inv2.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
+ })
+ pos_inv2.submit()
+
+ pcv_doc = make_closing_entry_from_opening(opening_entry)
+ payment = pcv_doc.payment_reconciliation[0]
+
+ self.assertEqual(payment.mode_of_payment, 'Cash')
+
+ for d in pcv_doc.payment_reconciliation:
+ if d.mode_of_payment == 'Cash':
+ d.closing_amount = 6700
+
+ pcv_doc.submit()
+
+ pos_inv1.load_from_db()
+ self.assertRaises(frappe.ValidationError, pos_inv1.cancel)
+
+ si_doc = frappe.get_doc("Sales Invoice", pos_inv1.consolidated_invoice)
+ self.assertRaises(frappe.ValidationError, si_doc.cancel)
+
+ pcv_doc.load_from_db()
+ pcv_doc.cancel()
+ si_doc.load_from_db()
+ pos_inv1.load_from_db()
+ self.assertEqual(si_doc.docstatus, 2)
+ self.assertEqual(pos_inv1.status, 'Paid')
+
+
+def init_user_and_profile(**args):
user = 'test@example.com'
test_user = frappe.get_doc('User', user)
@@ -53,7 +99,7 @@
test_user.add_roles(*roles)
frappe.set_user(user)
- pos_profile = make_pos_profile()
+ pos_profile = make_pos_profile(**args)
pos_profile.append('applicable_for_users', {
'default': 1,
'user': user
@@ -61,4 +107,4 @@
pos_profile.save()
- return test_user, pos_profile
\ No newline at end of file
+ return test_user, pos_profile
diff --git a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
index 798637a..6e7768d 100644
--- a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
+++ b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
@@ -7,8 +7,8 @@
"field_order": [
"mode_of_payment",
"opening_amount",
- "closing_amount",
"expected_amount",
+ "closing_amount",
"difference"
],
"fields": [
@@ -26,8 +26,7 @@
"in_list_view": 1,
"label": "Expected Amount",
"options": "company:company_currency",
- "read_only": 1,
- "reqd": 1
+ "read_only": 1
},
{
"fieldname": "difference",
@@ -55,9 +54,10 @@
"reqd": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-29 15:03:34.533607",
+ "modified": "2020-10-23 16:45:43.662034",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Closing Entry Detail",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 3be4304..493bd44 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -2,6 +2,7 @@
// For license information, please see license.txt
{% include 'erpnext/selling/sales_common.js' %};
+frappe.provide("erpnext.accounts");
erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend({
setup(doc) {
@@ -9,80 +10,70 @@
this._super(doc);
},
- onload() {
- this._super();
- if(this.frm.doc.__islocal && this.frm.doc.is_pos) {
- //Load pos profile data on the invoice if the default value of Is POS is 1
+ company: function() {
+ erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
+ },
- me.frm.script_manager.trigger("is_pos");
- me.frm.refresh_fields();
+ onload(doc) {
+ this._super();
+ this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
+ if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
+ this.frm.script_manager.trigger("is_pos");
+ this.frm.refresh_fields();
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
refresh(doc) {
this._super();
if (doc.docstatus == 1 && !doc.is_return) {
- if(doc.outstanding_amount >= 0 || Math.abs(flt(doc.outstanding_amount)) < flt(doc.grand_total)) {
- cur_frm.add_custom_button(__('Return'),
- this.make_sales_return, __('Create'));
- cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
- }
+ this.frm.add_custom_button(__('Return'), this.make_sales_return, __('Create'));
+ this.frm.page.set_inner_btn_group_as_primary(__('Create'));
}
- if (this.frm.doc.is_return) {
+ if (doc.is_return && doc.__islocal) {
this.frm.return_print_format = "Sales Invoice Return";
- cur_frm.set_value('consolidated_invoice', '');
+ this.frm.set_value('consolidated_invoice', '');
}
},
- is_pos: function(frm){
+ is_pos: function() {
this.set_pos_data();
},
- set_pos_data: function() {
+ set_pos_data: async function() {
if(this.frm.doc.is_pos) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0);
frappe.msgprint(__("Please specify Company to proceed"));
} else {
- var me = this;
- return this.frm.call({
- doc: me.frm.doc,
+ const r = await this.frm.call({
+ doc: this.frm.doc,
method: "set_missing_values",
- callback: function(r) {
- if(!r.exc) {
- if(r.message) {
- me.frm.pos_print_format = r.message.print_format || "";
- me.frm.meta.default_print_format = r.message.print_format || "";
- me.frm.allow_edit_rate = r.message.allow_edit_rate;
- me.frm.allow_edit_discount = r.message.allow_edit_discount;
- me.frm.doc.campaign = r.message.campaign;
- me.frm.allow_print_before_pay = r.message.allow_print_before_pay;
- }
- me.frm.script_manager.trigger("update_stock");
- me.calculate_taxes_and_totals();
- if(me.frm.doc.taxes_and_charges) {
- me.frm.script_manager.trigger("taxes_and_charges");
- }
- frappe.model.set_default_values(me.frm.doc);
- me.set_dynamic_labels();
-
- }
- }
+ freeze: true
});
+ if(!r.exc) {
+ if(r.message) {
+ this.frm.pos_print_format = r.message.print_format || "";
+ this.frm.meta.default_print_format = r.message.print_format || "";
+ this.frm.doc.campaign = r.message.campaign;
+ this.frm.allow_print_before_pay = r.message.allow_print_before_pay;
+ }
+ this.frm.script_manager.trigger("update_stock");
+ this.calculate_taxes_and_totals();
+ this.frm.doc.taxes_and_charges && this.frm.script_manager.trigger("taxes_and_charges");
+ frappe.model.set_default_values(this.frm.doc);
+ this.set_dynamic_labels();
+ }
}
}
- else this.frm.trigger("refresh");
},
customer() {
if (!this.frm.doc.customer) return
-
- if (this.frm.doc.is_pos){
- var pos_profile = this.frm.doc.pos_profile;
- }
- var me = this;
+ const pos_profile = this.frm.doc.pos_profile;
if(this.frm.updating_party_details) return;
erpnext.utils.get_party_details(this.frm,
"erpnext.accounts.party.get_party_details", {
@@ -92,8 +83,8 @@
account: this.frm.doc.debit_to,
price_list: this.frm.doc.selling_price_list,
pos_profile: pos_profile
- }, function() {
- me.apply_pricing_rule();
+ }, () => {
+ this.apply_pricing_rule();
});
},
@@ -201,5 +192,47 @@
}
frm.set_value("loyalty_amount", loyalty_amount);
}
+ },
+
+ request_for_payment: function (frm) {
+ if (!frm.doc.contact_mobile) {
+ frappe.throw(__('Please enter mobile number first.'));
+ }
+ frm.dirty();
+ frm.save().then(() => {
+ frappe.dom.freeze(__('Waiting for payment...'));
+ frappe
+ .call({
+ method: 'create_payment_request',
+ doc: frm.doc
+ })
+ .fail(() => {
+ frappe.dom.unfreeze();
+ frappe.msgprint(__('Payment request failed'));
+ })
+ .then(({ message }) => {
+ const payment_request_name = message.name;
+ setTimeout(() => {
+ frappe.db.get_value('Payment Request', payment_request_name, ['status', 'grand_total']).then(({ message }) => {
+ if (message.status != 'Paid') {
+ frappe.dom.unfreeze();
+ frappe.msgprint({
+ message: __('Payment Request took too long to respond. Please try requesting for payment again.'),
+ title: __('Request Timeout')
+ });
+ } else if (frappe.dom.freeze_count != 0) {
+ frappe.dom.unfreeze();
+ cur_frm.reload_doc();
+ cur_pos.payment.events.submit_invoice();
+
+ frappe.show_alert({
+ message: __("Payment of {0} received successfully.", [format_currency(message.grand_total, frm.doc.currency, 0)]),
+ indicator: 'green'
+ });
+ }
+ });
+ }, 60000);
+ });
+ });
}
});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index 4780688..7459c11 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2020-01-24 15:29:29.933693",
@@ -12,11 +13,11 @@
"customer",
"customer_name",
"tax_id",
- "is_pos",
"pos_profile",
- "offline_pos_name",
- "is_return",
"consolidated_invoice",
+ "is_pos",
+ "is_return",
+ "update_billed_amount_in_sales_order",
"column_break1",
"company",
"posting_date",
@@ -24,10 +25,7 @@
"set_posting_time",
"due_date",
"amended_from",
- "returns",
"return_against",
- "column_break_21",
- "update_billed_amount_in_sales_order",
"accounting_dimensions_section",
"project",
"dimension_col_break",
@@ -182,8 +180,7 @@
"column_break_140",
"auto_repeat",
"update_auto_repeat_reference",
- "against_income_account",
- "pos_total_qty"
+ "against_income_account"
],
"fields": [
{
@@ -265,22 +262,13 @@
"print_hide": 1
},
{
- "fieldname": "offline_pos_name",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Offline POS Name",
- "print_hide": 1,
- "read_only": 1
- },
- {
"allow_on_submit": 1,
"default": "0",
"fieldname": "is_return",
"fieldtype": "Check",
"label": "Is Return (Credit Note)",
"no_copy": 1,
- "print_hide": 1,
- "set_only_once": 1
+ "print_hide": 1
},
{
"fieldname": "column_break1",
@@ -350,25 +338,15 @@
},
{
"depends_on": "return_against",
- "fieldname": "returns",
- "fieldtype": "Section Break",
- "label": "Returns"
- },
- {
- "depends_on": "return_against",
"fieldname": "return_against",
"fieldtype": "Link",
- "label": "Return Against POS Invoice",
+ "label": "Return Against",
"no_copy": 1,
"options": "POS Invoice",
"print_hide": 1,
"read_only": 1
},
{
- "fieldname": "column_break_21",
- "fieldtype": "Column Break"
- },
- {
"default": "0",
"depends_on": "eval: doc.is_return && doc.return_against",
"fieldname": "update_billed_amount_in_sales_order",
@@ -461,7 +439,7 @@
},
{
"fieldname": "contact_mobile",
- "fieldtype": "Small Text",
+ "fieldtype": "Data",
"hidden": 1,
"label": "Mobile No",
"read_only": 1
@@ -587,19 +565,21 @@
},
{
"fieldname": "sec_warehouse",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Warehouse"
},
{
"depends_on": "update_stock",
"fieldname": "set_warehouse",
"fieldtype": "Link",
- "label": "Set Source Warehouse",
+ "label": "Source Warehouse",
"options": "Warehouse",
"print_hide": 1
},
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "label": "Items",
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -1501,7 +1481,7 @@
"allow_on_submit": 1,
"fieldname": "sales_team",
"fieldtype": "Table",
- "label": "Sales Team1",
+ "label": "Sales Team",
"oldfieldname": "sales_team",
"oldfieldtype": "Table",
"options": "Sales Team",
@@ -1561,15 +1541,6 @@
"report_hide": 1
},
{
- "fieldname": "pos_total_qty",
- "fieldtype": "Float",
- "hidden": 1,
- "label": "Total Qty",
- "print_hide": 1,
- "print_hide_if_no_value": 1,
- "read_only": 1
- },
- {
"allow_on_submit": 1,
"fieldname": "consolidated_invoice",
"fieldtype": "Link",
@@ -1579,10 +1550,9 @@
}
],
"icon": "fa fa-file-text",
- "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-09-07 12:43:09.138720",
+ "modified": "2021-02-01 15:03:33.800707",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
@@ -1627,7 +1597,6 @@
"role": "All"
}
],
- "quick_entry": 1,
"search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount",
"show_name_in_global_search": 1,
"sort_field": "modified",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index ba68df7..402d157 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -6,15 +6,13 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from erpnext.controllers.selling_controller import SellingController
-from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.party import get_party_account, get_due_date
-from erpnext.accounts.doctype.loyalty_program.loyalty_program import \
- get_loyalty_program_details_with_points, validate_loyalty_points
-
-from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice, get_bank_cash_account, update_multi_mode_option
-from erpnext.stock.doctype.serial_no.serial_no import get_pos_reserved_serial_nos
+from frappe.utils import cint, flt, getdate, nowdate, get_link_to_form
+from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
+from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
+from erpnext.stock.doctype.serial_no.serial_no import get_pos_reserved_serial_nos, get_serial_nos
+from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice, get_bank_cash_account, update_multi_mode_option, get_mode_of_payment_info
from six import iteritems
@@ -29,8 +27,7 @@
# run on validate method of selling controller
super(SalesInvoice, self).validate()
self.validate_auto_set_posting_time()
- self.validate_pos_paid_amount()
- self.validate_pos_return()
+ self.validate_mode_of_payment()
self.validate_uom_is_integer("stock_uom", "stock_qty")
self.validate_uom_is_integer("uom", "qty")
self.validate_debit_to_acc()
@@ -40,11 +37,12 @@
self.validate_item_cost_centers()
self.validate_serialised_or_batched_item()
self.validate_stock_availablility()
- self.validate_return_items()
+ self.validate_return_items_qty()
+ self.validate_non_stock_items()
self.set_status()
self.set_account_for_mode_of_payment()
self.validate_pos()
- self.verify_payment_amount()
+ self.validate_payment_amount()
self.validate_loyalty_transaction()
def on_submit(self):
@@ -57,8 +55,25 @@
against_psi_doc.make_loyalty_point_entry()
if self.redeem_loyalty_points and self.loyalty_points:
self.apply_loyalty_points()
+ self.check_phone_payments()
self.set_status(update=True)
+ def before_cancel(self):
+ if self.consolidated_invoice and frappe.db.get_value('Sales Invoice', self.consolidated_invoice, 'docstatus') == 1:
+ pos_closing_entry = frappe.get_all(
+ "POS Invoice Reference",
+ ignore_permissions=True,
+ filters={ 'pos_invoice': self.name },
+ pluck="parent",
+ limit=1
+ )
+ frappe.throw(
+ _('You need to cancel POS Closing Entry {} to be able to cancel this document.').format(
+ get_link_to_form("POS Closing Entry", pos_closing_entry[0])
+ ),
+ title=_('Not Allowed')
+ )
+
def on_cancel(self):
# run on cancel method of selling controller
super(SalesInvoice, self).on_cancel()
@@ -69,77 +84,136 @@
against_psi_doc.delete_loyalty_point_entry()
against_psi_doc.make_loyalty_point_entry()
- def validate_stock_availablility(self):
- allow_negative_stock = frappe.db.get_value('Stock Settings', None, 'allow_negative_stock')
+ def check_phone_payments(self):
+ for pay in self.payments:
+ if pay.type == "Phone" and pay.amount >= 0:
+ paid_amt = frappe.db.get_value("Payment Request",
+ filters=dict(
+ reference_doctype="POS Invoice", reference_name=self.name,
+ mode_of_payment=pay.mode_of_payment, status="Paid"),
+ fieldname="grand_total")
+ if paid_amt and pay.amount != paid_amt:
+ return frappe.throw(_("Payment related to {0} is not completed").format(pay.mode_of_payment))
+
+ def validate_stock_availablility(self):
+ if self.is_return:
+ return
+
+ allow_negative_stock = frappe.db.get_value('Stock Settings', None, 'allow_negative_stock')
+ error_msg = []
for d in self.get('items'):
+ msg = ""
if d.serial_no:
- filters = {
- "item_code": d.item_code,
- "warehouse": d.warehouse,
- "delivery_document_no": "",
- "sales_invoice": ""
- }
+ filters = { "item_code": d.item_code, "warehouse": d.warehouse }
if d.batch_no:
filters["batch_no"] = d.batch_no
- reserved_serial_nos, unreserved_serial_nos = get_pos_reserved_serial_nos(filters)
- serial_nos = d.serial_no.split("\n")
- serial_nos = ' '.join(serial_nos).split() # remove whitespaces
- invalid_serial_nos = []
- for s in serial_nos:
- if s in reserved_serial_nos:
- invalid_serial_nos.append(s)
- if len(invalid_serial_nos):
- multiple_nos = 's' if len(invalid_serial_nos) > 1 else ''
- frappe.throw(_("Row #{}: Serial No{}. {} has already been transacted into another POS Invoice. \
- Please select valid serial no.".format(d.idx, multiple_nos,
- frappe.bold(', '.join(invalid_serial_nos)))), title=_("Not Available"))
+ reserved_serial_nos = get_pos_reserved_serial_nos(filters)
+ serial_nos = get_serial_nos(d.serial_no)
+ invalid_serial_nos = [s for s in serial_nos if s in reserved_serial_nos]
+
+ bold_invalid_serial_nos = frappe.bold(', '.join(invalid_serial_nos))
+ if len(invalid_serial_nos) == 1:
+ msg = (_("Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.")
+ .format(d.idx, bold_invalid_serial_nos))
+ elif invalid_serial_nos:
+ msg = (_("Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.")
+ .format(d.idx, bold_invalid_serial_nos))
+
else:
if allow_negative_stock:
return
available_stock = get_stock_availability(d.item_code, d.warehouse)
- if not (flt(available_stock) > 0):
- frappe.throw(_('Row #{}: Item Code: {} is not available under warehouse {}.'
- .format(d.idx, frappe.bold(d.item_code), frappe.bold(d.warehouse))), title=_("Not Available"))
+ item_code, warehouse, qty = frappe.bold(d.item_code), frappe.bold(d.warehouse), frappe.bold(d.qty)
+ if flt(available_stock) <= 0:
+ msg = (_('Row #{}: Item Code: {} is not available under warehouse {}.').format(d.idx, item_code, warehouse))
elif flt(available_stock) < flt(d.qty):
- frappe.msgprint(_('Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. \
- Available quantity {}.'.format(d.idx, frappe.bold(d.item_code),
- frappe.bold(d.warehouse), frappe.bold(d.qty))), title=_("Not Available"))
+ msg = (_('Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.')
+ .format(d.idx, item_code, warehouse, qty))
+ if msg:
+ error_msg.append(msg)
+
+ if error_msg:
+ frappe.throw(error_msg, title=_("Item Unavailable"), as_list=True)
def validate_serialised_or_batched_item(self):
+ error_msg = []
for d in self.get("items"):
serialized = d.get("has_serial_no")
batched = d.get("has_batch_no")
no_serial_selected = not d.get("serial_no")
no_batch_selected = not d.get("batch_no")
-
+ msg = ""
+ item_code = frappe.bold(d.item_code)
+ serial_nos = get_serial_nos(d.serial_no)
if serialized and batched and (no_batch_selected or no_serial_selected):
- frappe.throw(_('Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.'
- .format(d.idx, frappe.bold(d.item_code))), title=_("Invalid Item"))
- if serialized and no_serial_selected:
- frappe.throw(_('Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.'
- .format(d.idx, frappe.bold(d.item_code))), title=_("Invalid Item"))
- if batched and no_batch_selected:
- frappe.throw(_('Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.'
- .format(d.idx, frappe.bold(d.item_code))), title=_("Invalid Item"))
+ msg = (_('Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.')
+ .format(d.idx, item_code))
+ elif serialized and no_serial_selected:
+ msg = (_('Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.')
+ .format(d.idx, item_code))
+ elif batched and no_batch_selected:
+ msg = (_('Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.')
+ .format(d.idx, item_code))
+ elif serialized and not no_serial_selected and len(serial_nos) != d.qty:
+ msg = (_("Row #{}: You must select {} serial numbers for item {}.").format(d.idx, frappe.bold(cint(d.qty)), item_code))
- def validate_return_items(self):
+ if msg:
+ error_msg.append(msg)
+
+ if error_msg:
+ frappe.throw(error_msg, title=_("Invalid Item"), as_list=True)
+
+ def validate_return_items_qty(self):
if not self.get("is_return"): return
for d in self.get("items"):
if d.get("qty") > 0:
- frappe.throw(_("Row #{}: You cannot add postive quantities in a return invoice. Please remove item {} to complete the return.")
- .format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item"))
+ frappe.throw(
+ _("Row #{}: You cannot add postive quantities in a return invoice. Please remove item {} to complete the return.")
+ .format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item")
+ )
+ if d.get("serial_no"):
+ serial_nos = get_serial_nos(d.serial_no)
+ for sr in serial_nos:
+ serial_no_exists = frappe.db.sql("""
+ SELECT name
+ FROM `tabPOS Invoice Item`
+ WHERE
+ parent = %s
+ and (serial_no = %s
+ or serial_no like %s
+ or serial_no like %s
+ or serial_no like %s
+ )
+ """, (self.return_against, sr, sr+'\n%', '%\n'+sr, '%\n'+sr+'\n%'))
- def validate_pos_paid_amount(self):
- if len(self.payments) == 0 and self.is_pos:
+ if not serial_no_exists:
+ bold_return_against = frappe.bold(self.return_against)
+ bold_serial_no = frappe.bold(sr)
+ frappe.throw(
+ _("Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {}")
+ .format(d.idx, bold_serial_no, bold_return_against)
+ )
+
+ def validate_non_stock_items(self):
+ for d in self.get("items"):
+ is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item")
+ if not is_stock_item:
+ frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice. ").format(
+ d.idx, frappe.bold(d.item_code)
+ ), title=_("Invalid Item"))
+
+ def validate_mode_of_payment(self):
+ if len(self.payments) == 0:
frappe.throw(_("At least one mode of payment is required for POS invoice."))
def validate_change_account(self):
- if frappe.db.get_value("Account", self.account_for_change_amount, "company") != self.company:
+ if self.change_amount and self.account_for_change_amount and \
+ frappe.db.get_value("Account", self.account_for_change_amount, "company") != self.company:
frappe.throw(_("The selected change account {} doesn't belongs to Company {}.").format(self.account_for_change_amount, self.company))
def validate_change_amount(self):
@@ -147,26 +221,24 @@
base_grand_total = flt(self.base_rounded_total) or flt(self.base_grand_total)
if not flt(self.change_amount) and grand_total < flt(self.paid_amount):
self.change_amount = flt(self.paid_amount - grand_total + flt(self.write_off_amount))
- self.base_change_amount = flt(self.base_paid_amount - base_grand_total + flt(self.base_write_off_amount))
+ self.base_change_amount = flt(self.base_paid_amount) - base_grand_total + flt(self.base_write_off_amount)
if flt(self.change_amount) and not self.account_for_change_amount:
- msgprint(_("Please enter Account for Change Amount"), raise_exception=1)
+ frappe.msgprint(_("Please enter Account for Change Amount"), raise_exception=1)
- def verify_payment_amount(self):
+ def validate_payment_amount(self):
+ total_amount_in_payments = 0
for entry in self.payments:
+ total_amount_in_payments += entry.amount
if not self.is_return and entry.amount < 0:
frappe.throw(_("Row #{0} (Payment Table): Amount must be positive").format(entry.idx))
if self.is_return and entry.amount > 0:
frappe.throw(_("Row #{0} (Payment Table): Amount must be negative").format(entry.idx))
- def validate_pos_return(self):
- if self.is_pos and self.is_return:
- total_amount_in_payments = 0
- for payment in self.payments:
- total_amount_in_payments += payment.amount
+ if self.is_return:
invoice_total = self.rounded_total or self.grand_total
- if total_amount_in_payments < invoice_total:
- frappe.throw(_("Total payments amount can't be greater than {}".format(-invoice_total)))
+ if total_amount_in_payments and total_amount_in_payments < invoice_total:
+ frappe.throw(_("Total payments amount can't be greater than {}").format(-invoice_total))
def validate_loyalty_transaction(self):
if self.redeem_loyalty_points and (not self.loyalty_redemption_account or not self.loyalty_redemption_cost_center):
@@ -218,57 +290,54 @@
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {}
+ if not pos_profile:
+ frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
self.pos_profile = pos_profile.get('name')
- pos = {}
+ profile = {}
if self.pos_profile:
- pos = frappe.get_doc('POS Profile', self.pos_profile)
+ profile = frappe.get_doc('POS Profile', self.pos_profile)
if not self.get('payments') and not for_validate:
- update_multi_mode_option(self, pos)
+ update_multi_mode_option(self, profile)
- if not self.account_for_change_amount:
- self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account')
+ if self.is_return and not for_validate:
+ add_return_modes(self, profile)
- if pos:
- if not for_validate:
- self.tax_category = pos.get("tax_category")
-
+ if profile:
if not for_validate and not self.customer:
- self.customer = pos.customer
+ self.customer = profile.customer
- self.ignore_pricing_rule = pos.ignore_pricing_rule
- if pos.get('account_for_change_amount'):
- self.account_for_change_amount = pos.get('account_for_change_amount')
- if pos.get('warehouse'):
- self.set_warehouse = pos.get('warehouse')
+ self.ignore_pricing_rule = profile.ignore_pricing_rule
+ self.account_for_change_amount = profile.get('account_for_change_amount') or self.account_for_change_amount
+ self.set_warehouse = profile.get('warehouse') or self.set_warehouse
- for fieldname in ('naming_series', 'currency', 'letter_head', 'tc_name',
+ for fieldname in ('currency', 'letter_head', 'tc_name',
'company', 'select_print_heading', 'write_off_account', 'taxes_and_charges',
- 'write_off_cost_center', 'apply_discount_on', 'cost_center'):
- if (not for_validate) or (for_validate and not self.get(fieldname)):
- self.set(fieldname, pos.get(fieldname))
-
- if pos.get("company_address"):
- self.company_address = pos.get("company_address")
+ 'write_off_cost_center', 'apply_discount_on', 'cost_center', 'tax_category',
+ 'ignore_pricing_rule', 'company_address', 'update_stock'):
+ if not for_validate:
+ self.set(fieldname, profile.get(fieldname))
if self.customer:
- customer_price_list, customer_group = frappe.db.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
+ customer_price_list, customer_group, customer_currency = frappe.db.get_value(
+ "Customer", self.customer, ['default_price_list', 'customer_group', 'default_currency']
+ )
customer_group_price_list = frappe.db.get_value("Customer Group", customer_group, 'default_price_list')
- selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list')
+ selling_price_list = customer_price_list or customer_group_price_list or profile.get('selling_price_list')
+ if customer_currency != profile.get('currency'):
+ self.set('currency', customer_currency)
+
else:
- selling_price_list = pos.get('selling_price_list')
+ selling_price_list = profile.get('selling_price_list')
if selling_price_list:
self.set('selling_price_list', selling_price_list)
- if not for_validate:
- self.update_stock = cint(pos.get("update_stock"))
-
# set pos values in items
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)
+ profile_details = get_pos_profile_item_details(profile.get("company"), frappe._dict(item.as_dict()), profile)
for fname, val in iteritems(profile_details):
if (not for_validate) or (for_validate and not item.get(fname)):
item.set(fname, val)
@@ -281,10 +350,13 @@
if self.taxes_and_charges and not len(self.get("taxes")):
self.set_taxes()
- return pos
+ if not self.account_for_change_amount:
+ self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account')
+
+ return profile
def set_missing_values(self, for_validate=False):
- pos = self.set_pos_fields(for_validate)
+ profile = self.set_pos_fields(for_validate)
if not self.debit_to:
self.debit_to = get_party_account("Customer", self.customer, self.company)
@@ -294,25 +366,81 @@
super(SalesInvoice, self).set_missing_values(for_validate)
- print_format = pos.get("print_format") if pos else None
+ print_format = profile.get("print_format") if profile else None
if not print_format and not cint(frappe.db.get_value('Print Format', 'POS Invoice', 'disabled')):
print_format = 'POS Invoice'
- if pos:
+ if profile:
return {
"print_format": print_format,
- "allow_edit_rate": pos.get("allow_user_to_edit_rate"),
- "allow_edit_discount": pos.get("allow_user_to_edit_discount"),
- "campaign": pos.get("campaign"),
- "allow_print_before_pay": pos.get("allow_print_before_pay")
+ "campaign": profile.get("campaign"),
+ "allow_print_before_pay": profile.get("allow_print_before_pay")
}
+ def reset_mode_of_payments(self):
+ if self.pos_profile:
+ pos_profile = frappe.get_cached_doc('POS Profile', self.pos_profile)
+ update_multi_mode_option(self, pos_profile)
+ self.paid_amount = 0
+
def set_account_for_mode_of_payment(self):
self.payments = [d for d in self.payments if d.amount or d.base_amount or d.default]
for pay in self.payments:
if not pay.account:
pay.account = get_bank_cash_account(pay.mode_of_payment, self.company).get("account")
+ def create_payment_request(self):
+ for pay in self.payments:
+ if pay.type == "Phone":
+ if pay.amount <= 0:
+ frappe.throw(_("Payment amount cannot be less than or equal to 0"))
+
+ if not self.contact_mobile:
+ frappe.throw(_("Please enter the phone number first"))
+
+ pay_req = self.get_existing_payment_request(pay)
+ if not pay_req:
+ pay_req = self.get_new_payment_request(pay)
+ pay_req.submit()
+ else:
+ pay_req.request_phone_payment()
+
+ return pay_req
+
+ def get_new_payment_request(self, mop):
+ payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
+ "payment_account": mop.account,
+ }, ["name"])
+
+ args = {
+ "dt": "POS Invoice",
+ "dn": self.name,
+ "recipient_id": self.contact_mobile,
+ "mode_of_payment": mop.mode_of_payment,
+ "payment_gateway_account": payment_gateway_account,
+ "payment_request_type": "Inward",
+ "party_type": "Customer",
+ "party": self.customer,
+ "return_doc": True
+ }
+ return make_payment_request(**args)
+
+ def get_existing_payment_request(self, pay):
+ payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
+ "payment_account": pay.account,
+ }, ["name"])
+
+ args = {
+ 'doctype': 'Payment Request',
+ 'reference_doctype': 'POS Invoice',
+ 'reference_name': self.name,
+ 'payment_gateway_account': payment_gateway_account,
+ 'email_to': self.contact_mobile
+ }
+ pr = frappe.db.exists(args)
+ if pr:
+ return frappe.get_doc('Payment Request', pr[0][0])
+
@frappe.whitelist()
def get_stock_availability(item_code, warehouse):
latest_sle = frappe.db.sql("""select qty_after_transaction
@@ -334,11 +462,9 @@
sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
pos_sales_qty = pos_sales_qty[0].qty or 0 if pos_sales_qty else 0
- if sle_qty and pos_sales_qty and sle_qty > pos_sales_qty:
+ if sle_qty and pos_sales_qty:
return sle_qty - pos_sales_qty
else:
- # when sle_qty is 0
- # when sle_qty > 0 and pos_sales_qty is 0
return sle_qty
@frappe.whitelist()
@@ -371,4 +497,19 @@
})
if merge_log.get('pos_invoices'):
- return merge_log.as_dict()
\ No newline at end of file
+ return merge_log.as_dict()
+
+def add_return_modes(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.account = payment_mode.default_account
+ payment.type = payment_mode.type
+
+ for pos_payment_method in pos_profile.get('payments'):
+ pos_payment_method = pos_payment_method.as_dict()
+ mode_of_payment = pos_payment_method.mode_of_payment
+ if pos_payment_method.allow_in_returns and not [d for d in doc.get('payments') if d.mode_of_payment == mode_of_payment]:
+ payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company)
+ append_payment(payment_mode[0])
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 514a2ac..054afe5 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -7,8 +7,18 @@
import unittest, copy, time
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.item.test_item import make_item
class TestPOSInvoice(unittest.TestCase):
+ def tearDown(self):
+ if frappe.session.user != "Administrator":
+ frappe.set_user("Administrator")
+
+ if frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
+ frappe.db.set_value("Selling Settings", None, "validate_selling_price", 0)
+
def test_timestamp_change(self):
w = create_pos_invoice(do_not_save=1)
w.docstatus = 0
@@ -97,10 +107,10 @@
item_row = inv.get("items")[0]
add_items = [
- (54, '_Test Account Excise Duty @ 12'),
- (288, '_Test Account Excise Duty @ 15'),
- (144, '_Test Account Excise Duty @ 20'),
- (430, '_Test Item Tax Template 1')
+ (54, '_Test Account Excise Duty @ 12 - _TC'),
+ (288, '_Test Account Excise Duty @ 15 - _TC'),
+ (144, '_Test Account Excise Duty @ 20 - _TC'),
+ (430, '_Test Item Tax Template 1 - _TC')
]
for qty, item_tax_template in add_items:
item_row_copy = copy.deepcopy(item_row)
@@ -196,6 +206,65 @@
self.assertEqual(pos_return.get('payments')[0].amount, -500)
self.assertEqual(pos_return.get('payments')[1].amount, -500)
+ def test_pos_return_for_serialized_item(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+ se = make_serialized_item(company='_Test Company',
+ target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
+
+ serial_nos = get_serial_nos(se.get("items")[0].serial_no)
+
+ pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+ account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+ expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
+ item=se.get("items")[0].item_code, rate=1000, do_not_save=1)
+
+ pos.get("items")[0].serial_no = serial_nos[0]
+ pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 1000, 'default': 1})
+
+ pos.insert()
+ pos.submit()
+
+ pos_return = make_sales_return(pos.name)
+
+ pos_return.insert()
+ pos_return.submit()
+ self.assertEqual(pos_return.get('items')[0].serial_no, serial_nos[0])
+
+ def test_partial_pos_returns(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+ se = make_serialized_item(company='_Test Company',
+ target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
+
+ serial_nos = get_serial_nos(se.get("items")[0].serial_no)
+
+ pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+ account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+ expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
+ item=se.get("items")[0].item_code, qty=2, rate=1000, do_not_save=1)
+
+ pos.get("items")[0].serial_no = serial_nos[0] + "\n" + serial_nos[1]
+ pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 1000, 'default': 1})
+
+ pos.insert()
+ pos.submit()
+
+ pos_return1 = make_sales_return(pos.name)
+
+ # partial return 1
+ pos_return1.get('items')[0].qty = -1
+ pos_return1.get('items')[0].serial_no = serial_nos[0]
+ pos_return1.insert()
+ pos_return1.submit()
+
+ # partial return 2
+ pos_return2 = make_sales_return(pos.name)
+ self.assertEqual(pos_return2.get('items')[0].qty, -1)
+ self.assertEqual(pos_return2.get('items')[0].serial_no, serial_nos[1])
+
def test_pos_change_amount(self):
pos = create_pos_invoice(company= "_Test Company", debit_to="Debtors - _TC",
income_account = "Sales - _TC", expense_account = "Cost of Goods Sold - _TC", rate=105,
@@ -221,29 +290,29 @@
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
- se = make_serialized_item(company='_Test Company with perpetual inventory',
- target_warehouse="Stores - TCP1", cost_center='Main - TCP1', expense_account='Cost of Goods Sold - TCP1')
+ se = make_serialized_item(company='_Test Company',
+ target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
- pos = create_pos_invoice(company='_Test Company with perpetual inventory', debit_to='Debtors - TCP1',
- account_for_change_amount='Cash - TCP1', warehouse='Stores - TCP1', income_account='Sales - TCP1',
- expense_account='Cost of Goods Sold - TCP1', cost_center='Main - TCP1',
+ pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+ account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+ expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
item=se.get("items")[0].item_code, rate=1000, do_not_save=1)
pos.get("items")[0].serial_no = serial_nos[0]
- pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 1000})
+ pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 1000})
pos.insert()
pos.submit()
- pos2 = create_pos_invoice(company='_Test Company with perpetual inventory', debit_to='Debtors - TCP1',
- account_for_change_amount='Cash - TCP1', warehouse='Stores - TCP1', income_account='Sales - TCP1',
- expense_account='Cost of Goods Sold - TCP1', cost_center='Main - TCP1',
+ pos2 = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+ account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+ expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
item=se.get("items")[0].item_code, rate=1000, do_not_save=1)
pos2.get("items")[0].serial_no = serial_nos[0]
- pos2.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 1000})
+ pos2.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 1000})
self.assertRaises(frappe.ValidationError, pos2.insert)
@@ -286,6 +355,117 @@
after_redeem_lp_details = get_loyalty_program_details_with_points(inv.customer, company=inv.company, loyalty_program=inv.loyalty_program)
self.assertEqual(after_redeem_lp_details.loyalty_points, 9)
+ def test_merging_into_sales_invoice_with_discount(self):
+ from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
+ from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
+
+ frappe.db.sql("delete from `tabPOS Invoice`")
+ test_user, pos_profile = init_user_and_profile()
+ pos_inv = create_pos_invoice(rate=300, additional_discount_percentage=10, do_not_submit=1)
+ pos_inv.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 270
+ })
+ pos_inv.submit()
+
+ pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
+ pos_inv2.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
+ })
+ pos_inv2.submit()
+
+ consolidate_pos_invoices()
+
+ pos_inv.load_from_db()
+ rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
+ self.assertEqual(rounded_total, 3470)
+
+ def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
+ from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
+ from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
+
+ frappe.db.sql("delete from `tabPOS Invoice`")
+ test_user, pos_profile = init_user_and_profile()
+ pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
+ pos_inv.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
+ })
+ pos_inv.append('taxes', {
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Service Tax - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Service Tax",
+ "rate": 14,
+ 'included_in_print_rate': 1
+ })
+ pos_inv.submit()
+
+ pos_inv2 = create_pos_invoice(rate=300, qty=2, do_not_submit=1)
+ pos_inv2.additional_discount_percentage = 10
+ pos_inv2.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 540
+ })
+ pos_inv2.append('taxes', {
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Service Tax - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Service Tax",
+ "rate": 14,
+ 'included_in_print_rate': 1
+ })
+ pos_inv2.submit()
+
+ consolidate_pos_invoices()
+
+ pos_inv.load_from_db()
+ rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
+ self.assertEqual(rounded_total, 840)
+
+ def test_merging_with_validate_selling_price(self):
+ from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
+ from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
+
+ if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
+ frappe.db.set_value("Selling Settings", "Selling Settings", "validate_selling_price", 1)
+
+ item = "Test Selling Price Validation"
+ make_item(item, {"is_stock_item": 1})
+ make_purchase_receipt(item_code=item, warehouse="_Test Warehouse - _TC", qty=1, rate=300)
+ frappe.db.sql("delete from `tabPOS Invoice`")
+ test_user, pos_profile = init_user_and_profile()
+ pos_inv = create_pos_invoice(item=item, rate=300, do_not_submit=1)
+ pos_inv.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
+ })
+ pos_inv.append('taxes', {
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Service Tax - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Service Tax",
+ "rate": 14,
+ 'included_in_print_rate': 1
+ })
+ self.assertRaises(frappe.ValidationError, pos_inv.submit)
+
+ pos_inv2 = create_pos_invoice(item=item, rate=400, do_not_submit=1)
+ pos_inv2.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 400
+ })
+ pos_inv2.append('taxes', {
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Service Tax - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Service Tax",
+ "rate": 14,
+ 'included_in_print_rate': 1
+ })
+ pos_inv2.submit()
+
+ consolidate_pos_invoices()
+
+ pos_inv2.load_from_db()
+ rounded_total = frappe.db.get_value("Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total")
+ self.assertEqual(rounded_total, 400)
+
def create_pos_invoice(**args):
args = frappe._dict(args)
pos_profile = None
@@ -294,12 +474,11 @@
pos_profile.save()
pos_inv = frappe.new_doc("POS Invoice")
+ pos_inv.update(args)
pos_inv.update_stock = 1
pos_inv.is_pos = 1
pos_inv.pos_profile = args.pos_profile or pos_profile.name
- pos_inv.set_missing_values()
-
if args.posting_date:
pos_inv.set_posting_time = 1
pos_inv.posting_date = args.posting_date or frappe.utils.nowdate()
@@ -313,6 +492,8 @@
pos_inv.conversion_rate = args.conversion_rate or 1
pos_inv.account_for_change_amount = args.account_for_change_amount or "Cash - _TC"
+ pos_inv.set_missing_values()
+
pos_inv.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
@@ -333,4 +514,4 @@
else:
pos_inv.payment_schedule = []
- return pos_inv
\ No newline at end of file
+ return pos_inv
diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
index 2b6e7de..8b71eb0 100644
--- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
+++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
@@ -87,6 +87,7 @@
"edit_references",
"sales_order",
"so_detail",
+ "pos_invoice_item",
"column_break_74",
"delivery_note",
"dn_detail",
@@ -790,11 +791,20 @@
"fieldtype": "Link",
"label": "Project",
"options": "Project"
+ },
+ {
+ "fieldname": "pos_invoice_item",
+ "fieldtype": "Data",
+ "ignore_user_permissions": 1,
+ "label": "POS Invoice Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-07-22 13:40:34.418346",
+ "modified": "2021-01-04 17:34:49.924531",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",
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 8f97639..da2984f 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
@@ -7,6 +7,8 @@
"field_order": [
"posting_date",
"customer",
+ "column_break_3",
+ "pos_closing_entry",
"section_break_3",
"pos_invoices",
"references_section",
@@ -76,11 +78,22 @@
"label": "Consolidated Credit Note",
"options": "Sales Invoice",
"read_only": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "pos_closing_entry",
+ "fieldtype": "Link",
+ "label": "POS Closing Entry",
+ "options": "POS Closing Entry"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-05-29 15:08:41.317100",
+ "modified": "2020-12-01 11:53:57.267579",
"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 11b9d25..40f77b4 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
@@ -5,10 +5,13 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
-from frappe.model.document import Document
-from frappe.model.mapper import map_doc
from frappe.model import default_fields
+from frappe.model.document import Document
+from frappe.utils import flt, getdate, nowdate
+from frappe.utils.background_jobs import enqueue
+from frappe.model.mapper import map_doc, map_child_doc
+from frappe.utils.scheduler import is_scheduler_inactive
+from frappe.core.page.background_jobs.background_jobs import get_info
from six import iteritems
@@ -27,17 +30,24 @@
status, docstatus, is_return, return_against = frappe.db.get_value(
'POS Invoice', d.pos_invoice, ['status', 'docstatus', 'is_return', 'return_against'])
+ bold_pos_invoice = frappe.bold(d.pos_invoice)
+ bold_status = frappe.bold(status)
if docstatus != 1:
- frappe.throw(_("Row #{}: POS Invoice {} is not submitted yet").format(d.idx, d.pos_invoice))
+ frappe.throw(_("Row #{}: POS Invoice {} is not submitted yet").format(d.idx, bold_pos_invoice))
if status == "Consolidated":
- frappe.throw(_("Row #{}: POS Invoice {} has been {}").format(d.idx, d.pos_invoice, status))
- if is_return and return_against not in [d.pos_invoice for d in self.pos_invoices] and status != "Consolidated":
- # if return entry is not getting merged in the current pos closing and if it is not consolidated
- frappe.throw(
- _("Row #{}: Return Invoice {} cannot be made against unconsolidated invoice. \
- You can add original invoice {} manually to proceed.")
- .format(d.idx, frappe.bold(d.pos_invoice), frappe.bold(return_against))
- )
+ frappe.throw(_("Row #{}: POS Invoice {} has been {}").format(d.idx, bold_pos_invoice, bold_status))
+ if is_return and return_against and return_against not in [d.pos_invoice for d in self.pos_invoices]:
+ bold_return_against = frappe.bold(return_against)
+ return_against_status = frappe.db.get_value('POS Invoice', return_against, "status")
+ if return_against_status != "Consolidated":
+ # if return entry is not getting merged in the current pos closing and if it is not consolidated
+ bold_unconsolidated = frappe.bold("not Consolidated")
+ msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}. ")
+ .format(d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated))
+ msg += _("Original invoice should be consolidated before or along with the return invoice.")
+ msg += "<br><br>"
+ msg += _("You can add original invoice {} manually to proceed.").format(bold_return_against)
+ frappe.throw(msg)
def on_submit(self):
pos_invoice_docs = [frappe.get_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
@@ -48,17 +58,23 @@
sales_invoice, credit_note = "", ""
if sales:
sales_invoice = self.process_merging_into_sales_invoice(sales)
-
+
if returns:
credit_note = self.process_merging_into_credit_note(returns)
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
- self.update_pos_invoices(sales_invoice, credit_note)
+ self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
+
+ def on_cancel(self):
+ pos_invoice_docs = [frappe.get_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
+
+ self.update_pos_invoices(pos_invoice_docs)
+ self.cancel_linked_invoices()
def process_merging_into_sales_invoice(self, data):
sales_invoice = self.get_new_sales_invoice()
-
+
sales_invoice = self.merge_pos_invoice_into(sales_invoice, data)
sales_invoice.is_consolidated = 1
@@ -76,37 +92,51 @@
credit_note.is_consolidated = 1
# TODO: return could be against multiple sales invoice which could also have been consolidated?
- credit_note.return_against = self.consolidated_invoice
+ # credit_note.return_against = self.consolidated_invoice
credit_note.save()
credit_note.submit()
self.consolidated_credit_note = credit_note.name
return credit_note.name
-
+
def merge_pos_invoice_into(self, invoice, data):
items, payments, taxes = [], [], []
loyalty_amount_sum, loyalty_points_sum = 0, 0
for doc in data:
map_doc(doc, invoice, table_map={ "doctype": invoice.doctype })
-
+
if doc.redeem_loyalty_points:
invoice.loyalty_redemption_account = doc.loyalty_redemption_account
invoice.loyalty_redemption_cost_center = doc.loyalty_redemption_cost_center
loyalty_points_sum += doc.loyalty_points
loyalty_amount_sum += doc.loyalty_amount
-
+
for item in doc.get('items'):
- items.append(item)
-
+ 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):
+ found = True
+ i.qty = i.qty + item.qty
+
+ if not found:
+ item.rate = item.net_rate
+ item.price_list_rate = 0
+ si_item = map_child_doc(item, invoice, {"doctype": "Sales Invoice Item"})
+ items.append(si_item)
+
for tax in doc.get('taxes'):
found = False
for t in taxes:
- if t.account_head == tax.account_head and t.cost_center == tax.cost_center and t.rate == tax.rate:
- t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount)
- t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount)
+ if t.account_head == tax.account_head and t.cost_center == tax.cost_center:
+ t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount_after_discount_amount)
+ t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount_after_discount_amount)
found = True
if not found:
tax.charge_type = 'Actual'
+ 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
taxes.append(tax)
for payment in doc.get('payments'):
@@ -127,9 +157,13 @@
invoice.set('items', items)
invoice.set('payments', payments)
invoice.set('taxes', taxes)
+ invoice.additional_discount_percentage = 0
+ invoice.discount_amount = 0.0
+ invoice.taxes_and_charges = None
+ invoice.ignore_pricing_rule = 1
return invoice
-
+
def get_new_sales_invoice(self):
sales_invoice = frappe.new_doc('Sales Invoice')
sales_invoice.customer = self.customer
@@ -139,17 +173,21 @@
return sales_invoice
- def update_pos_invoices(self, sales_invoice, credit_note):
- for d in self.pos_invoices:
- doc = frappe.get_doc('POS Invoice', d.pos_invoice)
- if not doc.is_return:
- doc.update({'consolidated_invoice': sales_invoice})
- else:
- doc.update({'consolidated_invoice': credit_note})
+ def update_pos_invoices(self, invoice_docs, sales_invoice='', credit_note=''):
+ for doc in invoice_docs:
+ doc.load_from_db()
+ doc.update({ 'consolidated_invoice': None if self.docstatus==2 else (credit_note if doc.is_return else sales_invoice) })
doc.set_status(update=True)
doc.save()
-def get_all_invoices():
+ def cancel_linked_invoices(self):
+ for si_name in [self.consolidated_invoice, self.consolidated_credit_note]:
+ if not si_name: continue
+ si = frappe.get_doc('Sales Invoice', si_name)
+ si.flags.ignore_validate = True
+ si.cancel()
+
+def get_all_unconsolidated_invoices():
filters = {
'consolidated_invoice': [ 'in', [ '', None ]],
'status': ['not in', ['Consolidated']],
@@ -157,33 +195,95 @@
}
pos_invoices = frappe.db.get_all('POS Invoice', filters=filters,
fields=["name as pos_invoice", 'posting_date', 'grand_total', 'customer'])
-
+
return pos_invoices
-def get_invoices_customer_map(pos_invoices):
+def get_invoice_customer_map(pos_invoices):
# pos_invoice_customer_map = { 'Customer 1': [{}, {}, {}], 'Custoemr 2' : [{}] }
pos_invoice_customer_map = {}
for invoice in pos_invoices:
customer = invoice.get('customer')
pos_invoice_customer_map.setdefault(customer, [])
pos_invoice_customer_map[customer].append(invoice)
-
+
return pos_invoice_customer_map
-def merge_pos_invoices(pos_invoices=[]):
- if not pos_invoices:
- pos_invoices = get_all_invoices()
-
- pos_invoice_map = get_invoices_customer_map(pos_invoices)
- create_merge_logs(pos_invoice_map)
+def consolidate_pos_invoices(pos_invoices=[], closing_entry={}):
+ invoices = pos_invoices or closing_entry.get('pos_transactions') or get_all_unconsolidated_invoices()
+ invoice_by_customer = get_invoice_customer_map(invoices)
-def create_merge_logs(pos_invoice_customer_map):
- for customer, invoices in iteritems(pos_invoice_customer_map):
+ if len(invoices) >= 5 and closing_entry:
+ closing_entry.set_status(update=True, status='Queued')
+ enqueue_job(create_merge_logs, invoice_by_customer, closing_entry)
+ else:
+ create_merge_logs(invoice_by_customer, closing_entry)
+
+def unconsolidate_pos_invoices(closing_entry):
+ merge_logs = frappe.get_all(
+ 'POS Invoice Merge Log',
+ filters={ 'pos_closing_entry': closing_entry.name },
+ pluck='name'
+ )
+
+ if len(merge_logs) >= 5:
+ closing_entry.set_status(update=True, status='Queued')
+ enqueue_job(cancel_merge_logs, merge_logs, closing_entry)
+ else:
+ cancel_merge_logs(merge_logs, closing_entry)
+
+def create_merge_logs(invoice_by_customer, closing_entry={}):
+ for customer, invoices in iteritems(invoice_by_customer):
merge_log = frappe.new_doc('POS Invoice Merge Log')
merge_log.posting_date = getdate(nowdate())
merge_log.customer = customer
+ merge_log.pos_closing_entry = closing_entry.get('name', None)
merge_log.set('pos_invoices', invoices)
merge_log.save(ignore_permissions=True)
merge_log.submit()
+
+ if closing_entry:
+ closing_entry.set_status(update=True, status='Submitted')
+ closing_entry.update_opening_entry()
+def cancel_merge_logs(merge_logs, closing_entry={}):
+ for log in merge_logs:
+ merge_log = frappe.get_doc('POS Invoice Merge Log', log)
+ merge_log.flags.ignore_permissions = True
+ merge_log.cancel()
+
+ if closing_entry:
+ closing_entry.set_status(update=True, status='Cancelled')
+ closing_entry.update_opening_entry(for_cancel=True)
+
+def enqueue_job(job, invoice_by_customer, closing_entry):
+ check_scheduler_status()
+
+ job_name = closing_entry.get("name")
+ if not job_already_enqueued(job_name):
+ enqueue(
+ job,
+ queue="long",
+ timeout=10000,
+ event="processing_merge_logs",
+ job_name=job_name,
+ closing_entry=closing_entry,
+ invoice_by_customer=invoice_by_customer,
+ now=frappe.conf.developer_mode or frappe.flags.in_test
+ )
+
+ if job == create_merge_logs:
+ msg = _('POS Invoices will be consolidated in a background process')
+ else:
+ msg = _('POS Invoices will be unconsolidated in a background process')
+
+ frappe.msgprint(msg, alert=1)
+
+def check_scheduler_status():
+ if is_scheduler_inactive() and not frappe.flags.in_test:
+ frappe.throw(_("Scheduler is inactive. Cannot enqueue job."), title=_("Scheduler Inactive"))
+
+def job_already_enqueued(job_name):
+ enqueued_jobs = [d.get("job_name") for d in get_info()]
+ if job_name in enqueued_jobs:
+ return True
\ No newline at end of file
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 0f34272..d880caa 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
@@ -7,92 +7,96 @@
import unittest
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
-from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
+from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
class TestPOSInvoiceMergeLog(unittest.TestCase):
def test_consolidated_invoice_creation(self):
frappe.db.sql("delete from `tabPOS Invoice`")
- test_user, pos_profile = init_user_and_profile()
+ try:
+ test_user, pos_profile = init_user_and_profile()
- pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
- pos_inv.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
- })
- pos_inv.submit()
+ pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
+ pos_inv.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
+ })
+ pos_inv.submit()
- pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
- pos_inv2.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
- })
- pos_inv2.submit()
+ pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
+ pos_inv2.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
+ })
+ pos_inv2.submit()
- pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
- pos_inv3.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 2300
- })
- pos_inv3.submit()
+ pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
+ pos_inv3.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 2300
+ })
+ pos_inv3.submit()
- merge_pos_invoices()
+ consolidate_pos_invoices()
- pos_inv.load_from_db()
- self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
+ pos_inv.load_from_db()
+ self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
- pos_inv3.load_from_db()
- self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv3.consolidated_invoice))
+ pos_inv3.load_from_db()
+ self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv3.consolidated_invoice))
- self.assertFalse(pos_inv.consolidated_invoice == pos_inv3.consolidated_invoice)
+ self.assertFalse(pos_inv.consolidated_invoice == pos_inv3.consolidated_invoice)
- frappe.set_user("Administrator")
- frappe.db.sql("delete from `tabPOS Profile`")
- frappe.db.sql("delete from `tabPOS Invoice`")
-
+ finally:
+ frappe.set_user("Administrator")
+ frappe.db.sql("delete from `tabPOS Profile`")
+ frappe.db.sql("delete from `tabPOS Invoice`")
+
def test_consolidated_credit_note_creation(self):
frappe.db.sql("delete from `tabPOS Invoice`")
- test_user, pos_profile = init_user_and_profile()
+ try:
+ test_user, pos_profile = init_user_and_profile()
- pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
- pos_inv.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
- })
- pos_inv.submit()
+ pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
+ pos_inv.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
+ })
+ pos_inv.submit()
- pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
- pos_inv2.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
- })
- pos_inv2.submit()
+ pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
+ pos_inv2.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
+ })
+ pos_inv2.submit()
- pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
- pos_inv3.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 2300
- })
- pos_inv3.submit()
+ pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
+ pos_inv3.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 2300
+ })
+ pos_inv3.submit()
- pos_inv_cn = make_sales_return(pos_inv.name)
- pos_inv_cn.set("payments", [])
- pos_inv_cn.append('payments', {
- 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': -300
- })
- pos_inv_cn.paid_amount = -300
- pos_inv_cn.submit()
+ pos_inv_cn = make_sales_return(pos_inv.name)
+ pos_inv_cn.set("payments", [])
+ pos_inv_cn.append('payments', {
+ 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': -300
+ })
+ pos_inv_cn.paid_amount = -300
+ pos_inv_cn.submit()
- merge_pos_invoices()
+ consolidate_pos_invoices()
- pos_inv.load_from_db()
- self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
+ pos_inv.load_from_db()
+ self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
- pos_inv3.load_from_db()
- self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv3.consolidated_invoice))
+ pos_inv3.load_from_db()
+ self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv3.consolidated_invoice))
- pos_inv_cn.load_from_db()
- self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv_cn.consolidated_invoice))
- self.assertTrue(frappe.db.get_value("Sales Invoice", pos_inv_cn.consolidated_invoice, "is_return"))
+ pos_inv_cn.load_from_db()
+ self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv_cn.consolidated_invoice))
+ self.assertTrue(frappe.db.get_value("Sales Invoice", pos_inv_cn.consolidated_invoice, "is_return"))
- frappe.set_user("Administrator")
- frappe.db.sql("delete from `tabPOS Profile`")
- frappe.db.sql("delete from `tabPOS Invoice`")
+ finally:
+ frappe.set_user("Administrator")
+ frappe.db.sql("delete from `tabPOS Profile`")
+ frappe.db.sql("delete from `tabPOS Invoice`")
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 b9e07b8..0023a84 100644
--- a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py
+++ b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py
@@ -6,7 +6,6 @@
import frappe
from frappe import _
from frappe.utils import cint, get_link_to_form
-from frappe.model.document import Document
from erpnext.controllers.status_updater import StatusUpdater
class POSOpeningEntry(StatusUpdater):
@@ -17,18 +16,26 @@
def validate_pos_profile_and_cashier(self):
if self.company != frappe.db.get_value("POS Profile", self.pos_profile, "company"):
- frappe.throw(_("POS Profile {} does not belongs to company {}".format(self.pos_profile, self.company)))
+ frappe.throw(_("POS Profile {} does not belongs to company {}").format(self.pos_profile, self.company))
if not cint(frappe.db.get_value("User", self.user, "enabled")):
- frappe.throw(_("User {} has been disabled. Please select valid user/cashier".format(self.user)))
-
+ frappe.throw(_("User {} is disabled. Please select valid user/cashier").format(self.user))
+
def validate_payment_method_account(self):
+ invalid_modes = []
for d in self.balance_details:
- account = frappe.db.get_value("Mode of Payment Account",
- {"parent": d.mode_of_payment, "company": self.company}, "default_account")
- if not account:
- frappe.throw(_("Please set default Cash or Bank account in Mode of Payment {0}")
- .format(get_link_to_form("Mode of Payment", mode_of_payment)), title=_("Missing Account"))
+ if d.mode_of_payment:
+ account = frappe.db.get_value("Mode of Payment Account",
+ {"parent": d.mode_of_payment, "company": self.company}, "default_account")
+ if not account:
+ invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment))
+
+ if invalid_modes:
+ if invalid_modes == 1:
+ msg = _("Please set default Cash or Bank account in Mode of Payment {}")
+ else:
+ msg = _("Please set default Cash or Bank account in Mode of Payments {}")
+ frappe.throw(msg.format(", ".join(invalid_modes)), title=_("Missing Account"))
def on_submit(self):
self.set_status(update=True)
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry_list.js b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry_list.js
index 6c26ded..1ad3c91 100644
--- a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry_list.js
+++ b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry_list.js
@@ -5,7 +5,7 @@
frappe.listview_settings['POS Opening Entry'] = {
get_indicator: function(doc) {
var status_color = {
- "Draft": "grey",
+ "Draft": "red",
"Open": "orange",
"Closed": "green",
"Cancelled": "red"
diff --git a/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.json b/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.json
index 4d5e1eb..30ebd30 100644
--- a/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.json
+++ b/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.json
@@ -6,6 +6,7 @@
"engine": "InnoDB",
"field_order": [
"default",
+ "allow_in_returns",
"mode_of_payment"
],
"fields": [
@@ -24,11 +25,19 @@
"label": "Mode of Payment",
"options": "Mode of Payment",
"reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_in_returns",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Allow In Returns"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-29 15:08:41.704844",
+ "modified": "2020-10-20 12:58:46.114456",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Payment Method",
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js
index 8ec6a53..efdeb1a 100755
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.js
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js
@@ -15,15 +15,6 @@
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
-
- frm.call({
- method: "erpnext.accounts.doctype.pos_profile.pos_profile.get_series",
- callback: function(r) {
- if(!r.exc) {
- set_field_options("naming_series", r.message);
- }
- }
- });
});
frappe.ui.form.on('POS Profile', {
@@ -44,6 +35,15 @@
};
});
+ frm.set_query("taxes_and_charges", function() {
+ return {
+ filters: [
+ ['Sales Taxes and Charges Template', 'company', '=', frm.doc.company],
+ ['Sales Taxes and Charges Template', 'docstatus', '!=', 2]
+ ]
+ };
+ });
+
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(__('Please set Company'));
@@ -57,6 +57,8 @@
}
};
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
@@ -67,6 +69,7 @@
company: function(frm) {
frm.trigger("toggle_display_account_head");
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
toggle_display_account_head: function(frm) {
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json
index d4c1791..8afa0ab 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.json
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json
@@ -6,15 +6,11 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
- "disabled",
- "section_break_2",
- "naming_series",
- "customer",
"company",
+ "customer",
"country",
+ "disabled",
"column_break_9",
- "update_stock",
- "ignore_pricing_rule",
"warehouse",
"campaign",
"company_address",
@@ -23,8 +19,17 @@
"section_break_11",
"payments",
"section_break_14",
- "item_groups",
+ "hide_images",
+ "hide_unavailable_items",
+ "auto_add_item_to_cart",
"column_break_16",
+ "update_stock",
+ "ignore_pricing_rule",
+ "allow_rate_change",
+ "allow_discount_change",
+ "section_break_23",
+ "item_groups",
+ "column_break_25",
"customer_groups",
"section_break_16",
"print_format",
@@ -56,21 +61,6 @@
"label": "Disabled"
},
{
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Series",
- "no_copy": 1,
- "oldfieldname": "naming_series",
- "oldfieldtype": "Select",
- "options": "[Select]",
- "reqd": 1
- },
- {
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
@@ -135,7 +125,8 @@
},
{
"fieldname": "section_break_14",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Configuration"
},
{
"description": "Only show Items from these Item Groups",
@@ -302,28 +293,91 @@
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
- "mandatory_depends_on": "update_stock",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
- "options": "Warehouse"
- },
- {
- "default": "0",
- "fieldname": "update_stock",
- "fieldtype": "Check",
- "label": "Update Stock"
+ "options": "Warehouse",
+ "reqd": 1
},
{
"default": "0",
"fieldname": "ignore_pricing_rule",
"fieldtype": "Check",
"label": "Ignore Pricing Rule"
+ },
+ {
+ "default": "1",
+ "fieldname": "update_stock",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Update Stock",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "hide_unavailable_items",
+ "fieldtype": "Check",
+ "label": "Hide Unavailable Items"
+ },
+ {
+ "default": "0",
+ "fieldname": "hide_images",
+ "fieldtype": "Check",
+ "label": "Hide Images"
+ },
+ {
+ "default": "0",
+ "fieldname": "auto_add_item_to_cart",
+ "fieldtype": "Check",
+ "label": "Automatically Add Filtered Item To Cart"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_rate_change",
+ "fieldtype": "Check",
+ "label": "Allow User to Edit Rate"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_discount_change",
+ "fieldtype": "Check",
+ "label": "Allow User to Edit Discount"
+ },
+ {
+ "fieldname": "section_break_23",
+ "fieldtype": "Section Break",
+ "label": "Filters"
+ },
+ {
+ "fieldname": "column_break_25",
+ "fieldtype": "Column Break"
}
],
"icon": "icon-cog",
"idx": 1,
- "links": [],
- "modified": "2020-06-29 12:20:30.977272",
+ "index_web_pages_for_search": 1,
+ "links": [
+ {
+ "group": "Invoices",
+ "link_doctype": "Sales Invoice",
+ "link_fieldname": "pos_profile"
+ },
+ {
+ "group": "Invoices",
+ "link_doctype": "POS Invoice",
+ "link_fieldname": "pos_profile"
+ },
+ {
+ "group": "Opening & Closing",
+ "link_doctype": "POS Opening Entry",
+ "link_fieldname": "pos_profile"
+ },
+ {
+ "group": "Opening & Closing",
+ "link_doctype": "POS Closing Entry",
+ "link_fieldname": "pos_profile"
+ }
+ ],
+ "modified": "2021-02-01 13:52:51.081311",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",
@@ -350,4 +404,4 @@
],
"sort_field": "modified",
"sort_order": "DESC"
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py
index 1386b70..ee76bba 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py
@@ -56,19 +56,29 @@
if not self.payments:
frappe.throw(_("Payment methods are mandatory. Please add at least one payment method."))
- default_mode_of_payment = [d.default for d in self.payments if d.default]
- if not default_mode_of_payment:
+ default_mode = [d.default for d in self.payments if d.default]
+ if not default_mode:
frappe.throw(_("Please select a default mode of payment"))
- if len(default_mode_of_payment) > 1:
+ if len(default_mode) > 1:
frappe.throw(_("You can only select one mode of payment as default"))
+ invalid_modes = []
for d in self.payments:
- account = frappe.db.get_value("Mode of Payment Account",
- {"parent": d.mode_of_payment, "company": self.company}, "default_account")
+ account = frappe.db.get_value(
+ "Mode of Payment Account",
+ {"parent": d.mode_of_payment, "company": self.company},
+ "default_account"
+ )
if not account:
- frappe.throw(_("Please set default Cash or Bank account in Mode of Payment {0}")
- .format(get_link_to_form("Mode of Payment", mode_of_payment)), title=_("Missing Account"))
+ invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment))
+
+ if invalid_modes:
+ if invalid_modes == 1:
+ msg = _("Please set default Cash or Bank account in Mode of Payment {}")
+ else:
+ msg = _("Please set default Cash or Bank account in Mode of Payments {}")
+ frappe.throw(msg.format(", ".join(invalid_modes)), title=_("Missing Account"))
def on_update(self):
self.set_defaults()
@@ -110,10 +120,6 @@
lft >= {lft} and rgt <= {rgt} order by lft""".format(tab=group_type, lft=lft, rgt=rgt), as_dict=1)
@frappe.whitelist()
-def get_series():
- return frappe.get_meta("POS Invoice").get_field("naming_series").options or "s"
-
-@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):
user = frappe.session['user']
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile_dashboard.py b/erpnext/accounts/doctype/pos_profile/pos_profile_dashboard.py
deleted file mode 100644
index 2e4632a..0000000
--- a/erpnext/accounts/doctype/pos_profile/pos_profile_dashboard.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from __future__ import unicode_literals
-
-from frappe import _
-
-
-def get_data():
- return {
- 'fieldname': 'pos_profile',
- 'transactions': [
- {
- 'items': ['Sales Invoice', 'POS Closing Entry', 'POS Opening Entry']
- }
- ]
- }
diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
index edf8659..62dc1fc 100644
--- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
@@ -70,6 +70,7 @@
""".format(cond=cond), tuple([company] + args_list), as_dict=1)
def make_pos_profile(**args):
+ frappe.db.sql("delete from `tabPOS Payment Method`")
frappe.db.sql("delete from `tabPOS Profile`")
args = frappe._dict(args)
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.js b/erpnext/accounts/doctype/pos_settings/pos_settings.js
index 05cb7f0..8890d59 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.js
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.js
@@ -9,8 +9,7 @@
get_invoice_fields: function(frm) {
frappe.model.with_doctype("POS Invoice", () => {
var fields = $.map(frappe.get_doc("DocType", "POS Invoice").fields, function(d) {
- if (frappe.model.no_value_type.indexOf(d.fieldtype) === -1 ||
- ['Table', 'Button'].includes(d.fieldtype)) {
+ if (frappe.model.no_value_type.indexOf(d.fieldtype) === -1 || ['Button'].includes(d.fieldtype)) {
return { label: d.label + ' (' + d.fieldtype + ')', value: d.fieldname };
} else {
return null;
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
index c92b58b..d79ad5f 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
@@ -42,56 +42,56 @@
<tr><td>
<h4>
<i class="fa fa-hand-right"></i>
- ${__('Notes')}
+ {{__('Notes')}}
</h4>
<ul>
<li>
- ${__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}
+ {{__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}}
</li>
<li>
- ${__("If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.")}
+ {{__("If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.")}}
</li>
<li>
- ${__('Discount Percentage can be applied either against a Price List or for all Price List.')}
+ {{__('Discount Percentage can be applied either against a Price List or for all Price List.')}}
</li>
<li>
- ${__('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.')}
+ {{__('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.')}}
</li>
</ul>
</td></tr>
<tr><td>
<h4><i class="fa fa-question-sign"></i>
- ${__('How Pricing Rule is applied?')}
+ {{__('How Pricing Rule is applied?')}}
</h4>
<ol>
<li>
- ${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
+ {{__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}}
</li>
<li>
- ${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}
+ {{__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}}
</li>
<li>
- ${__('Pricing Rules are further filtered based on quantity.')}
+ {{__('Pricing Rules are further filtered based on quantity.')}}
</li>
<li>
- ${__('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.')}
+ {{__('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.')}}
</li>
<li>
- ${__('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:')}
+ {{__('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:')}}
<ul>
<li>
- ${__('Item Code > Item Group > Brand')}
+ {{__('Item Code > Item Group > Brand')}}
</li>
<li>
- ${__('Customer > Customer Group > Territory')}
+ {{__('Customer > Customer Group > Territory')}}
</li>
<li>
- ${__('Supplier > Supplier Type')}
+ {{__('Supplier > Supplier Type')}}
</li>
</ul>
</li>
<li>
- ${__('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.')}
+ {{__('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.')}}
</li>
</ol>
</td></tr>
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 29d8378..428989a 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:title",
@@ -43,6 +44,14 @@
"column_break_21",
"min_amt",
"max_amt",
+ "product_discount_scheme_section",
+ "same_item",
+ "free_item",
+ "free_qty",
+ "free_item_rate",
+ "column_break_42",
+ "free_item_uom",
+ "is_recursive",
"section_break_23",
"valid_from",
"valid_upto",
@@ -61,16 +70,10 @@
"discount_amount",
"discount_percentage",
"for_price_list",
- "product_discount_scheme_section",
- "same_item",
- "free_item",
- "free_qty",
- "column_break_51",
- "free_item_uom",
- "free_item_rate",
"section_break_13",
"threshold_percentage",
"priority",
+ "condition",
"column_break_66",
"apply_multiple_pricing_rules",
"apply_discount_on_rate",
@@ -355,7 +358,6 @@
"reqd": 1
},
{
- "depends_on": "eval: doc.selling == 1",
"fieldname": "margin",
"fieldtype": "Section Break",
"label": "Margin"
@@ -404,6 +406,7 @@
"fieldtype": "Column Break"
},
{
+ "default": "0",
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
"fieldname": "rate",
"fieldtype": "Currency",
@@ -457,16 +460,13 @@
"label": "Qty"
},
{
- "fieldname": "column_break_51",
- "fieldtype": "Column Break"
- },
- {
"fieldname": "free_item_uom",
"fieldtype": "Link",
"label": "UOM",
"options": "UOM"
},
{
+ "description": "If rate is zero them item will be treated as \"Free Item\"",
"fieldname": "free_item_rate",
"fieldtype": "Currency",
"label": "Rate"
@@ -502,10 +502,10 @@
},
{
"default": "0",
- "depends_on": "eval:in_list(['Discount Percentage', 'Discount Amount'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
+ "depends_on": "eval:in_list(['Discount Percentage'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
"fieldname": "apply_discount_on_rate",
"fieldtype": "Check",
- "label": "Apply Discount on Rate"
+ "label": "Apply Discount on Discounted Rate"
},
{
"default": "0",
@@ -549,12 +549,33 @@
"fieldname": "promotional_scheme",
"fieldtype": "Link",
"label": "Promotional Scheme",
- "options": "Promotional Scheme"
+ "no_copy": 1,
+ "options": "Promotional Scheme",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "description": "Simple Python Expression, Example: territory != 'All Territories'",
+ "fieldname": "condition",
+ "fieldtype": "Code",
+ "label": "Condition"
+ },
+ {
+ "fieldname": "column_break_42",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "description": "Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on",
+ "fieldname": "is_recursive",
+ "fieldtype": "Check",
+ "label": "Is Recursive"
}
],
"icon": "fa fa-gift",
"idx": 1,
- "modified": "2019-12-18 17:29:22.957077",
+ "links": [],
+ "modified": "2021-03-06 22:01:24.840422",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index aa6194c..aedf1c6 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -6,9 +6,10 @@
import frappe
import json
import copy
+import re
+
from frappe import throw, _
from frappe.utils import flt, cint, getdate
-
from frappe.model.document import Document
from six import string_types
@@ -30,6 +31,7 @@
self.validate_max_discount()
self.validate_price_list_with_currency()
self.validate_dates()
+ self.validate_condition()
if not self.margin_type: self.margin_rate_or_amount = 0.0
@@ -58,6 +60,15 @@
if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
+ if self.apply_discount_on_rate:
+ if not self.priority:
+ throw(_("As the field {0} is enabled, the field {1} is mandatory.")
+ .format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")))
+
+ if self.priority and cint(self.priority) == 1:
+ throw(_("As the field {0} is enabled, the value of the field {1} should be more than 1.")
+ .format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")))
+
def validate_applicable_for_selling_or_buying(self):
if not self.selling and not self.buying:
throw(_("Atleast one of the Selling or Buying must be selected"))
@@ -125,7 +136,7 @@
for d in self.items:
max_discount = frappe.get_cached_value("Item", d.item_code, "max_discount")
if max_discount and flt(self.discount_percentage) > flt(max_discount):
- throw(_("Max discount allowed for item: {0} is {1}%").format(self.item_code, max_discount))
+ throw(_("Max discount allowed for item: {0} is {1}%").format(d.item_code, max_discount))
def validate_price_list_with_currency(self):
if self.currency and self.for_price_list:
@@ -140,6 +151,10 @@
if self.valid_from and self.valid_upto and getdate(self.valid_from) > getdate(self.valid_upto):
frappe.throw(_("Valid from date must be less than valid upto date"))
+ def validate_condition(self):
+ if self.condition and ("=" in self.condition) and re.match("""[\w\.:_]+\s*={1}\s*[\w\.@'"]+""", self.condition):
+ frappe.throw(_("Invalid condition expression"))
+
#--------------------------------------------------------------------------------
@frappe.whitelist()
@@ -220,12 +235,12 @@
item_details = frappe._dict({
"doctype": args.doctype,
+ "has_margin": False,
"name": args.name,
+ "free_item_data": [],
"parent": args.parent,
"parenttype": args.parenttype,
- "child_docname": args.get('child_docname'),
- "discount_percentage_on_rate": [],
- "discount_amount_on_rate": []
+ "child_docname": args.get('child_docname')
})
if args.ignore_pricing_rule or not args.item_code:
@@ -273,6 +288,10 @@
else:
get_product_discount_rule(pricing_rule, item_details, args, doc)
+ if not item_details.get("has_margin"):
+ item_details.margin_type = None
+ item_details.margin_rate_or_amount = 0.0
+
item_details.has_pricing_rule = 1
item_details.pricing_rules = frappe.as_json([d.pricing_rule for d in rules])
@@ -324,20 +343,28 @@
def apply_price_discount_rule(pricing_rule, item_details, args):
item_details.pricing_rule_for = pricing_rule.rate_or_discount
- if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
+ if ((pricing_rule.margin_type in ['Amount', 'Percentage'] and pricing_rule.currency == args.currency)
or (pricing_rule.margin_type == 'Percentage')):
item_details.margin_type = pricing_rule.margin_type
- item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
- else:
- item_details.margin_type = None
- item_details.margin_rate_or_amount = 0.0
+ item_details.has_margin = True
+
+ if pricing_rule.apply_multiple_pricing_rules and item_details.margin_rate_or_amount is not None:
+ item_details.margin_rate_or_amount += pricing_rule.margin_rate_or_amount
+ else:
+ item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
if pricing_rule.rate_or_discount == 'Rate':
pricing_rule_rate = 0.0
if pricing_rule.currency == args.currency:
pricing_rule_rate = pricing_rule.rate
+
+ if pricing_rule_rate:
+ # Override already set price list rate (from item price)
+ # if pricing_rule_rate > 0
+ item_details.update({
+ "price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
+ })
item_details.update({
- "price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
"discount_percentage": 0.0
})
@@ -345,9 +372,9 @@
if pricing_rule.rate_or_discount != apply_on: continue
field = frappe.scrub(apply_on)
- if pricing_rule.apply_discount_on_rate:
- discount_field = "{0}_on_rate".format(field)
- item_details[discount_field].append(pricing_rule.get(field, 0))
+ if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"):
+ # Apply discount on discounted rate
+ item_details[field] += ((100 - item_details[field]) * (pricing_rule.get(field, 0) / 100))
else:
if field not in item_details:
item_details.setdefault(field, 0)
@@ -355,14 +382,6 @@
item_details[field] += (pricing_rule.get(field, 0)
if pricing_rule else args.get(field, 0))
-def set_discount_amount(rate, item_details):
- for field in ['discount_percentage_on_rate', 'discount_amount_on_rate']:
- for d in item_details.get(field):
- dis_amount = (rate * d / 100
- if field == 'discount_percentage_on_rate' else d)
- rate -= dis_amount
- item_details.rate = rate
-
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
from erpnext.accounts.doctype.pricing_rule.utils import (get_applied_pricing_rules,
get_pricing_rule_items)
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 2bf0b72..f28cee7 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -56,6 +56,7 @@
self.assertEqual(details.get("discount_percentage"), 10)
prule = frappe.get_doc(test_record.copy())
+ prule.priority = 1
prule.applicable_for = "Customer"
prule.title = "_Test Pricing Rule for Customer"
self.assertRaises(MandatoryError, prule.insert)
@@ -261,6 +262,7 @@
"rate_or_discount": "Discount Percentage",
"rate": 0,
"discount_percentage": 17.5,
+ "priority": 1,
"company": "_Test Company"
}).insert()
@@ -385,7 +387,7 @@
so.load_from_db()
self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item 2")
-
+
def test_cumulative_pricing_rule(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Cumulative Pricing Rule')
test_record = {
@@ -430,6 +432,113 @@
self.assertTrue(details)
+ def test_pricing_rule_for_condition(self):
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
+
+ make_pricing_rule(selling=1, margin_type="Percentage", \
+ condition="customer=='_Test Customer 1' and is_return==0", discount_percentage=10)
+
+ # Incorrect Customer and Correct is_return value
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 2", is_return=0)
+ si.items[0].price_list_rate = 1000
+ si.submit()
+ item = si.items[0]
+ self.assertEquals(item.rate, 100)
+
+ # Correct Customer and Incorrect is_return value
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
+ si.items[0].price_list_rate = 1000
+ si.submit()
+ item = si.items[0]
+ self.assertEquals(item.rate, 100)
+
+ # Correct Customer and correct is_return value
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
+ si.items[0].price_list_rate = 1000
+ si.submit()
+ item = si.items[0]
+ self.assertEquals(item.rate, 900)
+
+ def test_multiple_pricing_rules(self):
+ make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
+ title="_Test Pricing Rule 1")
+ make_pricing_rule(discount_percentage=10, selling=1, title="_Test Pricing Rule 2", priority=2,
+ apply_multiple_pricing_rules=1)
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
+ self.assertEqual(si.items[0].discount_percentage, 30)
+ si.delete()
+
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
+
+ def test_multiple_pricing_rules_with_apply_discount_on_discounted_rate(self):
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
+
+ make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
+ title="_Test Pricing Rule 1")
+ make_pricing_rule(discount_percentage=10, selling=1, priority=2,
+ apply_discount_on_rate=1, title="_Test Pricing Rule 2", apply_multiple_pricing_rules=1)
+
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
+ self.assertEqual(si.items[0].discount_percentage, 28)
+ si.delete()
+
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
+
+ def test_item_price_with_pricing_rule(self):
+ item = make_item("Water Flask")
+ make_item_price("Water Flask", "_Test Price List", 100)
+
+ pricing_rule_record = {
+ "doctype": "Pricing Rule",
+ "title": "_Test Water Flask Rule",
+ "apply_on": "Item Code",
+ "items": [{
+ "item_code": "Water Flask",
+ }],
+ "selling": 1,
+ "currency": "INR",
+ "rate_or_discount": "Rate",
+ "rate": 0,
+ "margin_type": "Percentage",
+ "margin_rate_or_amount": 2,
+ "company": "_Test Company"
+ }
+ rule = frappe.get_doc(pricing_rule_record)
+ rule.insert()
+
+ si = create_sales_invoice(do_not_save=True, item_code="Water Flask")
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # If rate in Rule is 0, give preference to Item Price if it exists
+ self.assertEqual(si.items[0].price_list_rate, 100)
+ self.assertEqual(si.items[0].margin_rate_or_amount, 2)
+ self.assertEqual(si.items[0].rate_with_margin, 102)
+ self.assertEqual(si.items[0].rate, 102)
+
+ si.delete()
+ rule.delete()
+ frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete()
+ item.delete()
+
+ def test_pricing_rule_for_transaction(self):
+ make_item("Water Flask 1")
+ frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
+ make_pricing_rule(selling=1, min_qty=5, price_or_product_discount="Product",
+ apply_on="Transaction", free_item="Water Flask 1", free_qty=1, free_item_rate=10)
+
+ si = create_sales_invoice(qty=5, do_not_submit=True)
+ self.assertEquals(len(si.items), 2)
+ self.assertEquals(si.items[1].rate, 10)
+
+ si1 = create_sales_invoice(qty=2, do_not_submit=True)
+ self.assertEquals(len(si1.items), 1)
+
+ for doc in [si, si1]:
+ doc.delete()
+
def make_pricing_rule(**args):
args = frappe._dict(args)
@@ -441,21 +550,31 @@
"applicable_for": args.applicable_for,
"selling": args.selling or 0,
"currency": "USD",
+ "apply_discount_on_rate": args.apply_discount_on_rate or 0,
"buying": args.buying or 0,
"min_qty": args.min_qty or 0.0,
"max_qty": args.max_qty or 0.0,
"rate_or_discount": args.rate_or_discount or "Discount Percentage",
"discount_percentage": args.discount_percentage or 0.0,
"rate": args.rate or 0.0,
- "margin_type": args.margin_type,
- "margin_rate_or_amount": args.margin_rate_or_amount or 0.0
+ "margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
+ "condition": args.condition or '',
+ "priority": 1,
+ "apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
})
+ for field in ["free_item", "free_qty", "free_item_rate", "priority",
+ "margin_type", "price_or_product_discount"]:
+ if args.get(field):
+ doc.set(field, args.get(field))
+
apply_on = doc.apply_on.replace(' ', '_').lower()
child_table = {'Item Code': 'items', 'Item Group': 'item_groups', 'Brand': 'brands'}
- doc.append(child_table.get(doc.apply_on), {
- apply_on: args.get(apply_on) or "_Test Item"
- })
+
+ if doc.apply_on != "Transaction":
+ doc.append(child_table.get(doc.apply_on), {
+ apply_on: args.get(apply_on) or "_Test Item"
+ })
doc.insert(ignore_permissions=True)
if args.get(apply_on) and apply_on != "item_code":
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 53b0cf7b..c676abd 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -14,9 +14,8 @@
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
from erpnext.stock.get_item_details import get_conversion_factor
-from frappe import _, throw
-from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
-
+from frappe import _, bold
+from frappe.utils import cint, flt, get_link_to_form, getdate, today, fmt_money
class MultiplePricingRuleConflict(frappe.ValidationError): pass
@@ -37,12 +36,16 @@
rules = []
+ pricing_rules = filter_pricing_rule_based_on_condition(pricing_rules, doc)
+
if not pricing_rules: return []
if apply_multiple_pricing_rules(pricing_rules):
+ pricing_rules = sorted_by_priority(pricing_rules, args, doc)
for pricing_rule in pricing_rules:
- pricing_rule = filter_pricing_rules(args, pricing_rule, doc)
- if pricing_rule:
+ if isinstance(pricing_rule, list):
+ rules.extend(pricing_rule)
+ else:
rules.append(pricing_rule)
else:
pricing_rule = filter_pricing_rules(args, pricing_rules, doc)
@@ -51,6 +54,42 @@
return rules
+def sorted_by_priority(pricing_rules, args, doc=None):
+ # If more than one pricing rules, then sort by priority
+ pricing_rules_list = []
+ pricing_rule_dict = {}
+
+ for pricing_rule in pricing_rules:
+ pricing_rule = filter_pricing_rules(args, pricing_rule, doc)
+ if pricing_rule:
+ if not pricing_rule.get('priority'):
+ pricing_rule['priority'] = 1
+
+ if pricing_rule.get('apply_multiple_pricing_rules'):
+ pricing_rule_dict.setdefault(cint(pricing_rule.get("priority")), []).append(pricing_rule)
+
+ for key in sorted(pricing_rule_dict):
+ pricing_rules_list.extend(pricing_rule_dict.get(key))
+
+ return pricing_rules_list or pricing_rules
+
+def filter_pricing_rule_based_on_condition(pricing_rules, doc=None):
+ filtered_pricing_rules = []
+ if doc:
+ for pricing_rule in pricing_rules:
+ if pricing_rule.condition:
+ try:
+ if frappe.safe_eval(pricing_rule.condition, None, doc.as_dict()):
+ filtered_pricing_rules.append(pricing_rule)
+ except:
+ pass
+ else:
+ filtered_pricing_rules.append(pricing_rule)
+ else:
+ filtered_pricing_rules = pricing_rules
+
+ return filtered_pricing_rules
+
def _get_pricing_rules(apply_on, args, values):
apply_on_field = frappe.scrub(apply_on)
@@ -111,9 +150,7 @@
if not apply_multiple_rule: return False
- if (apply_multiple_rule
- and len(apply_multiple_rule) == len(pricing_rules)):
- return True
+ return True
def _get_tree_conditions(args, parenttype, table, allow_blank=True):
field = frappe.scrub(parenttype)
@@ -131,7 +168,15 @@
frappe.throw(_("Invalid {0}").format(args.get(field)))
parent_groups = frappe.db.sql_list("""select name from `tab%s`
- where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
+ where lft>=%s and rgt<=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
+
+ if parenttype in ["Customer Group", "Item Group", "Territory"]:
+ parent_field = "parent_{0}".format(frappe.scrub(parenttype))
+ root_name = frappe.db.get_list(parenttype,
+ {"is_group": 1, parent_field: ("is", "not set")}, "name", as_list=1)
+
+ if root_name and root_name[0][0]:
+ parent_groups.append(root_name[0][0])
if parent_groups:
if allow_blank: parent_groups.append('')
@@ -223,18 +268,6 @@
if max_priority:
pricing_rules = list(filter(lambda x: cint(x.priority)==max_priority, pricing_rules))
- # apply internal priority
- all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
- "supplier", "supplier_group", "campaign", "sales_partner", "variant_of"]
-
- if len(pricing_rules) > 1:
- for field_set in [["item_code", "variant_of", "item_group", "brand"],
- ["customer", "customer_group", "territory"], ["supplier", "supplier_group"]]:
- remaining_fields = list(set(all_fields) - set(field_set))
- if if_all_rules_same(pricing_rules, remaining_fields):
- pricing_rules = apply_internal_priority(pricing_rules, field_set, args)
- break
-
if pricing_rules and not isinstance(pricing_rules, list):
pricing_rules = list(pricing_rules)
@@ -265,12 +298,13 @@
fieldname = field
if fieldname:
- msg = _("""If you {0} {1} quantities of the item <b>{2}</b>, the scheme <b>{3}</b>
- will be applied on the item.""").format(type_of_transaction, args.get(fieldname), item_code, args.rule_description)
+ msg = (_("If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.")
+ .format(type_of_transaction, args.get(fieldname), bold(item_code), bold(args.rule_description)))
if fieldname in ['min_amt', 'max_amt']:
- msg = _("""If you {0} {1} worth item <b>{2}</b>, the scheme <b>{3}</b> will be applied on the item.
- """).format(frappe.fmt_money(type_of_transaction, args.get(fieldname)), item_code, args.rule_description)
+ msg = (_("If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.")
+ .format(type_of_transaction, fmt_money(args.get(fieldname), currency=args.get("currency")),
+ bold(item_code), bold(args.rule_description)))
frappe.msgprint(msg)
@@ -333,7 +367,7 @@
if items and doc.get("items"):
for row in doc.get('items'):
- if row.get(apply_on) not in items: continue
+ if (row.get(apply_on) or args.get(apply_on)) not in items: continue
if pr_doc.mixed_conditions:
amt = args.get('qty') * args.get("price_list_rate")
@@ -423,6 +457,9 @@
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
doc.total, pricing_rules)
+ if not pricing_rules:
+ remove_free_item(doc)
+
for d in pricing_rules:
if d.price_or_product_discount == 'Price':
if d.apply_discount_on:
@@ -442,10 +479,16 @@
doc.calculate_taxes_and_totals()
elif d.price_or_product_discount == 'Product':
- item_details = frappe._dict({'parenttype': doc.doctype})
+ item_details = frappe._dict({'parenttype': doc.doctype, 'free_item_data': []})
get_product_discount_rule(d, item_details, doc=doc)
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
doc.set_missing_values()
+ doc.calculate_taxes_and_totals()
+
+def remove_free_item(doc):
+ for d in doc.items:
+ if d.is_free_item:
+ doc.remove(d)
def get_applied_pricing_rules(pricing_rules):
if pricing_rules:
@@ -458,16 +501,23 @@
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
free_item = pricing_rule.free_item
- if pricing_rule.same_item:
+ if pricing_rule.same_item and pricing_rule.get("apply_on") != 'Transaction':
free_item = item_details.item_code or args.item_code
if not free_item:
frappe.throw(_("Free item not set in the pricing rule {0}")
.format(get_link_to_form("Pricing Rule", pricing_rule.name)))
- item_details.free_item_data = {
+ qty = pricing_rule.free_qty or 1
+ if pricing_rule.is_recursive:
+ transaction_qty = args.get('qty') if args else doc.total_qty
+ if transaction_qty:
+ qty = flt(transaction_qty) * qty
+
+ free_item_data_args = {
'item_code': free_item,
- 'qty': pricing_rule.free_qty or 1,
+ 'qty': qty,
+ 'pricing_rules': pricing_rule.name,
'rate': pricing_rule.free_item_rate or 0,
'price_list_rate': pricing_rule.free_item_rate or 0,
'is_free_item': 1
@@ -476,24 +526,26 @@
item_data = frappe.get_cached_value('Item', free_item, ['item_name',
'description', 'stock_uom'], as_dict=1)
- item_details.free_item_data.update(item_data)
- item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
- item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item,
- item_details.free_item_data['uom']).get("conversion_factor", 1)
+ free_item_data_args.update(item_data)
+ free_item_data_args['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
+ free_item_data_args['conversion_factor'] = get_conversion_factor(free_item,
+ free_item_data_args['uom']).get("conversion_factor", 1)
if item_details.get("parenttype") == 'Purchase Order':
- item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today()
+ free_item_data_args['schedule_date'] = doc.schedule_date if doc else today()
if item_details.get("parenttype") == 'Sales Order':
- item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
+ free_item_data_args['delivery_date'] = doc.delivery_date if doc else today()
+
+ item_details.free_item_data.append(free_item_data_args)
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
- if pricing_rule_args.get('item_code'):
- items = [d.item_code for d in doc.items
- if d.item_code == (pricing_rule_args.get("item_code")) and d.is_free_item]
+ if pricing_rule_args:
+ items = tuple([(d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item])
- if not items:
- doc.append('items', pricing_rule_args)
+ for args in pricing_rule_args:
+ if not items or (args.get('item_code'), args.get('pricing_rules')) not in items:
+ doc.append('items', args)
def get_pricing_rule_items(pr_doc):
apply_on_data = []
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 31356c6..e08a0e5 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
@@ -21,7 +21,7 @@
item.no_of_months = 12
item.save()
- si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
+ si = create_sales_invoice(item=item.name, update_stock=0, posting_date="2019-01-10", do_not_submit=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"
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 89f7238..523e9ee 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -12,16 +12,16 @@
pricing_rule_fields = ['apply_on', 'mixed_conditions', 'is_cumulative', 'other_item_code', 'other_item_group'
'apply_rule_on_other', 'other_brand', 'selling', 'buying', 'applicable_for', 'valid_from',
'valid_upto', 'customer', 'customer_group', 'territory', 'sales_partner', 'campaign', 'supplier',
- 'supplier_group', 'company', 'currency']
+ 'supplier_group', 'company', 'currency', 'apply_multiple_pricing_rules']
other_fields = ['min_qty', 'max_qty', 'min_amt',
'max_amt', 'priority','warehouse', 'threshold_percentage', 'rule_description']
price_discount_fields = ['rate_or_discount', 'apply_discount_on', 'apply_discount_on_rate',
- 'rate', 'discount_amount', 'discount_percentage', 'validate_applied_rule']
+ 'rate', 'discount_amount', 'discount_percentage', 'validate_applied_rule', 'apply_multiple_pricing_rules']
product_discount_fields = ['free_item', 'free_qty', 'free_item_uom',
- 'free_item_rate', 'same_item']
+ 'free_item_rate', 'same_item', 'is_recursive', 'apply_multiple_pricing_rules']
class PromotionalScheme(Document):
def validate(self):
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 224b8de..795fb1c 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
@@ -1,792 +1,181 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
+ "actions": [],
"creation": "2019-03-24 14:48:59.649168",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "disable",
+ "apply_multiple_pricing_rules",
+ "column_break_2",
+ "rule_description",
+ "section_break_2",
+ "min_qty",
+ "max_qty",
+ "column_break_3",
+ "min_amount",
+ "max_amount",
+ "section_break_6",
+ "rate_or_discount",
+ "column_break_10",
+ "rate",
+ "discount_amount",
+ "discount_percentage",
+ "section_break_11",
+ "warehouse",
+ "threshold_percentage",
+ "validate_applied_rule",
+ "column_break_14",
+ "priority",
+ "apply_discount_on_rate"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"fieldname": "disable",
"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",
- "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
+ "label": "Disable"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_2",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "rule_description",
"fieldtype": "Small 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": "Rule Description",
- "length": 0,
"no_copy": 1,
- "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
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_2",
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 1,
"default": "0",
"fieldname": "min_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": "Min Qty",
- "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
+ "label": "Min Qty"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 1,
"default": "0",
"fieldname": "max_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": "Max Qty",
- "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
+ "label": "Max Qty"
},
{
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
"fieldname": "min_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": "Min Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Min Amount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
- "depends_on": "",
"fieldname": "max_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": "Max Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Max Amount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"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,
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "Discount Percentage",
- "depends_on": "",
"fieldname": "rate_or_discount",
"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": "Discount Type",
- "length": 0,
- "no_copy": 0,
- "options": "\nRate\nDiscount Percentage\nDiscount Amount",
- "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
+ "options": "\nRate\nDiscount Percentage\nDiscount Amount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "column_break_10",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 2,
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
"fieldname": "rate",
"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": "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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Rate"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.rate_or_discount==\"Discount Amount\"",
"fieldname": "discount_amount",
"fieldtype": "Currency",
- "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": "Discount Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Discount Amount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.rate_or_discount==\"Discount Percentage\"",
"fieldname": "discount_percentage",
"fieldtype": "Float",
- "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": "Discount Percentage",
- "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
+ "label": "Discount Percentage"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_11",
- "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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "warehouse",
"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": "Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "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
+ "options": "Warehouse"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "threshold_percentage",
"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": "Threshold for Suggestion",
- "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
+ "label": "Threshold for Suggestion"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "1",
"fieldname": "validate_applied_rule",
"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": "Validate Applied Rule",
- "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
+ "label": "Validate Applied Rule"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_14",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "priority",
"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": "Priority",
- "length": 0,
- "no_copy": 0,
- "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
- "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
+ "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"depends_on": "priority",
"fieldname": "apply_multiple_pricing_rules",
"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": "Apply Multiple Pricing Rules",
- "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
+ "label": "Apply Multiple Pricing Rules"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
"depends_on": "eval:in_list(['Discount Percentage', 'Discount Amount'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
"fieldname": "apply_discount_on_rate",
"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": "Apply Discount on 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Apply Discount on Rate"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
+ "index_web_pages_for_search": 1,
"istable": 1,
- "max_attachments": 0,
- "modified": "2019-03-24 14:48:59.649168",
+ "links": [],
+ "modified": "2021-03-07 11:56:23.424137",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Price Discount",
- "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
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.json b/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.json
index 72d53bf..3eab515 100644
--- a/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.json
+++ b/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.json
@@ -1,10 +1,12 @@
{
+ "actions": [],
"creation": "2019-03-24 14:48:59.649168",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"disable",
+ "apply_multiple_pricing_rules",
"column_break_2",
"rule_description",
"section_break_1",
@@ -25,7 +27,7 @@
"threshold_percentage",
"column_break_15",
"priority",
- "apply_multiple_pricing_rules"
+ "is_recursive"
],
"fields": [
{
@@ -152,10 +154,19 @@
"fieldname": "apply_multiple_pricing_rules",
"fieldtype": "Check",
"label": "Apply Multiple Pricing Rules"
+ },
+ {
+ "default": "0",
+ "description": "Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on",
+ "fieldname": "is_recursive",
+ "fieldtype": "Check",
+ "label": "Is Recursive"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-07-21 00:00:56.674284",
+ "links": [],
+ "modified": "2021-03-06 21:58:18.162346",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Product Discount",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index fe5301d..66a8e20 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -15,7 +15,22 @@
return (doc.qty<=doc.received_qty) ? "green" : "orange";
});
}
+
+ this.frm.set_query("unrealized_profit_loss_account", function() {
+ return {
+ filters: {
+ company: doc.company,
+ is_group: 0,
+ root_type: "Liability",
+ }
+ };
+ });
},
+
+ company: function() {
+ erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
+ },
+
onload: function() {
this._super();
@@ -31,6 +46,8 @@
if (this.frm.doc.supplier && this.frm.doc.__islocal) {
this.frm.trigger('supplier');
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
refresh: function(doc) {
@@ -99,6 +116,7 @@
target: me.frm,
setters: {
supplier: me.frm.doc.supplier || undefined,
+ schedule_date: undefined
},
get_query_filters: {
docstatus: 1,
@@ -107,16 +125,16 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
this.frm.add_custom_button(__('Purchase Receipt'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
source_doctype: "Purchase Receipt",
target: me.frm,
- date_field: "posting_date",
setters: {
supplier: me.frm.doc.supplier || undefined,
+ posting_date: undefined
},
get_query_filters: {
docstatus: 1,
@@ -125,7 +143,7 @@
is_return: 0
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
}
this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
@@ -257,8 +275,11 @@
supplier: function() {
var me = this;
- if(this.frm.updating_party_details)
+
+ // Do not update if inter company reference is there as the details will already be updated
+ if(this.frm.updating_party_details || this.frm.doc.inter_company_invoice_reference)
return;
+
erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details",
{
posting_date: this.frm.doc.posting_date,
@@ -487,7 +508,7 @@
frappe.ui.form.on("Purchase Invoice", {
setup: function(frm) {
frm.custom_make_buttons = {
- 'Purchase Invoice': 'Debit Note',
+ 'Purchase Invoice': 'Return / Debit Note',
'Payment Entry': 'Payment'
}
@@ -500,19 +521,10 @@
}
}
}
-
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company,
- is_group: 0
- }
- };
- });
},
onload: function(frm) {
- if(frm.doc.__onload) {
+ if(frm.doc.__onload && frm.is_new()) {
if(frm.doc.supplier) {
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
}
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index d62e73b..18b6637 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -57,8 +57,9 @@
"set_warehouse",
"rejected_warehouse",
"col_break_warehouse",
- "is_subcontracted",
+ "set_from_warehouse",
"supplier_warehouse",
+ "is_subcontracted",
"items_section",
"update_stock",
"scan_barcode",
@@ -126,6 +127,7 @@
"write_off_cost_center",
"advances_section",
"allocate_advances_automatically",
+ "adjust_advance_taxes",
"get_advances",
"advances",
"payment_schedule_section",
@@ -151,9 +153,11 @@
"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",
@@ -361,6 +365,7 @@
"fieldname": "bill_date",
"fieldtype": "Date",
"label": "Supplier Invoice Date",
+ "no_copy": 1,
"oldfieldname": "bill_date",
"oldfieldtype": "Date",
"print_hide": 1
@@ -511,6 +516,7 @@
},
{
"depends_on": "update_stock",
+ "description": "Sets 'Accepted Warehouse' in each row of the items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
"label": "Set Accepted Warehouse",
@@ -540,17 +546,6 @@
"print_hide": 1
},
{
- "depends_on": "eval:doc.is_subcontracted==\"Yes\"",
- "fieldname": "supplier_warehouse",
- "fieldtype": "Link",
- "label": "Supplier Warehouse",
- "no_copy": 1,
- "options": "Warehouse",
- "print_hide": 1,
- "print_width": "50px",
- "width": "50px"
- },
- {
"fieldname": "items_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
@@ -1221,14 +1216,16 @@
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Status",
- "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled",
+ "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled\nInternal Transfer",
"print_hide": 1
},
{
"fieldname": "inter_company_invoice_reference",
"fieldtype": "Link",
"label": "Inter Company Invoice Reference",
+ "no_copy": 1,
"options": "Sales Invoice",
+ "print_hide": 1,
"read_only": 1
},
{
@@ -1328,13 +1325,60 @@
"fieldtype": "Link",
"label": "Project",
"options": "Project"
+ },
+ {
+ "default": "0",
+ "description": "Taxes paid while advance payment will be adjusted against this invoice",
+ "fieldname": "adjust_advance_taxes",
+ "fieldtype": "Check",
+ "label": "Adjust Advance Taxes"
+ },
+ {
+ "depends_on": "eval:doc.is_internal_supplier",
+ "description": "Unrealized Profit / Loss account for intra-company transfers",
+ "fieldname": "unrealized_profit_loss_account",
+ "fieldtype": "Link",
+ "label": "Unrealized Profit / Loss Account",
+ "options": "Account"
+ },
+ {
+ "depends_on": "eval:doc.is_internal_supplier",
+ "description": "Company which internal supplier represents",
+ "fetch_from": "supplier.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company"
+ },
+ {
+ "depends_on": "eval:doc.update_stock && doc.is_internal_supplier",
+ "description": "Sets 'From Warehouse' in each row of the items table.",
+ "fieldname": "set_from_warehouse",
+ "fieldtype": "Link",
+ "label": "Set From Warehouse",
+ "no_copy": 1,
+ "options": "Warehouse",
+ "print_hide": 1,
+ "print_width": "50px",
+ "width": "50px"
+ },
+ {
+ "depends_on": "eval:doc.update_stock && doc.is_subcontracted==\"Yes\"",
+ "fieldname": "supplier_warehouse",
+ "fieldtype": "Link",
+ "label": "Supplier Warehouse",
+ "no_copy": 1,
+ "options": "Warehouse",
+ "print_hide": 1,
+ "print_width": "50px",
+ "width": "50px"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-03 23:20:04.466153",
+ "modified": "2021-03-09 21:12:30.422084",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
@@ -1396,4 +1440,4 @@
"timeline_field": "supplier",
"title_field": "title",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 079f599..5c4e32e 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -147,18 +147,25 @@
throw(_("Conversion rate cannot be 0 or 1"))
def validate_credit_to_acc(self):
+ if not self.credit_to:
+ self.credit_to = get_party_account("Supplier", self.supplier, self.company)
+ if not self.credit_to:
+ self.raise_missing_debit_credit_account_error("Supplier", self.supplier)
+
account = frappe.db.get_value("Account", self.credit_to,
["account_type", "report_type", "account_currency"], as_dict=True)
if account.report_type != "Balance Sheet":
- frappe.throw(_("Please ensure {} account is a Balance Sheet account. \
- You can change the parent account to a Balance Sheet account or select a different account.")
- .format(frappe.bold("Credit To")), title=_("Invalid Account"))
+ frappe.throw(
+ _("Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.")
+ .format(frappe.bold("Credit To")), title=_("Invalid Account")
+ )
if self.supplier and account.account_type != "Payable":
- frappe.throw(_("Please ensure {} account is a Payable account. \
- Change the account type to Payable or select a different account.")
- .format(frappe.bold("Credit To")), title=_("Invalid Account"))
+ frappe.throw(
+ _("Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.")
+ .format(frappe.bold("Credit To")), title=_("Invalid Account")
+ )
self.party_account_currency = account.account_currency
@@ -199,8 +206,8 @@
["Purchase Receipt", "purchase_receipt", "pr_detail"]
])
- def validate_warehouse(self):
- if self.update_stock:
+ def validate_warehouse(self, for_validate=True):
+ if self.update_stock and for_validate:
for d in self.get('items'):
if not d.warehouse:
frappe.throw(_("Warehouse required at Row No {0}, please set default warehouse for the item {1} for the company {2}").
@@ -226,7 +233,7 @@
if self.update_stock:
self.validate_item_code()
- self.validate_warehouse()
+ self.validate_warehouse(for_validate)
if auto_accounting_for_stock:
warehouse_account = get_warehouse_account_map(self.company)
@@ -244,10 +251,10 @@
if self.update_stock and (not item.from_warehouse):
if for_validate and item.expense_account and item.expense_account != warehouse_account[item.warehouse]["account"]:
- frappe.msgprint(_('''Row {0}: Expense Head changed to {1} because account {2}
- is not linked to warehouse {3} or it is not the default inventory account'''.format(
- item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]),
- frappe.bold(item.expense_account), frappe.bold(item.warehouse))))
+ msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]))
+ msg += _("because account {} is not linked to warehouse {} ").format(frappe.bold(item.expense_account), frappe.bold(item.warehouse))
+ msg += _("or it is not the default inventory account")
+ frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = warehouse_account[item.warehouse]["account"]
else:
@@ -259,19 +266,19 @@
if negative_expense_booked_in_pr:
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
- frappe.msgprint(_('''Row {0}: Expense Head changed to {1} because
- expense is booked against this account in Purchase Receipt {2}'''.format(
- item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.purchase_receipt))))
+ msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account))
+ msg += _("because expense is booked against this account in Purchase Receipt {}").format(frappe.bold(item.purchase_receipt))
+ frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = stock_not_billed_account
else:
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
# This is done in cases when Purchase Invoice is created before Purchase Receipt
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
- frappe.msgprint(_('''Row {0}: Expense Head changed to {1} as no Purchase
- Receipt is created against Item {2}. This is done to handle accounting for cases
- when Purchase Receipt is created after Purchase Invoice'''.format(
- item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.item_code))))
+ msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account))
+ msg += _("as no Purchase Receipt is created against Item {}. ").format(frappe.bold(item.item_code))
+ msg += _("This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice")
+ frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = stock_not_billed_account
@@ -299,10 +306,11 @@
for d in self.get('items'):
if not d.purchase_order:
- throw(_("""Purchase Order Required for item {0}
- To submit the invoice without purchase order please set
- {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold(_('Purchase Order Required')),
- frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')))
+ msg = _("Purchase Order Required for item {}").format(frappe.bold(d.item_code))
+ msg += "<br><br>"
+ msg += _("To submit the invoice without purchase order please set {} ").format(frappe.bold(_('Purchase Order Required')))
+ msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
+ throw(msg, title=_("Mandatory Purchase Order"))
def pr_required(self):
stock_items = self.get_stock_items()
@@ -313,10 +321,11 @@
for d in self.get('items'):
if not d.purchase_receipt and d.item_code in stock_items:
- throw(_("""Purchase Receipt Required for item {0}
- To submit the invoice without purchase receipt please set
- {1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold(_('Purchase Receipt Required')),
- frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')))
+ msg = _("Purchase Receipt Required for item {}").format(frappe.bold(d.item_code))
+ msg += "<br><br>"
+ msg += _("To submit the invoice without purchase receipt please set {} ").format(frappe.bold(_('Purchase Receipt Required')))
+ msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
+ throw(msg, title=_("Mandatory Purchase Receipt"))
def validate_write_off_account(self):
if self.write_off_amount and not self.write_off_account:
@@ -401,10 +410,13 @@
# this sequence because outstanding may get -negative
self.make_gl_entries()
+ if self.update_stock == 1:
+ self.repost_future_sle_and_gle()
+
self.update_project()
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
- def make_gl_entries(self, gl_entries=None):
+ def make_gl_entries(self, gl_entries=None, from_repost=False):
if not gl_entries:
gl_entries = self.get_gl_entries()
@@ -412,7 +424,7 @@
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
if self.docstatus == 1:
- make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
+ make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
elif self.docstatus == 2:
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
@@ -427,9 +439,11 @@
self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
if self.auto_accounting_for_stock:
self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed")
+ self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
else:
self.stock_received_but_not_billed = None
- self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+ self.expenses_included_in_valuation = None
+
self.negative_expense_to_be_booked = 0.0
gl_entries = []
@@ -440,6 +454,7 @@
self.get_asset_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
+ self.make_internal_transfer_gl_entries(gl_entries)
gl_entries = make_regional_gl_entries(gl_entries, self)
@@ -448,7 +463,6 @@
self.make_payment_gl_entries(gl_entries)
self.make_write_off_gl_entry(gl_entries)
self.make_gle_for_rounding_adjustment(gl_entries)
-
return gl_entries
def check_asset_cwip_enabled(self):
@@ -465,31 +479,30 @@
# because rounded_total had value even before introcution of posting GLE based on rounded total
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
- if grand_total:
- # Didnot use base_grand_total to book rounding loss gle
- grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
- self.precision("grand_total"))
- gl_entries.append(
- self.get_gl_dict({
- "account": self.credit_to,
- "party_type": "Supplier",
- "party": self.supplier,
- "due_date": self.due_date,
- "against": self.against_expense_account,
- "credit": grand_total_in_company_currency,
- "credit_in_account_currency": grand_total_in_company_currency \
- if self.party_account_currency==self.company_currency else grand_total,
- "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
- "against_voucher_type": self.doctype,
- "project": self.project,
- "cost_center": self.cost_center
- }, self.party_account_currency, item=self)
- )
+ if grand_total and not self.is_internal_transfer():
+ # Did not use base_grand_total to book rounding loss gle
+ grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
+ self.precision("grand_total"))
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.credit_to,
+ "party_type": "Supplier",
+ "party": self.supplier,
+ "due_date": self.due_date,
+ "against": self.against_expense_account,
+ "credit": grand_total_in_company_currency,
+ "credit_in_account_currency": grand_total_in_company_currency \
+ if self.party_account_currency==self.company_currency else grand_total,
+ "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
+ "against_voucher_type": self.doctype,
+ "project": self.project,
+ "cost_center": self.cost_center
+ }, self.party_account_currency, item=self)
+ )
def make_item_gl_entries(self, gl_entries):
# item gl entries
stock_items = self.get_stock_items()
- expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
if self.update_stock and self.auto_accounting_for_stock:
warehouse_account = get_warehouse_account_map(self.company)
@@ -498,8 +511,8 @@
voucher_wise_stock_value = {}
if self.update_stock:
for d in frappe.get_all('Stock Ledger Entry',
- fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}):
- voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference)
+ fields = ["voucher_detail_no", "stock_value_difference", "warehouse"], filters={'voucher_no': self.name}):
+ voucher_wise_stock_value.setdefault((d.voucher_detail_no, d.warehouse), d.stock_value_difference)
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
if d.category in ('Valuation', 'Total and Valuation')
@@ -517,7 +530,6 @@
item, voucher_wise_stock_value, account_currency)
if item.from_warehouse:
-
gl_entries.append(self.get_gl_dict({
"account": warehouse_account[item.warehouse]['account'],
"against": warehouse_account[item.from_warehouse]["account"],
@@ -537,28 +549,31 @@
"debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")),
}, warehouse_account[item.from_warehouse]["account_currency"], item=item))
- gl_entries.append(
- self.get_gl_dict({
- "account": item.expense_account,
- "against": self.supplier,
- "debit": flt(item.base_net_amount, item.precision("base_net_amount")),
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "cost_center": item.cost_center,
- "project": item.project
- }, account_currency, item=item)
- )
+ # Do not book expense for transfer within same company transfer
+ if not self.is_internal_transfer():
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": item.expense_account,
+ "against": self.supplier,
+ "debit": flt(item.base_net_amount, item.precision("base_net_amount")),
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "cost_center": item.cost_center,
+ "project": item.project
+ }, account_currency, item=item)
+ )
else:
- gl_entries.append(
- self.get_gl_dict({
- "account": item.expense_account,
- "against": self.supplier,
- "debit": warehouse_debit_amount,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "cost_center": item.cost_center,
- "project": item.project or self.project
- }, account_currency, item=item)
- )
+ if not self.is_internal_transfer():
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": item.expense_account,
+ "against": self.supplier,
+ "debit": warehouse_debit_amount,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item)
+ )
# Amount added through landed-cost-voucher
if landed_cost_entries:
@@ -568,7 +583,8 @@
"against": item.expense_account,
"cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(amount),
+ "credit": flt(amount["base_amount"]),
+ "credit_in_account_currency": flt(amount["amount"]),
"project": item.project or self.project
}, item=item))
@@ -610,13 +626,14 @@
if expense_booked_in_pr:
expense_account = service_received_but_not_billed_account
- gl_entries.append(self.get_gl_dict({
- "account": expense_account,
- "against": self.supplier,
- "debit": amount,
- "cost_center": item.cost_center,
- "project": item.project or self.project
- }, account_currency, item=item))
+ if not self.is_internal_transfer():
+ gl_entries.append(self.get_gl_dict({
+ "account": expense_account,
+ "against": self.supplier,
+ "debit": amount,
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item))
# If asset is bought through this document and not linked to PR
if self.update_stock and item.landed_cost_voucher_amount:
@@ -711,7 +728,8 @@
item.item_tax_amount / self.conversion_rate)
}, item=item))
else:
- cwip_account = get_asset_account("capital_work_in_progress_account", company = self.company)
+ cwip_account = get_asset_account("capital_work_in_progress_account",
+ asset_category=item.asset_category,company=self.company)
cwip_account_currency = get_account_currency(cwip_account)
gl_entries.append(self.get_gl_dict({
@@ -780,10 +798,10 @@
# Stock ledger value is not matching with the warehouse amount
if (self.update_stock and voucher_wise_stock_value.get(item.name) and
- warehouse_debit_amount != flt(voucher_wise_stock_value.get(item.name), net_amt_precision)):
+ warehouse_debit_amount != flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)):
cost_of_goods_sold_account = self.get_company_default("default_expense_account")
- stock_amount = flt(voucher_wise_stock_value.get(item.name), net_amt_precision)
+ stock_amount = flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)
stock_adjustment_amt = warehouse_debit_amount - stock_amount
gl_entries.append(
@@ -822,7 +840,8 @@
}, account_currency, item=tax)
)
# accumulate valuation tax
- if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
+ if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount) \
+ and not self.is_internal_transfer():
if self.auto_accounting_for_stock and not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
valuation_tax.setdefault(tax.name, 0)
@@ -866,8 +885,19 @@
"against": self.supplier,
"credit": valuation_tax[tax.name],
"remarks": self.remarks or "Accounting Entry for Stock"
- }, item=tax)
- )
+ }, item=tax))
+
+ def make_internal_transfer_gl_entries(self, gl_entries):
+ if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
+ account_currency = get_account_currency(self.unrealized_profit_loss_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.unrealized_profit_loss_account,
+ "against": self.supplier,
+ "credit": flt(self.total_taxes_and_charges),
+ "credit_in_account_currency": flt(self.base_total_taxes_and_charges),
+ "cost_center": self.cost_center
+ }, account_currency, item=self))
def make_payment_gl_entries(self, gl_entries):
# Make Cash GL Entries
@@ -938,7 +968,7 @@
# base_rounding_adjustment may become zero due to small precision
# eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2
# then base_rounding_adjustment becomes zero and error is thrown in GL Entry
- if self.rounding_adjustment and self.base_rounding_adjustment:
+ if not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
@@ -972,11 +1002,15 @@
self.delete_auto_created_batches()
self.make_gl_entries_on_cancel()
+
+ if self.update_stock == 1:
+ self.repost_future_sle_and_gle()
+
self.update_project()
frappe.db.set(self, 'status', 'Cancelled')
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
def update_project(self):
project_list = []
@@ -1027,7 +1061,9 @@
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified)
for pr in set(updated_pr):
- frappe.get_doc("Purchase Receipt", pr).update_billing_percentage(update_modified=update_modified)
+ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage
+ pr_doc = frappe.get_doc("Purchase Receipt", pr)
+ update_billing_percentage(pr_doc, update_modified=update_modified)
def on_recurring(self, reference_doc, auto_repeat_doc):
self.due_date = None
@@ -1083,7 +1119,9 @@
if self.docstatus == 2:
status = "Cancelled"
elif self.docstatus == 1:
- if outstanding_amount > 0 and due_date < nowdate:
+ if self.is_internal_transfer():
+ self.status = 'Internal Transfer'
+ elif outstanding_amount > 0 and due_date < nowdate:
self.status = "Overdue"
elif outstanding_amount > 0 and due_date >= nowdate:
self.status = "Unpaid"
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
index 86c2e40..914a245 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
@@ -4,23 +4,25 @@
// 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"],
+ "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') {
+ 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) {
+ } 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) {
+ } 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) {
+ } 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"), "darkgrey", "is_return,=,Yes"];
- } else if(flt(doc.outstanding_amount)==0 && doc.docstatus==1) {
+ } 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"];
}
}
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 9a666bf..50492f5 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -9,8 +9,7 @@
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from frappe.utils import cint, flt, today, nowdate, add_days, getdate
import frappe.defaults
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
- test_records as pr_test_records, make_purchase_receipt, get_taxes
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt, get_taxes
from erpnext.controllers.accounts_controller import get_payment_terms
from erpnext.exceptions import InvalidCurrency
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
@@ -33,13 +32,10 @@
def test_gl_entries_without_perpetual_inventory(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
- wrapper = frappe.copy_doc(test_records[0])
- set_perpetual_inventory(0, wrapper.company)
- self.assertTrue(not cint(erpnext.is_perpetual_inventory_enabled(wrapper.company)))
- wrapper.insert()
- wrapper.submit()
- wrapper.load_from_db()
- dl = wrapper
+ pi = frappe.copy_doc(test_records[0])
+ self.assertTrue(not cint(erpnext.is_perpetual_inventory_enabled(pi.company)))
+ pi.insert()
+ pi.submit()
expected_gl_entries = {
"_Test Payable - _TC": [0, 1512.0],
@@ -54,12 +50,16 @@
"Round Off - _TC": [0, 0.3]
}
gl_entries = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
- where voucher_type = 'Purchase Invoice' and voucher_no = %s""", dl.name, as_dict=1)
+ where voucher_type = 'Purchase Invoice' and voucher_no = %s""", pi.name, as_dict=1)
for d in gl_entries:
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
def test_gl_entries_with_perpetual_inventory(self):
- pi = make_purchase_invoice(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1", get_taxes_and_charges=True, qty=10)
+ pi = make_purchase_invoice(company="_Test Company with perpetual inventory",
+ warehouse= "Stores - TCP1", cost_center = "Main - TCP1",
+ expense_account ="_Test Account Cost for Goods Sold - TCP1",
+ get_taxes_and_charges=True, qty=10)
+
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pi.company)), 1)
self.check_gle_for_pi(pi.name)
@@ -198,8 +198,6 @@
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", get_taxes_and_charges=True,)
- self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
-
pi = make_purchase_invoice(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1", get_taxes_and_charges=True, qty=10,do_not_save= "True")
for d in pi.items:
@@ -247,17 +245,11 @@
self.assertRaises(frappe.CannotChangeConstantError, pi.save)
- def test_gl_entries_with_aia_for_non_stock_items(self):
- pi = frappe.copy_doc(test_records[1])
- set_perpetual_inventory(1, pi.company)
- self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pi.company)), 1)
- pi.get("items")[0].item_code = "_Test Non Stock Item"
- pi.get("items")[0].expense_account = "_Test Account Cost for Goods Sold - _TC"
- pi.get("taxes").pop(0)
- pi.get("taxes").pop(1)
- pi.insert()
- pi.submit()
- pi.load_from_db()
+ def test_gl_entries_for_non_stock_items_with_perpetual_inventory(self):
+ pi = make_purchase_invoice(item_code = "_Test Non Stock Item",
+ company = "_Test Company with perpetual inventory", warehouse= "Stores - TCP1",
+ cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
+
self.assertTrue(pi.status, "Unpaid")
gl_entries = frappe.db.sql("""select account, debit, credit
@@ -265,17 +257,15 @@
order by account asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries)
- expected_values = sorted([
- ["_Test Payable - _TC", 0, 620],
- ["_Test Account Cost for Goods Sold - _TC", 500.0, 0],
- ["_Test Account VAT - _TC", 120.0, 0],
- ])
+ expected_values = [
+ ["_Test Account Cost for Goods Sold - TCP1", 250.0, 0],
+ ["Creditors - TCP1", 0, 250]
+ ]
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[i][0], gle.account)
self.assertEqual(expected_values[i][1], gle.debit)
self.assertEqual(expected_values[i][2], gle.credit)
- set_perpetual_inventory(0, pi.company)
def test_purchase_invoice_calculation(self):
pi = frappe.copy_doc(test_records[0])
@@ -436,33 +426,39 @@
)
def test_total_purchase_cost_for_project(self):
- make_project({'project_name':'_Test Project'})
+ if not frappe.db.exists("Project", {"project_name": "_Test Project for Purchase"}):
+ project = make_project({'project_name':'_Test Project for Purchase'})
+ else:
+ project = frappe.get_doc("Project", {"project_name": "_Test Project for Purchase"})
existing_purchase_cost = frappe.db.sql("""select sum(base_net_amount)
- from `tabPurchase Invoice Item` where project = '_Test Project' and docstatus=1""")
+ from `tabPurchase Invoice Item`
+ where project = '{0}'
+ and docstatus=1""".format(project.name))
existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0
- pi = make_purchase_invoice(currency="USD", conversion_rate=60, project="_Test Project")
- self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"),
+ pi = make_purchase_invoice(currency="USD", conversion_rate=60, project=project.name)
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_purchase_cost"),
existing_purchase_cost + 15000)
- pi1 = make_purchase_invoice(qty=10, project="_Test Project")
- self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"),
+ pi1 = make_purchase_invoice(qty=10, project=project.name)
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_purchase_cost"),
existing_purchase_cost + 15500)
pi1.cancel()
- self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"),
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_purchase_cost"),
existing_purchase_cost + 15000)
pi.cancel()
- self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), existing_purchase_cost)
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_purchase_cost"), existing_purchase_cost)
- def test_return_purchase_invoice(self):
- set_perpetual_inventory()
+ def test_return_purchase_invoice_with_perpetual_inventory(self):
+ pi = make_purchase_invoice(company = "_Test Company with perpetual inventory", warehouse= "Stores - TCP1",
+ cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
- pi = make_purchase_invoice()
-
- return_pi = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2)
+ return_pi = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2,
+ company = "_Test Company with perpetual inventory", warehouse= "Stores - TCP1",
+ cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
# check gl entries for return
@@ -473,19 +469,15 @@
self.assertTrue(gl_entries)
expected_values = {
- "Creditors - _TC": [100.0, 0.0],
- "Stock Received But Not Billed - _TC": [0.0, 100.0],
+ "Creditors - TCP1": [100.0, 0.0],
+ "Stock Received But Not Billed - TCP1": [0.0, 100.0],
}
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
- set_perpetual_inventory(0)
-
def test_multi_currency_gle(self):
- set_perpetual_inventory(0)
-
pi = make_purchase_invoice(supplier="_Test Supplier USD", credit_to="_Test Payable USD - _TC",
currency="USD", conversion_rate=50)
@@ -640,10 +632,9 @@
self.assertEqual(len(pi.get("supplied_items")), 2)
rm_supp_cost = sum([d.amount for d in pi.get("supplied_items")])
- self.assertEqual(pi.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
+ self.assertEqual(flt(pi.get("items")[0].rm_supp_cost, 2), flt(rm_supp_cost, 2))
def test_rejected_serial_no(self):
- set_perpetual_inventory(0)
pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1,
rejected_qty=1, rate=500, update_stock=1,
rejected_warehouse = "_Test Rejected Warehouse - _TC")
@@ -874,17 +865,17 @@
})
pi = make_purchase_invoice(credit_to="Creditors - _TC" ,do_not_save=1)
- pi.items[0].project = item_project.project_name
- pi.project = project.project_name
+ pi.items[0].project = item_project.name
+ pi.project = project.name
pi.submit()
expected_values = {
"Creditors - _TC": {
- "project": project.project_name
+ "project": project.name
},
"_Test Account Cost for Goods Sold - _TC": {
- "project": item_project.project_name
+ "project": item_project.name
}
}
@@ -907,7 +898,7 @@
acc_settings.submit_journal_entries = 1
acc_settings.save()
- item = create_item("_Test Item for Deferred Accounting")
+ item = create_item("_Test Item for Deferred Accounting", is_purchase_item=True)
item.enable_deferred_expense = 1
item.deferred_expense_account = deferred_account
item.save()
@@ -998,11 +989,12 @@
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"conversion_factor": 1.0,
"serial_no": args.serial_no,
- "stock_uom": "_Test UOM",
+ "stock_uom": args.uom or "_Test UOM",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"project": args.project,
"rejected_warehouse": args.rejected_warehouse or "",
- "rejected_serial_no": args.rejected_serial_no or ""
+ "rejected_serial_no": args.rejected_serial_no or "",
+ "asset_location": args.location or ""
})
if args.get_taxes_and_charges:
@@ -1039,7 +1031,8 @@
pi.is_return = args.is_return
pi.credit_to = args.return_against or "Creditors - _TC"
pi.is_subcontracted = args.is_subcontracted or "No"
- pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
+ if args.supplier_warehouse:
+ pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_records.json b/erpnext/accounts/doctype/purchase_invoice/test_records.json
index 7030faf..e7166c5 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_records.json
+++ b/erpnext/accounts/doctype/purchase_invoice/test_records.json
@@ -18,7 +18,7 @@
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"item_code": "_Test Item Home Desktop 100",
"item_name": "_Test Item Home Desktop 100",
- "item_tax_template": "_Test Account Excise Duty @ 10",
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
"parentfield": "items",
"qty": 10,
"rate": 50,
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 f6d76e5..96ad0fd 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-05-22 12:43:10",
"doctype": "DocType",
@@ -27,10 +28,16 @@
"stock_qty",
"sec_break1",
"price_list_rate",
- "discount_percentage",
- "discount_amount",
"col_break3",
"base_price_list_rate",
+ "section_break_26",
+ "margin_type",
+ "margin_rate_or_amount",
+ "rate_with_margin",
+ "column_break_30",
+ "discount_percentage",
+ "discount_amount",
+ "base_rate_with_margin",
"sec_break2",
"rate",
"amount",
@@ -39,6 +46,7 @@
"base_rate",
"base_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_22",
"net_rate",
@@ -87,6 +95,7 @@
"po_detail",
"purchase_receipt",
"pr_detail",
+ "sales_invoice_item",
"item_weight_details",
"weight_per_unit",
"total_weight",
@@ -553,8 +562,8 @@
"fieldtype": "Link",
"hidden": 1,
"label": "Brand",
- "print_hide": 1,
- "options": "Brand"
+ "options": "Brand",
+ "print_hide": 1
},
{
"fetch_from": "item_code.item_group",
@@ -562,9 +571,9 @@
"fieldname": "item_group",
"fieldtype": "Link",
"label": "Item Group",
+ "options": "Item Group",
"print_hide": 1,
- "read_only": 1,
- "options": "Item Group"
+ "read_only": 1
},
{
"description": "Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges",
@@ -759,10 +768,11 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.is_internal_supplier && parent.update_stock",
"fieldname": "from_warehouse",
"fieldtype": "Link",
"ignore_user_permissions": 1,
- "label": "Supplier Warehouse",
+ "label": "From Warehouse",
"options": "Warehouse"
},
{
@@ -779,11 +789,71 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "sales_invoice_item",
+ "fieldtype": "Data",
+ "label": "Sales Invoice Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_26",
+ "fieldtype": "Section Break",
+ "label": "Discount and Margin"
+ },
+ {
+ "depends_on": "price_list_rate",
+ "fieldname": "margin_type",
+ "fieldtype": "Select",
+ "label": "Margin Type",
+ "options": "\nPercentage\nAmount",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate",
+ "fieldname": "margin_rate_or_amount",
+ "fieldtype": "Float",
+ "label": "Margin Rate or Amount",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "rate_with_margin",
+ "fieldtype": "Currency",
+ "label": "Rate With Margin",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_30",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "label": "Rate With Margin (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2020-08-20 11:48:01.398356",
+ "links": [],
+ "modified": "2021-02-23 00:59:52.614805",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
@@ -791,4 +861,4 @@
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
-}
+}
\ No newline at end of file
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 56576df..50ec7d8 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py
@@ -6,8 +6,5 @@
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
-
class PurchaseInvoiceItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
diff --git a/erpnext/accounts/doctype/salary_component_account/salary_component_account.json b/erpnext/accounts/doctype/salary_component_account/salary_component_account.json
index 23dc6c4..f1ed8ef 100644
--- a/erpnext/accounts/doctype/salary_component_account/salary_component_account.json
+++ b/erpnext/accounts/doctype/salary_component_account/salary_component_account.json
@@ -1,92 +1,38 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-07-27 17:24:24.956896",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
+ "actions": [],
+ "creation": "2016-07-27 17:24:24.956896",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "account"
+ ],
"fields": [
{
- "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_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",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.",
- "fieldname": "default_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Default Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "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
+ "description": "Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.",
+ "fieldname": "account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Account",
+ "options": "Account"
}
- ],
- "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-09-02 07:49:06.567389",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Salary Component Account",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_seen": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-10-18 17:57:57.110257",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Salary Component Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js
index 6336db1..f54bce8 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js
@@ -1,6 +1,8 @@
{% include "erpnext/regional/india/taxes.js" %}
+{% include "erpnext/regional/india/e_invoice/einvoice.js" %}
erpnext.setup_auto_gst_taxation('Sales Invoice');
+erpnext.setup_einvoice_actions('Sales Invoice')
frappe.ui.form.on("Sales Invoice", {
setup: function(frm) {
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 9af584e..b361c0c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -5,18 +5,22 @@
cur_frm.pformat.print_heading = 'Invoice';
{% include 'erpnext/selling/sales_common.js' %};
-
-
frappe.provide("erpnext.accounts");
+
+
erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({
setup: function(doc) {
this.setup_posting_date_time_check();
this._super(doc);
},
+ company: function() {
+ erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
+ },
onload: function() {
var me = this;
this._super();
+ this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice'];
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
// show debit_to in print format
this.frm.set_df_property("debit_to", "print_hide", 0);
@@ -33,6 +37,7 @@
me.frm.refresh_fields();
}
erpnext.queries.setup_warehouse_query(this.frm);
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
refresh: function(doc, dt, dn) {
@@ -126,16 +131,15 @@
this.set_default_print_format();
if (doc.docstatus == 1 && !doc.inter_company_invoice_reference) {
- frappe.model.with_doc("Customer", me.frm.doc.customer, function() {
- var customer = frappe.model.get_doc("Customer", me.frm.doc.customer);
- var internal = customer.is_internal_customer;
- var disabled = customer.disabled;
- if (internal == 1 && disabled == 0) {
- me.frm.add_custom_button("Inter Company Invoice", function() {
- me.make_inter_company_invoice();
- }, __('Create'));
- }
- });
+ let internal = me.frm.doc.is_internal_customer;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Invoice" :
+ "Inter Company Purchase Invoice";
+
+ me.frm.add_custom_button(button_label, function() {
+ me.make_inter_company_invoice();
+ }, __('Create'));
+ }
}
},
@@ -199,7 +203,7 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
},
quotation_btn: function() {
@@ -223,7 +227,7 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
},
delivery_note_btn: function() {
@@ -251,7 +255,7 @@
};
}
});
- }, __("Get items from"));
+ }, __("Get Items From"));
},
tc_name: function() {
@@ -571,18 +575,19 @@
};
});
- frm.set_query("cost_center", function() {
+ frm.set_query("unrealized_profit_loss_account", function() {
return {
filters: {
company: frm.doc.company,
- is_group: 0
+ is_group: 0,
+ root_type: "Liability",
}
};
});
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
- 'Sales Invoice': 'Sales Return',
+ 'Sales Invoice': 'Return / Credit Note',
'Payment Request': 'Payment Request',
'Payment Entry': 'Payment'
},
@@ -664,12 +669,12 @@
};
},
// When multiple companies are set up. in case company name is changed set default company address
- company:function(frm){
- if (frm.doc.company)
- {
+ company: function(frm){
+ if (frm.doc.company) {
frappe.call({
- method:"erpnext.setup.doctype.company.company.get_default_company_address",
- args:{name:frm.doc.company, existing_address: frm.doc.company_address},
+ method: "erpnext.setup.doctype.company.company.get_default_company_address",
+ args: {name:frm.doc.company, existing_address: frm.doc.company_address || ""},
+ debounce: 2000,
callback: function(r){
if (r.message){
frm.set_value("company_address",r.message)
@@ -690,6 +695,7 @@
refresh_field(['timesheets'])
}
})
+ frm.refresh();
},
onload: function(frm) {
@@ -805,6 +811,65 @@
},
refresh: function(frm) {
+ if (frm.doc.project) {
+ frm.add_custom_button(__('Fetch Timesheet'), function() {
+ let d = new frappe.ui.Dialog({
+ title: __('Fetch Timesheet'),
+ fields: [
+ {
+ "label" : "From",
+ "fieldname": "from_time",
+ "fieldtype": "Date",
+ "reqd": 1,
+ },
+ {
+ fieldtype: 'Column Break',
+ fieldname: 'col_break_1',
+ },
+ {
+ "label" : "To",
+ "fieldname": "to_time",
+ "fieldtype": "Date",
+ "reqd": 1,
+ }
+ ],
+ 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: frm.doc.project
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ if(r.message.length > 0) {
+ frm.clear_table('timesheets')
+ r.message.forEach((d) => {
+ frm.add_child('timesheets',{
+ 'time_sheet': d.parent,
+ 'billing_hours': d.billing_hours,
+ 'billing_amount': d.billing_amt,
+ 'timesheet_detail': d.name
+ });
+ });
+ frm.refresh_field('timesheets')
+ }
+ else {
+ frappe.msgprint(__('No Timesheet Found.'))
+ }
+ d.hide();
+ }
+ }
+ });
+ },
+ primary_action_label: __('Get Timesheets')
+ });
+ d.show();
+ })
+ }
+
if (frappe.boot.active_domains.includes("Healthcare")) {
frm.set_df_property("patient", "hidden", 0);
frm.set_df_property("patient_name", "hidden", 0);
@@ -812,10 +877,10 @@
if (cint(frm.doc.docstatus==0) && cur_frm.page.current_view_name!=="pos" && !frm.doc.is_return) {
frm.add_custom_button(__('Healthcare Services'), function() {
get_healthcare_services_to_invoice(frm);
- },"Get items from");
+ },"Get Items From");
frm.add_custom_button(__('Prescriptions'), function() {
get_drugs_to_invoice(frm);
- },"Get items from");
+ },"Get Items From");
}
}
else {
@@ -1080,7 +1145,7 @@
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: {
+ filters: {
patient: dialog.get_value("patient"),
company: frm.doc.company,
docstatus: 1
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 2397b7d..720a917 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -12,22 +12,20 @@
"customer",
"customer_name",
"tax_id",
+ "pos_profile",
"is_pos",
"is_consolidated",
- "pos_profile",
- "offline_pos_name",
"is_return",
+ "update_billed_amount_in_sales_order",
"column_break1",
"company",
+ "company_tax_id",
"posting_date",
"posting_time",
"set_posting_time",
"due_date",
- "amended_from",
- "returns",
"return_against",
- "column_break_21",
- "update_billed_amount_in_sales_order",
+ "amended_from",
"accounting_dimensions_section",
"project",
"dimension_col_break",
@@ -59,6 +57,8 @@
"ignore_pricing_rule",
"sec_warehouse",
"set_warehouse",
+ "column_break_55",
+ "set_target_warehouse",
"items_section",
"update_stock",
"scan_barcode",
@@ -156,6 +156,7 @@
"more_information",
"inter_company_invoice_reference",
"is_internal_customer",
+ "represents_company",
"customer_group",
"campaign",
"is_discounted",
@@ -169,6 +170,7 @@
"c_form_applicable",
"c_form_no",
"column_break8",
+ "unrealized_profit_loss_account",
"remarks",
"sales_team_section_break",
"sales_partner",
@@ -183,8 +185,7 @@
"column_break_140",
"auto_repeat",
"update_auto_repeat_reference",
- "against_income_account",
- "pos_total_qty"
+ "against_income_account"
],
"fields": [
{
@@ -292,16 +293,6 @@
"print_hide": 1
},
{
- "fieldname": "offline_pos_name",
- "fieldtype": "Data",
- "hidden": 1,
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Offline POS Name",
- "print_hide": 1,
- "read_only": 1
- },
- {
"default": "0",
"fieldname": "is_return",
"fieldtype": "Check",
@@ -401,19 +392,11 @@
},
{
"depends_on": "return_against",
- "fieldname": "returns",
- "fieldtype": "Section Break",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Returns"
- },
- {
- "depends_on": "return_against",
"fieldname": "return_against",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Return Against Sales Invoice",
+ "label": "Return Against",
"no_copy": 1,
"options": "Sales Invoice",
"print_hide": 1,
@@ -421,12 +404,6 @@
"search_index": 1
},
{
- "fieldname": "column_break_21",
- "fieldtype": "Column Break",
- "hide_days": 1,
- "hide_seconds": 1
- },
- {
"default": "0",
"depends_on": "eval: doc.is_return && doc.return_against",
"fieldname": "update_billed_amount_in_sales_order",
@@ -673,7 +650,8 @@
"fieldname": "sec_warehouse",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "label": "Warehouse"
},
{
"depends_on": "update_stock",
@@ -681,7 +659,7 @@
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Set Source Warehouse",
+ "label": "Source Warehouse",
"options": "Warehouse",
"print_hide": 1
},
@@ -690,6 +668,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
+ "label": "Items",
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -1653,7 +1632,7 @@
"in_standard_filter": 1,
"label": "Status",
"no_copy": 1,
- "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled",
+ "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer",
"print_hide": 1,
"read_only": 1
},
@@ -1825,7 +1804,7 @@
"fieldtype": "Table",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Sales Team1",
+ "label": "Sales Contributions and Incentives",
"oldfieldname": "sales_team",
"oldfieldtype": "Table",
"options": "Sales Team",
@@ -1900,17 +1879,6 @@
"report_hide": 1
},
{
- "fieldname": "pos_total_qty",
- "fieldtype": "Float",
- "hidden": 1,
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Total Qty",
- "print_hide": 1,
- "print_hide_if_no_value": 1,
- "read_only": 1
- },
- {
"collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
@@ -1926,6 +1894,7 @@
},
{
"default": "0",
+ "depends_on": "eval:(doc.is_pos && doc.is_consolidated)",
"fieldname": "is_consolidated",
"fieldtype": "Check",
"label": "Is Consolidated",
@@ -1940,13 +1909,56 @@
"hide_seconds": 1,
"label": "Is Internal Customer",
"read_only": 1
+ },
+ {
+ "fetch_from": "company.tax_id",
+ "fieldname": "company_tax_id",
+ "fieldtype": "Data",
+ "label": "Company Tax ID",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.is_internal_customer",
+ "description": "Unrealized Profit / Loss account for intra-company transfers",
+ "fieldname": "unrealized_profit_loss_account",
+ "fieldtype": "Link",
+ "label": "Unrealized Profit / Loss Account",
+ "options": "Account"
+ },
+ {
+ "depends_on": "eval:doc.is_internal_customer",
+ "description": "Company which internal customer represents",
+ "fetch_from": "customer.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_55",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval: doc.is_internal_customer && doc.update_stock",
+ "fieldname": "set_target_warehouse",
+ "fieldtype": "Link",
+ "label": "Set Target Warehouse",
+ "options": "Warehouse"
}
],
"icon": "fa fa-file-text",
"idx": 181,
"is_submittable": 1,
- "links": [],
- "modified": "2020-08-27 01:56:28.532140",
+ "links": [
+ {
+ "custom": 1,
+ "group": "Reference",
+ "link_doctype": "POS Invoice",
+ "link_fieldname": "consolidated_invoice"
+ }
+ ],
+ "modified": "2021-02-01 15:42:26.261540",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 92e49d5..a1bf66b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -4,9 +4,9 @@
from __future__ import unicode_literals
import frappe, erpnext
import frappe.defaults
-from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate, get_link_to_form
+from frappe.utils import cint, flt, getdate, add_days, cstr, nowdate, get_link_to_form, formatdate
from frappe import _, msgprint, throw
-from erpnext.accounts.party import get_party_account, get_due_date
+from erpnext.accounts.party import get_party_account, get_due_date, get_party_details
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.selling_controller import SellingController
from erpnext.accounts.utils import get_account_currency
@@ -21,6 +21,9 @@
from erpnext.accounts.doctype.loyalty_program.loyalty_program import \
get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points
from erpnext.accounts.deferred_revenue import validate_service_stop_date
+from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
+from frappe.model.utils import get_fetch_values
+from frappe.contacts.doctype.address.address import get_address_display
from erpnext.healthcare.utils import manage_invoice_submit_cancel
@@ -53,7 +56,7 @@
"""Set indicator for portal"""
if self.outstanding_amount < 0:
self.indicator_title = _("Credit Note Issued")
- self.indicator_color = "darkgrey"
+ self.indicator_color = "gray"
elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()):
self.indicator_color = "orange"
self.indicator_title = _("Unpaid")
@@ -62,7 +65,7 @@
self.indicator_title = _("Overdue")
elif cint(self.is_return) == 1:
self.indicator_title = _("Return")
- self.indicator_color = "darkgrey"
+ self.indicator_color = "gray"
else:
self.indicator_color = "green"
self.indicator_title = _("Paid")
@@ -74,6 +77,8 @@
if not self.is_pos:
self.so_dn_required()
+ self.set_tax_withholding()
+
self.validate_proj_cust()
self.validate_pos_return()
self.validate_with_previous_doc()
@@ -151,6 +156,32 @@
if cost_center_company != self.company:
frappe.throw(_("Row #{0}: Cost Center {1} does not belong to company {2}").format(frappe.bold(item.idx), frappe.bold(item.cost_center), frappe.bold(self.company)))
+ def set_tax_withholding(self):
+ tax_withholding_details = get_party_tax_withholding_details(self)
+
+ if not tax_withholding_details:
+ return
+
+ accounts = []
+ tax_withholding_account = tax_withholding_details.get("account_head")
+
+ for d in self.taxes:
+ if d.account_head == tax_withholding_account:
+ d.update(tax_withholding_details)
+ accounts.append(d.account_head)
+
+ if not accounts or tax_withholding_account not in accounts:
+ self.append("taxes", tax_withholding_details)
+
+ to_remove = [d for d in self.taxes
+ if not d.tax_amount and d.charge_type == "Actual" and d.account_head == tax_withholding_account]
+
+ for d in to_remove:
+ self.remove(d)
+
+ # calculate totals again after applying TDS
+ self.calculate_taxes_and_totals()
+
def before_save(self):
set_account_for_mode_of_payment(self)
@@ -180,6 +211,9 @@
# this sequence because outstanding may get -ve
self.make_gl_entries()
+ if self.update_stock == 1:
+ self.repost_future_sle_and_gle()
+
if not self.is_return:
self.update_billing_status_for_zero_amount_refdoc("Delivery Note")
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
@@ -228,9 +262,27 @@
if len(self.payments) == 0 and self.is_pos:
frappe.throw(_("At least one mode of payment is required for POS invoice."))
- def before_cancel(self):
- self.update_time_sheet(None)
+ def check_if_consolidated_invoice(self):
+ # since POS Invoice extends Sales Invoice, we explicitly check if doctype is Sales Invoice
+ if self.doctype == "Sales Invoice" and self.is_consolidated:
+ invoice_or_credit_note = "consolidated_credit_note" if self.is_return else "consolidated_invoice"
+ pos_closing_entry = frappe.get_all(
+ "POS Invoice Merge Log",
+ filters={ invoice_or_credit_note: self.name },
+ pluck="pos_closing_entry"
+ )
+ if pos_closing_entry:
+ msg = _("To cancel a {} you need to cancel the POS Closing Entry {}. ").format(
+ frappe.bold("Consolidated Sales Invoice"),
+ get_link_to_form("POS Closing Entry", pos_closing_entry[0])
+ )
+ frappe.throw(msg, title=_("Not Allowed"))
+ def before_cancel(self):
+ self.check_if_consolidated_invoice()
+
+ super(SalesInvoice, self).before_cancel()
+ self.update_time_sheet(None)
def on_cancel(self):
super(SalesInvoice, self).on_cancel()
@@ -258,6 +310,10 @@
self.update_stock_ledger()
self.make_gl_entries_on_cancel()
+
+ if self.update_stock == 1:
+ self.repost_future_sle_and_gle()
+
frappe.db.set(self, 'status', 'Cancelled')
if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') == "Each Transaction":
@@ -279,7 +335,7 @@
if "Healthcare" in active_domains:
manage_invoice_submit_cancel(self, "on_cancel")
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
def update_status_updater_args(self):
if cint(self.update_stock):
@@ -405,6 +461,8 @@
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {}
+ if not pos_profile:
+ frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
self.pos_profile = pos_profile.get('name')
pos = {}
@@ -424,11 +482,13 @@
if not for_validate and not self.customer:
self.customer = pos.customer
- self.ignore_pricing_rule = pos.ignore_pricing_rule
+ if not for_validate:
+ self.ignore_pricing_rule = pos.ignore_pricing_rule
+
if pos.get('account_for_change_amount'):
self.account_for_change_amount = pos.get('account_for_change_amount')
- for fieldname in ('naming_series', 'currency', 'letter_head', 'tc_name',
+ for fieldname in ('currency', 'letter_head', 'tc_name',
'company', 'select_print_heading', 'write_off_account', 'taxes_and_charges',
'write_off_cost_center', 'apply_discount_on', 'cost_center'):
if (not for_validate) or (for_validate and not self.get(fieldname)):
@@ -472,6 +532,11 @@
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
def validate_debit_to_acc(self):
+ if not self.debit_to:
+ self.debit_to = get_party_account("Customer", self.customer, self.company)
+ if not self.debit_to:
+ self.raise_missing_debit_credit_account_error("Customer", self.customer)
+
account = frappe.get_cached_value("Account", self.debit_to,
["account_type", "report_type", "account_currency"], as_dict=True)
@@ -479,14 +544,14 @@
frappe.throw(_("Debit To is required"), title=_("Account Missing"))
if account.report_type != "Balance Sheet":
- frappe.throw(_("Please ensure {} account is a Balance Sheet account. \
- You can change the parent account to a Balance Sheet account or select a different account.")
- .format(frappe.bold("Debit To")), title=_("Invalid Account"))
+ msg = _("Please ensure {} account is a Balance Sheet account. ").format(frappe.bold("Debit To"))
+ msg += _("You can change the parent account to a Balance Sheet account or select a different account.")
+ frappe.throw(msg, title=_("Invalid Account"))
if self.customer and account.account_type != "Receivable":
- frappe.throw(_("Please ensure {} account is a Receivable account. \
- Change the account type to Receivable or select a different account.")
- .format(frappe.bold("Debit To")), title=_("Invalid Account"))
+ msg = _("Please ensure {} account is a Receivable account. ").format(frappe.bold("Debit To"))
+ msg += _("Change the account type to Receivable or select a different account.")
+ frappe.throw(msg, title=_("Invalid Account"))
self.party_account_currency = account.account_currency
@@ -535,7 +600,12 @@
self.against_income_account = ','.join(against_acc)
def add_remarks(self):
- if not self.remarks: self.remarks = 'No Remarks'
+ if not self.remarks:
+ if self.po_no and self.po_date:
+ self.remarks = _("Against Customer Order {0} dated {1}").format(self.po_no,
+ formatdate(self.po_date))
+ else:
+ self.remarks = _("No Remarks")
def validate_auto_set_posting_time(self):
# Don't auto set the posting date and time if invoice is amended
@@ -572,7 +642,8 @@
def validate_pos(self):
if self.is_return:
- if flt(self.paid_amount) + flt(self.write_off_amount) - flt(self.grand_total) > \
+ invoice_total = self.rounded_total or self.grand_total
+ if flt(self.paid_amount) + flt(self.write_off_amount) - flt(invoice_total) > \
1.0/(10.0**(self.precision("grand_total") + 1.0)):
frappe.throw(_("Paid amount + Write Off Amount can not be greater than Grand Total"))
@@ -714,22 +785,20 @@
if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
- def make_gl_entries(self, gl_entries=None):
- from erpnext.accounts.general_ledger import make_reverse_gl_entries
+ def make_gl_entries(self, gl_entries=None, from_repost=False):
+ from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
if not gl_entries:
gl_entries = self.get_gl_entries()
if gl_entries:
- from erpnext.accounts.general_ledger import make_gl_entries
-
# if POS and amount is written off, updating outstanding amt after posting all gl entries
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account or
cint(self.redeem_loyalty_points)) else "Yes"
if self.docstatus == 1:
- make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
+ make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
elif self.docstatus == 2:
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
@@ -750,6 +819,7 @@
self.make_customer_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
+ self.make_internal_transfer_gl_entries(gl_entries)
self.make_item_gl_entries(gl_entries)
@@ -769,7 +839,7 @@
# Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
- if grand_total:
+ if grand_total and not self.is_internal_transfer():
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total"))
@@ -808,6 +878,18 @@
}, account_currency, item=tax)
)
+ def make_internal_transfer_gl_entries(self, gl_entries):
+ if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
+ account_currency = get_account_currency(self.unrealized_profit_loss_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.unrealized_profit_loss_account,
+ "against": self.customer,
+ "debit": flt(self.total_taxes_and_charges),
+ "debit_in_account_currency": flt(self.base_total_taxes_and_charges),
+ "cost_center": self.cost_center
+ }, account_currency, item=self))
+
def make_item_gl_entries(self, gl_entries):
# income account gl entries
for item in self.get("items"):
@@ -830,22 +912,24 @@
asset.db_set("disposal_date", self.posting_date)
asset.set_status("Sold" if self.docstatus==1 else None)
else:
- income_account = (item.income_account
- if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
+ # Do not book income for transfer within same company
+ if not self.is_internal_transfer():
+ income_account = (item.income_account
+ if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
- account_currency = get_account_currency(income_account)
- gl_entries.append(
- self.get_gl_dict({
- "account": income_account,
- "against": self.customer,
- "credit": flt(item.base_net_amount, item.precision("base_net_amount")),
- "credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount"))
- if account_currency==self.company_currency
- else flt(item.net_amount, item.precision("net_amount"))),
- "cost_center": item.cost_center,
- "project": item.project or self.project
- }, account_currency, item=item)
- )
+ account_currency = get_account_currency(income_account)
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": income_account,
+ "against": self.customer,
+ "credit": flt(item.base_net_amount, item.precision("base_net_amount")),
+ "credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount"))
+ if account_currency==self.company_currency
+ else flt(item.net_amount, item.precision("net_amount"))),
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item)
+ )
# expense account gl entries
if cint(self.update_stock) and \
@@ -975,7 +1059,8 @@
)
def make_gle_for_rounding_adjustment(self, gl_entries):
- if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment:
+ if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment \
+ and not self.is_internal_transfer():
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
@@ -1140,8 +1225,10 @@
where redeem_against=%s''', (lp_entry[0].name), as_dict=1)
if against_lp_entry:
invoice_list = ", ".join([d.invoice for d in against_lp_entry])
- frappe.throw(_('''{} can't be cancelled since the Loyalty Points earned has been redeemed.
- First cancel the {} No {}''').format(self.doctype, self.doctype, invoice_list))
+ frappe.throw(
+ _('''{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {}''')
+ .format(self.doctype, self.doctype, invoice_list)
+ )
else:
frappe.db.sql('''delete from `tabLoyalty Point Entry` where invoice=%s''', (self.name))
# Set loyalty program
@@ -1255,7 +1342,9 @@
if self.docstatus == 2:
status = "Cancelled"
elif self.docstatus == 1:
- if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed':
+ if self.is_internal_transfer():
+ self.status = 'Internal Transfer'
+ elif outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed':
self.status = "Overdue and Discounted"
elif outstanding_amount > 0 and due_date < nowdate:
self.status = "Overdue"
@@ -1398,6 +1487,7 @@
def set_missing_values(source, target):
target.ignore_pricing_rule = 1
target.run_method("set_missing_values")
+ target.run_method("set_po_nos")
target.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
@@ -1496,7 +1586,7 @@
details = get_inter_company_details(doc, doctype)
price_list = doc.selling_price_list if doctype in ["Sales Invoice", "Sales Order", "Delivery Note"] else doc.buying_price_list
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
- if not valid_price_list:
+ if not valid_price_list and not doc.is_internal_transfer():
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
party = details.get("party")
@@ -1519,15 +1609,21 @@
if doctype in ["Sales Invoice", "Sales Order"]:
source_doc = frappe.get_doc(doctype, source_name)
target_doctype = "Purchase Invoice" if doctype == "Sales Invoice" else "Purchase Order"
+ target_detail_field = "sales_invoice_item" if doctype == "Sales Invoice" else "sales_order_item"
+ source_document_warehouse_field = 'target_warehouse'
+ target_document_warehouse_field = 'from_warehouse'
else:
source_doc = frappe.get_doc(doctype, source_name)
target_doctype = "Sales Invoice" if doctype == "Purchase Invoice" else "Sales Order"
+ source_document_warehouse_field = 'from_warehouse'
+ target_document_warehouse_field = 'target_warehouse'
validate_inter_company_transaction(source_doc, doctype)
details = get_inter_company_details(source_doc, doctype)
def set_missing_values(source, target):
target.run_method("set_missing_values")
+ set_purchase_references(target)
def update_details(source_doc, target_doc, source_parent):
target_doc.inter_company_invoice_reference = source_doc.name
@@ -1535,41 +1631,184 @@
currency = frappe.db.get_value('Supplier', details.get('party'), 'default_currency')
target_doc.company = details.get("company")
target_doc.supplier = details.get("party")
+ target_doc.is_internal_supplier = 1
+ target_doc.ignore_pricing_rule = 1
target_doc.buying_price_list = source_doc.selling_price_list
+ # Invert Addresses
+ update_address(target_doc, 'supplier_address', 'address_display', source_doc.company_address)
+ update_address(target_doc, 'shipping_address', 'shipping_address_display', source_doc.customer_address)
+
if currency:
target_doc.currency = currency
+
+ update_taxes(target_doc, party=target_doc.supplier, party_type='Supplier', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.supplier_address,
+ company_address=target_doc.shipping_address)
+
else:
currency = frappe.db.get_value('Customer', details.get('party'), 'default_currency')
target_doc.company = details.get("company")
target_doc.customer = details.get("party")
target_doc.selling_price_list = source_doc.buying_price_list
+ update_address(target_doc, 'company_address', 'company_address_display', source_doc.supplier_address)
+ update_address(target_doc, 'shipping_address_name', 'shipping_address', source_doc.shipping_address)
+ update_address(target_doc, 'customer_address', 'address_display', source_doc.shipping_address)
+
if currency:
target_doc.currency = currency
+ update_taxes(target_doc, party=target_doc.customer, party_type='Customer', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.customer_address,
+ company_address=target_doc.company_address, shipping_address_name=target_doc.shipping_address_name)
+
+ item_field_map = {
+ "doctype": target_doctype + " Item",
+ "field_no_map": [
+ "income_account",
+ "expense_account",
+ "cost_center",
+ "warehouse"
+ ],
+ "field_map": {
+ 'rate': 'rate',
+ }
+ }
+
+ if doctype in ["Sales Invoice", "Sales Order"]:
+ item_field_map["field_map"].update({
+ "name": target_detail_field,
+ })
+
+ if source_doc.get('update_stock'):
+ item_field_map["field_map"].update({
+ source_document_warehouse_field: target_document_warehouse_field,
+ 'batch_no': 'batch_no',
+ 'serial_no': 'serial_no'
+ })
+
doclist = get_mapped_doc(doctype, source_name, {
doctype: {
"doctype": target_doctype,
"postprocess": update_details,
+ "set_target_warehouse": "set_from_warehouse",
"field_no_map": [
- "taxes_and_charges"
+ "taxes_and_charges",
+ "set_warehouse",
+ "shipping_address"
]
},
- doctype +" Item": {
- "doctype": target_doctype + " Item",
- "field_no_map": [
- "income_account",
- "expense_account",
- "cost_center",
- "warehouse"
- ]
- }
+ doctype +" Item": item_field_map
}, target_doc, set_missing_values)
return doclist
+def set_purchase_references(doc):
+ # add internal PO or PR links if any
+ if doc.is_internal_transfer():
+ if doc.doctype == 'Purchase Receipt':
+ so_item_map = get_delivery_note_details(doc.inter_company_invoice_reference)
+
+ if so_item_map:
+ pd_item_map, parent_child_map, warehouse_map = \
+ get_pd_details('Purchase Order Item', so_item_map, 'sales_order_item')
+
+ update_pr_items(doc, so_item_map, pd_item_map, parent_child_map, warehouse_map)
+
+ elif doc.doctype == 'Purchase Invoice':
+ dn_item_map, so_item_map = get_sales_invoice_details(doc.inter_company_invoice_reference)
+ # First check for Purchase receipt
+ if list(dn_item_map.values()):
+ pd_item_map, parent_child_map, warehouse_map = \
+ get_pd_details('Purchase Receipt Item', dn_item_map, 'delivery_note_item')
+
+ update_pi_items(doc, 'pr_detail', 'purchase_receipt',
+ dn_item_map, pd_item_map, parent_child_map, warehouse_map)
+
+ if list(so_item_map.values()):
+ pd_item_map, parent_child_map, warehouse_map = \
+ get_pd_details('Purchase Order Item', so_item_map, 'sales_order_item')
+
+ update_pi_items(doc, 'po_detail', 'purchase_order',
+ so_item_map, pd_item_map, parent_child_map, warehouse_map)
+
+def update_pi_items(doc, detail_field, parent_field, sales_item_map,
+ purchase_item_map, parent_child_map, warehouse_map):
+ for item in doc.get('items'):
+ item.set(detail_field, purchase_item_map.get(sales_item_map.get(item.sales_invoice_item)))
+ item.set(parent_field, parent_child_map.get(sales_item_map.get(item.sales_invoice_item)))
+ if doc.update_stock:
+ item.warehouse = warehouse_map.get(sales_item_map.get(item.sales_invoice_item))
+
+def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, warehouse_map):
+ for item in doc.get('items'):
+ item.purchase_order_item = purchase_item_map.get(sales_item_map.get(item.delivery_note_item))
+ item.warehouse = warehouse_map.get(sales_item_map.get(item.delivery_note_item))
+ item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
+
+def get_delivery_note_details(internal_reference):
+ so_item_map = {}
+
+ si_item_details = frappe.get_all('Delivery Note Item', fields=['name', 'so_detail'],
+ filters={'parent': internal_reference})
+
+ for d in si_item_details:
+ so_item_map.setdefault(d.name, d.so_detail)
+
+ return so_item_map
+
+def get_sales_invoice_details(internal_reference):
+ dn_item_map = {}
+ so_item_map = {}
+
+ si_item_details = frappe.get_all('Sales Invoice Item', fields=['name', 'so_detail',
+ 'dn_detail'], filters={'parent': internal_reference})
+
+ for d in si_item_details:
+ if d.dn_detail:
+ dn_item_map.setdefault(d.name, d.dn_detail)
+ if d.so_detail:
+ so_item_map.setdefault(d.name, d.so_detail)
+
+ return dn_item_map, so_item_map
+
+def get_pd_details(doctype, sd_detail_map, sd_detail_field):
+ pd_item_map = {}
+ accepted_warehouse_map = {}
+ parent_child_map = {}
+
+ pd_item_details = frappe.get_all(doctype,
+ fields=[sd_detail_field, 'name', 'warehouse', 'parent'], filters={sd_detail_field: ('in', list(sd_detail_map.values()))})
+
+ for d in pd_item_details:
+ pd_item_map.setdefault(d.get(sd_detail_field), d.name)
+ parent_child_map.setdefault(d.get(sd_detail_field), d.parent)
+ accepted_warehouse_map.setdefault(d.get(sd_detail_field), d.warehouse)
+
+ return pd_item_map, parent_child_map, accepted_warehouse_map
+
+def update_taxes(doc, party=None, party_type=None, company=None, doctype=None, party_address=None,
+ company_address=None, shipping_address_name=None, master_doctype=None):
+ # Update Party Details
+ party_details = get_party_details(party=party, party_type=party_type, company=company,
+ doctype=doctype, party_address=party_address, company_address=company_address,
+ shipping_address=shipping_address_name)
+
+ # Update taxes and charges if any
+ doc.taxes_and_charges = party_details.get('taxes_and_charges')
+ doc.set('taxes', party_details.get('taxes'))
+
+def update_address(doc, address_field, address_display_field, address_name):
+ doc.set(address_field, address_name)
+ fetch_values = get_fetch_values(doc.doctype, address_field, address_name)
+
+ for key, value in fetch_values.items():
+ doc.set(key, value)
+
+ doc.set(address_display_field, get_address_display(doc.get(address_field)))
+
@frappe.whitelist()
def get_loyalty_programs(customer):
''' sets applicable loyalty program to the customer or returns a list of applicable programs '''
@@ -1612,17 +1851,25 @@
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()
payment_mode = get_mode_of_payment_info(pos_payment_method.mode_of_payment, doc.company)
if not payment_mode:
- frappe.throw(_("Please set default Cash or Bank account in Mode of Payment {0}")
- .format(get_link_to_form("Mode of Payment", pos_payment_method.mode_of_payment)), title=_("Missing Account"))
+ invalid_modes.append(get_link_to_form("Mode of Payment", pos_payment_method.mode_of_payment))
+ continue
payment_mode[0].default = pos_payment_method.default
append_payment(payment_mode[0])
+ if invalid_modes:
+ if invalid_modes == 1:
+ msg = _("Please set default Cash or Bank account in Mode of Payment {}")
+ else:
+ msg = _("Please set default Cash or Bank account in Mode of Payments {}")
+ frappe.throw(msg.format(", ".join(invalid_modes)), title=_("Missing Account"))
+
def get_all_mode_of_payments(doc):
return frappe.db.sql("""
select mpa.default_account, mpa.parent, mp.type as type
@@ -1637,6 +1884,7 @@
where mpa.parent = mp.name and mpa.company = %s and mp.enabled = 1 and mp.name = %s""",
(company, mode_of_payment), as_dict=1)
+@frappe.whitelist()
def create_dunning(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
from erpnext.accounts.doctype.dunning.dunning import get_dunning_letter_text, calculate_interest_and_amount
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
index 2980213..f106928 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
@@ -13,8 +13,7 @@
'Auto Repeat': 'reference_document',
},
'internal_links': {
- 'Sales Order': ['items', 'sales_order'],
- 'Delivery Note': ['items', 'delivery_note']
+ 'Sales Order': ['items', 'sales_order']
},
'transactions': [
{
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
index 05d49df..1a01cb5 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
@@ -10,12 +10,12 @@
"Draft": "grey",
"Unpaid": "orange",
"Paid": "green",
- "Return": "darkgrey",
- "Credit Note Issued": "darkgrey",
+ "Return": "gray",
+ "Credit Note Issued": "gray",
"Unpaid and Discounted": "orange",
"Overdue and Discounted": "red",
- "Overdue": "red"
-
+ "Overdue": "red",
+ "Internal Transfer": "darkgrey"
};
return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
},
diff --git a/erpnext/accounts/doctype/sales_invoice/test_records.json b/erpnext/accounts/doctype/sales_invoice/test_records.json
index 11ebe6a..e00a58f 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_records.json
+++ b/erpnext/accounts/doctype/sales_invoice/test_records.json
@@ -17,7 +17,8 @@
"description": "138-CMS Shoe",
"doctype": "Sales Invoice Item",
"income_account": "Sales - _TC",
- "expense_account": "_Test Account Cost for Goods Sold - _TC",
+ "expense_account": "_Test Account Cost for Goods Sold - _TC",
+ "item_code": "138-CMS Shoe",
"item_name": "138-CMS Shoe",
"parentfield": "items",
"qty": 1.0,
@@ -147,7 +148,7 @@
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"item_code": "_Test Item Home Desktop 100",
"item_name": "_Test Item Home Desktop 100",
- "item_tax_template": "_Test Account Excise Duty @ 10",
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
"parentfield": "items",
"price_list_rate": 50,
"qty": 10,
@@ -275,7 +276,7 @@
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"item_code": "_Test Item Home Desktop 100",
"item_name": "_Test Item Home Desktop 100",
- "item_tax_template": "_Test Account Excise Duty @ 10",
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
"parentfield": "items",
"price_list_rate": 62.5,
"qty": 10,
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 9660c95..90e2144 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -10,7 +10,6 @@
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
from frappe.model.naming import make_autoname
@@ -23,6 +22,7 @@
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
+from erpnext.stock.utils import get_incoming_rate
class TestSalesInvoice(unittest.TestCase):
def make(self):
@@ -405,10 +405,10 @@
item_row = si.get("items")[0]
add_items = [
- (54, '_Test Account Excise Duty @ 12'),
- (288, '_Test Account Excise Duty @ 15'),
- (144, '_Test Account Excise Duty @ 20'),
- (430, '_Test Item Tax Template 1')
+ (54, '_Test Account Excise Duty @ 12 - _TC'),
+ (288, '_Test Account Excise Duty @ 15 - _TC'),
+ (144, '_Test Account Excise Duty @ 20 - _TC'),
+ (430, '_Test Item Tax Template 1 - _TC')
]
for qty, item_tax_template in add_items:
item_row_copy = copy.deepcopy(item_row)
@@ -659,7 +659,6 @@
def test_sales_invoice_gl_entry_without_perpetual_inventory(self):
si = frappe.copy_doc(test_records[1])
- set_perpetual_inventory(0, si.company)
si.insert()
si.submit()
@@ -690,7 +689,8 @@
self.assertTrue(gle)
def test_pos_gl_entry_with_perpetual_inventory(self):
- make_pos_profile()
+ make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
+ expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
@@ -746,7 +746,8 @@
self.assertEqual(pos_return.get('payments')[0].amount, -1000)
def test_pos_change_amount(self):
- make_pos_profile()
+ make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
+ expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
@@ -813,7 +814,6 @@
frappe.db.sql("delete from `tabPOS Profile`")
def test_pos_si_without_payment(self):
- set_perpetual_inventory()
make_pos_profile()
pos = copy.deepcopy(test_records[1])
@@ -827,9 +827,8 @@
self.assertRaises(frappe.ValidationError, si.submit)
def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self):
- set_perpetual_inventory()
-
- si = frappe.get_doc(test_records[1])
+ si = create_sales_invoice(company="_Test Company with perpetual inventory", debit_to = "Debtors - TCP1",
+ income_account="Sales - TCP1", cost_center = "Main - TCP1", do_not_save=True)
si.get("items")[0].item_code = None
si.insert()
si.submit()
@@ -840,24 +839,16 @@
self.assertTrue(gl_entries)
expected_values = dict((d[0], d) for d in [
- [si.debit_to, 630.0, 0.0],
- [test_records[1]["items"][0]["income_account"], 0.0, 500.0],
- [test_records[1]["taxes"][0]["account_head"], 0.0, 80.0],
- [test_records[1]["taxes"][1]["account_head"], 0.0, 50.0],
+ ["Debtors - TCP1", 100.0, 0.0],
+ ["Sales - TCP1", 0.0, 100.0]
])
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
- set_perpetual_inventory(0)
-
def test_sales_invoice_gl_entry_with_perpetual_inventory_non_stock_item(self):
- set_perpetual_inventory()
- si = frappe.get_doc(test_records[1])
- si.get("items")[0].item_code = "_Test Non Stock Item"
- si.insert()
- si.submit()
+ si = create_sales_invoice(item="_Test Non Stock Item")
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
@@ -865,17 +856,14 @@
self.assertTrue(gl_entries)
expected_values = dict((d[0], d) for d in [
- [si.debit_to, 630.0, 0.0],
- [test_records[1]["items"][0]["income_account"], 0.0, 500.0],
- [test_records[1]["taxes"][0]["account_head"], 0.0, 80.0],
- [test_records[1]["taxes"][1]["account_head"], 0.0, 50.0],
+ [si.debit_to, 100.0, 0.0],
+ [test_records[1]["items"][0]["income_account"], 0.0, 100.0]
])
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
- set_perpetual_inventory(0)
def _insert_purchase_receipt(self):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
@@ -1104,7 +1092,6 @@
self.assertEqual(si.grand_total, 859.43)
def test_multi_currency_gle(self):
- set_perpetual_inventory(0)
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50)
@@ -1571,7 +1558,7 @@
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
-
+
def test_sales_invoice_with_project_link(self):
from erpnext.projects.doctype.project.test_project import make_project
@@ -1587,17 +1574,17 @@
})
sales_invoice = create_sales_invoice(do_not_save=1)
- sales_invoice.items[0].project = item_project.project_name
- sales_invoice.project = project.project_name
+ sales_invoice.items[0].project = item_project.name
+ sales_invoice.project = project.name
sales_invoice.submit()
expected_values = {
"Debtors - _TC": {
- "project": project.project_name
+ "project": project.name
},
"Sales - _TC": {
- "project": item_project.project_name
+ "project": item_project.name
}
}
@@ -1605,9 +1592,9 @@
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", sales_invoice.name, as_dict=1)
-
+
self.assertTrue(gl_entries)
-
+
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["project"], gle.project)
@@ -1774,99 +1761,104 @@
si.submit()
target_doc = make_inter_company_transaction("Sales Invoice", si.name)
+ target_doc.items[0].update({
+ "expense_account": "Cost of Goods Sold - _TC1",
+ "cost_center": "Main - _TC1",
+ "warehouse": "Stores - _TC1"
+ })
target_doc.submit()
self.assertEqual(target_doc.company, "_Test Company 1")
self.assertEqual(target_doc.supplier, "_Test Internal Supplier")
+ def test_internal_transfer_gl_entry(self):
+ ## Create internal transfer account
+ account = create_account(account_name="Unrealized Profit",
+ parent_account="Current Liabilities - TCP1", company="_Test Company with perpetual inventory")
+
+ frappe.db.set_value('Company', '_Test Company with perpetual inventory',
+ 'unrealized_profit_loss_account', account)
+
+ customer = create_internal_customer("_Test Internal Customer 2", "_Test Company with perpetual inventory",
+ "_Test Company with perpetual inventory")
+
+ create_internal_supplier("_Test Internal Supplier 2", "_Test Company with perpetual inventory",
+ "_Test Company with perpetual inventory")
+
+ si = create_sales_invoice(
+ company = "_Test Company with perpetual inventory",
+ customer = customer,
+ debit_to = "Debtors - TCP1",
+ warehouse = "Stores - TCP1",
+ income_account = "Sales - TCP1",
+ expense_account = "Cost of Goods Sold - TCP1",
+ cost_center = "Main - TCP1",
+ currency = "INR",
+ do_not_save = 1
+ )
+
+ si.selling_price_list = "_Test Price List Rest of the World"
+ si.update_stock = 1
+ si.items[0].target_warehouse = 'Work In Progress - TCP1'
+
+ # Add stock to stores for succesful stock transfer
+ make_stock_entry(
+ target="Stores - TCP1",
+ company = "_Test Company with perpetual inventory",
+ qty=1,
+ basic_rate=100
+ )
+
+ add_taxes(si)
+ si.save()
+
+ rate = 0.0
+ for d in si.get('items'):
+ rate = get_incoming_rate({
+ "item_code": d.item_code,
+ "warehouse": d.warehouse,
+ "posting_date": si.posting_date,
+ "posting_time": si.posting_time,
+ "qty": -1 * flt(d.get('stock_qty')),
+ "serial_no": d.serial_no,
+ "company": si.company,
+ "voucher_type": 'Sales Invoice',
+ "voucher_no": si.name,
+ "allow_zero_valuation": d.get("allow_zero_valuation")
+ }, raise_error_if_no_rate=False)
+
+ rate = flt(rate, 2)
+
+ si.submit()
+
+ target_doc = make_inter_company_transaction("Sales Invoice", si.name)
+ target_doc.company = '_Test Company with perpetual inventory'
+ target_doc.items[0].warehouse = 'Finished Goods - TCP1'
+ add_taxes(target_doc)
+ target_doc.save()
+ target_doc.submit()
+
+ tax_amount = flt(rate * (12/100), 2)
+ si_gl_entries = [
+ ["_Test Account Excise Duty - TCP1", 0.0, tax_amount, nowdate()],
+ ["Unrealized Profit - TCP1", tax_amount, 0.0, nowdate()]
+ ]
+
+ check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1))
+
+ pi_gl_entries = [
+ ["_Test Account Excise Duty - TCP1", tax_amount , 0.0, nowdate()],
+ ["Unrealized Profit - TCP1", 0.0, tax_amount, nowdate()]
+ ]
+
+ # Sale and Purchase both should be at valuation rate
+ self.assertEqual(si.items[0].rate, rate)
+ self.assertEqual(target_doc.items[0].rate, rate)
+
+ check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
+
def test_eway_bill_json(self):
- if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
- address = frappe.get_doc({
- "address_line1": "_Test Address Line 1",
- "address_title": "_Test Address for Eway bill",
- "address_type": "Billing",
- "city": "_Test City",
- "state": "Test State",
- "country": "India",
- "doctype": "Address",
- "is_primary_address": 1,
- "phone": "+91 0000000000",
- "gstin": "27AAECE4835E1ZR",
- "gst_state": "Maharashtra",
- "gst_state_number": "27",
- "pincode": "401108"
- }).insert()
-
- address.append("links", {
- "link_doctype": "Company",
- "link_name": "_Test Company"
- })
-
- 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_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": "+91 0000000000",
- "gst_state": "Maharashtra",
- "gst_state_number": "27",
- "pincode": "410038"
- }).insert()
-
- address.append("links", {
- "link_doctype": "Customer",
- "link_name": "_Test Customer"
- })
-
- address.save()
-
- gst_settings = frappe.get_doc("GST Settings")
-
- gst_account = frappe.get_all(
- "GST Account",
- fields=["cgst_account", "sgst_account", "igst_account"],
- filters = {"company": "_Test Company"})
-
- if not gst_account:
- gst_settings.append("gst_accounts", {
- "company": "_Test Company",
- "cgst_account": "CGST - _TC",
- "sgst_account": "SGST - _TC",
- "igst_account": "IGST - _TC",
- })
-
- gst_settings.save()
-
- si = create_sales_invoice(do_not_save =1, rate = '60000')
-
- si.distance = 2000
- si.company_address = "_Test Address for Eway bill-Billing"
- si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
- si.vehicle_no = "KA12KA1234"
- si.gst_category = "Registered Regular"
-
- si.append("taxes", {
- "charge_type": "On Net Total",
- "account_head": "CGST - _TC",
- "cost_center": "Main - _TC",
- "description": "CGST @ 9.0",
- "rate": 9
- })
-
- si.append("taxes", {
- "charge_type": "On Net Total",
- "account_head": "SGST - _TC",
- "cost_center": "Main - _TC",
- "description": "SGST @ 9.0",
- "rate": 9
- })
+ si = make_sales_invoice_for_ewaybill()
si.submit()
@@ -1883,6 +1875,197 @@
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
+ def test_einvoice_submission_without_irn(self):
+ # init
+ frappe.db.set_value('E Invoice Settings', 'E Invoice Settings', 'enable', 1)
+ country = frappe.flags.country
+ frappe.flags.country = 'India'
+
+ si = make_sales_invoice_for_ewaybill()
+ self.assertRaises(frappe.ValidationError, si.submit)
+
+ si.irn = 'test_irn'
+ si.submit()
+
+ # reset
+ frappe.db.set_value('E Invoice Settings', 'E Invoice Settings', 'enable', 0)
+ frappe.flags.country = country
+
+ def test_einvoice_json(self):
+ from erpnext.regional.india.e_invoice.utils import make_einvoice
+
+ si = make_sales_invoice_for_ewaybill()
+ si.naming_series = 'INV-2020-.#####'
+ si.items = []
+ si.append("items", {
+ "item_code": "_Test Item",
+ "uom": "Nos",
+ "warehouse": "_Test Warehouse - _TC",
+ "qty": 2000,
+ "rate": 12,
+ "income_account": "Sales - _TC",
+ "expense_account": "Cost of Goods Sold - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ })
+ si.append("items", {
+ "item_code": "_Test Item 2",
+ "uom": "Nos",
+ "warehouse": "_Test Warehouse - _TC",
+ "qty": 420,
+ "rate": 15,
+ "income_account": "Sales - _TC",
+ "expense_account": "Cost of Goods Sold - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ })
+ si.discount_amount = 100
+ si.save()
+
+ einvoice = make_einvoice(si)
+
+ total_item_ass_value = 0
+ total_item_cgst_value = 0
+ total_item_sgst_value = 0
+ total_item_igst_value = 0
+ total_item_value = 0
+
+ for item in einvoice['ItemList']:
+ total_item_ass_value += item['AssAmt']
+ total_item_cgst_value += item['CgstAmt']
+ total_item_sgst_value += item['SgstAmt']
+ total_item_igst_value += item['IgstAmt']
+ total_item_value += item['TotItemVal']
+
+ self.assertTrue(item['AssAmt'], item['TotAmt'] - item['Discount'])
+ self.assertTrue(item['TotItemVal'], item['AssAmt'] + item['CgstAmt'] + item['SgstAmt'] + item['IgstAmt'])
+
+ value_details = einvoice['ValDtls']
+
+ self.assertEqual(einvoice['Version'], '1.1')
+ self.assertEqual(value_details['AssVal'], total_item_ass_value)
+ self.assertEqual(value_details['CgstVal'], total_item_cgst_value)
+ self.assertEqual(value_details['SgstVal'], total_item_sgst_value)
+ self.assertEqual(value_details['IgstVal'], total_item_igst_value)
+
+ calculated_invoice_value = \
+ value_details['AssVal'] + value_details['CgstVal'] \
+ + value_details['SgstVal'] + value_details['IgstVal'] \
+ + value_details['OthChrg'] - value_details['Discount']
+
+ self.assertTrue(value_details['TotInvVal'] - calculated_invoice_value < 0.1)
+
+ self.assertEqual(value_details['TotInvVal'], si.base_grand_total)
+ self.assertTrue(einvoice['EwbDtls'])
+
+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_title": "_Test Address for Eway bill",
+ "address_type": "Billing",
+ "city": "_Test City",
+ "state": "Test State",
+ "country": "India",
+ "doctype": "Address",
+ "is_primary_address": 1,
+ "phone": "+910000000000",
+ "gstin": "27AAECE4835E1ZR",
+ "gst_state": "Maharashtra",
+ "gst_state_number": "27",
+ "pincode": "401108"
+ }).insert()
+
+ address.append("links", {
+ "link_doctype": "Company",
+ "link_name": "_Test Company"
+ })
+
+ 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_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",
+ "gstin": "27AACCM7806M1Z3",
+ "gst_state": "Maharashtra",
+ "gst_state_number": "27",
+ "pincode": "410038"
+ }).insert()
+
+ address.append("links", {
+ "link_doctype": "Customer",
+ "link_name": "_Test Customer"
+ })
+
+ address.save()
+
+def make_test_transporter_for_ewaybill():
+ if not frappe.db.exists('Supplier', '_Test Transporter'):
+ frappe.get_doc({
+ "doctype": "Supplier",
+ "supplier_name": "_Test Transporter",
+ "country": "India",
+ "supplier_group": "_Test Supplier Group",
+ "supplier_type": "Company",
+ "is_transporter": 1
+ }).insert()
+
+def make_sales_invoice_for_ewaybill():
+ make_test_address_for_ewaybill()
+ make_test_transporter_for_ewaybill()
+
+ gst_settings = frappe.get_doc("GST Settings")
+
+ gst_account = frappe.get_all(
+ "GST Account",
+ fields=["cgst_account", "sgst_account", "igst_account"],
+ filters = {"company": "_Test Company"}
+ )
+
+ if not gst_account:
+ gst_settings.append("gst_accounts", {
+ "company": "_Test Company",
+ "cgst_account": "CGST - _TC",
+ "sgst_account": "SGST - _TC",
+ "igst_account": "IGST - _TC",
+ })
+
+ gst_settings.save()
+
+ si = create_sales_invoice(do_not_save=1, rate='60000')
+
+ si.distance = 2000
+ si.company_address = "_Test Address for Eway bill-Billing"
+ si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
+ si.vehicle_no = "KA12KA1234"
+ si.gst_category = "Registered Regular"
+ si.mode_of_transport = 'Road'
+ si.transporter = '_Test Transporter'
+
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "CGST - _TC",
+ "cost_center": "Main - _TC",
+ "description": "CGST @ 9.0",
+ "rate": 9
+ })
+
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "SGST - _TC",
+ "cost_center": "Main - _TC",
+ "description": "SGST @ 9.0",
+ "rate": 9
+ })
+
+ return si
+
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
@@ -1903,14 +2086,14 @@
item.save()
item.append("taxes", {
- "item_tax_template": "_Test Item Tax Template 1",
+ "item_tax_template": "_Test Item Tax Template 1 - _TC",
"valid_from": add_days(nowdate(), 1)
})
item.save()
sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
- sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1"
+ sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC"
self.assertRaises(frappe.ValidationError, sales_invoice.save)
item.taxes = []
@@ -1935,14 +2118,19 @@
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
+ "item_name": args.item_name or "_Test Item",
+ "description": args.description or "_Test Item",
"gst_hsn_code": "999800",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1,
+ "uom": args.uom or "Nos",
+ "stock_uom": args.uom or "Nos",
"rate": args.rate if args.get("rate") is not None else 100,
"income_account": args.income_account or "Sales - _TC",
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
- "serial_no": args.serial_no
+ "serial_no": args.serial_no,
+ "conversion_factor": 1
})
if not args.do_not_save:
@@ -2037,4 +2225,57 @@
"parentfield": "taxes",
"rate": 2,
"row_id": 1
- }]
\ No newline at end of file
+ }]
+
+def create_internal_customer(customer_name, represents_company, allowed_to_interact_with):
+ if not frappe.db.exists("Customer", customer_name):
+ customer = frappe.get_doc({
+ "customer_group": "_Test Customer Group",
+ "customer_name": customer_name,
+ "customer_type": "Individual",
+ "doctype": "Customer",
+ "territory": "_Test Territory",
+ "is_internal_customer": 1,
+ "represents_company": represents_company
+ })
+
+ customer.append("companies", {
+ "company": allowed_to_interact_with
+ })
+
+ customer.insert()
+ customer_name = customer.name
+ else:
+ customer_name = frappe.db.get_value("Customer", customer_name)
+
+ return customer_name
+
+def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with):
+ if not frappe.db.exists("Supplier", supplier_name):
+ supplier = frappe.get_doc({
+ "supplier_group": "_Test Supplier Group",
+ "supplier_name": supplier_name,
+ "doctype": "Supplier",
+ "is_internal_supplier": 1,
+ "represents_company": represents_company
+ })
+
+ supplier.append("companies", {
+ "company": allowed_to_interact_with
+ })
+
+ supplier.insert()
+ supplier_name = supplier.name
+ else:
+ supplier_name = frappe.db.exists("Supplier", supplier_name)
+
+ return supplier_name
+
+def add_taxes(doc):
+ doc.append('taxes', {
+ 'account_head': '_Test Account Excise Duty - TCP1',
+ "charge_type": "On Net Total",
+ "cost_center": "Main - TCP1",
+ "description": "Excise Duty",
+ "rate": 12
+ })
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index fb3dd6a..8e6952a 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-06-04 11:02:19",
"doctype": "DocType",
@@ -44,6 +45,7 @@
"base_rate",
"base_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_21",
"net_rate",
@@ -51,6 +53,7 @@
"column_break_24",
"base_net_rate",
"base_net_amount",
+ "incoming_rate",
"drop_ship",
"delivered_by_supplier",
"accounting",
@@ -563,11 +566,12 @@
"print_hide": 1
},
{
+ "depends_on": "eval: parent.is_internal_customer && parent.update_stock",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "label": "Customer Warehouse (Optional)",
+ "label": "Target Warehouse",
"no_copy": 1,
"options": "Warehouse",
"print_hide": 1
@@ -792,20 +796,37 @@
"options": "Project"
},
{
- "depends_on": "eval:parent.update_stock == 1",
- "fieldname": "sales_invoice_item",
- "fieldtype": "Data",
- "ignore_user_permissions": 1,
- "label": "Sales Invoice Item",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- }
+ "depends_on": "eval:parent.update_stock == 1",
+ "fieldname": "sales_invoice_item",
+ "fieldtype": "Data",
+ "ignore_user_permissions": 1,
+ "label": "Sales Invoice Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "incoming_rate",
+ "fieldtype": "Currency",
+ "label": "Incoming Rate",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
+ }
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-08-20 11:24:41.749986",
+ "modified": "2021-02-23 01:05:22.123527",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
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 7a62f8e..a73b03a 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
@@ -5,8 +5,6 @@
import frappe
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
class SalesInvoiceItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js
index 97a6fdd..0e01188 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js
@@ -5,3 +5,25 @@
{% include "erpnext/public/js/controllers/accounts.js" %}
+frappe.tour['Sales Taxes and Charges Template'] = [
+ {
+ fieldname: "title",
+ title: __("Title"),
+ description: __("A name by which you will identify this template. You can change this later."),
+ },
+ {
+ fieldname: "company",
+ title: __("Company"),
+ description: __("Company for which this tax template will be applicable"),
+ },
+ {
+ fieldname: "is_default",
+ title: __("Is this Default?"),
+ description: __("Set this template as the default for all sales transactions"),
+ },
+ {
+ fieldname: "taxes",
+ title: __("Taxes Table"),
+ description: __("You can add a row for a tax rule here. These rules can be applied on the net total, or can be a flat amount."),
+ }
+];
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 b46de6c..52d19d5 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
@@ -34,6 +34,9 @@
validate_disabled(doc)
+ # Validate with existing taxes and charges template for unique tax category
+ validate_for_tax_category(doc)
+
for tax in doc.get("taxes"):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, doc)
@@ -41,3 +44,7 @@
def validate_disabled(doc):
if doc.is_default and doc.disabled:
frappe.throw(_("Disabled template must not be default template"))
+
+def validate_for_tax_category(doc):
+ if frappe.db.exists(doc.doctype, {"company": doc.company, "tax_category": doc.tax_category, "disabled": 0, "name": ["!=", doc.name]}):
+ frappe.throw(_("A template with tax category {0} already exists. Only one template is allowed with each tax category").format(frappe.bold(doc.tax_category)))
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
index d0904ee..8e4b806 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
@@ -1,16 +1,18 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-frappe.ui.form.on('Shipping Rule', {
- refresh: function(frm) {
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- }
- })
+frappe.provide('erpnext.accounts.dimensions');
+frappe.ui.form.on('Shipping Rule', {
+ onload: function(frm) {
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
+ refresh: function(frm) {
frm.set_query("account", function() {
return {
filters: {
diff --git a/erpnext/accounts/doctype/subscription/subscription.js b/erpnext/accounts/doctype/subscription/subscription.js
index ba98eb9..1a90664 100644
--- a/erpnext/accounts/doctype/subscription/subscription.js
+++ b/erpnext/accounts/doctype/subscription/subscription.js
@@ -10,6 +10,14 @@
}
}
});
+
+ frm.set_query('cost_center', function() {
+ return {
+ filters: {
+ company: frm.doc.company
+ }
+ };
+ });
},
refresh: function(frm) {
diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json
index afb94fe..e80df2a 100644
--- a/erpnext/accounts/doctype/subscription/subscription.json
+++ b/erpnext/accounts/doctype/subscription/subscription.json
@@ -7,9 +7,10 @@
"engine": "InnoDB",
"field_order": [
"party_type",
- "status",
- "cb_1",
"party",
+ "cb_1",
+ "company",
+ "status",
"subscription_period",
"start_date",
"end_date",
@@ -44,80 +45,107 @@
{
"allow_on_submit": 1,
"fieldname": "cb_1",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
+ "no_copy": 1,
"options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "subscription_period",
"fieldtype": "Section Break",
- "label": "Subscription Period"
+ "label": "Subscription Period",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cancelation_date",
"fieldtype": "Date",
"label": "Cancelation Date",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
"fieldname": "trial_period_start",
"fieldtype": "Date",
"label": "Trial Period Start Date",
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.trial_period_start",
"fieldname": "trial_period_end",
"fieldtype": "Date",
"label": "Trial Period End Date",
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_11",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "current_invoice_start",
"fieldtype": "Date",
"label": "Current Invoice Start Date",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "current_invoice_end",
"fieldtype": "Date",
"label": "Current Invoice End Date",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"description": "Number of days that the subscriber has to pay invoices generated by this subscription",
"fieldname": "days_until_due",
"fieldtype": "Int",
- "label": "Days Until Due"
+ "label": "Days Until Due",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "cancel_at_period_end",
"fieldtype": "Check",
- "label": "Cancel At End Of Period"
+ "label": "Cancel At End Of Period",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "generate_invoice_at_period_start",
"fieldtype": "Check",
- "label": "Generate Invoice At Beginning Of Period"
+ "label": "Generate Invoice At Beginning Of Period",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
"fieldname": "sb_4",
"fieldtype": "Section Break",
- "label": "Plans"
+ "label": "Plans",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"allow_on_submit": 1,
@@ -125,62 +153,84 @@
"fieldtype": "Table",
"label": "Plans",
"options": "Subscription Plan Detail",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:['Customer', 'Supplier'].includes(doc.party_type)",
"fieldname": "sb_1",
"fieldtype": "Section Break",
- "label": "Taxes"
+ "label": "Taxes",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "sb_2",
"fieldtype": "Section Break",
- "label": "Discounts"
+ "label": "Discounts",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "apply_additional_discount",
"fieldtype": "Select",
"label": "Apply Additional Discount On",
- "options": "\nGrand Total\nNet Total"
+ "options": "\nGrand Total\nNet Total",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cb_2",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "additional_discount_percentage",
"fieldtype": "Percent",
- "label": "Additional DIscount Percentage"
+ "label": "Additional DIscount Percentage",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "additional_discount_amount",
"fieldtype": "Currency",
- "label": "Additional DIscount Amount"
+ "label": "Additional DIscount Amount",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.invoices",
"fieldname": "sb_3",
"fieldtype": "Section Break",
- "label": "Invoices"
+ "label": "Invoices",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "invoices",
"fieldtype": "Table",
"label": "Invoices",
- "options": "Subscription Invoice"
+ "options": "Subscription Invoice",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
- "label": "Accounting Dimensions"
+ "label": "Accounting Dimensions",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "party_type",
@@ -188,7 +238,9 @@
"label": "Party Type",
"options": "DocType",
"reqd": 1,
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "party",
@@ -197,21 +249,27 @@
"label": "Party",
"options": "party_type",
"reqd": 1,
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.party_type === 'Customer'",
"fieldname": "sales_tax_template",
"fieldtype": "Link",
"label": "Sales Taxes and Charges Template",
- "options": "Sales Taxes and Charges Template"
+ "options": "Sales Taxes and Charges Template",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.party_type === 'Supplier'",
"fieldname": "purchase_tax_template",
"fieldtype": "Link",
"label": "Purchase Taxes and Charges Template",
- "options": "Purchase Taxes and Charges Template"
+ "options": "Purchase Taxes and Charges Template",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -219,36 +277,55 @@
"fieldname": "follow_calendar_months",
"fieldtype": "Check",
"label": "Follow Calendar Months",
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"description": "New invoices will be generated as per schedule even if current invoices are unpaid or past due date",
"fieldname": "generate_new_invoices_past_due_date",
"fieldtype": "Check",
- "label": "Generate New Invoices Past Due Date"
+ "label": "Generate New Invoices Past Due Date",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "end_date",
"fieldtype": "Date",
"label": "Subscription End Date",
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "start_date",
"fieldtype": "Date",
"label": "Subscription Start Date",
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
- "options": "Cost Center"
+ "options": "Cost Center",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "show_days": 1,
+ "show_seconds": 1
}
],
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-06-25 10:52:52.265105",
+ "modified": "2021-02-09 15:44:20.024789",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 0752531..826044a 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -1,3 +1,4 @@
+
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
@@ -5,12 +6,13 @@
from __future__ import unicode_literals
import frappe
+import erpnext
from frappe import _
from frappe.model.document import Document
from frappe.utils.data import nowdate, getdate, cstr, cint, add_days, date_diff, get_last_day, add_to_date, flt
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
-
+from erpnext import get_default_company
class Subscription(Document):
def before_insert(self):
@@ -243,6 +245,7 @@
self.validate_plans_billing_cycle(self.get_billing_cycle_and_interval())
self.validate_end_date()
self.validate_to_follow_calendar_months()
+ self.cost_center = erpnext.get_default_cost_center(self.get('company'))
def validate_trial_period(self):
"""
@@ -304,6 +307,14 @@
doctype = 'Sales Invoice' if self.party_type == 'Customer' else 'Purchase Invoice'
invoice = frappe.new_doc(doctype)
+
+ # For backward compatibility
+ # Earlier subscription didn't had any company field
+ company = self.get('company') or get_default_company()
+ if not company:
+ frappe.throw(_("Company is mandatory was generating invoice. Please set default company in Global Defaults"))
+
+ invoice.company = company
invoice.set_posting_time = 1
invoice.posting_date = self.current_invoice_start if self.generate_invoice_at_period_start \
else self.current_invoice_end
@@ -330,6 +341,7 @@
# for that reason
items_list = self.get_items_from_plans(self.plans, prorate)
for item in items_list:
+ item['cost_center'] = self.cost_center
invoice.append('items', item)
# Taxes
@@ -345,13 +357,14 @@
invoice.set_taxes()
# Due date
- invoice.append(
- 'payment_schedule',
- {
- 'due_date': add_days(invoice.posting_date, cint(self.days_until_due)),
- 'invoice_portion': 100
- }
- )
+ if self.days_until_due:
+ invoice.append(
+ 'payment_schedule',
+ {
+ 'due_date': add_days(invoice.posting_date, cint(self.days_until_due)),
+ 'invoice_portion': 100
+ }
+ )
# Discounts
if self.additional_discount_percentage:
@@ -379,7 +392,8 @@
Returns the `Item`s linked to `Subscription Plan`
"""
if prorate:
- prorate_factor = get_prorata_factor(self.current_invoice_end, self.current_invoice_start)
+ prorate_factor = get_prorata_factor(self.current_invoice_end, self.current_invoice_start,
+ self.generate_invoice_at_period_start)
items = []
party = self.party
@@ -445,7 +459,7 @@
if not self.generate_invoice_at_period_start:
return False
- if self.is_new_subscription():
+ if self.is_new_subscription() and getdate() >= getdate(self.current_invoice_start):
return True
# Check invoice dates and make sure it doesn't have outstanding invoices
@@ -582,10 +596,13 @@
return calendar_months
-def get_prorata_factor(period_end, period_start):
- diff = flt(date_diff(nowdate(), period_start) + 1)
- plan_days = flt(date_diff(period_end, period_start) + 1)
- prorate_factor = diff / plan_days
+def get_prorata_factor(period_end, period_start, is_prepaid):
+ if is_prepaid:
+ prorate_factor = 1
+ else:
+ diff = flt(date_diff(nowdate(), period_start) + 1)
+ plan_days = flt(date_diff(period_end, period_start) + 1)
+ prorate_factor = diff / plan_days
return prorate_factor
diff --git a/erpnext/accounts/doctype/subscription/subscription_list.js b/erpnext/accounts/doctype/subscription/subscription_list.js
index a4edb77..c7325fb 100644
--- a/erpnext/accounts/doctype/subscription/subscription_list.js
+++ b/erpnext/accounts/doctype/subscription/subscription_list.js
@@ -11,7 +11,7 @@
} else if(doc.status === 'Unpaid') {
return [__("Unpaid"), "red"];
} else if(doc.status === 'Cancelled') {
- return [__("Cancelled"), "darkgrey"];
+ return [__("Cancelled"), "gray"];
}
}
};
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py
index 811fc35..7c58e98 100644
--- a/erpnext/accounts/doctype/subscription/test_subscription.py
+++ b/erpnext/accounts/doctype/subscription/test_subscription.py
@@ -237,7 +237,7 @@
subscription.party_type = 'Customer'
subscription.party = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
- subscription.start_date = '2018-01-01'
+ subscription.start_date = add_days(nowdate(), -1000)
subscription.insert()
subscription.process() # generate first invoice
@@ -321,7 +321,8 @@
self.assertEqual(
flt(
- get_prorata_factor(subscription.current_invoice_end, subscription.current_invoice_start),
+ get_prorata_factor(subscription.current_invoice_end, subscription.current_invoice_start,
+ subscription.generate_invoice_at_period_start),
2),
flt(prorate_factor, 2)
)
@@ -561,9 +562,7 @@
current_inv = subscription.get_current_invoice()
self.assertEqual(current_inv.status, "Unpaid")
- diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
- plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
- prorate_factor = flt(diff / plan_days)
+ prorate_factor = 1
self.assertEqual(flt(current_inv.grand_total, 2), flt(prorate_factor * 900, 2))
diff --git a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json
index f54e887..8a0d1de 100644
--- a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json
+++ b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json
@@ -13,21 +13,28 @@
"fieldname": "document_type",
"fieldtype": "Link",
"label": "Document Type ",
+ "no_copy": 1,
"options": "DocType",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "invoice",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Invoice",
+ "no_copy": 1,
"options": "document_type",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-06-01 22:23:54.462718",
+ "modified": "2021-02-09 15:43:32.026233",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription Invoice",
diff --git a/erpnext/accounts/doctype/tax_category/tax_category.json b/erpnext/accounts/doctype/tax_category/tax_category.json
index 6f682a0..f7145af 100644
--- a/erpnext/accounts/doctype/tax_category/tax_category.json
+++ b/erpnext/accounts/doctype/tax_category/tax_category.json
@@ -11,15 +11,18 @@
],
"fields": [
{
+ "allow_in_quick_entry": 1,
"fieldname": "title",
"fieldtype": "Data",
+ "in_list_view": 1,
"label": "Title",
+ "reqd": 1,
"unique": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-08-30 19:41:25.783852",
+ "modified": "2021-03-03 11:50:38.748872",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Category",
diff --git a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
index bbbcc7f..632e30d 100644
--- a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
+++ b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
@@ -6,6 +6,8 @@
import frappe
import unittest
from erpnext.accounts.doctype.tax_rule.tax_rule import IncorrectCustomerGroup, IncorrectSupplierType, ConflictingTaxRule, get_tax_template
+from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity
+from erpnext.crm.doctype.opportunity.opportunity import make_quotation
test_records = frappe.get_test_records('Tax Rule')
@@ -144,6 +146,23 @@
self.assertEqual(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
"_Test Sales Taxes and Charges Template 1 - _TC")
+ def test_taxes_fetch_via_tax_rule(self):
+ make_tax_rule(customer= "_Test Customer", billing_city = "_Test City",
+ sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
+
+ # create opportunity for customer
+ opportunity = make_opportunity(with_items=1)
+
+ # make quotation from opportunity
+ quotation = make_quotation(opportunity.name)
+ quotation.save()
+
+ self.assertEqual(quotation.taxes_and_charges, "_Test Sales Taxes and Charges Template - _TC")
+
+ # Check if accounts heads and rate fetched are also fetched from tax template or not
+ self.assertTrue(len(quotation.taxes) > 0)
+
+
def make_tax_rule(**args):
args = frappe._dict(args)
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 83d7967..961bdb1 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -12,37 +12,62 @@
class TaxWithholdingCategory(Document):
pass
-def get_party_tax_withholding_details(ref_doc, tax_withholding_category=None):
+def get_party_details(inv):
+ party_type, party = '', ''
+ if inv.doctype == 'Sales Invoice':
+ party_type = 'Customer'
+ party = inv.customer
+ else:
+ party_type = 'Supplier'
+ party = inv.supplier
+
+ return party_type, party
+
+def get_party_tax_withholding_details(inv, tax_withholding_category=None):
pan_no = ''
- suppliers = []
+ parties = []
+ party_type, party = get_party_details(inv)
if not tax_withholding_category:
- tax_withholding_category, pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, ['tax_withholding_category', 'pan'])
+ tax_withholding_category, pan_no = frappe.db.get_value(party_type, party, ['tax_withholding_category', 'pan'])
if not tax_withholding_category:
return
+ # if tax_withholding_category passed as an argument but not pan_no
if not pan_no:
- pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, 'pan')
+ pan_no = frappe.db.get_value(party_type, party, 'pan')
# Get others suppliers with the same PAN No
if pan_no:
- suppliers = [d.name for d in frappe.get_all('Supplier', fields=['name'], filters={'pan': pan_no})]
+ parties = frappe.get_all(party_type, filters={ 'pan': pan_no }, pluck='name')
- if not suppliers:
- suppliers.append(ref_doc.supplier)
+ if not parties:
+ parties.append(party)
- fy = get_fiscal_year(ref_doc.posting_date, company=ref_doc.company)
- tax_details = get_tax_withholding_details(tax_withholding_category, fy[0], ref_doc.company)
+ fiscal_year = get_fiscal_year(inv.posting_date, company=inv.company)
+ tax_details = get_tax_withholding_details(tax_withholding_category, fiscal_year[0], inv.company)
+
if not tax_details:
frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}')
- .format(tax_withholding_category, ref_doc.company))
+ .format(tax_withholding_category, inv.company))
- tds_amount = get_tds_amount(suppliers, ref_doc.net_total, ref_doc.company,
- tax_details, fy, ref_doc.posting_date, pan_no)
+ if party_type == 'Customer' and not tax_details.cumulative_threshold:
+ # TCS is only chargeable on sum of invoiced value
+ frappe.throw(_('Tax Withholding Category {} against Company {} for Customer {} should have Cumulative Threshold value.')
+ .format(tax_withholding_category, inv.company, party))
- tax_row = get_tax_row(tax_details, tds_amount)
+ tax_amount, tax_deducted = get_tax_amount(
+ party_type, parties,
+ inv, tax_details,
+ fiscal_year, pan_no
+ )
+
+ if party_type == 'Supplier':
+ tax_row = get_tax_row_for_tds(tax_details, tax_amount)
+ else:
+ tax_row = get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted)
return tax_row
@@ -69,145 +94,254 @@
frappe.throw(_("No Tax Withholding data found for the current Fiscal Year."))
-def get_tax_row(tax_details, tds_amount):
-
- return {
+def get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted):
+ row = {
"category": "Total",
- "add_deduct_tax": "Deduct",
"charge_type": "Actual",
- "account_head": tax_details.account_head,
+ "tax_amount": tax_amount,
"description": tax_details.description,
- "tax_amount": tds_amount
+ "account_head": tax_details.account_head
}
-def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_details, posting_date, pan_no=None):
- fiscal_year, year_start_date, year_end_date = fiscal_year_details
- tds_amount = 0
- tds_deducted = 0
+ if tax_deducted:
+ # TCS already deducted on previous invoices
+ # So, TCS will be calculated by 'Previous Row Total'
- def _get_tds(amount, rate):
- if amount <= 0:
- return 0
-
- return amount * rate / 100
-
- ldc_name = frappe.db.get_value('Lower Deduction Certificate',
- {
- 'pan_no': pan_no,
- 'fiscal_year': fiscal_year
- }, 'name')
- ldc = ''
-
- if ldc_name:
- ldc = frappe.get_doc('Lower Deduction Certificate', ldc_name)
-
- entries = frappe.db.sql("""
- select voucher_no, credit
- from `tabGL Entry`
- where company = %s and
- party in %s and fiscal_year=%s and credit > 0
- """, (company, tuple(suppliers), fiscal_year), as_dict=1)
-
- vouchers = [d.voucher_no for d in entries]
- advance_vouchers = get_advance_vouchers(suppliers, fiscal_year=fiscal_year, company=company)
-
- tds_vouchers = vouchers + advance_vouchers
-
- if tds_vouchers:
- tds_deducted = frappe.db.sql("""
- SELECT sum(credit) FROM `tabGL Entry`
- WHERE
- account=%s and fiscal_year=%s and credit > 0
- and voucher_no in ({0})""". format(','.join(['%s'] * len(tds_vouchers))),
- ((tax_details.account_head, fiscal_year) + tuple(tds_vouchers)))
-
- tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
-
- if tds_deducted:
- if ldc:
- limit_consumed = frappe.db.get_value('Purchase Invoice',
- {
- 'supplier': ('in', suppliers),
- 'apply_tds': 1,
- 'docstatus': 1
- }, 'sum(net_total)')
-
- if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, limit_consumed, net_total,
- ldc.certificate_limit):
-
- tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
+ taxes_excluding_tcs = [d for d in inv.taxes if d.account_head != tax_details.account_head]
+ if taxes_excluding_tcs:
+ # chargeable amount is the total amount after other charges are applied
+ row.update({
+ "charge_type": "On Previous Row Total",
+ "row_id": len(taxes_excluding_tcs),
+ "rate": tax_details.rate
+ })
else:
- tds_amount = _get_tds(net_total, tax_details.rate)
- else:
- supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
- fields = ['sum(net_amount)'],
- filters = {'parent': ('in', vouchers), 'docstatus': 1}, as_list=1)
+ # if only TCS is to be charged, then net total is chargeable amount
+ row.update({
+ "charge_type": "On Net Total",
+ "rate": tax_details.rate
+ })
- supplier_credit_amount = (supplier_credit_amount[0][0]
- if supplier_credit_amount and supplier_credit_amount[0][0] else 0)
+ return row
- jv_supplier_credit_amt = frappe.get_all('Journal Entry Account',
- fields = ['sum(credit_in_account_currency)'],
- filters = {
- 'parent': ('in', vouchers), 'docstatus': 1,
- 'party': ('in', suppliers),
- 'reference_type': ('not in', ['Purchase Invoice'])
- }, as_list=1)
+def get_tax_row_for_tds(tax_details, tax_amount):
+ return {
+ "category": "Total",
+ "charge_type": "Actual",
+ "tax_amount": tax_amount,
+ "add_deduct_tax": "Deduct",
+ "description": tax_details.description,
+ "account_head": tax_details.account_head
+ }
- supplier_credit_amount += (jv_supplier_credit_amt[0][0]
- if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
+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')
+ if ldc_name:
+ return frappe.get_doc('Lower Deduction Certificate', ldc_name)
- supplier_credit_amount += net_total
+def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, pan_no=None):
+ fiscal_year = fiscal_year_details[0]
- debit_note_amount = get_debit_note_amount(suppliers, year_start_date, year_end_date)
- supplier_credit_amount -= debit_note_amount
+ 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)
+ taxable_vouchers = vouchers + advance_vouchers
- if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
- or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
+ tax_deducted = 0
+ if taxable_vouchers:
+ tax_deducted = get_deducted_tax(taxable_vouchers, fiscal_year, tax_details)
- if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, tds_deducted, net_total,
- ldc.certificate_limit):
- tds_amount = get_ltds_amount(supplier_credit_amount, 0, ldc.certificate_limit, ldc.rate,
- tax_details)
+ tax_amount = 0
+ posting_date = inv.posting_date
+ if party_type == 'Supplier':
+ ldc = get_lower_deduction_certificate(fiscal_year, 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)
else:
- tds_amount = _get_tds(supplier_credit_amount, tax_details.rate)
+ 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
+ )
+
+ elif party_type == 'Customer':
+ if tax_deducted:
+ # if already TCS is charged, then amount will be calculated based on 'Previous Row Total'
+ tax_amount = 0
+ 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
+ )
+
+ return tax_amount, tax_deducted
+
+def get_invoice_vouchers(parties, fiscal_year, company, party_type='Supplier'):
+ dr_or_cr = 'credit' if party_type == 'Supplier' else 'debit'
+
+ filters = {
+ dr_or_cr: ['>', 0],
+ 'company': company,
+ 'party_type': party_type,
+ 'party': ['in', parties],
+ 'fiscal_year': fiscal_year,
+ 'is_opening': 'No',
+ 'is_cancelled': 0
+ }
+
+ return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck="voucher_no") or [""]
+
+def get_advance_vouchers(parties, fiscal_year=None, 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'
+
+ filters = {
+ dr_or_cr: ['>', 0],
+ 'is_opening': 'No',
+ 'is_cancelled': 0,
+ 'party_type': party_type,
+ 'party': ['in', parties],
+ 'against_voucher': ['is', 'not set']
+ }
+
+ if fiscal_year:
+ filters['fiscal_year'] = fiscal_year
+ if company:
+ filters['company'] = company
+ if from_date and to_date:
+ filters['posting_date'] = ['between', (from_date, to_date)]
+
+ return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck='voucher_no') or [""]
+
+def get_deducted_tax(taxable_vouchers, fiscal_year, tax_details):
+ # check if TDS / TCS account is already charged on taxable vouchers
+ filters = {
+ 'is_cancelled': 0,
+ 'credit': ['>', 0],
+ 'fiscal_year': fiscal_year,
+ 'account': tax_details.account_head,
+ 'voucher_no': ['in', taxable_vouchers],
+ }
+ field = "sum(credit)"
+
+ return frappe.db.get_value('GL Entry', filters, field) or 0.0
+
+def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers):
+ tds_amount = 0
+
+ supp_credit_amt = frappe.db.get_value('Purchase Invoice', {
+ 'name': ('in', vouchers), 'docstatus': 1, 'apply_tds': 1
+ }, 'sum(net_total)') or 0.0
+
+ supp_jv_credit_amt = frappe.db.get_value('Journal Entry Account', {
+ 'parent': ('in', vouchers), 'docstatus': 1,
+ 'party': ('in', parties), 'reference_type': ('!=', 'Purchase Invoice')
+ }, 'sum(credit_in_account_currency)') or 0.0
+
+ 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)
+ supp_credit_amt -= debit_note_amount
+
+ threshold = tax_details.get('threshold', 0)
+ cumulative_threshold = tax_details.get('cumulative_threshold', 0)
+
+ if ((threshold and supp_credit_amt >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
+ if ldc and is_valid_certificate(
+ ldc.valid_from, ldc.valid_upto,
+ inv.posting_date, tax_deducted,
+ inv.net_total, ldc.certificate_limit
+ ):
+ tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
+ else:
+ tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
return tds_amount
-def get_advance_vouchers(suppliers, fiscal_year=None, company=None, from_date=None, to_date=None):
- condition = "fiscal_year=%s" % fiscal_year
+def get_tcs_amount(parties, inv, tax_details, fiscal_year_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', {
+ 'is_cancelled': 0,
+ 'party': ['in', parties],
+ 'company': inv.company,
+ 'voucher_no': ['in', vouchers],
+ }, 'sum(debit)') or 0.0
+
+ # sum of credit entries made from PE / JV with unset 'against voucher'
+ advance_amt = frappe.db.get_value('GL Entry', {
+ 'is_cancelled': 0,
+ 'party': ['in', parties],
+ 'company': inv.company,
+ 'voucher_no': ['in', adv_vouchers],
+ }, 'sum(credit)') or 0.0
+
+ # sum of credit entries made from sales invoice
+ credit_note_amt = frappe.db.get_value('GL Entry', {
+ 'is_cancelled': 0,
+ 'credit': ['>', 0],
+ 'party': ['in', parties],
+ 'fiscal_year': fiscal_year,
+ 'company': inv.company,
+ 'voucher_type': 'Sales Invoice',
+ }, 'sum(credit)') or 0.0
+
+ 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)):
+ chargeable_amt = total_invoiced_amt - cumulative_threshold
+ tcs_amount = chargeable_amt * tax_details.rate / 100 if chargeable_amt > 0 else 0
+
+ return tcs_amount
+
+def get_invoice_total_without_tcs(inv, tax_details):
+ tcs_tax_row = [d for d in inv.taxes if d.account_head == tax_details.account_head]
+ tcs_tax_row_amount = tcs_tax_row[0].base_tax_amount if tcs_tax_row else 0
+
+ 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):
+ tds_amount = 0
+ limit_consumed = frappe.db.get_value('Purchase Invoice', {
+ 'supplier': ('in', parties),
+ 'apply_tds': 1,
+ 'docstatus': 1
+ }, 'sum(net_total)')
+
+ if is_valid_certificate(
+ ldc.valid_from, ldc.valid_upto,
+ posting_date, limit_consumed,
+ net_total, ldc.certificate_limit
+ ):
+ tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
+
+ return tds_amount
+
+def get_debit_note_amount(suppliers, fiscal_year_details, company=None):
+ _, year_start_date, year_end_date = fiscal_year_details
+
+ filters = {
+ 'supplier': ['in', suppliers],
+ 'is_return': 1,
+ 'docstatus': 1,
+ 'posting_date': ['between', (year_start_date, year_end_date)]
+ }
+ fields = ['abs(sum(net_total)) as net_total']
if company:
- condition += "and company =%s" % (company)
- if from_date and to_date:
- condition += "and posting_date between %s and %s" % (from_date, to_date)
+ filters['company'] = company
- ## Appending the same supplier again if length of suppliers list is 1
- ## since tuple of single element list contains None, For example ('Test Supplier 1', )
- ## and the below query fails
- if len(suppliers) == 1:
- suppliers.append(suppliers[0])
-
- return frappe.db.sql_list("""
- select distinct voucher_no
- from `tabGL Entry`
- where party in %s and %s and debit > 0
- """, (tuple(suppliers), condition)) or []
-
-def get_debit_note_amount(suppliers, year_start_date, year_end_date, company=None):
- condition = "and 1=1"
- if company:
- condition = " and company=%s " % company
-
- if len(suppliers) == 1:
- suppliers.append(suppliers[0])
-
- return flt(frappe.db.sql("""
- select abs(sum(net_total))
- from `tabPurchase Invoice`
- where supplier in %s and is_return=1 and docstatus=1
- and posting_date between %s and %s %s
- """, (tuple(suppliers), year_start_date, year_end_date, condition)))
+ return frappe.get_all('Purchase Invoice', filters, fields)[0].get('net_total') or 0.0
def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
if current_amount < (certificate_limit - deducted_amount):
@@ -225,4 +359,4 @@
certificate_limit > deducted_amount):
valid = True
- return valid
\ No newline at end of file
+ return valid
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 b146899..dd3b49a 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
@@ -7,8 +7,9 @@
import unittest
from frappe.utils import today
from erpnext.accounts.utils import get_fiscal_year
+from erpnext.buying.doctype.supplier.test_supplier import create_supplier
-test_dependencies = ["Supplier Group"]
+test_dependencies = ["Supplier Group", "Customer Group"]
class TestTaxWithholdingCategory(unittest.TestCase):
@classmethod
@@ -17,6 +18,9 @@
create_records()
create_tax_with_holding_category()
+ def tearDown(self):
+ cancel_invoices()
+
def test_cumulative_threshold_tds(self):
frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "Cumulative Threshold TDS")
invoices = []
@@ -101,15 +105,91 @@
for d in invoices:
d.cancel()
+ def test_single_threshold_tds_with_previous_vouchers_and_no_tds(self):
+ invoices = []
+ doc = create_supplier(supplier_name = "Test TDS Supplier ABC",
+ tax_withholding_category="Single Threshold TDS")
+ supplier = doc.name
+
+ pi = create_purchase_invoice(supplier=supplier)
+ pi.submit()
+ invoices.append(pi)
+
+ # TDS not applied
+ pi = create_purchase_invoice(supplier=supplier, do_not_apply_tds=True)
+ pi.submit()
+ invoices.append(pi)
+
+ pi = create_purchase_invoice(supplier=supplier)
+ pi.submit()
+ invoices.append(pi)
+
+ self.assertEqual(pi.taxes_and_charges_deducted, 2000)
+ self.assertEqual(pi.grand_total, 8000)
+
+ # delete invoices to avoid clashing
+ for d in invoices:
+ d.cancel()
+
+ def test_cumulative_threshold_tcs(self):
+ frappe.db.set_value("Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS")
+ invoices = []
+
+ # create invoices for lower than single threshold tax rate
+ for _ in range(2):
+ si = create_sales_invoice(customer = "Test TCS Customer")
+ si.submit()
+ invoices.append(si)
+
+ # create another invoice whose total when added to previously created invoice,
+ # surpasses cumulative threshhold
+ si = create_sales_invoice(customer = "Test TCS Customer", rate=12000)
+ si.submit()
+
+ # assert tax collection on total invoice amount created until now
+ tcs_charged = sum([d.base_tax_amount for d in si.taxes if d.account_head == 'TCS - _TC'])
+ self.assertEqual(tcs_charged, 200)
+ self.assertEqual(si.grand_total, 12200)
+ invoices.append(si)
+
+ # TCS is already collected once, so going forward system will collect TCS on every invoice
+ si = create_sales_invoice(customer = "Test TCS Customer", rate=5000)
+ si.submit()
+
+ tcs_charged = sum([d.base_tax_amount for d in si.taxes if d.account_head == 'TCS - _TC'])
+ self.assertEqual(tcs_charged, 500)
+ invoices.append(si)
+
+ #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']],
+ 'docstatus': 1
+ }, pluck="name")
+
+ sales_invoices = frappe.get_all("Sales Invoice", {
+ 'customer': 'Test TCS Customer',
+ 'docstatus': 1
+ }, pluck="name")
+
+ for d in purchase_invoices:
+ frappe.get_doc('Purchase Invoice', d).cancel()
+
+ for d in sales_invoices:
+ frappe.get_doc('Sales Invoice', d).cancel()
+
def create_purchase_invoice(**args):
# return sales invoice doc object
- item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
+ item = frappe.db.get_value('Item', {'item_name': 'TDS Item'}, "name")
args = frappe._dict(args)
pi = frappe.get_doc({
"doctype": "Purchase Invoice",
"posting_date": today(),
- "apply_tds": 1,
+ "apply_tds": 0 if args.do_not_apply_tds else 1,
"supplier": args.supplier,
"company": '_Test Company',
"taxes_and_charges": "",
@@ -118,7 +198,7 @@
"taxes": [],
"items": [{
'doctype': 'Purchase Invoice Item',
- 'item_code': item.name,
+ 'item_code': item,
'qty': args.qty or 1,
'rate': args.rate or 10000,
'cost_center': 'Main - _TC',
@@ -129,6 +209,34 @@
pi.save()
return pi
+def create_sales_invoice(**args):
+ # return sales invoice doc object
+ item = frappe.db.get_value('Item', {'item_name': 'TCS Item'}, "name")
+
+ args = frappe._dict(args)
+ si = frappe.get_doc({
+ "doctype": "Sales Invoice",
+ "posting_date": today(),
+ "customer": args.customer,
+ "company": '_Test Company',
+ "taxes_and_charges": "",
+ "currency": "INR",
+ "debit_to": "Debtors - _TC",
+ "taxes": [],
+ "items": [{
+ 'doctype': 'Sales Invoice Item',
+ 'item_code': item,
+ 'qty': args.qty or 1,
+ 'rate': args.rate or 10000,
+ 'cost_center': 'Main - _TC',
+ 'expense_account': 'Cost of Goods Sold - _TC',
+ 'warehouse': args.warehouse or '_Test Warehouse - _TC'
+ }]
+ })
+
+ si.save()
+ return si
+
def create_records():
# create a new suppliers
for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']:
@@ -141,7 +249,17 @@
"doctype": "Supplier",
}).insert()
- # create an item
+ for name in ['Test TCS Customer']:
+ if frappe.db.exists('Customer', name):
+ continue
+
+ frappe.get_doc({
+ "customer_group": "_Test Customer Group",
+ "customer_name": name,
+ "doctype": "Customer"
+ }).insert()
+
+ # create item
if not frappe.db.exists('Item', "TDS Item"):
frappe.get_doc({
"doctype": "Item",
@@ -151,7 +269,16 @@
"is_stock_item": 0,
}).insert()
- # create an account
+ if not frappe.db.exists('Item', "TCS Item"):
+ frappe.get_doc({
+ "doctype": "Item",
+ "item_code": "TCS Item",
+ "item_name": "TCS Item",
+ "item_group": "All Item Groups",
+ "is_stock_item": 1
+ }).insert()
+
+ # create tds account
if not frappe.db.exists("Account", "TDS - _TC"):
frappe.get_doc({
'doctype': 'Account',
@@ -162,6 +289,17 @@
'root_type': 'Asset'
}).insert()
+ # create tcs account
+ if not frappe.db.exists("Account", "TCS - _TC"):
+ frappe.get_doc({
+ 'doctype': 'Account',
+ 'company': '_Test Company',
+ 'account_name': 'TCS',
+ 'parent_account': 'Duties and Taxes - _TC',
+ 'report_type': 'Balance Sheet',
+ 'root_type': 'Liability'
+ }).insert()
+
def create_tax_with_holding_category():
fiscal_year = get_fiscal_year(today(), company="_Test Company")[0]
@@ -183,6 +321,23 @@
}]
}).insert()
+ if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TCS"):
+ frappe.get_doc({
+ "doctype": "Tax Withholding Category",
+ "name": "Cumulative Threshold TCS",
+ "category_name": "10% TCS",
+ "rates": [{
+ 'fiscal_year': fiscal_year,
+ 'tax_withholding_rate': 10,
+ 'single_threshold': 0,
+ 'cumulative_threshold': 30000.00
+ }],
+ "accounts": [{
+ 'company': '_Test Company',
+ 'account': 'TCS - _TC'
+ }]
+ }).insert()
+
# Single thresold
if not frappe.db.exists("Tax Withholding Category", "Single Threshold TDS"):
frappe.get_doc({
@@ -199,4 +354,4 @@
'company': '_Test Company',
'account': 'TDS - _TC'
}]
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index c12e006d..dac0c21 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -5,23 +5,19 @@
import frappe, erpnext
from frappe.utils import flt, cstr, cint, comma_and, today, getdate, formatdate, now
from frappe import _
-from erpnext.accounts.utils import get_stock_and_account_balance
from frappe.model.meta import get_field_precision
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
-
class ClosedAccountingPeriod(frappe.ValidationError): pass
-class StockAccountInvalidTransaction(frappe.ValidationError): pass
-class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
-def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'):
+def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
if gl_map:
if not cancel:
validate_accounting_period(gl_map)
gl_map = process_gl_map(gl_map, merge_entries)
if gl_map and len(gl_map) > 1:
- save_entries(gl_map, adv_adj, update_outstanding)
+ save_entries(gl_map, adv_adj, update_outstanding, from_repost)
else:
frappe.throw(_("Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."))
else:
@@ -48,9 +44,9 @@
frappe.throw(_("You cannot create or cancel any accounting entries with in the closed Accounting Period {0}")
.format(frappe.bold(accounting_periods[0].name)), ClosedAccountingPeriod)
-def process_gl_map(gl_map, merge_entries=True):
+def process_gl_map(gl_map, merge_entries=True, precision=None):
if merge_entries:
- gl_map = merge_similar_entries(gl_map)
+ gl_map = merge_similar_entries(gl_map, precision)
for entry in gl_map:
# toggle debit, credit if negative entry
if flt(entry.debit) < 0:
@@ -73,7 +69,7 @@
return gl_map
-def merge_similar_entries(gl_map):
+def merge_similar_entries(gl_map, precision=None):
merged_gl_map = []
accounting_dimensions = get_accounting_dimensions()
for entry in gl_map:
@@ -92,7 +88,9 @@
company = gl_map[0].company if gl_map else erpnext.get_default_company()
company_currency = erpnext.get_company_currency(company)
- precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
+
+ if not precision:
+ precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
# filter zero debit and credit entries
merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map)
@@ -119,8 +117,9 @@
if same_head:
return e
-def save_entries(gl_map, adv_adj, update_outstanding):
- validate_cwip_accounts(gl_map)
+def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
+ if not from_repost:
+ validate_cwip_accounts(gl_map)
round_off_debit_credit(gl_map)
@@ -128,76 +127,19 @@
check_freezing_date(gl_map[0]["posting_date"], adv_adj)
for entry in gl_map:
- make_entry(entry, adv_adj, update_outstanding)
+ make_entry(entry, adv_adj, update_outstanding, from_repost)
- # check against budget
- validate_expense_against_budget(entry)
-
- validate_account_for_perpetual_inventory(gl_map)
-
-
-def make_entry(args, adv_adj, update_outstanding):
+def make_entry(args, adv_adj, update_outstanding, from_repost=False):
gle = frappe.new_doc("GL Entry")
gle.update(args)
gle.flags.ignore_permissions = 1
- gle.insert()
- gle.run_method("on_update_with_args", adv_adj, update_outstanding)
+ gle.flags.from_repost = from_repost
+ gle.flags.adv_adj = adv_adj
+ gle.flags.update_outstanding = update_outstanding or 'Yes'
gle.submit()
- # check against budget
- validate_expense_against_budget(args)
-
-def validate_account_for_perpetual_inventory(gl_map):
- if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
- account_list = [gl_entries.account for gl_entries in gl_map]
-
- aii_accounts = [d.name for d in frappe.get_all("Account",
- filters={'account_type': 'Stock', 'is_group': 0, 'company': gl_map[0].company})]
-
- for account in account_list:
- if account not in aii_accounts:
- continue
-
- # Always use current date to get stock and account balance as there can future entries for
- # other items
- account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
- getdate(), gl_map[0].company)
-
- if gl_map[0].voucher_type=="Journal Entry":
- # In case of Journal Entry, there are no corresponding SL entries,
- # hence deducting currency amount
- account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit)
- if account_bal == stock_bal:
- frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
- .format(account), StockAccountInvalidTransaction)
-
- elif account_bal != stock_bal:
- precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
- currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
-
- diff = flt(stock_bal - account_bal, precision)
- error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
- stock_bal, account_bal, frappe.bold(account))
- error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
- stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
-
- db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
- db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
-
- journal_entry_args = {
- 'accounts':[
- {'account': account, db_or_cr_warehouse_account : abs(diff)},
- {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
- }
-
- frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
- raise_exception=StockValueAndAccountBalanceOutOfSync,
- title=_('Values Out Of Sync'),
- primary_action={
- 'label': _('Make Journal Entry'),
- 'client_action': 'erpnext.route_to_adjustment_jv',
- 'args': journal_entry_args
- })
+ if not from_repost:
+ validate_expense_against_budget(args)
def validate_cwip_accounts(gl_map):
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
@@ -254,7 +196,7 @@
if not round_off_gle:
for k in ["voucher_type", "voucher_no", "company",
- "posting_date", "remarks", "is_opening"]:
+ "posting_date", "remarks"]:
round_off_gle[k] = gl_map[0][k]
round_off_gle.update({
@@ -266,6 +208,7 @@
"cost_center": round_off_cost_center,
"party_type": None,
"party": None,
+ "is_opening": "No",
"against_voucher_type": None,
"against_voucher": None
})
diff --git a/erpnext/accounts/module_onboarding/accounts/accounts.json b/erpnext/accounts/module_onboarding/accounts/accounts.json
index ba1a779..6b5c5a1 100644
--- a/erpnext/accounts/module_onboarding/accounts/accounts.json
+++ b/erpnext/accounts/module_onboarding/accounts/accounts.json
@@ -13,14 +13,14 @@
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/accounts",
"idx": 0,
"is_complete": 0,
- "modified": "2020-07-08 14:06:09.033880",
+ "modified": "2020-10-30 15:41:15.547225",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts",
"owner": "Administrator",
"steps": [
{
- "step": "Chart Of Accounts"
+ "step": "Chart of Accounts"
},
{
"step": "Setup Taxes"
diff --git a/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json b/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json
index cbd022b..fc49bd6 100644
--- a/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json
+++ b/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json
@@ -1,20 +1,25 @@
{
"action": "Go to Page",
+ "action_label": "View Chart of Accounts",
+ "callback_message": "You can continue with the onboarding after exploring this page",
+ "callback_title": "Awesome Work",
"creation": "2020-05-13 19:58:20.928127",
+ "description": "# Chart Of Accounts\n\nThe Chart of Accounts is the blueprint of the accounts in your organization.\nIt is a tree view of the names of the Accounts (Ledgers and Groups) that a Company requires to manage its books of accounts. ERPNext sets up a simple chart of accounts for each Company you create, but you can modify it according to your needs and legal requirements.\n\nFor each company, Chart of Accounts signifies the way to classify the accounting entries, mostly\nbased on statutory (tax, compliance to government regulations) requirements.\n\nThere's a brief video tutorial about chart of accounts in the next step.",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
+ "intro_video_url": "https://www.youtube.com/embed/AcfMCT7wLLo",
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 17:40:28.410447",
+ "modified": "2020-10-30 14:35:59.474920",
"modified_by": "Administrator",
- "name": "Chart Of Accounts",
+ "name": "Chart of Accounts",
"owner": "Administrator",
"path": "Tree/Account",
"reference_document": "Account",
+ "show_form_tour": 0,
"show_full_form": 0,
- "title": "Review Chart Of Accounts",
+ "title": "Review Chart of Accounts",
"validate_action": 0
}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json b/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json
index c8be357..c84430a 100644
--- a/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json
+++ b/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json
@@ -1,18 +1,19 @@
{
- "action": "Create Entry",
+ "action": "Show Form Tour",
"creation": "2020-05-14 17:53:00.876946",
+ "description": "# Account Settings\n\nThis is a crucial piece of configuration. There are various account settings in ERPNext to restrict and configure actions in the Accounting module.\n\nThe following settings are avaialble for you to configure\n\n1. Account Freezing \n2. Credit and Overbilling\n3. Invoicing and Tax Automations\n4. Balance Sheet configurations\n\nThere's much more, you can check it all out in this step",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 1,
"is_skipped": 0,
- "modified": "2020-05-14 18:06:25.212923",
+ "modified": "2020-10-19 14:40:55.584484",
"modified_by": "Administrator",
"name": "Configure Account Settings",
"owner": "Administrator",
"reference_document": "Accounts Settings",
+ "show_form_tour": 0,
"show_full_form": 1,
"title": "Configure Account Settings",
"validate_action": 1
diff --git a/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json b/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json
index 5a403b0..0b6750c 100644
--- a/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json
+++ b/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json
@@ -1,18 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 17:46:41.831517",
+ "description": "## Who is a Customer?\n\nA customer, who is sometimes known as a client, buyer, or purchaser is the one who receives goods, services, products, or ideas, from a seller for a monetary consideration.\n\nEvery customer needs to be assigned a unique id. Customer name itself can be the id or you can set a naming series for ids to be generated in Selling Settings.\n\nJust like the supplier, let's quickly create a customer.",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-06-01 13:16:19.731719",
+ "modified": "2020-10-30 15:28:46.659660",
"modified_by": "Administrator",
"name": "Create a Customer",
"owner": "Administrator",
"reference_document": "Customer",
+ "show_form_tour": 0,
"show_full_form": 0,
"title": "Create a Customer",
"validate_action": 1
diff --git a/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json b/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json
index d2068e1..d76f645 100644
--- a/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json
+++ b/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json
@@ -1,19 +1,21 @@
{
"action": "Create Entry",
"creation": "2020-05-12 18:16:06.624554",
+ "description": "## Products and Services\n\nDepending on the nature of your business, you might be selling products or services to your clients or even both. \nERPNext is optimized for itemized management of your sales and purchase.\n\nThe **Item Master** is where you can add all your sales items. If you are in services, you can create an Item for each service that you offer. If you run a manufacturing business, the same master is used for keeping a record of raw materials, sub-assemblies etc.\n\nCompleting the Item Master is very essential for the successful implementation of ERPNext. We have a brief video introducing the item master for you, you can watch it in the next step.",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
+ "intro_video_url": "https://www.youtube.com/watch?v=Sl5UFA5H5EQ",
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-12 18:30:02.489949",
+ "modified": "2020-10-30 15:20:30.133495",
"modified_by": "Administrator",
"name": "Create a Product",
"owner": "Administrator",
"reference_document": "Item",
+ "show_form_tour": 0,
"show_full_form": 0,
- "title": "Create a Product",
+ "title": "Create a Sales Item",
"validate_action": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json b/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json
index 7a64224..64bc7bb 100644
--- a/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json
+++ b/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json
@@ -1,18 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 22:09:10.043554",
+ "description": "## Who is a Supplier?\n\nSuppliers are companies or individuals who provide you with products or services. ERPNext has comprehensive features for purchase cycles. \n\nLet's quickly create a supplier with the minimal details required. You need the name of the supplier, assign the supplier to a group, and select the type of the supplier, viz. Company or Individual.",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 22:09:10.043554",
+ "modified": "2020-10-30 15:26:48.315772",
"modified_by": "Administrator",
"name": "Create a Supplier",
"owner": "Administrator",
"reference_document": "Supplier",
+ "show_form_tour": 0,
"show_full_form": 0,
"title": "Create a Supplier",
"validate_action": 1
diff --git a/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json b/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json
index 3a2b8d3..ddbc89e 100644
--- a/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json
+++ b/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json
@@ -1,18 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 22:10:07.049704",
+ "description": "# What's a Purchase Invoice?\n\nA Purchase Invoice is a bill you receive from your Suppliers against which you need to make the payment.\nPurchase Invoice is the exact opposite of your Sales Invoice. Here you accrue expenses to your Supplier. \n\nThe following is what a typical purchase cycle looks like, however you can create a purchase invoice directly as well.\n\n\n\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 22:10:07.049704",
+ "modified": "2020-10-30 15:30:26.337773",
"modified_by": "Administrator",
"name": "Create Your First Purchase Invoice",
"owner": "Administrator",
"reference_document": "Purchase Invoice",
+ "show_form_tour": 0,
"show_full_form": 1,
"title": "Create Your First Purchase Invoice ",
"validate_action": 1
diff --git a/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json b/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json
index 473de50..9e7dd67 100644
--- a/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json
+++ b/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json
@@ -1,18 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 17:48:21.019019",
+ "description": "# All about sales invoice\n\nA Sales Invoice is a bill that you send to your Customers against which the Customer makes the payment. Sales Invoice is an accounting transaction. On submission of Sales Invoice, the system updates the receivable and books income against a Customer Account.\n\nHere's the flow of how a sales invoice is generally created\n\n\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 17:48:21.019019",
+ "modified": "2020-10-16 12:59:16.987507",
"modified_by": "Administrator",
"name": "Create Your First Sales Invoice",
"owner": "Administrator",
"reference_document": "Sales Invoice",
+ "show_form_tour": 0,
"show_full_form": 1,
"title": "Create Your First Sales Invoice ",
"validate_action": 1
diff --git a/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json b/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json
index 8e00067..a492201 100644
--- a/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json
+++ b/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json
@@ -1,18 +1,20 @@
{
"action": "Create Entry",
+ "action_label": "Make a Sales Tax Template",
"creation": "2020-05-13 19:29:43.844463",
+ "description": "# Setting up Taxes\n\nAny sophisticated accounting system, including ERPNext will have automatic tax calculations for your transactions. These calculations are based on user defined rules in compliance to local rules and regulations.\n\nERPNext allows this via *Tax Templates*. These templates can be used in Sales Orders and Sales Invoices. Other types of charges that may apply to your invoices (like shipping, insurance etc.) can also be configured as taxes.\n\nFor Tax Accounts that you want to use in the tax templates, go to:\n\n`> Accounting > Taxes > Sales Taxes and Charges Template`\n\nYou can read more about these templates in our documentation [here](https://docs.erpnext.com/docs/user/manual/en/selling/sales-taxes-and-charges-template)\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 17:40:16.014413",
+ "modified": "2020-10-30 14:54:18.087383",
"modified_by": "Administrator",
"name": "Setup Taxes",
"owner": "Administrator",
"reference_document": "Sales Taxes and Charges Template",
+ "show_form_tour": 1,
"show_full_form": 1,
"title": "Lets create a Tax Template for Sales ",
"validate_action": 0
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
deleted file mode 100644
index 9703527..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
+++ /dev/null
@@ -1,585 +0,0 @@
-frappe.provide("erpnext.accounts");
-
-frappe.pages['bank-reconciliation'].on_page_load = function(wrapper) {
- new erpnext.accounts.bankReconciliation(wrapper);
-}
-
-erpnext.accounts.bankReconciliation = class BankReconciliation {
- constructor(wrapper) {
- this.page = frappe.ui.make_app_page({
- parent: wrapper,
- title: __("Bank Reconciliation"),
- single_column: true
- });
- this.parent = wrapper;
- this.page = this.parent.page;
-
- this.check_plaid_status();
- this.make();
- }
-
- make() {
- const me = this;
-
- me.$main_section = $(`<div class="reconciliation page-main-content"></div>`).appendTo(me.page.main);
- const empty_state = __("Upload a bank statement, link or reconcile a bank account")
- me.$main_section.append(`<div class="flex justify-center align-center text-muted"
- style="height: 50vh; display: flex;"><h5 class="text-muted">${empty_state}</h5></div>`)
-
- me.page.add_field({
- fieldtype: 'Link',
- label: __('Company'),
- fieldname: 'company',
- options: "Company",
- onchange: function() {
- if (this.value) {
- me.company = this.value;
- } else {
- me.company = null;
- me.bank_account = null;
- }
- }
- })
- me.page.add_field({
- fieldtype: 'Link',
- label: __('Bank Account'),
- fieldname: 'bank_account',
- options: "Bank Account",
- get_query: function() {
- if(!me.company) {
- frappe.throw(__("Please select company first"));
- return
- }
-
- return {
- filters: {
- "company": me.company
- }
- }
- },
- onchange: function() {
- if (this.value) {
- me.bank_account = this.value;
- me.add_actions();
- } else {
- me.bank_account = null;
- me.page.hide_actions_menu();
- }
- }
- })
- }
-
- check_plaid_status() {
- const me = this;
- frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
- if (r && r.enabled === "1") {
- me.plaid_status = "active"
- } else {
- me.plaid_status = "inactive"
- }
- })
- }
-
- add_actions() {
- const me = this;
-
- me.page.show_menu()
-
- me.page.add_menu_item(__("Upload a statement"), function() {
- me.clear_page_content();
- new erpnext.accounts.bankTransactionUpload(me);
- }, true)
-
- if (me.plaid_status==="active") {
- me.page.add_menu_item(__("Synchronize this account"), function() {
- me.clear_page_content();
- new erpnext.accounts.bankTransactionSync(me);
- }, true)
- }
-
- me.page.add_menu_item(__("Reconcile this account"), function() {
- me.clear_page_content();
- me.make_reconciliation_tool();
- }, true)
- }
-
- clear_page_content() {
- const me = this;
- $(me.page.body).find('.frappe-list').remove();
- me.$main_section.empty();
- }
-
- make_reconciliation_tool() {
- const me = this;
- frappe.model.with_doctype("Bank Transaction", () => {
- erpnext.accounts.ReconciliationList = new erpnext.accounts.ReconciliationTool({
- parent: me.parent,
- doctype: "Bank Transaction"
- });
- })
- }
-}
-
-
-erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
- constructor(parent) {
- this.parent = parent;
- this.data = [];
-
- const assets = [
- "/assets/frappe/css/frappe-datatable.css",
- "/assets/frappe/js/lib/clusterize.min.js",
- "/assets/frappe/js/lib/Sortable.min.js",
- "/assets/frappe/js/lib/frappe-datatable.js"
- ];
-
- frappe.require(assets, () => {
- this.make();
- });
- }
-
- make() {
- const me = this;
- new frappe.ui.FileUploader({
- method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
- allow_multiple: 0,
- on_success: function(attachment, r) {
- if (!r.exc && r.message) {
- me.data = r.message;
- me.setup_transactions_dom();
- me.create_datatable();
- me.add_primary_action();
- }
- }
- })
- }
-
- setup_transactions_dom() {
- const me = this;
- me.parent.$main_section.append(`<div class="transactions-table"></div>`)
- }
-
- create_datatable() {
- try {
- this.datatable = new DataTable('.transactions-table', {
- columns: this.data.columns,
- data: this.data.data
- })
- }
- catch(err) {
- let msg = __(`Your file could not be processed by ERPNext.
- <br>It should be a standard CSV or XLSX file.
- <br>The headers should be in the first row.`)
- frappe.throw(msg)
- }
-
- }
-
- add_primary_action() {
- const me = this;
- me.parent.page.set_primary_action(__("Submit"), function() {
- me.add_bank_entries()
- }, null, __("Creating bank entries..."))
- }
-
- add_bank_entries() {
- const me = this;
- frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.create_bank_entries',
- {columns: this.datatable.datamanager.columns, data: this.datatable.datamanager.data, bank_account: me.parent.bank_account}
- ).then((result) => {
- let result_title = result.errors == 0 ? __("{0} bank transaction(s) created", [result.success]) : __("{0} bank transaction(s) created and {1} errors", [result.success, result.errors])
- let result_msg = `
- <div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
- <h5 class="text-muted">${result_title}</h5>
- </div>`
- me.parent.page.clear_primary_action();
- me.parent.$main_section.empty();
- me.parent.$main_section.append(result_msg);
- if (result.errors == 0) {
- frappe.show_alert({message:__("All bank transactions have been created"), indicator:'green'});
- } else {
- frappe.show_alert({message:__("Please check the error log for details about the import errors"), indicator:'red'});
- }
- })
- }
-}
-
-erpnext.accounts.bankTransactionSync = class bankTransactionSync {
- constructor(parent) {
- this.parent = parent;
- this.data = [];
-
- this.init_config()
- }
-
- init_config() {
- const me = this;
- frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_plaid_configuration')
- .then(result => {
- me.plaid_env = result.plaid_env;
- me.client_name = result.client_name;
- me.link_token = result.link_token;
- me.sync_transactions();
- })
- }
-
- sync_transactions() {
- const me = this;
- frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (r) => {
- frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', {
- bank: r.bank,
- bank_account: me.parent.bank_account,
- freeze: true
- })
- .then((result) => {
- let result_title = (result && result.length > 0)
- ? __("{0} bank transaction(s) created", [result.length])
- : __("This bank account is already synchronized");
-
- let result_msg = `
- <div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
- <h5 class="text-muted">${result_title}</h5>
- </div>`
-
- this.parent.$main_section.append(result_msg)
- frappe.show_alert({ message: __("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator: 'green' });
- })
- })
- }
-}
-
-
-erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.views.BaseList {
- constructor(opts) {
- super(opts);
- this.show();
- }
-
- setup_defaults() {
- super.setup_defaults();
-
- this.page_title = __("Bank Reconciliation");
- this.doctype = 'Bank Transaction';
- this.fields = ['date', 'description', 'debit', 'credit', 'currency']
-
- }
-
- setup_view() {
- this.render_header();
- }
-
- setup_side_bar() {
- //
- }
-
- make_standard_filters() {
- //
- }
-
- freeze() {
- this.$result.find('.list-count').html(`<span>${__('Refreshing')}...</span>`);
- }
-
- get_args() {
- const args = super.get_args();
-
- return Object.assign({}, args, {
- ...args.filters.push(["Bank Transaction", "docstatus", "=", 1],
- ["Bank Transaction", "unallocated_amount", ">", 0])
- });
-
- }
-
- update_data(r) {
- let data = r.message || [];
-
- if (this.start === 0) {
- this.data = data;
- } else {
- this.data = this.data.concat(data);
- }
- }
-
- render() {
- const me = this;
- this.$result.find('.list-row-container').remove();
- $('[data-fieldname="name"]').remove();
- me.data.map((value) => {
- const row = $('<div class="list-row-container">').data("data", value).appendTo(me.$result).get(0);
- new erpnext.accounts.ReconciliationRow(row, value);
- })
- }
-
- render_header() {
- const me = this;
- if ($(this.wrapper).find('.transaction-header').length === 0) {
- me.$result.append(frappe.render_template("bank_transaction_header"));
- }
- }
-}
-
-erpnext.accounts.ReconciliationRow = class ReconciliationRow {
- constructor(row, data) {
- this.data = data;
- this.row = row;
- this.make();
- this.bind_events();
- }
-
- make() {
- $(this.row).append(frappe.render_template("bank_transaction_row", this.data))
- }
-
- bind_events() {
- const me = this;
- $(me.row).on('click', '.clickable-section', function() {
- me.bank_entry = $(this).attr("data-name");
- me.show_dialog($(this).attr("data-name"));
- })
-
- $(me.row).on('click', '.new-reconciliation', function() {
- me.bank_entry = $(this).attr("data-name");
- me.show_dialog($(this).attr("data-name"));
- })
-
- $(me.row).on('click', '.new-payment', function() {
- me.bank_entry = $(this).attr("data-name");
- me.new_payment();
- })
-
- $(me.row).on('click', '.new-invoice', function() {
- me.bank_entry = $(this).attr("data-name");
- me.new_invoice();
- })
-
- $(me.row).on('click', '.new-expense', function() {
- me.bank_entry = $(this).attr("data-name");
- me.new_expense();
- })
- }
-
- new_payment() {
- const me = this;
- const paid_amount = me.data.credit > 0 ? me.data.credit : me.data.debit;
- const payment_type = me.data.credit > 0 ? "Receive": "Pay";
- const party_type = me.data.credit > 0 ? "Customer": "Supplier";
-
- frappe.new_doc("Payment Entry", {"payment_type": payment_type, "paid_amount": paid_amount,
- "party_type": party_type, "paid_from": me.data.bank_account})
- }
-
- new_invoice() {
- const me = this;
- const invoice_type = me.data.credit > 0 ? "Sales Invoice" : "Purchase Invoice";
-
- frappe.new_doc(invoice_type)
- }
-
- new_expense() {
- frappe.new_doc("Expense Claim")
- }
-
-
- show_dialog(data) {
- const me = this;
-
- frappe.db.get_value("Bank Account", me.data.bank_account, "account", (r) => {
- me.gl_account = r.account;
- })
-
- frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
- { bank_transaction: data, freeze: true, freeze_message: __("Finding linked payments") }
- ).then((result) => {
- me.make_dialog(result)
- })
- }
-
- make_dialog(data) {
- const me = this;
- me.selected_payment = null;
-
- const fields = [
- {
- fieldtype: 'Section Break',
- fieldname: 'section_break_1',
- label: __('Automatic Reconciliation')
- },
- {
- fieldtype: 'HTML',
- fieldname: 'payment_proposals'
- },
- {
- fieldtype: 'Section Break',
- fieldname: 'section_break_2',
- label: __('Search for a payment')
- },
- {
- fieldtype: 'Link',
- fieldname: 'payment_doctype',
- options: 'DocType',
- label: 'Payment DocType',
- get_query: () => {
- return {
- filters : {
- "name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
- }
- }
- },
- },
- {
- fieldtype: 'Column Break',
- fieldname: 'column_break_1',
- },
- {
- fieldtype: 'Dynamic Link',
- fieldname: 'payment_entry',
- options: 'payment_doctype',
- label: 'Payment Document',
- get_query: () => {
- let dt = this.dialog.fields_dict.payment_doctype.value;
- if (dt === "Payment Entry") {
- return {
- query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.payment_entry_query",
- filters : {
- "bank_account": this.data.bank_account,
- "company": this.data.company
- }
- }
- } else if (dt === "Journal Entry") {
- return {
- query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.journal_entry_query",
- filters : {
- "bank_account": this.data.bank_account,
- "company": this.data.company
- }
- }
- } else if (dt === "Sales Invoice") {
- return {
- query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
- }
- } else if (dt === "Purchase Invoice") {
- return {
- filters : [
- ["Purchase Invoice", "ifnull(clearance_date, '')", "=", ""],
- ["Purchase Invoice", "docstatus", "=", 1],
- ["Purchase Invoice", "company", "=", this.data.company]
- ]
- }
- } else if (dt === "Expense Claim") {
- return {
- filters : [
- ["Expense Claim", "ifnull(clearance_date, '')", "=", ""],
- ["Expense Claim", "docstatus", "=", 1],
- ["Expense Claim", "company", "=", this.data.company]
- ]
- }
- }
- },
- onchange: function() {
- if (me.selected_payment !== this.value) {
- me.selected_payment = this.value;
- me.display_payment_details(this);
- }
- }
- },
- {
- fieldtype: 'Section Break',
- fieldname: 'section_break_3'
- },
- {
- fieldtype: 'HTML',
- fieldname: 'payment_details'
- },
- ];
-
- me.dialog = new frappe.ui.Dialog({
- title: __("Choose a corresponding payment"),
- fields: fields,
- size: "large"
- });
-
- const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
- if (data && data.length > 0) {
- proposals_wrapper.append(frappe.render_template("linked_payment_header"));
- data.map(value => {
- proposals_wrapper.append(frappe.render_template("linked_payment_row", value))
- })
- } else {
- const empty_data_msg = __("ERPNext could not find any matching payment entry")
- proposals_wrapper.append(`<div class="text-center"><h5 class="text-muted">${empty_data_msg}</h5></div>`)
- }
-
- $(me.dialog.body).on('click', '.reconciliation-btn', (e) => {
- const payment_entry = $(e.target).attr('data-name');
- const payment_doctype = $(e.target).attr('data-doctype');
- frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile',
- {bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_name: payment_entry})
- .then((result) => {
- setTimeout(function(){
- erpnext.accounts.ReconciliationList.refresh();
- }, 2000);
- me.dialog.hide();
- })
- })
-
- me.dialog.show();
- }
-
- display_payment_details(event) {
- const me = this;
- if (event.value) {
- let dt = me.dialog.fields_dict.payment_doctype.value;
- me.dialog.fields_dict['payment_details'].$wrapper.empty();
- frappe.db.get_doc(dt, event.value)
- .then(doc => {
- let displayed_docs = []
- let payment = []
- if (dt === "Payment Entry") {
- payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
- payment.doctype = dt
- payment.posting_date = doc.posting_date;
- payment.party = doc.party;
- payment.reference_no = doc.reference_no;
- payment.reference_date = doc.reference_date;
- payment.paid_amount = doc.paid_amount;
- payment.name = doc.name;
- displayed_docs.push(payment);
- } else if (dt === "Journal Entry") {
- doc.accounts.forEach(payment => {
- if (payment.account === me.gl_account) {
- payment.doctype = dt;
- payment.posting_date = doc.posting_date;
- payment.party = doc.pay_to_recd_from;
- payment.reference_no = doc.cheque_no;
- payment.reference_date = doc.cheque_date;
- payment.currency = payment.account_currency;
- payment.paid_amount = payment.credit > 0 ? payment.credit : payment.debit;
- payment.name = doc.name;
- displayed_docs.push(payment);
- }
- })
- } else if (dt === "Sales Invoice") {
- doc.payments.forEach(payment => {
- if (payment.clearance_date === null || payment.clearance_date === "") {
- payment.doctype = dt;
- payment.posting_date = doc.posting_date;
- payment.party = doc.customer;
- payment.reference_no = doc.remarks;
- payment.currency = doc.currency;
- payment.paid_amount = payment.amount;
- payment.name = doc.name;
- displayed_docs.push(payment);
- }
- })
- }
-
- const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
- details_wrapper.append(frappe.render_template("linked_payment_header"));
- displayed_docs.forEach(payment => {
- details_wrapper.append(frappe.render_template("linked_payment_row", payment));
- })
- })
- }
-
- }
-}
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.json b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.json
deleted file mode 100644
index feea368..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "content": null,
- "creation": "2018-11-24 12:03:14.646669",
- "docstatus": 0,
- "doctype": "Page",
- "idx": 0,
- "modified": "2018-11-24 12:03:14.646669",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "bank-reconciliation",
- "owner": "Administrator",
- "page_name": "bank-reconciliation",
- "roles": [
- {
- "role": "System Manager"
- },
- {
- "role": "Accounts Manager"
- },
- {
- "role": "Accounts User"
- }
- ],
- "script": null,
- "standard": "Yes",
- "style": null,
- "system_page": 0,
- "title": "Bank Reconciliation"
-}
\ No newline at end of file
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
deleted file mode 100644
index ce6baa6..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
+++ /dev/null
@@ -1,386 +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 _
-import difflib
-from frappe.utils import flt
-from six import iteritems
-from erpnext import get_company_currency
-
-@frappe.whitelist()
-def reconcile(bank_transaction, payment_doctype, payment_name):
- transaction = frappe.get_doc("Bank Transaction", bank_transaction)
- payment_entry = frappe.get_doc(payment_doctype, payment_name)
-
- account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
- gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
-
- if payment_doctype == "Payment Entry" and payment_entry.unallocated_amount > transaction.unallocated_amount:
- frappe.throw(_("The unallocated amount of Payment Entry {0} \
- is greater than the Bank Transaction's unallocated amount").format(payment_name))
-
- if transaction.unallocated_amount == 0:
- frappe.throw(_("This bank transaction is already fully reconciled"))
-
- if transaction.credit > 0 and gl_entry.credit > 0:
- frappe.throw(_("The selected payment entry should be linked with a debtor bank transaction"))
-
- if transaction.debit > 0 and gl_entry.debit > 0:
- frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction"))
-
- add_payment_to_transaction(transaction, payment_entry, gl_entry)
-
- return 'reconciled'
-
-def add_payment_to_transaction(transaction, payment_entry, gl_entry):
- gl_amount, transaction_amount = (gl_entry.credit, transaction.debit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.credit)
- allocated_amount = gl_amount if gl_amount <= transaction_amount else transaction_amount
- transaction.append("payment_entries", {
- "payment_document": payment_entry.doctype,
- "payment_entry": payment_entry.name,
- "allocated_amount": allocated_amount
- })
-
- transaction.save()
- transaction.update_allocations()
-
-@frappe.whitelist()
-def get_linked_payments(bank_transaction):
- transaction = frappe.get_doc("Bank Transaction", bank_transaction)
- bank_account = frappe.db.get_values("Bank Account", transaction.bank_account, ["account", "company"], as_dict=True)
-
- # Get all payment entries with a matching amount
- amount_matching = check_matching_amount(bank_account[0].account, bank_account[0].company, transaction)
-
- # Get some data from payment entries linked to a corresponding bank transaction
- description_matching = get_matching_descriptions_data(bank_account[0].company, transaction)
-
- if amount_matching:
- return check_amount_vs_description(amount_matching, description_matching)
-
- elif description_matching:
- description_matching = filter(lambda x: not x.get('clearance_date'), description_matching)
- if not description_matching:
- return []
-
- return sorted(list(description_matching), key = lambda x: x["posting_date"], reverse=True)
-
- else:
- return []
-
-def check_matching_amount(bank_account, company, transaction):
- payments = []
- amount = transaction.credit if transaction.credit > 0 else transaction.debit
-
- payment_type = "Receive" if transaction.credit > 0 else "Pay"
- account_from_to = "paid_to" if transaction.credit > 0 else "paid_from"
- currency_field = "paid_to_account_currency as currency" if transaction.credit > 0 else "paid_from_account_currency as currency"
-
- payment_entries = frappe.get_all("Payment Entry", fields=["'Payment Entry' as doctype", "name", "paid_amount", "payment_type", "reference_no", "reference_date",
- "party", "party_type", "posting_date", "{0}".format(currency_field)], filters=[["paid_amount", "like", "{0}%".format(amount)],
- ["docstatus", "=", "1"], ["payment_type", "=", [payment_type, "Internal Transfer"]], ["ifnull(clearance_date, '')", "=", ""], ["{0}".format(account_from_to), "=", "{0}".format(bank_account)]])
-
- if transaction.credit > 0:
- journal_entries = frappe.db.sql("""
- SELECT
- 'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
- je.pay_to_recd_from as party, je.cheque_date as reference_date, jea.debit_in_account_currency as paid_amount
- FROM
- `tabJournal Entry Account` as jea
- JOIN
- `tabJournal Entry` as je
- ON
- jea.parent = je.name
- WHERE
- (je.clearance_date is null or je.clearance_date='0000-00-00')
- AND
- jea.account = %s
- AND
- jea.debit_in_account_currency like %s
- AND
- je.docstatus = 1
- """, (bank_account, amount), as_dict=True)
- else:
- journal_entries = frappe.db.sql("""
- SELECT
- 'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
- jea.account_currency as currency, je.pay_to_recd_from as party, je.cheque_date as reference_date,
- jea.credit_in_account_currency as paid_amount
- FROM
- `tabJournal Entry Account` as jea
- JOIN
- `tabJournal Entry` as je
- ON
- jea.parent = je.name
- WHERE
- (je.clearance_date is null or je.clearance_date='0000-00-00')
- AND
- jea.account = %(bank_account)s
- AND
- jea.credit_in_account_currency like %(txt)s
- AND
- je.docstatus = 1
- """, {
- 'bank_account': bank_account,
- 'txt': '%%%s%%' % amount
- }, as_dict=True)
-
- if transaction.credit > 0:
- sales_invoices = frappe.db.sql("""
- SELECT
- 'Sales Invoice' as doctype, si.name, si.customer as party,
- si.posting_date, sip.amount as paid_amount
- FROM
- `tabSales Invoice Payment` as sip
- JOIN
- `tabSales Invoice` as si
- ON
- sip.parent = si.name
- WHERE
- (sip.clearance_date is null or sip.clearance_date='0000-00-00')
- AND
- sip.account = %s
- AND
- sip.amount like %s
- AND
- si.docstatus = 1
- """, (bank_account, amount), as_dict=True)
- else:
- sales_invoices = []
-
- if transaction.debit > 0:
- purchase_invoices = frappe.get_all("Purchase Invoice",
- fields = ["'Purchase Invoice' as doctype", "name", "paid_amount", "supplier as party", "posting_date", "currency"],
- filters=[
- ["paid_amount", "like", "{0}%".format(amount)],
- ["docstatus", "=", "1"],
- ["is_paid", "=", "1"],
- ["ifnull(clearance_date, '')", "=", ""],
- ["cash_bank_account", "=", "{0}".format(bank_account)]
- ]
- )
-
- mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
- filters={"default_account": bank_account}, fields=["parent"])]
-
- company_currency = get_company_currency(company)
-
- expense_claims = frappe.get_all("Expense Claim",
- fields=["'Expense Claim' as doctype", "name", "total_sanctioned_amount as paid_amount",
- "employee as party", "posting_date", "'{0}' as currency".format(company_currency)],
- filters=[
- ["total_sanctioned_amount", "like", "{0}%".format(amount)],
- ["docstatus", "=", "1"],
- ["is_paid", "=", "1"],
- ["ifnull(clearance_date, '')", "=", ""],
- ["mode_of_payment", "in", "{0}".format(tuple(mode_of_payments))]
- ]
- )
- else:
- purchase_invoices = expense_claims = []
-
- for data in [payment_entries, journal_entries, sales_invoices, purchase_invoices, expense_claims]:
- if data:
- payments.extend(data)
-
- return payments
-
-def get_matching_descriptions_data(company, transaction):
- if not transaction.description :
- return []
-
- bank_transactions = frappe.db.sql("""
- SELECT
- bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry
- FROM
- `tabBank Transaction` as bt
- LEFT JOIN
- `tabBank Transaction Payments` as btp
- ON
- bt.name = btp.parent
- WHERE
- bt.allocated_amount > 0
- AND
- bt.docstatus = 1
- """, as_dict=True)
-
- selection = []
- for bank_transaction in bank_transactions:
- if bank_transaction.description:
- seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description)
-
- if seq.ratio() > 0.6:
- bank_transaction["ratio"] = seq.ratio()
- selection.append(bank_transaction)
-
- document_types = set([x["payment_document"] for x in selection])
-
- links = {}
- for document_type in document_types:
- links[document_type] = [x["payment_entry"] for x in selection if x["payment_document"]==document_type]
-
-
- data = []
- company_currency = get_company_currency(company)
- for key, value in iteritems(links):
- if key == "Payment Entry":
- data.extend(frappe.get_all("Payment Entry", filters=[["name", "in", value]],
- fields=["'Payment Entry' as doctype", "posting_date", "party", "reference_no",
- "reference_date", "paid_amount", "paid_to_account_currency as currency", "clearance_date"]))
- if key == "Journal Entry":
- journal_entries = frappe.get_all("Journal Entry", filters=[["name", "in", value]],
- fields=["name", "'Journal Entry' as doctype", "posting_date",
- "pay_to_recd_from as party", "cheque_no as reference_no", "cheque_date as reference_date",
- "total_credit as paid_amount", "clearance_date"])
- for journal_entry in journal_entries:
- journal_entry_accounts = frappe.get_all("Journal Entry Account", filters={"parenttype": journal_entry["doctype"], "parent": journal_entry["name"]}, fields=["account_currency"])
- journal_entry["currency"] = journal_entry_accounts[0]["account_currency"] if journal_entry_accounts else company_currency
- data.extend(journal_entries)
- if key == "Sales Invoice":
- data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer_name as party", "paid_amount", "currency"]))
- if key == "Purchase Invoice":
- data.extend(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["'Purchase Invoice' as doctype", "posting_date", "supplier_name as party", "paid_amount", "currency"]))
- if key == "Expense Claim":
- expense_claims = frappe.get_all("Expense Claim", filters=[["name", "in", value]], fields=["'Expense Claim' as doctype", "posting_date", "employee_name as party", "total_amount_reimbursed as paid_amount"])
- data.extend([dict(x,**{"currency": company_currency}) for x in expense_claims])
-
- return data
-
-def check_amount_vs_description(amount_matching, description_matching):
- result = []
-
- if description_matching:
- for am_match in amount_matching:
- for des_match in description_matching:
- if des_match.get("clearance_date"):
- continue
-
- if am_match["party"] == des_match["party"]:
- if am_match not in result:
- result.append(am_match)
- continue
-
- if "reference_no" in am_match and "reference_no" in des_match:
- if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]).ratio() > 70:
- if am_match not in result:
- result.append(am_match)
- if result:
- return sorted(result, key = lambda x: x["posting_date"], reverse=True)
- else:
- return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
-
- else:
- return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
-
-def get_matching_transactions_payments(description_matching):
- payments = [x["payment_entry"] for x in description_matching]
-
- payment_by_ratio = {x["payment_entry"]: x["ratio"] for x in description_matching}
-
- if payments:
- reference_payment_list = frappe.get_all("Payment Entry", fields=["name", "paid_amount", "payment_type", "reference_no", "reference_date",
- "party", "party_type", "posting_date", "paid_to_account_currency"], filters=[["name", "in", payments]])
-
- return sorted(reference_payment_list, key=lambda x: payment_by_ratio[x["name"]])
-
- else:
- return []
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
- account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
- if not account:
- return
-
- return frappe.db.sql("""
- SELECT
- name, party, paid_amount, received_amount, reference_no
- FROM
- `tabPayment Entry`
- WHERE
- (clearance_date is null or clearance_date='0000-00-00')
- AND (paid_from = %(account)s or paid_to = %(account)s)
- AND (name like %(txt)s or party like %(txt)s)
- AND docstatus = 1
- ORDER BY
- if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
- LIMIT
- %(start)s, %(page_len)s""",
- {
- 'txt': "%%%s%%" % txt,
- '_txt': txt.replace("%", ""),
- 'start': start,
- 'page_len': page_len,
- 'account': account
- }
- )
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
- account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
-
- return frappe.db.sql("""
- SELECT
- jea.parent, je.pay_to_recd_from,
- if(jea.debit_in_account_currency > 0, jea.debit_in_account_currency, jea.credit_in_account_currency)
- FROM
- `tabJournal Entry Account` as jea
- LEFT JOIN
- `tabJournal Entry` as je
- ON
- jea.parent = je.name
- WHERE
- (je.clearance_date is null or je.clearance_date='0000-00-00')
- AND
- jea.account = %(account)s
- AND
- (jea.parent like %(txt)s or je.pay_to_recd_from like %(txt)s)
- AND
- je.docstatus = 1
- ORDER BY
- if(locate(%(_txt)s, jea.parent), locate(%(_txt)s, jea.parent), 99999),
- jea.parent
- LIMIT
- %(start)s, %(page_len)s""",
- {
- 'txt': "%%%s%%" % txt,
- '_txt': txt.replace("%", ""),
- 'start': start,
- 'page_len': page_len,
- 'account': account
- }
- )
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
- return frappe.db.sql("""
- SELECT
- sip.parent, si.customer, sip.amount, sip.mode_of_payment
- FROM
- `tabSales Invoice Payment` as sip
- LEFT JOIN
- `tabSales Invoice` as si
- ON
- sip.parent = si.name
- WHERE
- (sip.clearance_date is null or sip.clearance_date='0000-00-00')
- AND
- (sip.parent like %(txt)s or si.customer like %(txt)s)
- ORDER BY
- if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
- sip.parent
- LIMIT
- %(start)s, %(page_len)s""",
- {
- 'txt': "%%%s%%" % txt,
- '_txt': txt.replace("%", ""),
- 'start': start,
- 'page_len': page_len
- }
- )
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_transaction_header.html b/erpnext/accounts/page/bank_reconciliation/bank_transaction_header.html
deleted file mode 100644
index 94f183b..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_transaction_header.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="transaction-header">
- <div class="level list-row list-row-head text-muted small">
- <div class="col-sm-2 ellipsis hidden-xs">
- {{ __("Date") }}
- </div>
- <div class="col-xs-11 col-sm-4 ellipsis list-subject">
- {{ __("Description") }}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {{ __("Debit") }}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {{ __("Credit") }}
- </div>
- <div class="col-sm-1 ellipsis hidden-xs">
- {{ __("Currency") }}
- </div>
- <div class="col-sm-1 ellipsis">
- </div>
- </div>
-</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_transaction_row.html b/erpnext/accounts/page/bank_reconciliation/bank_transaction_row.html
deleted file mode 100644
index 742b84c..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_transaction_row.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<div class="list-row transaction-item">
- <div>
- <div class="clickable-section" data-name={{ name }}>
- <div class="col-sm-2 ellipsis hidden-xs">
- {%= frappe.datetime.str_to_user(date) %}
- </div>
- <div class="col-xs-8 col-sm-4 ellipsis list-subject">
- {{ description }}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {%= format_currency(debit, currency) %}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {%= format_currency(credit, currency) %}
- </div>
- <div class="col-sm-1 ellipsis hidden-xs">
- {{ currency }}
- </div>
- </div>
- <div class="col-xs-3 col-sm-1">
- <div class="btn-group">
- <a class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- <span>Actions </span>
- <span class="caret"></span>
- </a>
- <ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;">
- <li><a class="new-reconciliation" data-name={{ name }}>{{ __("Reconcile") }}</a></li>
- <li class="divider"></li>
- <li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li>
- <li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li>
- <li><a class="new-expense" data-name={{ name }}>{{ __("New Expense") }}</a></li>
- </ul>
- </div>
- </div>
- </div>
-</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/linked_payment_header.html b/erpnext/accounts/page/bank_reconciliation/linked_payment_header.html
deleted file mode 100644
index 4542c36..0000000
--- a/erpnext/accounts/page/bank_reconciliation/linked_payment_header.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="transaction-header">
- <div class="level list-row list-row-head text-muted small">
- <div class="col-xs-3 col-sm-2 ellipsis">
- {{ __("Payment Name") }}
- </div>
- <div class="col-xs-3 col-sm-2 ellipsis">
- {{ __("Reference Date") }}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {{ __("Amount") }}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {{ __("Party") }}
- </div>
- <div class="col-xs-3 col-sm-2 ellipsis">
- {{ __("Reference Number") }}
- </div>
- <div class="col-xs-2 col-sm-2">
- </div>
- </div>
-</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/linked_payment_row.html b/erpnext/accounts/page/bank_reconciliation/linked_payment_row.html
deleted file mode 100644
index bdbc9fc..0000000
--- a/erpnext/accounts/page/bank_reconciliation/linked_payment_row.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<div class="list-row">
- <div>
- <div class="col-xs-3 col-sm-2 ellipsis">
- {{ name }}
- </div>
- <div class="col-xs-3 col-sm-2 ellipsis">
- {% if (typeof reference_date !== "undefined") %}
- {%= frappe.datetime.str_to_user(reference_date) %}
- {% else %}
- {% if (typeof posting_date !== "undefined") %}
- {%= frappe.datetime.str_to_user(posting_date) %}
- {% endif %}
- {% endif %}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {{ format_currency(paid_amount, currency) }}
- </div>
- <div class="col-sm-2 ellipsis hidden-xs">
- {% if (typeof party !== "undefined") %}
- {{ party }}
- {% endif %}
- </div>
- <div class="col-xs-3 col-sm-2 ellipsis">
- {% if (typeof reference_no !== "undefined") %}
- {{ reference_no }}
- {% else %}
- {{ "" }}
- {% endif %}
- </div>
- <div class="col-xs-2 col-sm-2">
- <div class="text-right margin-bottom">
- <button class="btn btn-primary btn-xs reconciliation-btn" data-doctype="{{ doctype }}" data-name="{{ name }}">{{ __("Reconcile") }}</button>
- </div>
- </div>
- </div>
-</div>
\ No newline at end of file
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 2f800bb..e01cb6e 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -39,7 +39,7 @@
party_details = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
party = party_details[party_type.lower()]
- if not ignore_permissions and not frappe.has_permission(party_type, "read", party):
+ if not ignore_permissions and not (frappe.has_permission(party_type, "read", party) or frappe.has_permission(party_type, "select", party)):
frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError)
party = frappe.get_doc(party_type, party)
@@ -59,7 +59,7 @@
billing_address=party_address, shipping_address=shipping_address)
if fetch_payment_terms_template:
- party_details["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
+ party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
if not party_details.get("currency"):
party_details["currency"] = currency
@@ -203,7 +203,7 @@
return out
@frappe.whitelist()
-def get_party_account(party_type, party, company):
+def get_party_account(party_type, party, 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),
@@ -315,7 +315,7 @@
due_date = None
if (bill_date or posting_date) and party:
due_date = bill_date or posting_date
- template_name = get_pyt_term_template(party, party_type, company)
+ template_name = get_payment_terms_template(party, party_type, company)
if template_name:
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
@@ -422,7 +422,7 @@
@frappe.whitelist()
-def get_pyt_term_template(party_name, party_type, company=None):
+def get_payment_terms_template(party_name, party_type, company=None):
if party_type not in ("Customer", "Supplier"):
return
template = None
@@ -617,6 +617,7 @@
FROM `tabGL Entry`
WHERE
party_type = %s and against_voucher is null
+ and is_cancelled = 0
and {1} GROUP BY party"""
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
diff --git a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
index 6fe6999..e588ed6 100644
--- a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
+++ b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
@@ -19,7 +19,7 @@
</div>
<div class="col-xs-6">
<table>
- <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
+ <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
</table>
</div>
</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/accounts/print_format/gst_e_invoice/__init__.py
similarity index 100%
rename from erpnext/accounts/page/bank_reconciliation/__init__.py
rename to erpnext/accounts/print_format/gst_e_invoice/__init__.py
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
new file mode 100644
index 0000000..71c26e8
--- /dev/null
+++ b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
@@ -0,0 +1,162 @@
+{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%}
+{%- set einvoice = json.loads(doc.signed_einvoice) -%}
+
+<div class="page-break">
+ <div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}>
+ {% if letter_head and not no_letterhead %}
+ <div class="letter-head">{{ letter_head }}</div>
+ {% endif %}
+ <div class="print-heading">
+ <h2>E Invoice<br><small>{{ doc.name }}</small></h2>
+ </div>
+ </div>
+ {% if print_settings.repeat_header_footer %}
+ <div id="footer-html" class="visible-pdf">
+ {% if not no_letterhead and footer %}
+ <div class="letter-head-footer">
+ {{ footer }}
+ </div>
+ {% endif %}
+ <p class="text-center small page-number visible-pdf">
+ {{ _("Page {0} of {1}").format('<span class="page"></span>', '<span class="topage"></span>') }}
+ </p>
+ </div>
+ {% endif %}
+ <h5 class="font-bold" style="margin-top: 0px;">1. Transaction Details</h5>
+ <div class="row section-break" style="border-bottom: 1px solid #d1d8dd; padding-bottom: 10px;">
+ <div class="col-xs-8 column-break">
+ <div class="row data-field">
+ <div class="col-xs-4"><label>IRN</label></div>
+ <div class="col-xs-8 value">{{ einvoice.Irn }}</div>
+ </div>
+ <div class="row data-field">
+ <div class="col-xs-4"><label>Ack. No</label></div>
+ <div class="col-xs-8 value">{{ einvoice.AckNo }}</div>
+ </div>
+ <div class="row data-field">
+ <div class="col-xs-4"><label>Ack. Date</label></div>
+ <div class="col-xs-8 value">{{ frappe.utils.format_datetime(einvoice.AckDt, "dd/MM/yyyy hh:mm:ss") }}</div>
+ </div>
+ <div class="row data-field">
+ <div class="col-xs-4"><label>Category</label></div>
+ <div class="col-xs-8 value">{{ einvoice.TranDtls.SupTyp }}</div>
+ </div>
+ <div class="row data-field">
+ <div class="col-xs-4"><label>Document Type</label></div>
+ <div class="col-xs-8 value">{{ einvoice.DocDtls.Typ }}</div>
+ </div>
+ <div class="row data-field">
+ <div class="col-xs-4"><label>Document No</label></div>
+ <div class="col-xs-8 value">{{ einvoice.DocDtls.No }}</div>
+ </div>
+ </div>
+ <div class="col-xs-4 column-break">
+ <img src="{{ doc.qrcode_image }}" width="175px" style="float: right;">
+ </div>
+ </div>
+ <h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">2. Party Details</h5>
+ <div class="row section-break" style="border-bottom: 1px solid #d1d8dd; padding-bottom: 10px;">
+ {%- set seller = einvoice.SellerDtls -%}
+ <div class="col-xs-6 column-break">
+ <h5 style="margin-bottom: 5px;">Seller</h5>
+ <p>{{ seller.Gstin }}</p>
+ <p>{{ seller.LglNm }}</p>
+ <p>{{ seller.Addr1 }}</p>
+ {%- if seller.Addr2 -%} <p>{{ seller.Addr2 }}</p> {% endif %}
+ <p>{{ seller.Loc }}</p>
+ <p>{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}</p>
+
+ {%- if einvoice.ShipDtls -%}
+ {%- set shipping = einvoice.ShipDtls -%}
+ <h5 style="margin-bottom: 5px;">Shipping</h5>
+ <p>{{ shipping.Gstin }}</p>
+ <p>{{ shipping.LglNm }}</p>
+ <p>{{ shipping.Addr1 }}</p>
+ {%- if shipping.Addr2 -%} <p>{{ shipping.Addr2 }}</p> {% endif %}
+ <p>{{ shipping.Loc }}</p>
+ <p>{{ frappe.db.get_value("Address", doc.shipping_address_name, "gst_state") }} - {{ shipping.Pin }}</p>
+ {% endif %}
+ </div>
+ {%- set buyer = einvoice.BuyerDtls -%}
+ <div class="col-xs-6 column-break">
+ <h5 style="margin-bottom: 5px;">Buyer</h5>
+ <p>{{ buyer.Gstin }}</p>
+ <p>{{ buyer.LglNm }}</p>
+ <p>{{ buyer.Addr1 }}</p>
+ {%- if buyer.Addr2 -%} <p>{{ buyer.Addr2 }}</p> {% endif %}
+ <p>{{ buyer.Loc }}</p>
+ <p>{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}</p>
+ </div>
+ </div>
+ <div style="overflow-x: auto;">
+ <h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">3. Item Details</h5>
+ <table class="table table-bordered">
+ <thead>
+ <tr>
+ <th class="text-left" style="width: 3%;">Sr. No.</th>
+ <th class="text-left">Item</th>
+ <th class="text-left" style="width: 10%;">HSN Code</th>
+ <th class="text-left" style="width: 5%;">Qty</th>
+ <th class="text-left" style="width: 5%;">UOM</th>
+ <th class="text-left">Rate</th>
+ <th class="text-left" style="width: 5%;">Discount</th>
+ <th class="text-left">Taxable Amount</th>
+ <th class="text-left" style="width: 7%;">Tax Rate</th>
+ <th class="text-left" style="width: 5%;">Other Charges</th>
+ <th class="text-left">Total</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for item in einvoice.ItemList %}
+ <tr>
+ <td class="text-left" style="width: 3%;">{{ item.SlNo }}</td>
+ <td class="text-left">{{ item.PrdDesc }}</td>
+ <td class="text-left" style="width: 10%;">{{ item.HsnCd }}</td>
+ <td class="text-right" style="width: 5%;">{{ item.Qty }}</td>
+ <td class="text-left" style="width: 5%;">{{ item.Unit }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(item.UnitPrice, None, "INR") }}</td>
+ <td class="text-right" style="width: 5%;">{{ frappe.utils.fmt_money(item.Discount, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(item.AssAmt, None, "INR") }}</td>
+ <td class="text-right" style="width: 7%;">{{ item.GstRt + item.CesRt }} %</td>
+ <td class="text-right" style="width: 5%;">{{ frappe.utils.fmt_money(0, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(item.TotItemVal, None, "INR") }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
+ <div style="overflow-x: auto;">
+ <h5 class="font-bold" style="margin-bottom: 0px;">4. Value Details</h5>
+ <table class="table table-bordered">
+ <thead>
+ <tr>
+ <th class="text-left">Taxable Amount</th>
+ <th class="text-left">CGST</th>
+ <th class="text-left"">SGST</th>
+ <th class="text-left">IGST</th>
+ <th class="text-left">CESS</th>
+ <th class="text-left" style="width: 10%;">State CESS</th>
+ <th class="text-left">Discount</th>
+ <th class="text-left" style="width: 10%;">Other Charges</th>
+ <th class="text-left" style="width: 10%;">Round Off</th>
+ <th class="text-left">Total Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ {%- set value_details = einvoice.ValDtls -%}
+ <tr>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.AssVal, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.CgstVal, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.SgstVal, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.IgstVal, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.CesVal, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(0, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.Discount, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.OthChrg, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.RndOffAmt, None, "INR") }}</td>
+ <td class="text-right">{{ frappe.utils.fmt_money(value_details.TotInvVal, None, "INR") }}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
new file mode 100644
index 0000000..1001199
--- /dev/null
+++ b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
@@ -0,0 +1,24 @@
+{
+ "align_labels_right": 1,
+ "creation": "2020-10-10 18:01:21.032914",
+ "custom_format": 0,
+ "default_print_language": "en-US",
+ "disabled": 1,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "",
+ "idx": 0,
+ "line_breaks": 1,
+ "modified": "2020-10-23 19:54:40.634936",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "GST E-Invoice",
+ "owner": "Administrator",
+ "print_format_builder": 0,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 1,
+ "standard": "Yes"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html b/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html
index 1351517..0ca940f8 100644
--- a/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html
+++ b/erpnext/accounts/print_format/journal_auditing_voucher/journal_auditing_voucher.html
@@ -17,7 +17,7 @@
</div>
<div class="col-xs-6">
<table>
- <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
+ <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
</table>
</div>
</div>
diff --git a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html
index f2e65d3..283d505 100644
--- a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html
+++ b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html
@@ -5,7 +5,7 @@
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
{%- for label, value in (
- (_("Received On"), frappe.utils.formatdate(doc.voucher_date)),
+ (_("Received On"), frappe.utils.format_date(doc.voucher_date)),
(_("Received From"), doc.pay_to_recd_from),
(_("Amount"), "<strong>" + doc.get_formatted("total_amount") + "</strong><br>" + (doc.total_amount_in_words or "") + "<br>"),
(_("Remarks"), doc.remark)
diff --git a/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html b/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html
index a7c3bce..043ac25 100644
--- a/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html
+++ b/erpnext/accounts/print_format/purchase_auditing_voucher/purchase_auditing_voucher.html
@@ -8,7 +8,7 @@
<div class="col-xs-6">
<table>
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
- <tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
+ <tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.format_date(doc.due_date) }}</td></tr>
<tr><td><strong>Address: </strong></td><td>{{doc.address_display}}</td></tr>
<tr><td><strong>Contact: </strong></td><td>{{doc.contact_display}}</td></tr>
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
@@ -17,7 +17,7 @@
<div class="col-xs-6">
<table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
- <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
+ <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
</table>
</div>
</div>
diff --git a/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html b/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html
index ef4ada1..a53b593 100644
--- a/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html
+++ b/erpnext/accounts/print_format/sales_auditing_voucher/sales_auditing_voucher.html
@@ -8,7 +8,7 @@
<div class="col-xs-6">
<table>
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
- <tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
+ <tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.format_date(doc.due_date) }}</td></tr>
<tr><td><strong>Address: </strong></td><td>{{doc.address_display}}</td></tr>
<tr><td><strong>Contact: </strong></td><td>{{doc.contact_display}}</td></tr>
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
@@ -17,7 +17,7 @@
<div class="col-xs-6">
<table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
- <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
+ <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
</table>
</div>
</div>
diff --git a/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
index 1d758e8..3d5a9b1 100644
--- a/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
+++ b/erpnext/accounts/print_format/sales_invoice_return/sales_invoice_return.html
@@ -1,5 +1,5 @@
{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value, fieldmeta,
- get_width, get_align_class -%}
+ get_width, get_align_class with context -%}
{%- macro render_currency(df, doc) -%}
<div class="row {% if df.bold %}important{% endif %} data-field">
@@ -63,14 +63,19 @@
<tr>
<td class="table-sr">{{ d.idx }}</td>
{% for tdf in visible_columns %}
- {% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
+ {% if not print_settings.compact_item_print or tdf.fieldname in doc.flags.compact_item_fields %}
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
{% if tdf.fieldname == 'qty' %}
<div class="value">{{ (d[tdf.fieldname])|abs }}</div></td>
{% elif tdf.fieldtype == 'Currency' %}
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|abs, currency=doc.currency) }}</div></td>
{% else %}
- <div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
+ {% if doc.child_print_templates %}
+ {%- set child_templates = doc.child_print_templates.get(df.fieldname) -%}
+ <div class="value">{{ print_value(tdf, d, doc, visible_columns, child_templates) }}</div></td>
+ {% else %}
+ <div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
+ {% endif %}
{% endif %}
{% endif %}
{% endfor %}
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index bb0d0a1..f4fd06b 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -42,11 +42,13 @@
{% if(filters.show_future_payments) { %}
{% var balance_row = data.slice(-1).pop();
- var range1 = report.columns[11].label;
- var range2 = report.columns[12].label;
- var range3 = report.columns[13].label;
- var range4 = report.columns[14].label;
- var range5 = report.columns[15].label;
+ var start = filters.based_on_payment_terms ? 13 : 11;
+ var range1 = report.columns[start].label;
+ var range2 = report.columns[start+1].label;
+ var range3 = report.columns[start+2].label;
+ var range4 = report.columns[start+3].label;
+ var range5 = report.columns[start+4].label;
+ var range6 = report.columns[start+5].label;
%}
{% if(balance_row) { %}
<table class="table table-bordered table-condensed">
@@ -70,20 +72,34 @@
<th>{%= __(range3) %}</th>
<th>{%= __(range4) %}</th>
<th>{%= __(range5) %}</th>
+ <th>{%= __(range6) %}</th>
<th>{%= __("Total") %}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{%= __("Total Outstanding") %}</td>
- <td class="text-right">{%= format_number(balance_row["range1"], null, 2) %}</td>
- <td class="text-right">{%= format_currency(balance_row["range2"]) %}</td>
- <td class="text-right">{%= format_currency(balance_row["range3"]) %}</td>
- <td class="text-right">{%= format_currency(balance_row["range4"]) %}</td>
- <td class="text-right">{%= format_currency(balance_row["range5"]) %}</td>
+ <td class="text-right">
+ {%= format_number(balance_row["age"], null, 2) %}
+ </td>
+ <td class="text-right">
+ {%= format_currency(balance_row["range1"], data[data.length-1]["currency"]) %}
+ </td>
+ <td class="text-right">
+ {%= format_currency(balance_row["range2"], data[data.length-1]["currency"]) %}
+ </td>
+ <td class="text-right">
+ {%= format_currency(balance_row["range3"], data[data.length-1]["currency"]) %}
+ </td>
+ <td class="text-right">
+ {%= format_currency(balance_row["range4"], data[data.length-1]["currency"]) %}
+ </td>
+ <td class="text-right">
+ {%= format_currency(balance_row["range5"], data[data.length-1]["currency"]) %}
+ </td>
<td class="text-right">
{%= format_currency(flt(balance_row["outstanding"]), data[data.length-1]["currency"]) %}
- </td>
+ </td>
</tr>
<td>{%= __("Future Payments") %}</td>
<td></td>
@@ -91,6 +107,7 @@
<td></td>
<td></td>
<td></td>
+ <td></td>
<td class="text-right">
{%= format_currency(flt(balance_row[("future_amount")]), data[data.length-1]["currency"]) %}
</td>
@@ -101,6 +118,7 @@
<th></th>
<th></th>
<th></th>
+ <th></th>
<th class="text-right">
{%= format_currency(flt(balance_row["outstanding"] - balance_row[("future_amount")]), data[data.length-1]["currency"]) %}</th>
</tr>
@@ -218,15 +236,15 @@
<td></td>
<td style="text-align: right"><b>{%= __("Total") %}</b></td>
<td style="text-align: right">
- {%= format_currency(data[i]["invoiced"], data[0]["currency"] ) %}</td>
+ {%= format_currency(data[i]["invoiced"], data[i]["currency"] ) %}</td>
{% if(!filters.show_future_payments) { %}
<td style="text-align: right">
- {%= format_currency(data[i]["paid"], data[0]["currency"]) %}</td>
- <td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %} </td>
+ {%= format_currency(data[i]["paid"], data[i]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %} </td>
{% } %}
<td style="text-align: right">
- {%= format_currency(data[i]["outstanding"], data[0]["currency"]) %}</td>
+ {%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}</td>
{% if(filters.show_future_payments) { %}
{% if(report.report_name === "Accounts Receivable") { %}
@@ -234,13 +252,13 @@
{%= data[i]["po_no"] %}</td>
{% } %}
<td style="text-align: right">{%= data[i]["future_ref"] %}</td>
- <td style="text-align: right">{%= format_currency(data[i]["future_amount"], data[0]["currency"]) %}</td>
- <td style="text-align: right">{%= format_currency(data[i]["remaining_balance"], data[0]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["future_amount"], data[i]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["remaining_balance"], data[i]["currency"]) %}</td>
{% } %}
{% } %}
{% } else { %}
{% if(data[i]["party"]|| " ") { %}
- {% if((data[i]["party"]) != __("'Total'")) { %}
+ {% if(!data[i]["is_total_row"]) { %}
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i]["party"] %}
@@ -256,10 +274,10 @@
{% } else { %}
<td><b>{%= __("Total") %}</b></td>
{% } %}
- <td style="text-align: right">{%= format_currency(data[i]["invoiced"], data[0]["currency"]) %}</td>
- <td style="text-align: right">{%= format_currency(data[i]["paid"], data[0]["currency"]) %}</td>
- <td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %}</td>
- <td style="text-align: right">{%= format_currency(data[i]["outstanding"], data[0]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["invoiced"], data[i]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["paid"], data[i]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %}</td>
+ <td style="text-align: right">{%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}</td>
{% } %}
{% } %}
</tr>
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 044fc1d..51fc7ec 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -160,6 +160,8 @@
else:
# advance / unlinked payment or other adjustment
row.paid -= gle_balance
+ if gle.cost_center:
+ row.cost_center = str(gle.cost_center)
def update_sub_total_row(self, row, party):
total_row = self.total_row_map.get(party)
@@ -210,7 +212,6 @@
for key, row in self.voucher_balance.items():
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
row.invoice_grand_total = row.invoiced
-
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
# non-zero oustanding, we must consider this row
@@ -577,7 +578,7 @@
self.gl_entries = frappe.db.sql("""
select
- name, posting_date, account, party_type, party, voucher_type, voucher_no,
+ name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
against_voucher_type, against_voucher, account_currency, remarks, {0}
from
`tabGL Entry`
@@ -741,6 +742,7 @@
self.add_column(_("Customer Contact"), fieldname='customer_primary_contact',
fieldtype='Link', options='Contact')
+ self.add_column(label=_('Cost Center'), fieldname='cost_center', fieldtype='Data')
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)
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 16bef56..2162a02 100644
--- a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py
+++ b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py
@@ -47,21 +47,22 @@
for d in gl_entries:
asset_data = assets_details.get(d.against_voucher)
- if not asset_data.get("accumulated_depreciation_amount"):
- asset_data.accumulated_depreciation_amount = d.debit
- else:
- asset_data.accumulated_depreciation_amount += d.debit
+ if asset_data:
+ if not asset_data.get("accumulated_depreciation_amount"):
+ asset_data.accumulated_depreciation_amount = d.debit
+ else:
+ asset_data.accumulated_depreciation_amount += d.debit
- row = frappe._dict(asset_data)
- row.update({
- "depreciation_amount": d.debit,
- "depreciation_date": d.posting_date,
- "amount_after_depreciation": (flt(row.gross_purchase_amount) -
- flt(row.accumulated_depreciation_amount)),
- "depreciation_entry": d.voucher_no
- })
+ row = frappe._dict(asset_data)
+ row.update({
+ "depreciation_amount": d.debit,
+ "depreciation_date": d.posting_date,
+ "amount_after_depreciation": (flt(row.gross_purchase_amount) -
+ flt(row.accumulated_depreciation_amount)),
+ "depreciation_entry": d.voucher_no
+ })
- data.append(row)
+ data.append(row)
return data
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index a858c19..1729abc 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -147,7 +147,6 @@
{
"value": net_asset,
"label": "Total Asset",
- "indicator": "Green",
"datatype": "Currency",
"currency": currency
},
@@ -155,14 +154,12 @@
"value": net_liability,
"label": "Total Liability",
"datatype": "Currency",
- "indicator": "Red",
"currency": currency
},
{
"value": net_equity,
"label": "Total Equity",
"datatype": "Currency",
- "indicator": "Blue",
"currency": currency
},
{
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 0861b20..79b0a6f 100644
--- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
+++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
@@ -15,15 +15,51 @@
return columns, data
def get_columns():
- return [
- _("Payment Document") + "::130",
- _("Payment Entry") + ":Dynamic Link/"+_("Payment Document")+":110",
- _("Posting Date") + ":Date:100",
- _("Cheque/Reference No") + "::120",
- _("Clearance Date") + ":Date:100",
- _("Against Account") + ":Link/Account:170",
- _("Amount") + ":Currency:120"
- ]
+ columns = [{
+ "label": _("Payment Document Type"),
+ "fieldname": "payment_document_type",
+ "fieldtype": "Link",
+ "options": "Doctype",
+ "width": 130
+ },
+ {
+ "label": _("Payment Entry"),
+ "fieldname": "payment_entry",
+ "fieldtype": "Dynamic Link",
+ "options": "payment_document_type",
+ "width": 140
+ },
+ {
+ "label": _("Posting Date"),
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "label": _("Cheque/Reference No"),
+ "fieldname": "cheque_no",
+ "width": 120
+ },
+ {
+ "label": _("Clearance Date"),
+ "fieldname": "clearance_date",
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "label": _("Against Account"),
+ "fieldname": "against",
+ "fieldtype": "Link",
+ "options": "Account",
+ "width": 170
+ },
+ {
+ "label": _("Amount"),
+ "fieldname": "amount",
+ "width": 120
+ }]
+
+ return columns
def get_conditions(filters):
conditions = ""
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
index 57fe4b0..8f02849 100644
--- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
+++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
@@ -4,6 +4,14 @@
frappe.query_reports["Bank Reconciliation Statement"] = {
"filters": [
{
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "reqd": 1,
+ "default": frappe.defaults.get_user_default("Company")
+ },
+ {
"fieldname":"account",
"label": __("Bank Account"),
"fieldtype": "Link",
@@ -12,11 +20,14 @@
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "",
"reqd": 1,
"get_query": function() {
+ var company = frappe.query_report.get_filter_value('company')
return {
"query": "erpnext.controllers.queries.get_account_list",
"filters": [
['Account', 'account_type', 'in', 'Bank, Cash'],
['Account', 'is_group', '=', 0],
+ ['Account', 'disabled', '=', 0],
+ ['Account', 'company', '=', company],
]
}
}
@@ -34,4 +45,4 @@
"fieldtype": "Check"
},
]
-}
\ No newline at end of file
+}
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 d011689..0c4a422 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -222,7 +222,7 @@
set_gl_entries_by_account(start_date,
end_date, root.lft, root.rgt, filters,
- gl_entries_by_account, accounts_by_name, ignore_closing_entries=False)
+ 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)
accumulate_values_into_parents(accounts, accounts_by_name, companies)
@@ -240,8 +240,7 @@
def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters):
for entries in gl_entries_by_account.values():
for entry in entries:
- key = entry.account_number or entry.account_name
- d = accounts_by_name.get(key)
+ d = accounts_by_name.get(entry.account_name)
if d:
for company in companies:
# check if posting date is within the period
@@ -256,7 +255,8 @@
"""accumulate children's values in parent accounts"""
for d in reversed(accounts):
if d.parent_account:
- account = d.parent_account.split(' - ')[0].strip()
+ account = d.parent_account_name
+
if not accounts_by_name.get(account):
continue
@@ -267,16 +267,34 @@
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)
if not accounts:
return None, None
+ accounts = update_parent_account_names(accounts)
+
accounts, accounts_by_name, parent_children_map = filter_accounts(accounts)
return accounts, accounts_by_name
+def update_parent_account_names(accounts):
+ """Update parent_account_name in accounts list.
+
+ parent_name is `name` of parent account which could have other prefix
+ 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 }
+
+ for account in accounts:
+ if account.parent_account:
+ account["parent_account_name"] = name_to_account_map[account.parent_account]
+
+ return accounts
+
def get_companies(filters):
companies = {}
all_companies = get_subsidiary_companies(filters.get('company'))
@@ -339,7 +357,7 @@
return data
def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, gl_entries_by_account,
- accounts_by_name, ignore_closing_entries=False):
+ accounts_by_name, accounts, ignore_closing_entries=False):
"""Returns a dict like { "account": [gl entries], ... }"""
company_lft, company_rgt = frappe.get_cached_value('Company',
@@ -381,16 +399,32 @@
convert_to_presentation_currency(gl_entries, currency_info, filters.get('company'))
for entry in gl_entries:
- key = entry.account_number or entry.account_name
- validate_entries(key, entry, accounts_by_name)
- gl_entries_by_account.setdefault(key, []).append(entry)
+ account_name = entry.account_name
+ validate_entries(account_name, entry, accounts_by_name, accounts)
+ gl_entries_by_account.setdefault(account_name, []).append(entry)
return gl_entries_by_account
-def validate_entries(key, entry, accounts_by_name):
+def get_account_details(account):
+ return frappe.get_cached_value('Account', account, ['name', 'report_type', 'root_type', 'company',
+ 'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1)
+
+def validate_entries(key, entry, accounts_by_name, accounts):
if key not in accounts_by_name:
- field = "Account number" if entry.account_number else "Account name"
- frappe.throw(_("{0} {1} is not present in the parent company").format(field, key))
+ args = get_account_details(entry.account)
+
+ if args.parent_account:
+ parent_args = get_account_details(args.parent_account)
+
+ args.update({
+ 'lft': parent_args.lft + 1,
+ 'rgt': parent_args.rgt - 1,
+ 'root_type': parent_args.root_type,
+ 'report_type': parent_args.report_type
+ })
+
+ accounts_by_name.setdefault(key, args)
+ accounts.append(args)
def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions = []
@@ -436,8 +470,7 @@
parent_children_map = {}
accounts_by_name = {}
for d in accounts:
- key = d.account_number or d.account_name
- accounts_by_name[key] = d
+ accounts_by_name[d.account_name] = d
parent_children_map.setdefault(d.parent_account or None, []).append(d)
filtered_accounts = []
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 3ffb3ac..515fd99 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
@@ -14,11 +14,93 @@
def get_column():
return [
- _("Delivery Note") + ":Link/Delivery Note:120", _("Status") + "::120", _("Date") + ":Date:100",
- _("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
- _("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
- _("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
- _("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
+ {
+ "label": _("Delivery Note"),
+ "fieldname": "name",
+ "fieldtype": "Link",
+ "options": "Delivery Note",
+ "width": 160
+ },
+ {
+ "label": _("Date"),
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "label": _("Customer"),
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "options": "Customer",
+ "width": 120
+ },
+ {
+ "label": _("Customer Name"),
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "label": _("Item Code"),
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "options": "Item",
+ "width": 120
+ },
+ {
+ "label": _("Amount"),
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "width": 100,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Billed Amount"),
+ "fieldname": "billed_amount",
+ "fieldtype": "Currency",
+ "width": 100,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Returned Amount"),
+ "fieldname": "returned_amount",
+ "fieldtype": "Currency",
+ "width": 120,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Pending Amount"),
+ "fieldname": "pending_amount",
+ "fieldtype": "Currency",
+ "width": 120,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Item Name"),
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "label": _("Description"),
+ "fieldname": "description",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "label": _("Project"),
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "options": "Project",
+ "width": 120
+ },
+ {
+ "label": _("Company"),
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "options": "Company",
+ "width": 120
+ }
]
def get_args():
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 1b65a31..14efa1f 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -51,7 +51,11 @@
"from_date": start_date
})
- to_date = add_months(start_date, months_to_add)
+ if i==0 and filter_based_on == 'Date Range':
+ to_date = add_months(get_first_day(start_date), months_to_add)
+ else:
+ to_date = add_months(start_date, months_to_add)
+
start_date = to_date
# Subtract one day from to_date, as it may be first day in next fiscal year or month
@@ -307,7 +311,7 @@
where company=%s and root_type=%s order by lft""", (company, root_type), as_dict=True)
-def filter_accounts(accounts, depth=10):
+def filter_accounts(accounts, depth=20):
parent_children_map = {}
accounts_by_name = {}
for d in accounts:
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index f735d87..b5d7992 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -129,6 +129,9 @@
order_by_statement = "order by posting_date, account, creation"
+ if filters.get("include_dimensions"):
+ order_by_statement = "order by posting_date, creation"
+
if filters.get("group_by") == _("Group by Voucher"):
order_by_statement = "order by posting_date, voucher_type, voucher_no"
@@ -142,7 +145,9 @@
distributed_cost_center_query = ""
if filters and filters.get('cost_center'):
- select_fields_with_percentage = """, debit*(DCC_allocation.percentage_allocation/100) as debit, credit*(DCC_allocation.percentage_allocation/100) as credit, debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
+ select_fields_with_percentage = """, debit*(DCC_allocation.percentage_allocation/100) as debit,
+ credit*(DCC_allocation.percentage_allocation/100) as credit,
+ debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
credit_in_account_currency*(DCC_allocation.percentage_allocation/100) as credit_in_account_currency """
distributed_cost_center_query = """
@@ -200,7 +205,7 @@
def get_conditions(filters):
conditions = []
- if filters.get("account"):
+ if filters.get("account") and not filters.get("include_dimensions"):
lft, rgt = frappe.db.get_value("Account", filters["account"], ["lft", "rgt"])
conditions.append("""account in (select name from tabAccount
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))
@@ -245,17 +250,19 @@
if match_conditions:
conditions.append(match_conditions)
- accounting_dimensions = get_accounting_dimensions(as_list=False)
+ if filters.get("include_dimensions"):
+ accounting_dimensions = get_accounting_dimensions(as_list=False)
- if accounting_dimensions:
- for dimension in accounting_dimensions:
- if filters.get(dimension.fieldname):
- if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
- filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
- filters.get(dimension.fieldname))
- conditions.append("{0} in %({0})s".format(dimension.fieldname))
- else:
- conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
+ if accounting_dimensions:
+ for dimension in accounting_dimensions:
+ if not dimension.disabled:
+ if filters.get(dimension.fieldname):
+ if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
+ filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
+ filters.get(dimension.fieldname))
+ conditions.append("{0} in %({0})s".format(dimension.fieldname))
+ else:
+ conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
return "and {}".format(" and ".join(conditions)) if conditions else ""
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 3445df7..cb4d9b4 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
@@ -8,6 +8,7 @@
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
get_group_by_conditions)
+from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details
def execute(filters=None):
return _execute(filters)
@@ -22,7 +23,7 @@
aii_account_map = get_aii_accounts()
if item_list:
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
- doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
+ doctype='Purchase Invoice', tax_doctype='Purchase Taxes and Charges')
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
@@ -34,22 +35,27 @@
if filters.get('group_by'):
grand_total = get_grand_total(filters, 'Purchase Invoice')
+ item_details = get_item_details()
+
for d in item_list:
if not d.stock_qty:
continue
+ item_record = item_details.get(d.item_code)
+
purchase_receipt = None
if d.purchase_receipt:
purchase_receipt = d.purchase_receipt
elif d.po_detail:
purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, []))
- expense_account = d.expense_account or aii_account_map.get(d.company)
+ expense_account = d.unrealized_profit_loss_account or d.expense_account \
+ or aii_account_map.get(d.company)
row = {
'item_code': d.item_code,
- 'item_name': d.item_name,
- 'item_group': d.item_group,
+ 'item_name': item_record.item_name if item_record else d.item_name,
+ 'item_group': item_record.item_group if item_record else d.item_group,
'description': d.description,
'invoice': d.parent,
'posting_date': d.posting_date,
@@ -81,10 +87,10 @@
for tax in tax_columns:
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
row.update({
- frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
- frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
+ frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0),
+ frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0),
})
- total_tax += flt(item_tax.get("tax_amount"))
+ total_tax += flt(item_tax.get('tax_amount'))
row.update({
'total_tax': total_tax,
@@ -309,8 +315,10 @@
select
`tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`,
`tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company,
- `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, `tabPurchase Invoice Item`.`item_code`,
- `tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`, `tabPurchase Invoice Item`.description,
+ `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total,
+ `tabPurchase Invoice`.unrealized_profit_loss_account,
+ `tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description,
+ `tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`,
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
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 a05dcd7..928b373 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
@@ -8,6 +8,7 @@
from frappe.model.meta import get_field_precision
from frappe.utils.xlsxutils import handle_html
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
+from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details, get_customer_details
def execute(filters=None):
return _execute(filters)
@@ -16,7 +17,7 @@
if not filters: filters = {}
columns = get_columns(additional_table_columns, filters)
- company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
+ company_currency = frappe.get_cached_value('Company', filters.get('company'), 'default_currency')
item_list = get_items(filters, additional_query_columns)
if item_list:
@@ -33,7 +34,13 @@
if filters.get('group_by'):
grand_total = get_grand_total(filters, 'Sales Invoice')
+ customer_details = get_customer_details()
+ item_details = get_item_details()
+
for d in item_list:
+ customer_record = customer_details.get(d.customer)
+ item_record = item_details.get(d.item_code)
+
delivery_note = None
if d.delivery_note:
delivery_note = d.delivery_note
@@ -45,14 +52,14 @@
row = {
'item_code': d.item_code,
- 'item_name': d.item_name,
- 'item_group': d.item_group,
+ 'item_name': item_record.item_name if item_record else d.item_name,
+ 'item_group': item_record.item_group if item_record else d.item_group,
'description': d.description,
'invoice': d.parent,
'posting_date': d.posting_date,
'customer': d.customer,
- 'customer_name': d.customer_name,
- 'customer_group': d.customer_group,
+ 'customer_name': customer_record.customer_name,
+ 'customer_group': customer_record.customer_group,
}
if additional_query_columns:
@@ -69,7 +76,7 @@
'company': d.company,
'sales_order': d.sales_order,
'delivery_note': d.delivery_note,
- 'income_account': d.income_account,
+ 'income_account': d.unrealized_profit_loss_account or d.income_account,
'cost_center': d.cost_center,
'stock_qty': d.stock_qty,
'stock_uom': d.stock_uom
@@ -90,10 +97,10 @@
for tax in tax_columns:
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
row.update({
- frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
- frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
+ frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0),
+ frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0),
})
- total_tax += flt(item_tax.get("tax_amount"))
+ total_tax += flt(item_tax.get('tax_amount'))
row.update({
'total_tax': total_tax,
@@ -226,7 +233,7 @@
if filters.get('group_by') != 'Territory':
columns.extend([
{
- 'label': _("Territory"),
+ 'label': _('Territory'),
'fieldname': 'territory',
'fieldtype': 'Link',
'options': 'Territory',
@@ -372,15 +379,16 @@
select
`tabSales Invoice Item`.name, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
+ `tabSales Invoice`.unrealized_profit_loss_account,
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
- `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.item_name,
- `tabSales Invoice Item`.item_group, `tabSales Invoice Item`.description, `tabSales Invoice Item`.sales_order,
- `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.income_account,
- `tabSales Invoice Item`.cost_center, `tabSales Invoice Item`.stock_qty,
- `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate,
- `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name,
- `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
+ `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
+ `tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`,
+ `tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
+ `tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
+ `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
+ `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
+ `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
from `tabSales Invoice`, `tabSales Invoice Item`
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
@@ -417,14 +425,14 @@
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
def get_tax_accounts(item_list, columns, company_currency,
- doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
+ doctype='Sales Invoice', tax_doctype='Sales Taxes and Charges'):
import json
item_row_map = {}
tax_columns = []
invoice_item_row = {}
itemised_tax = {}
- tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field("tax_amount"),
+ tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field('tax_amount'),
currency=company_currency) or 2
for d in item_list:
@@ -469,8 +477,8 @@
tax_rate = tax_data
tax_amount = 0
- if charge_type == "Actual" and not tax_rate:
- tax_rate = "NA"
+ if charge_type == 'Actual' and not tax_rate:
+ tax_rate = 'NA'
item_net_amount = sum([flt(d.base_net_amount)
for d in item_row_map.get(parent, {}).get(item_code, [])])
@@ -484,17 +492,17 @@
if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_value)
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
- "tax_rate": tax_rate,
- "tax_amount": tax_value
+ 'tax_rate': tax_rate,
+ 'tax_amount': tax_value
})
except ValueError:
continue
- elif charge_type == "Actual" and tax_amount:
+ elif charge_type == 'Actual' and tax_amount:
for d in invoice_item_row.get(parent, []):
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
- "tax_rate": "NA",
- "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total,
+ 'tax_rate': 'NA',
+ 'tax_amount': flt((tax_amount * d.base_net_amount) / d.base_net_total,
tax_amount_precision)
})
@@ -563,7 +571,7 @@
})
total_row_map.setdefault('total_row', {
- subtotal_display_field: "Total",
+ subtotal_display_field: 'Total',
'stock_qty': 0.0,
'amount': 0.0,
'bold': 1,
diff --git a/erpnext/accounts/report/non_billed_report.py b/erpnext/accounts/report/non_billed_report.py
index a9e25bc..2e18ce1 100644
--- a/erpnext/accounts/report/non_billed_report.py
+++ b/erpnext/accounts/report/non_billed_report.py
@@ -17,18 +17,26 @@
return frappe.db.sql("""
Select
- `{parent_tab}`.name, `{parent_tab}`.status, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
- {project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount,
+ `{parent_tab}`.name, `{parent_tab}`.{date_field},
+ `{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
+ `{child_tab}`.item_code,
+ `{child_tab}`.base_amount,
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
- (`{child_tab}`.base_amount - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1))),
- `{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company
+ (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0)),
+ (`{child_tab}`.base_amount -
+ (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)) -
+ (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))),
+ `{child_tab}`.item_name, `{child_tab}`.description,
+ {project_field}, `{parent_tab}`.company
from
`{parent_tab}`, `{child_tab}`
where
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1
and `{parent_tab}`.status not in ('Closed', 'Completed')
- and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt *
- ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount
+ and `{child_tab}`.amount > 0
+ and (`{child_tab}`.base_amount -
+ round(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) -
+ (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))) > 0
order by
`{parent_tab}`.{order} {order_by}
""".format(parent_tab = 'tab' + doctype, child_tab = 'tab' + child_tab, precision= precision, party = party,
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 57a1231..7195c7e 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
@@ -59,23 +59,111 @@
def get_columns(filters):
return [
- _("Payment Document") + ":: 100",
- _("Payment Entry") + ":Dynamic Link/"+_("Payment Document")+":140",
- _("Party Type") + "::100",
- _("Party") + ":Dynamic Link/Party Type:140",
- _("Posting Date") + ":Date:100",
- _("Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == _("Outgoing") else ":Link/Sales Invoice:130"),
- _("Invoice Posting Date") + ":Date:130",
- _("Payment Due Date") + ":Date:130",
- _("Debit") + ":Currency:120",
- _("Credit") + ":Currency:120",
- _("Remarks") + "::150",
- _("Age") +":Int:40",
- "0-30:Currency:100",
- "30-60:Currency:100",
- "60-90:Currency:100",
- _("90-Above") + ":Currency:100",
- _("Delay in payment (Days)") + "::150"
+ {
+ "fieldname": "payment_document",
+ "label": _("Payment Document Type"),
+ "fieldtype": "Data",
+ "width": 100
+ },
+ {
+ "fieldname": "payment_entry",
+ "label": _("Payment Document"),
+ "fieldtype": "Dynamic Link",
+ "options": "payment_document",
+ "width": 160
+ },
+ {
+ "fieldname": "party_type",
+ "label": _("Party Type"),
+ "fieldtype": "Data",
+ "width": 100
+ },
+ {
+ "fieldname": "party",
+ "label": _("Party"),
+ "fieldtype": "Dynamic Link",
+ "options": "party_type",
+ "width": 160
+ },
+ {
+ "fieldname": "posting_date",
+ "label": _("Posting Date"),
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "fieldname": "invoice",
+ "label": _("Invoice"),
+ "fieldtype": "Link",
+ "options": "Purchase Invoice" if filters.get("payment_type") == _("Outgoing") else "Sales Invoice",
+ "width": 160
+ },
+ {
+ "fieldname": "invoice_posting_date",
+ "label": _("Invoice Posting Date"),
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "fieldname": "due_date",
+ "label": _("Payment Due Date"),
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "fieldname": "debit",
+ "label": _("Debit"),
+ "fieldtype": "Currency",
+ "width": 140
+ },
+ {
+ "fieldname": "credit",
+ "label": _("Credit"),
+ "fieldtype": "Currency",
+ "width": 140
+ },
+ {
+ "fieldname": "remarks",
+ "label": _("Remarks"),
+ "fieldtype": "Data",
+ "width": 200
+ },
+ {
+ "fieldname": "age",
+ "label": _("Age"),
+ "fieldtype": "Int",
+ "width": 50
+ },
+ {
+ "fieldname": "range1",
+ "label": "0-30",
+ "fieldtype": "Currency",
+ "width": 140
+ },
+ {
+ "fieldname": "range2",
+ "label": "30-60",
+ "fieldtype": "Currency",
+ "width": 140
+ },
+ {
+ "fieldname": "range3",
+ "label": "60-90",
+ "fieldtype": "Currency",
+ "width": 140
+ },
+ {
+ "fieldname": "range4",
+ "label": _("90 Above"),
+ "fieldtype": "Currency",
+ "width": 140
+ },
+ {
+ "fieldname": "delay_in_payment",
+ "label": _("Delay in payment (Days)"),
+ "fieldtype": "Int",
+ "width": 100
+ }
]
def get_conditions(filters):
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/accounts/report/pos_register/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/accounts/report/pos_register/__init__.py
diff --git a/erpnext/accounts/report/pos_register/pos_register.js b/erpnext/accounts/report/pos_register/pos_register.js
new file mode 100644
index 0000000..b8d48d9
--- /dev/null
+++ b/erpnext/accounts/report/pos_register/pos_register.js
@@ -0,0 +1,76 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["POS Register"] = {
+ "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,
+ "width": "60px"
+ },
+ {
+ "fieldname":"to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.get_today(),
+ "reqd": 1,
+ "width": "60px"
+ },
+ {
+ "fieldname":"pos_profile",
+ "label": __("POS Profile"),
+ "fieldtype": "Link",
+ "options": "POS Profile"
+ },
+ {
+ "fieldname":"cashier",
+ "label": __("Cashier"),
+ "fieldtype": "Link",
+ "options": "User"
+ },
+ {
+ "fieldname":"customer",
+ "label": __("Customer"),
+ "fieldtype": "Link",
+ "options": "Customer"
+ },
+ {
+ "fieldname":"mode_of_payment",
+ "label": __("Payment Method"),
+ "fieldtype": "Link",
+ "options": "Mode of Payment"
+ },
+ {
+ "fieldname":"group_by",
+ "label": __("Group by"),
+ "fieldtype": "Select",
+ "options": ["", "POS Profile", "Cashier", "Payment Method", "Customer"],
+ "default": "POS Profile"
+ },
+ {
+ "fieldname":"is_return",
+ "label": __("Is Return"),
+ "fieldtype": "Check"
+ },
+ ],
+ "formatter": function(value, row, column, data, default_formatter) {
+ value = default_formatter(value, row, column, data);
+ if (data && data.bold) {
+ value = value.bold();
+
+ }
+ return value;
+ }
+};
diff --git a/erpnext/accounts/report/pos_register/pos_register.json b/erpnext/accounts/report/pos_register/pos_register.json
new file mode 100644
index 0000000..2398b10
--- /dev/null
+++ b/erpnext/accounts/report/pos_register/pos_register.json
@@ -0,0 +1,30 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2020-09-10 19:25:03.766871",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "json": "{}",
+ "modified": "2020-09-10 19:25:15.851331",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "POS Register",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "POS Invoice",
+ "report_name": "POS Register",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Accounts Manager"
+ },
+ {
+ "role": "Accounts User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/pos_register/pos_register.py b/erpnext/accounts/report/pos_register/pos_register.py
new file mode 100644
index 0000000..52f7fe2
--- /dev/null
+++ b/erpnext/accounts/report/pos_register/pos_register.py
@@ -0,0 +1,223 @@
+# 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 _, _dict
+from erpnext import get_company_currency, get_default_company
+from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
+
+def execute(filters=None):
+ if not filters:
+ return [], []
+
+ validate_filters(filters)
+
+ columns = get_columns(filters)
+
+ group_by_field = get_group_by_field(filters.get("group_by"))
+
+ pos_entries = get_pos_entries(filters, group_by_field)
+ if group_by_field != "mode_of_payment":
+ concat_mode_of_payments(pos_entries)
+
+ # return only entries if group by is unselected
+ if not group_by_field:
+ return columns, pos_entries
+
+ # handle grouping
+ invoice_map, grouped_data = {}, []
+ for d in pos_entries:
+ invoice_map.setdefault(d[group_by_field], []).append(d)
+
+ for key in invoice_map:
+ invoices = invoice_map[key]
+ grouped_data += invoices
+ add_subtotal_row(grouped_data, invoices, group_by_field, key)
+
+ # move group by column to first position
+ column_index = next((index for (index, d) in enumerate(columns) if d["fieldname"] == group_by_field), None)
+ columns.insert(0, columns.pop(column_index))
+
+ return columns, grouped_data
+
+def get_pos_entries(filters, group_by_field):
+ conditions = get_conditions(filters)
+ order_by = "p.posting_date"
+ select_mop_field, from_sales_invoice_payment, group_by_mop_condition = "", "", ""
+ if group_by_field == "mode_of_payment":
+ select_mop_field = ", sip.mode_of_payment"
+ from_sales_invoice_payment = ", `tabSales Invoice Payment` sip"
+ group_by_mop_condition = "sip.parent = p.name AND ifnull(sip.base_amount, 0) != 0 AND"
+ order_by += ", sip.mode_of_payment"
+
+ elif group_by_field:
+ order_by += ", p.{}".format(group_by_field)
+
+ return frappe.db.sql(
+ """
+ SELECT
+ p.posting_date, p.name as pos_invoice, p.pos_profile,
+ p.owner, p.base_grand_total as grand_total, p.base_paid_amount as paid_amount,
+ p.customer, p.is_return {select_mop_field}
+ FROM
+ `tabPOS Invoice` p {from_sales_invoice_payment}
+ WHERE
+ p.docstatus = 1 and
+ {group_by_mop_condition}
+ {conditions}
+ ORDER BY
+ {order_by}
+ """.format(
+ select_mop_field=select_mop_field,
+ from_sales_invoice_payment=from_sales_invoice_payment,
+ group_by_mop_condition=group_by_mop_condition,
+ conditions=conditions,
+ order_by=order_by
+ ), filters, as_dict=1)
+
+def concat_mode_of_payments(pos_entries):
+ mode_of_payments = get_mode_of_payments(set([d.pos_invoice for d in pos_entries]))
+ for entry in pos_entries:
+ if mode_of_payments.get(entry.pos_invoice):
+ entry.mode_of_payment = ", ".join(mode_of_payments.get(entry.pos_invoice, []))
+
+def add_subtotal_row(data, group_invoices, group_by_field, group_by_value):
+ grand_total = sum([d.grand_total for d in group_invoices])
+ paid_amount = sum([d.paid_amount for d in group_invoices])
+ data.append({
+ group_by_field: group_by_value,
+ "grand_total": grand_total,
+ "paid_amount": paid_amount,
+ "bold": 1
+ })
+ data.append({})
+
+def validate_filters(filters):
+ if not filters.get("company"):
+ frappe.throw(_("{0} is mandatory").format(_("Company")))
+
+ if not filters.get("from_date") and not filters.get("to_date"):
+ frappe.throw(_("{0} and {1} are mandatory").format(frappe.bold(_("From Date")), frappe.bold(_("To Date"))))
+
+ if filters.from_date > filters.to_date:
+ frappe.throw(_("From Date must be before To Date"))
+
+ if (filters.get("pos_profile") and filters.get("group_by") == _('POS Profile')):
+ frappe.throw(_("Can not filter based on POS Profile, if grouped by POS Profile"))
+
+ if (filters.get("customer") and filters.get("group_by") == _('Customer')):
+ frappe.throw(_("Can not filter based on Customer, if grouped by Customer"))
+
+ if (filters.get("owner") and filters.get("group_by") == _('Cashier')):
+ frappe.throw(_("Can not filter based on Cashier, if grouped by Cashier"))
+
+ if (filters.get("mode_of_payment") and filters.get("group_by") == _('Payment Method')):
+ frappe.throw(_("Can not filter based on Payment Method, if grouped by Payment Method"))
+
+def get_conditions(filters):
+ conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s".format(
+ company=filters.get("company"),
+ from_date=filters.get("from_date"),
+ to_date=filters.get("to_date"))
+
+ if filters.get("pos_profile"):
+ conditions += " AND pos_profile = %(pos_profile)s".format(pos_profile=filters.get("pos_profile"))
+
+ if filters.get("owner"):
+ conditions += " AND owner = %(owner)s".format(owner=filters.get("owner"))
+
+ if filters.get("customer"):
+ conditions += " AND customer = %(customer)s".format(customer=filters.get("customer"))
+
+ if filters.get("is_return"):
+ conditions += " AND is_return = %(is_return)s".format(is_return=filters.get("is_return"))
+
+ if filters.get("mode_of_payment"):
+ conditions += """
+ AND EXISTS(
+ SELECT name FROM `tabSales Invoice Payment` sip
+ WHERE parent=p.name AND ifnull(sip.mode_of_payment, '') = %(mode_of_payment)s
+ )"""
+
+ return conditions
+
+def get_group_by_field(group_by):
+ group_by_field = ""
+
+ if group_by == "POS Profile":
+ group_by_field = "pos_profile"
+ elif group_by == "Cashier":
+ group_by_field = "owner"
+ elif group_by == "Customer":
+ group_by_field = "customer"
+ elif group_by == "Payment Method":
+ group_by_field = "mode_of_payment"
+
+ return group_by_field
+
+def get_columns(filters):
+ columns = [
+ {
+ "label": _("Posting Date"),
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "width": 90
+ },
+ {
+ "label": _("POS Invoice"),
+ "fieldname": "pos_invoice",
+ "fieldtype": "Link",
+ "options": "POS Invoice",
+ "width": 120
+ },
+ {
+ "label": _("Customer"),
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "options": "Customer",
+ "width": 120
+ },
+ {
+ "label": _("POS Profile"),
+ "fieldname": "pos_profile",
+ "fieldtype": "Link",
+ "options": "POS Profile",
+ "width": 160
+ },
+ {
+ "label": _("Cashier"),
+ "fieldname": "owner",
+ "fieldtype": "Link",
+ "options": "User",
+ "width": 140
+ },
+ {
+ "label": _("Grand Total"),
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "options": "company:currency",
+ "width": 120
+ },
+ {
+ "label": _("Paid Amount"),
+ "fieldname": "paid_amount",
+ "fieldtype": "Currency",
+ "options": "company:currency",
+ "width": 120
+ },
+ {
+ "label": _("Payment Method"),
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Data",
+ "width": 150
+ },
+ {
+ "label": _("Is Return"),
+ "fieldname": "is_return",
+ "fieldtype": "Data",
+ "width": 80
+ },
+ ]
+
+ return columns
\ No newline at end of file
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 b34d037..fe261b3 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
@@ -60,23 +60,25 @@
return [
{
- "value": net_profit,
- "indicator": "Green" if net_profit > 0 else "Red",
- "label": profit_label,
- "datatype": "Currency",
- "currency": currency
- },
- {
"value": net_income,
"label": income_label,
"datatype": "Currency",
"currency": currency
},
+ { "type": "separator", "value": "-"},
{
"value": net_expense,
"label": expense_label,
"datatype": "Currency",
"currency": currency
+ },
+ { "type": "separator", "value": "=", "color": "blue"},
+ {
+ "value": net_profit,
+ "indicator": "Green" if net_profit > 0 else "Red",
+ "label": profit_label,
+ "datatype": "Currency",
+ "currency": currency
}
]
diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py
index 9399e70..8ac749d 100644
--- a/erpnext/accounts/report/purchase_register/purchase_register.py
+++ b/erpnext/accounts/report/purchase_register/purchase_register.py
@@ -14,13 +14,15 @@
if not filters: filters = {}
invoice_list = get_invoices(filters, additional_query_columns)
- columns, expense_accounts, tax_accounts = get_columns(invoice_list, additional_table_columns)
+ columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts \
+ = get_columns(invoice_list, additional_table_columns)
if not invoice_list:
msgprint(_("No record found"))
return columns, invoice_list
invoice_expense_map = get_invoice_expense_map(invoice_list)
+ internal_invoice_map = get_internal_invoice_map(invoice_list)
invoice_expense_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
invoice_expense_map, expense_accounts)
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
@@ -52,10 +54,17 @@
# map expense values
base_net_total = 0
for expense_acc in expense_accounts:
- expense_amount = flt(invoice_expense_map.get(inv.name, {}).get(expense_acc))
+ if inv.is_internal_supplier and inv.company == inv.represents_company:
+ expense_amount = 0
+ else:
+ expense_amount = flt(invoice_expense_map.get(inv.name, {}).get(expense_acc))
base_net_total += expense_amount
row.append(expense_amount)
+ # Add amount in unrealized account
+ for account in unrealized_profit_loss_accounts:
+ row.append(flt(internal_invoice_map.get((inv.name, account))))
+
# net total
row.append(base_net_total or inv.base_net_total)
@@ -96,7 +105,8 @@
"width": 80
}
]
- expense_accounts = tax_accounts = expense_columns = tax_columns = []
+ expense_accounts = tax_accounts = expense_columns = tax_columns = unrealized_profit_loss_accounts = \
+ unrealized_profit_loss_account_columns = []
if invoice_list:
expense_accounts = frappe.db.sql_list("""select distinct expense_account
@@ -112,17 +122,25 @@
and parent in (%s) order by account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
+ unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
+ from `tabPurchase Invoice` where docstatus = 1 and name in (%s)
+ and ifnull(unrealized_profit_loss_account, '') != ''
+ order by unrealized_profit_loss_account""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
expense_columns = [(account + ":Currency/currency:120") for account in expense_accounts]
+ unrealized_profit_loss_account_columns = [(account + ":Currency/currency:120") for account in unrealized_profit_loss_accounts]
+
for account in tax_accounts:
if account not in expense_accounts:
tax_columns.append(account + ":Currency/currency:120")
- columns = columns + expense_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
+ columns = columns + expense_columns + unrealized_profit_loss_account_columns + \
+ [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
[_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
_("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
- return columns, expense_accounts, tax_accounts
+ return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts
def get_conditions(filters):
conditions = ""
@@ -199,6 +217,19 @@
return invoice_expense_map
+def get_internal_invoice_map(invoice_list):
+ unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
+ base_net_total as amount from `tabPurchase Invoice` where name in (%s)
+ and is_internal_supplier = 1 and company = represents_company""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
+
+ internal_invoice_map = {}
+ for d in unrealized_amount_details:
+ if d.unrealized_profit_loss_account:
+ internal_invoice_map.setdefault((d.name, d.unrealized_profit_loss_account), d.amount)
+
+ return internal_invoice_map
+
def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts):
tax_details = frappe.db.sql("""
select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount_after_discount_amount)
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 5e8d773..e9e9c9c 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
@@ -14,11 +14,93 @@
def get_column():
return [
- _("Purchase Receipt") + ":Link/Purchase Receipt:120", _("Status") + "::120", _("Date") + ":Date:100",
- _("Supplier") + ":Link/Supplier:120", _("Supplier Name") + "::120",
- _("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
- _("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
- _("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
+ {
+ "label": _("Purchase Receipt"),
+ "fieldname": "name",
+ "fieldtype": "Link",
+ "options": "Purchase Receipt",
+ "width": 160
+ },
+ {
+ "label": _("Date"),
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "label": _("Supplier"),
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "options": "Supplier",
+ "width": 120
+ },
+ {
+ "label": _("Supplier Name"),
+ "fieldname": "supplier_name",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "label": _("Item Code"),
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "options": "Item",
+ "width": 120
+ },
+ {
+ "label": _("Amount"),
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "width": 100,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Billed Amount"),
+ "fieldname": "billed_amount",
+ "fieldtype": "Currency",
+ "width": 100,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Returned Amount"),
+ "fieldname": "returned_amount",
+ "fieldtype": "Currency",
+ "width": 120,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Pending Amount"),
+ "fieldname": "pending_amount",
+ "fieldtype": "Currency",
+ "width": 120,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "label": _("Item Name"),
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "label": _("Description"),
+ "fieldname": "description",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "label": _("Project"),
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "options": "Project",
+ "width": 120
+ },
+ {
+ "label": _("Company"),
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "options": "Company",
+ "width": 120
+ }
]
def get_args():
diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py
index b6e61b1..cb2c98b 100644
--- a/erpnext/accounts/report/sales_register/sales_register.py
+++ b/erpnext/accounts/report/sales_register/sales_register.py
@@ -15,13 +15,14 @@
if not filters: filters = frappe._dict({})
invoice_list = get_invoices(filters, additional_query_columns)
- columns, income_accounts, tax_accounts = get_columns(invoice_list, additional_table_columns)
+ columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns(invoice_list, additional_table_columns)
if not invoice_list:
msgprint(_("No record found"))
return columns, invoice_list
invoice_income_map = get_invoice_income_map(invoice_list)
+ internal_invoice_map = get_internal_invoice_map(invoice_list)
invoice_income_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
invoice_income_map, income_accounts)
#Cost Center & Warehouse Map
@@ -70,12 +71,22 @@
# map income values
base_net_total = 0
for income_acc in income_accounts:
- income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
+ if inv.is_internal_customer and inv.company == inv.represents_company:
+ income_amount = 0
+ else:
+ income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
+
base_net_total += income_amount
row.update({
frappe.scrub(income_acc): income_amount
})
+ # Add amount in unrealized account
+ for account in unrealized_profit_loss_accounts:
+ row.update({
+ frappe.scrub(account): flt(internal_invoice_map.get((inv.name, account)))
+ })
+
# net total
row.update({'net_total': base_net_total or inv.base_net_total})
@@ -230,6 +241,8 @@
tax_accounts = []
income_columns = []
tax_columns = []
+ unrealized_profit_loss_accounts = []
+ unrealized_profit_loss_account_columns = []
if invoice_list:
income_accounts = frappe.db.sql_list("""select distinct income_account
@@ -243,12 +256,18 @@
and parent in (%s) order by account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
+ unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
+ from `tabSales Invoice` where docstatus = 1 and name in (%s)
+ and ifnull(unrealized_profit_loss_account, '') != ''
+ order by unrealized_profit_loss_account""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
+
for account in income_accounts:
income_columns.append({
"label": account,
"fieldname": frappe.scrub(account),
"fieldtype": "Currency",
- "options": 'currency',
+ "options": "currency",
"width": 120
})
@@ -258,15 +277,24 @@
"label": account,
"fieldname": frappe.scrub(account),
"fieldtype": "Currency",
- "options": 'currency',
+ "options": "currency",
"width": 120
})
+ for account in unrealized_profit_loss_accounts:
+ unrealized_profit_loss_account_columns.append({
+ "label": account,
+ "fieldname": frappe.scrub(account),
+ "fieldtype": "Currency",
+ "options": "currency",
+ "width": 120
+ })
+
net_total_column = [{
"label": _("Net Total"),
"fieldname": "net_total",
"fieldtype": "Currency",
- "options": 'currency',
+ "options": "currency",
"width": 120
}]
@@ -301,9 +329,10 @@
}
]
- columns = columns + income_columns + net_total_column + tax_columns + total_columns
+ columns = columns + income_columns + unrealized_profit_loss_account_columns + \
+ net_total_column + tax_columns + total_columns
- return columns, income_accounts, tax_accounts
+ return columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts
def get_conditions(filters):
conditions = ""
@@ -368,7 +397,8 @@
return frappe.db.sql("""
select name, posting_date, debit_to, project, customer,
customer_name, owner, remarks, territory, tax_id, customer_group,
- base_net_total, base_grand_total, base_rounded_total, outstanding_amount {0}
+ base_net_total, base_grand_total, base_rounded_total, outstanding_amount,
+ is_internal_customer, represents_company, company {0}
from `tabSales Invoice`
where docstatus = 1 %s order by posting_date desc, name desc""".format(additional_query_columns or '') %
conditions, filters, as_dict=1)
@@ -385,6 +415,19 @@
return invoice_income_map
+def get_internal_invoice_map(invoice_list):
+ unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
+ base_net_total as amount from `tabSales Invoice` where name in (%s)
+ and is_internal_customer = 1 and company = represents_company""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
+
+ internal_invoice_map = {}
+ for d in unrealized_amount_details:
+ if d.unrealized_profit_loss_account:
+ internal_invoice_map.setdefault((d.name, d.unrealized_profit_loss_account), d.amount)
+
+ return internal_invoice_map
+
def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts):
tax_details = frappe.db.sql("""select parent, account_head,
sum(base_tax_amount_after_discount_amount) as tax_amount
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 c7cfee7..a8280c1 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
@@ -55,7 +55,7 @@
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.company, filters.from_date, filters.to_date, filters.fiscal_year)
if total_invoiced_amount or tds_deducted:
row = [supplier.pan, supplier.name]
@@ -68,7 +68,7 @@
return out
-def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date):
+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("""
@@ -94,7 +94,9 @@
""".format(', '.join(["'%s'" % d for d in vouchers])),
(account, from_date, to_date, company))[0][0])
- debit_note_amount = get_debit_note_amount([supplier], from_date, to_date, company=company)
+ 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
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 008f6e8..89a05b1 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -12,11 +12,12 @@
from six import iteritems
# imported to enable erpnext.accounts.utils.get_account_currency
from erpnext.accounts.doctype.account.account import get_account_currency
+from frappe.model.meta import get_field_precision
from erpnext.stock.utils import get_stock_value_on
from erpnext.stock import get_warehouse_account_map
-
+class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
class FiscalYearError(frappe.ValidationError): pass
@frappe.whitelist()
@@ -78,7 +79,10 @@
else:
return ((fy.name, fy.year_start_date, fy.year_end_date),)
- error_msg = _("""{0} {1} not in any active Fiscal Year.""").format(label, formatdate(transaction_date))
+ error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date))
+ if company:
+ error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company))
+
if verbose==1: frappe.msgprint(error_msg)
raise FiscalYearError(error_msg)
@@ -582,24 +586,6 @@
(dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
(d.diff, d.voucher_type, d.voucher_no))
-def get_stock_and_account_balance(account=None, posting_date=None, company=None):
- if not posting_date: posting_date = nowdate()
-
- warehouse_account = get_warehouse_account_map(company)
-
- account_balance = get_balance_on(account, posting_date, in_account_currency=False, ignore_account_permission=True)
-
- related_warehouses = [wh for wh, wh_details in warehouse_account.items()
- if wh_details.account == account and not wh_details.is_group]
-
- total_stock_value = 0.0
- for warehouse in related_warehouses:
- value = get_stock_value_on(warehouse, posting_date)
- total_stock_value += value
-
- precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
- return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses
-
def get_currency_precision():
precision = cint(frappe.db.get_default("currency_precision"))
if not precision:
@@ -796,7 +782,7 @@
return acc
-def create_payment_gateway_account(gateway):
+def create_payment_gateway_account(gateway, payment_channel="Email"):
from erpnext.setup.setup_wizard.operations.company_setup import create_bank_account
company = frappe.db.get_value("Global Defaults", None, "default_company")
@@ -831,7 +817,8 @@
"is_default": 1,
"payment_gateway": gateway,
"payment_account": bank_account.name,
- "currency": bank_account.account_currency
+ "currency": bank_account.account_currency,
+ "payment_channel": payment_channel
}).insert(ignore_permissions=True)
except frappe.DuplicateEntryError:
@@ -899,14 +886,13 @@
return accounts
-def get_stock_accounts(company):
- return frappe.get_all("Account", filters = {
- "account_type": "Stock",
- "company": company
- })
-
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None, company=None):
+ stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items, company)
+ repost_gle_for_stock_vouchers(stock_vouchers, posting_date, company, warehouse_account)
+
+
+def repost_gle_for_stock_vouchers(stock_vouchers, posting_date, company=None, warehouse_account=None):
def _delete_gl_entries(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
@@ -914,21 +900,21 @@
if not warehouse_account:
warehouse_account = get_warehouse_account_map(company)
- future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
- gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
+ precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit")) or 2
- for voucher_type, voucher_no in future_stock_vouchers:
+ gle = get_voucherwise_gl_entries(stock_vouchers, posting_date)
+ for voucher_type, voucher_no in stock_vouchers:
existing_gle = gle.get((voucher_type, voucher_no), [])
- voucher_obj = frappe.get_doc(voucher_type, voucher_no)
+ voucher_obj = frappe.get_cached_doc(voucher_type, voucher_no)
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
if expected_gle:
- if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle):
+ if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
_delete_gl_entries(voucher_type, voucher_no)
- voucher_obj.make_gl_entries(gl_entries=expected_gle, repost_future_gle=False, from_repost=True)
+ voucher_obj.make_gl_entries(gl_entries=expected_gle, from_repost=True)
else:
_delete_gl_entries(voucher_type, voucher_no)
-def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
+def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None, company=None):
future_stock_vouchers = []
values = []
@@ -941,9 +927,16 @@
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
values += for_warehouses
+ if company:
+ condition += " and company = %s"
+ values.append(company)
+
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
from `tabStock Ledger Entry` sle
- where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
+ where
+ timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s)
+ and is_cancelled = 0
+ {condition}
order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
tuple([posting_date, posting_time] + values), as_dict=True):
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
@@ -960,3 +953,107 @@
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
return gl_entries
+
+def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
+ matched = True
+ for entry in expected_gle:
+ account_existed = False
+ for e in existing_gle:
+ if entry.account == e.account:
+ account_existed = True
+ if (entry.account == e.account and entry.against_account == e.against_account
+ and (not entry.cost_center or not e.cost_center or entry.cost_center == e.cost_center)
+ and ( flt(entry.debit, precision) != flt(e.debit, precision) or
+ flt(entry.credit, precision) != flt(e.credit, precision))):
+ matched = False
+ break
+ if not account_existed:
+ matched = False
+ break
+ return matched
+
+def check_if_stock_and_account_balance_synced(posting_date, company, voucher_type=None, voucher_no=None):
+ if not cint(erpnext.is_perpetual_inventory_enabled(company)):
+ return
+
+ accounts = get_stock_accounts(company, voucher_type, voucher_no)
+ stock_adjustment_account = frappe.db.get_value("Company", company, "stock_adjustment_account")
+
+ for account in accounts:
+ account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
+ posting_date, company)
+
+ if abs(account_bal - stock_bal) > 0.1:
+ precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
+ currency=frappe.get_cached_value('Company', company, "default_currency"))
+
+ diff = flt(stock_bal - account_bal, precision)
+
+ error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses as on {3}.").format(
+ stock_bal, account_bal, frappe.bold(account), posting_date)
+ error_resolution = _("Please create an adjustment Journal Entry for amount {0} on {1}")\
+ .format(frappe.bold(diff), frappe.bold(posting_date))
+
+ frappe.msgprint(
+ msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
+ raise_exception=StockValueAndAccountBalanceOutOfSync,
+ title=_('Values Out Of Sync'),
+ primary_action={
+ 'label': _('Make Journal Entry'),
+ 'client_action': 'erpnext.route_to_adjustment_jv',
+ 'args': get_journal_entry(account, stock_adjustment_account, diff)
+ })
+
+def get_stock_accounts(company, voucher_type=None, voucher_no=None):
+ stock_accounts = [d.name for d in frappe.db.get_all("Account", {
+ "account_type": "Stock",
+ "company": company,
+ "is_group": 0
+ })]
+ if voucher_type and voucher_no:
+ if voucher_type == "Journal Entry":
+ stock_accounts = [d.account for d in frappe.db.get_all("Journal Entry Account", {
+ "parent": voucher_no,
+ "account": ["in", stock_accounts]
+ }, "account")]
+
+ else:
+ stock_accounts = [d.account for d in frappe.db.get_all("GL Entry", {
+ "voucher_type": voucher_type,
+ "voucher_no": voucher_no,
+ "account": ["in", stock_accounts]
+ }, "account")]
+
+ return stock_accounts
+
+def get_stock_and_account_balance(account=None, posting_date=None, company=None):
+ if not posting_date: posting_date = nowdate()
+
+ warehouse_account = get_warehouse_account_map(company)
+
+ account_balance = get_balance_on(account, posting_date, in_account_currency=False, ignore_account_permission=True)
+
+ related_warehouses = [wh for wh, wh_details in warehouse_account.items()
+ if wh_details.account == account and not wh_details.is_group]
+
+ total_stock_value = 0.0
+ for warehouse in related_warehouses:
+ value = get_stock_value_on(warehouse, posting_date)
+ total_stock_value += value
+
+ precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
+ return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses
+
+def get_journal_entry(account, stock_adjustment_account, amount):
+ db_or_cr_warehouse_account =('credit_in_account_currency' if amount < 0 else 'debit_in_account_currency')
+ db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if amount < 0 else 'credit_in_account_currency')
+
+ return {
+ 'accounts':[{
+ 'account': account,
+ db_or_cr_warehouse_account: abs(amount)
+ }, {
+ 'account': stock_adjustment_account,
+ db_or_cr_stock_adjustment_account : abs(amount)
+ }]
+ }
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
new file mode 100644
index 0000000..fadb665
--- /dev/null
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -0,0 +1,1119 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Profit and Loss",
+ "label": "Profit and Loss"
+ }
+ ],
+ "creation": "2020-03-02 15:41:59.515192",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "accounting",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Accounting",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounting Masters",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Company",
+ "link_to": "Company",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chart of Accounts",
+ "link_to": "Account",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounts Settings",
+ "link_to": "Accounts Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fiscal Year",
+ "link_to": "Fiscal Year",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounting Dimension",
+ "link_to": "Accounting Dimension",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Finance Book",
+ "link_to": "Finance Book",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounting Period",
+ "link_to": "Accounting Period",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payment Term",
+ "link_to": "Payment Term",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "General Ledger",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Journal Entry",
+ "link_to": "Journal Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Journal Entry Template",
+ "link_to": "Journal Entry Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "General Ledger",
+ "link_to": "General Ledger",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Ledger Summary",
+ "link_to": "Customer Ledger Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Supplier Ledger Summary",
+ "link_to": "Supplier Ledger Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounts Receivable",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Invoice",
+ "link_to": "Sales Invoice",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer",
+ "link_to": "Customer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payment Entry",
+ "link_to": "Payment Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payment Request",
+ "link_to": "Payment Request",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Accounts Receivable",
+ "link_to": "Accounts Receivable",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Accounts Receivable Summary",
+ "link_to": "Accounts Receivable Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Register",
+ "link_to": "Sales Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item-wise Sales Register",
+ "link_to": "Item-wise Sales Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Order Analysis",
+ "link_to": "Sales Order Analysis",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Delivered Items To Be Billed",
+ "link_to": "Delivered Items To Be Billed",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounts Payable",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Purchase Invoice",
+ "link_to": "Purchase Invoice",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier",
+ "link_to": "Supplier",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payment Entry",
+ "link_to": "Payment Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Accounts Payable",
+ "link_to": "Accounts Payable",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Accounts Payable Summary",
+ "link_to": "Accounts Payable Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Register",
+ "link_to": "Purchase Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item-wise Purchase Register",
+ "link_to": "Item-wise Purchase Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Order Analysis",
+ "link_to": "Purchase Order Analysis",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Received Items To Be Billed",
+ "link_to": "Received Items To Be Billed",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Trial Balance for Party",
+ "link_to": "Trial Balance for Party",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Journal Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Payment Period Based On Invoice Date",
+ "link_to": "Payment Period Based On Invoice Date",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Partners Commission",
+ "link_to": "Sales Partners Commission",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Credit Balance",
+ "link_to": "Customer Credit Balance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Payment Summary",
+ "link_to": "Sales Payment Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Address",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Address And Contacts",
+ "link_to": "Address And Contacts",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "DATEV Export",
+ "link_to": "DATEV",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Financial Statements",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Trial Balance",
+ "link_to": "Trial Balance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Profit and Loss Statement",
+ "link_to": "Profit and Loss Statement",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Balance Sheet",
+ "link_to": "Balance Sheet",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Cash Flow",
+ "link_to": "Cash Flow",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Consolidated Financial Statement",
+ "link_to": "Consolidated Financial Statement",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Multi Currency",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Currency",
+ "link_to": "Currency",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Currency Exchange",
+ "link_to": "Currency Exchange",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Exchange Rate Revaluation",
+ "link_to": "Exchange Rate Revaluation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payment Gateway Account",
+ "link_to": "Payment Gateway Account",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Terms and Conditions Template",
+ "link_to": "Terms and Conditions",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Mode of Payment",
+ "link_to": "Mode of Payment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank Statement",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank",
+ "link_to": "Bank",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank Account",
+ "link_to": "Bank Account",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank Clearance",
+ "link_to": "Bank Clearance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank Reconciliation",
+ "link_to": "bank-reconciliation",
+ "link_type": "Page",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Bank Reconciliation Statement",
+ "link_to": "Bank Reconciliation Statement",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank Statement Transaction Entry",
+ "link_to": "Bank Statement Transaction Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bank Statement Settings",
+ "link_to": "Bank Statement Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Subscription Management",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Subscription Plan",
+ "link_to": "Subscription Plan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Subscription",
+ "link_to": "Subscription",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Subscription Settings",
+ "link_to": "Subscription Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Goods and Services Tax (GST India)",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "GST Settings",
+ "link_to": "GST Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "GST HSN Code",
+ "link_to": "GST HSN Code",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "GSTR-1",
+ "link_to": "GSTR-1",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "GSTR-2",
+ "link_to": "GSTR-2",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "GSTR 3B Report",
+ "link_to": "GSTR 3B Report",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "GST Sales Register",
+ "link_to": "GST Sales Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "GST Purchase Register",
+ "link_to": "GST Purchase Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "GST Itemised Sales Register",
+ "link_to": "GST Itemised Sales Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "GST Itemised Purchase Register",
+ "link_to": "GST Itemised Purchase Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "C-Form",
+ "link_to": "C-Form",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lower Deduction Certificate",
+ "link_to": "Lower Deduction Certificate",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Share Management",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shareholder",
+ "link_to": "Shareholder",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Share Transfer",
+ "link_to": "Share Transfer",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Share Transfer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Share Ledger",
+ "link_to": "Share Ledger",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Share Transfer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Share Balance",
+ "link_to": "Share Balance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Cost Center and Budgeting",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chart of Cost Centers",
+ "link_to": "Cost Center",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Budget",
+ "link_to": "Budget",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounting Dimension",
+ "link_to": "Accounting Dimension",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Cost Center",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Budget Variance Report",
+ "link_to": "Budget Variance Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Monthly Distribution",
+ "link_to": "Monthly Distribution",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Opening and Closing",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Opening Invoice Creation Tool",
+ "link_to": "Opening Invoice Creation Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chart of Accounts Importer",
+ "link_to": "Chart of Accounts Importer",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Period Closing Voucher",
+ "link_to": "Period Closing Voucher",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Taxes",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Taxes and Charges Template",
+ "link_to": "Sales Taxes and Charges Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Purchase Taxes and Charges Template",
+ "link_to": "Purchase Taxes and Charges Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Tax Template",
+ "link_to": "Item Tax Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tax Category",
+ "link_to": "Tax Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tax Rule",
+ "link_to": "Tax Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tax Withholding Category",
+ "link_to": "Tax Withholding Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Profitability",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Gross Profit",
+ "link_to": "Gross Profit",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Profitability Analysis",
+ "link_to": "Profitability Analysis",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Invoice Trends",
+ "link_to": "Sales Invoice Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Invoice Trends",
+ "link_to": "Purchase Invoice Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2021-03-04 00:38:35.349024",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Accounting",
+ "onboarding": "Accounts",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "label": "Chart of Accounts",
+ "link_to": "Account",
+ "type": "DocType"
+ },
+ {
+ "label": "Sales Invoice",
+ "link_to": "Sales Invoice",
+ "type": "DocType"
+ },
+ {
+ "label": "Purchase Invoice",
+ "link_to": "Purchase Invoice",
+ "type": "DocType"
+ },
+ {
+ "label": "Journal Entry",
+ "link_to": "Journal Entry",
+ "type": "DocType"
+ },
+ {
+ "label": "Payment Entry",
+ "link_to": "Payment Entry",
+ "type": "DocType"
+ },
+ {
+ "label": "Accounts Receivable",
+ "link_to": "Accounts Receivable",
+ "type": "Report"
+ },
+ {
+ "label": "General Ledger",
+ "link_to": "General Ledger",
+ "type": "Report"
+ },
+ {
+ "label": "Trial Balance",
+ "link_to": "Trial Balance",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Accounts",
+ "type": "Dashboard"
+ }
+ ]
+}
diff --git a/erpnext/agriculture/desk_page/agriculture/agriculture.json b/erpnext/agriculture/desk_page/agriculture/agriculture.json
deleted file mode 100644
index e0d2c9c..0000000
--- a/erpnext/agriculture/desk_page/agriculture/agriculture.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Crops & Lands",
- "links": "[\n {\n \"label\": \"Crop\",\n \"name\": \"Crop\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Crop Cycle\",\n \"name\": \"Crop Cycle\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Analytics",
- "links": "[\n {\n \"label\": \"Plant Analysis\",\n \"name\": \"Plant Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Soil Analysis\",\n \"name\": \"Soil Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Water Analysis\",\n \"name\": \"Water Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Soil Texture\",\n \"name\": \"Soil Texture\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Weather\",\n \"name\": \"Weather\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Agriculture Analysis Criteria\",\n \"name\": \"Agriculture Analysis Criteria\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Diseases & Fertilizers",
- "links": "[\n {\n \"label\": \"Disease\",\n \"name\": \"Disease\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fertilizer\",\n \"name\": \"Fertilizer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Domains",
- "charts": [],
- "creation": "2020-03-02 17:23:34.339274",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends_another_page": 0,
- "idx": 0,
- "is_standard": 1,
- "label": "Agriculture",
- "modified": "2020-04-01 11:28:51.032822",
- "modified_by": "Administrator",
- "module": "Agriculture",
- "name": "Agriculture",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "restrict_to_domain": "Agriculture",
- "shortcuts": []
-}
\ No newline at end of file
diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py
index cae150c..afbd9b4 100644
--- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py
+++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py
@@ -48,7 +48,7 @@
def import_disease_tasks(self, disease, start_date):
disease_doc = frappe.get_doc('Disease', disease)
- self.create_task(disease_doc.treatment_task, self.name, start_date)
+ self.create_task(disease_doc.treatment_task, self.project, start_date)
def create_project(self, period, crop_tasks):
project = frappe.get_doc({
diff --git a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py
index 5510d5a..763b403 100644
--- a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py
+++ b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py
@@ -71,4 +71,4 @@
def check_project_creation():
- return True if frappe.db.exists('Project', 'Basil from seed 2017') else False
+ return True if frappe.db.exists('Project', {'project_name': 'Basil from seed 2017'}) else False
diff --git a/erpnext/agriculture/workspace/agriculture/agriculture.json b/erpnext/agriculture/workspace/agriculture/agriculture.json
new file mode 100644
index 0000000..2cc2524
--- /dev/null
+++ b/erpnext/agriculture/workspace/agriculture/agriculture.json
@@ -0,0 +1,157 @@
+{
+ "category": "Domains",
+ "charts": [],
+ "creation": "2020-03-02 17:23:34.339274",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "agriculture",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Agriculture",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Crops & Lands",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Crop",
+ "link_to": "Crop",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Crop Cycle",
+ "link_to": "Crop Cycle",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Location",
+ "link_to": "Location",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Analytics",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Plant Analysis",
+ "link_to": "Plant Analysis",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Soil Analysis",
+ "link_to": "Soil Analysis",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Water Analysis",
+ "link_to": "Water Analysis",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Soil Texture",
+ "link_to": "Soil Texture",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Weather",
+ "link_to": "Weather",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Agriculture Analysis Criteria",
+ "link_to": "Agriculture Analysis Criteria",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Diseases & Fertilizers",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Disease",
+ "link_to": "Disease",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fertilizer",
+ "link_to": "Fertilizer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:38.477493",
+ "modified_by": "Administrator",
+ "module": "Agriculture",
+ "name": "Agriculture",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "restrict_to_domain": "Agriculture",
+ "shortcuts": []
+}
\ No newline at end of file
diff --git a/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json b/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json
index bc2edc9..94debf1 100644
--- a/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json
+++ b/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json
@@ -9,9 +9,9 @@
"filters_json": "{\"status\":\"In Location\",\"filter_based_on\":\"Fiscal Year\",\"period_start_date\":\"2020-04-01\",\"period_end_date\":\"2021-03-31\",\"date_based_on\":\"Purchase Date\",\"group_by\":\"--Select a group--\"}",
"group_by_type": "Count",
"idx": 0,
- "is_public": 0,
+ "is_public": 1,
"is_standard": 1,
- "modified": "2020-07-23 13:53:33.211371",
+ "modified": "2020-10-28 23:15:58.432189",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Value Analytics",
diff --git a/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json b/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json
index e79d2d7..78611da 100644
--- a/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json
+++ b/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json
@@ -8,9 +8,9 @@
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}",
"filters_json": "{\"status\":\"In Location\",\"group_by\":\"Asset Category\",\"is_existing_asset\":0}",
"idx": 0,
- "is_public": 0,
+ "is_public": 1,
"is_standard": 1,
- "modified": "2020-07-23 13:39:32.429240",
+ "modified": "2020-10-28 23:16:16.939070",
"modified_by": "Administrator",
"module": "Assets",
"name": "Category-wise Asset Value",
diff --git a/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json b/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json
index 481586e..848184c 100644
--- a/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json
+++ b/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json
@@ -8,9 +8,9 @@
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}",
"filters_json": "{\"status\":\"In Location\",\"group_by\":\"Location\",\"is_existing_asset\":0}",
"idx": 0,
- "is_public": 0,
+ "is_public": 1,
"is_standard": 1,
- "modified": "2020-07-23 13:42:44.912551",
+ "modified": "2020-10-28 23:16:07.883312",
"modified_by": "Administrator",
"module": "Assets",
"name": "Location-wise Asset Value",
diff --git a/erpnext/assets/desk_page/assets/assets.json b/erpnext/assets/desk_page/assets/assets.json
deleted file mode 100644
index 449a5fa..0000000
--- a/erpnext/assets/desk_page/assets/assets.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Assets",
- "links": "[\n {\n \"label\": \"Asset\",\n \"name\": \"Asset\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Asset Category\",\n \"name\": \"Asset Category\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Transfer an asset from one warehouse to another\",\n \"label\": \"Asset Movement\",\n \"name\": \"Asset Movement\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Maintenance",
- "links": "[\n {\n \"label\": \"Asset Maintenance Team\",\n \"name\": \"Asset Maintenance Team\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance Team\"\n ],\n \"label\": \"Asset Maintenance\",\n \"name\": \"Asset Maintenance\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance\"\n ],\n \"label\": \"Asset Maintenance Log\",\n \"name\": \"Asset Maintenance Log\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"label\": \"Asset Value Adjustment\",\n \"name\": \"Asset Value Adjustment\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"label\": \"Asset Repair\",\n \"name\": \"Asset Repair\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"doctype\": \"Asset\",\n \"is_query_report\": true,\n \"label\": \"Asset Depreciation Ledger\",\n \"name\": \"Asset Depreciation Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"doctype\": \"Asset\",\n \"is_query_report\": true,\n \"label\": \"Asset Depreciations and Balances\",\n \"name\": \"Asset Depreciations and Balances\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance\"\n ],\n \"doctype\": \"Asset Maintenance\",\n \"label\": \"Asset Maintenance\",\n \"name\": \"Asset Maintenance\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Asset Value Analytics",
- "label": "Asset Value Analytics"
- }
- ],
- "creation": "2020-03-02 15:43:27.634865",
- "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": "Assets",
- "modified": "2020-05-20 18:05:23.994795",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Assets",
- "onboarding": "Assets",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "label": "Asset",
- "link_to": "Asset",
- "type": "DocType"
- },
- {
- "label": "Asset Category",
- "link_to": "Asset Category",
- "type": "DocType"
- },
- {
- "label": "Fixed Asset Register",
- "link_to": "Fixed Asset Register",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Asset",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 7ad164a..6f1bb28 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -2,6 +2,7 @@
// For license information, please see license.txt
frappe.provide("erpnext.asset");
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Asset', {
onload: function(frm) {
@@ -32,13 +33,11 @@
};
});
- frm.set_query("cost_center", function() {
- return {
- "filters": {
- "company": frm.doc.company,
- }
- };
- });
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
setup: function(frm) {
@@ -373,8 +372,8 @@
doctype_field = frappe.scrub(doctype)
frm.set_value(doctype_field, '');
frappe.msgprint({
- title: __(`Invalid ${doctype}`),
- message: __(`The selected ${doctype} doesn't contains selected Asset Item.`),
+ title: __('Invalid {0}', [__(doctype)]),
+ message: __('The selected {0} does not contain the selected Asset Item.', [__(doctype)]),
indicator: 'red'
});
}
@@ -436,7 +435,7 @@
depreciation_start_date: function(frm, cdt, cdn) {
const book = locals[cdt][cdn];
if (frm.doc.available_for_use_date && book.depreciation_start_date == frm.doc.available_for_use_date) {
- frappe.msgprint(__(`Depreciation Posting Date should not be equal to Available for Use Date.`));
+ frappe.msgprint(__("Depreciation Posting Date should not be equal to Available for Use Date."));
book.depreciation_start_date = "";
frm.refresh_field("finance_books");
}
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index a3152ab..421b9a6 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -8,21 +8,20 @@
"document_type": "Document",
"engine": "InnoDB",
"field_order": [
- "is_existing_asset",
- "section_break_2",
- "naming_series",
+ "company",
"item_code",
"item_name",
- "asset_category",
"asset_owner",
"asset_owner_company",
+ "is_existing_asset",
"supplier",
"customer",
"image",
"journal_entry_for_scrap",
"column_break_3",
- "company",
+ "naming_series",
"asset_name",
+ "asset_category",
"location",
"custodian",
"department",
@@ -95,12 +94,14 @@
"reqd": 1
},
{
+ "depends_on": "item_code",
"fetch_from": "item_code.item_name",
"fieldname": "item_name",
"fieldtype": "Read Only",
"label": "Item Name"
},
{
+ "depends_on": "item_code",
"fetch_from": "item_code.asset_category",
"fieldname": "asset_category",
"fieldtype": "Link",
@@ -307,12 +308,13 @@
{
"depends_on": "calculate_depreciation",
"fieldname": "section_break_14",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Depreciation Schedule"
},
{
"fieldname": "schedules",
"fieldtype": "Table",
- "label": "Depreciation Schedules",
+ "label": "Depreciation Schedule",
"no_copy": 1,
"options": "Depreciation Schedule"
},
@@ -459,10 +461,6 @@
"label": "Allow Monthly Depreciation"
},
{
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
"collapsible": 1,
"collapsible_depends_on": "is_existing_asset",
"fieldname": "purchase_details_section",
@@ -480,14 +478,31 @@
{
"depends_on": "calculate_depreciation",
"fieldname": "section_break_36",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Finance Books"
}
],
"idx": 72,
"image_field": "image",
"is_submittable": 1,
- "links": [],
- "modified": "2020-07-28 15:04:44.452224",
+ "links": [
+ {
+ "group": "Maintenance",
+ "link_doctype": "Asset Maintenance",
+ "link_fieldname": "asset_name"
+ },
+ {
+ "group": "Repair",
+ "link_doctype": "Asset Repair",
+ "link_fieldname": "asset_name"
+ },
+ {
+ "group": "Value",
+ "link_doctype": "Asset Value Adjustment",
+ "link_fieldname": "asset"
+ }
+ ],
+ "modified": "2021-01-22 12:38:59.091510",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
@@ -527,5 +542,6 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
- "title_field": "asset_name"
+ "title_field": "asset_name",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index efdbdb1..e8e8ec6 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -131,11 +131,12 @@
def validate_gross_and_purchase_amount(self):
if self.is_existing_asset: return
-
+
if self.gross_purchase_amount and self.gross_purchase_amount != self.purchase_receipt_amount:
- frappe.throw(_("Gross Purchase Amount should be {} to purchase amount of one single Asset. {}\
- Please do not book expense of multiple assets against one single Asset.")
- .format(frappe.bold("equal"), "<br>"), title=_("Invalid Gross Purchase Amount"))
+ error_message = _("Gross Purchase Amount should be <b>equal</b> to purchase amount of one single Asset.")
+ error_message += "<br>"
+ error_message += _("Please do not book expense of multiple assets against one single Asset.")
+ frappe.throw(error_message, title=_("Invalid Gross Purchase Amount"))
def make_asset_movement(self):
reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
@@ -466,29 +467,37 @@
def validate_make_gl_entry(self):
purchase_document = self.get_purchase_document()
- asset_bought_with_invoice = purchase_document == self.purchase_invoice
- fixed_asset_account, cwip_account = self.get_asset_accounts()
- cwip_enabled = is_cwip_accounting_enabled(self.asset_category)
- # check if expense already has been booked in case of cwip was enabled after purchasing asset
- expense_booked = False
- cwip_booked = False
-
- if asset_bought_with_invoice:
- expense_booked = frappe.db.sql("""SELECT name FROM `tabGL Entry` WHERE voucher_no = %s and account = %s""",
- (purchase_document, fixed_asset_account), as_dict=1)
- else:
- cwip_booked = frappe.db.sql("""SELECT name FROM `tabGL Entry` WHERE voucher_no = %s and account = %s""",
- (purchase_document, cwip_account), as_dict=1)
-
- if cwip_enabled and (expense_booked or not cwip_booked):
- # if expense has already booked from invoice or cwip is booked from receipt
+ if not purchase_document:
return False
- elif not cwip_enabled and (not expense_booked or cwip_booked):
- # if cwip is disabled but expense hasn't been booked yet
- return True
- elif cwip_enabled:
- # default condition
- return True
+
+ asset_bought_with_invoice = (purchase_document == self.purchase_invoice)
+ fixed_asset_account = self.get_fixed_asset_account()
+
+ cwip_enabled = is_cwip_accounting_enabled(self.asset_category)
+ cwip_account = self.get_cwip_account(cwip_enabled=cwip_enabled)
+
+ query = """SELECT name FROM `tabGL Entry` WHERE voucher_no = %s and account = %s"""
+ if asset_bought_with_invoice:
+ # with invoice purchase either expense or cwip has been booked
+ expense_booked = frappe.db.sql(query, (purchase_document, fixed_asset_account), as_dict=1)
+ if expense_booked:
+ # if expense is already booked from invoice then do not make gl entries regardless of cwip enabled/disabled
+ return False
+
+ cwip_booked = frappe.db.sql(query, (purchase_document, cwip_account), as_dict=1)
+ if cwip_booked:
+ # if cwip is booked from invoice then make gl entries regardless of cwip enabled/disabled
+ return True
+ else:
+ # with receipt purchase either cwip has been booked or no entries have been made
+ if not cwip_account:
+ # if cwip account isn't available do not make gl entries
+ return False
+
+ cwip_booked = frappe.db.sql(query, (purchase_document, cwip_account), as_dict=1)
+ # if cwip is not booked from receipt then do not make gl entries
+ # if cwip is booked from receipt then make gl entries
+ return cwip_booked
def get_purchase_document(self):
asset_bought_with_invoice = self.purchase_invoice and frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')
@@ -496,20 +505,25 @@
return purchase_document
- def get_asset_accounts(self):
- fixed_asset_account = get_asset_category_account('fixed_asset_account', asset=self.name,
- asset_category = self.asset_category, company = self.company)
+ def get_fixed_asset_account(self):
+ return get_asset_category_account('fixed_asset_account', None, self.name, None, self.asset_category, self.company)
- cwip_account = get_asset_account("capital_work_in_progress_account",
- self.name, self.asset_category, self.company)
+ def get_cwip_account(self, cwip_enabled=False):
+ cwip_account = None
+ try:
+ cwip_account = get_asset_account("capital_work_in_progress_account", self.name, self.asset_category, self.company)
+ except:
+ # if no cwip account found in category or company and "cwip is enabled" then raise else silently pass
+ if cwip_enabled:
+ raise
- return fixed_asset_account, cwip_account
+ return cwip_account
def make_gl_entries(self):
gl_entries = []
purchase_document = self.get_purchase_document()
- fixed_asset_account, cwip_account = self.get_asset_accounts()
+ fixed_asset_account, cwip_account = self.get_fixed_asset_account(), self.get_cwip_account()
if (purchase_document and self.purchase_receipt_amount and self.available_for_use_date <= nowdate()):
@@ -561,14 +575,18 @@
return 100 * (1 - flt(depreciation_rate, float_precision))
def update_maintenance_status():
- assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
+ assets = frappe.get_all(
+ "Asset", filters={"docstatus": 1, "maintenance_required": 1}
+ )
for asset in assets:
asset = frappe.get_doc("Asset", asset.name)
- if frappe.db.exists('Asset Maintenance Task', {'parent': asset.name, 'next_due_date': today()}):
- asset.set_status('In Maintenance')
- if frappe.db.exists('Asset Repair', {'asset_name': asset.name, 'repair_status': 'Pending'}):
- asset.set_status('Out of Order')
+ if frappe.db.exists("Asset Repair", {"asset_name": asset.name, "repair_status": "Pending"}):
+ asset.set_status("Out of Order")
+ elif frappe.db.exists("Asset Maintenance Task", {"parent": asset.name, "next_due_date": today()}):
+ asset.set_status("In Maintenance")
+ else:
+ asset.set_status()
def make_post_gl_entry():
@@ -642,7 +660,7 @@
frappe.db.commit()
- frappe.msgprint(_("Asset Movement record {0} created").format("<a href='#Form/Asset Movement/{0}'>{0}</a>").format(movement_entry.name))
+ frappe.msgprint(_("Asset Movement record {0} created").format("<a href='/app/Form/Asset Movement/{0}'>{0}</a>").format(movement_entry.name))
@frappe.whitelist()
def get_item_details(item_code, asset_category):
diff --git a/erpnext/assets/doctype/asset/asset_dashboard.py b/erpnext/assets/doctype/asset/asset_dashboard.py
index b489899..a5cf238 100644
--- a/erpnext/assets/doctype/asset/asset_dashboard.py
+++ b/erpnext/assets/doctype/asset/asset_dashboard.py
@@ -2,20 +2,11 @@
def get_data():
return {
- 'fieldname': 'asset_name',
'non_standard_fieldnames': {
'Asset Movement': 'asset'
},
'transactions': [
{
- 'label': ['Maintenance'],
- 'items': ['Asset Maintenance', 'Asset Maintenance Log']
- },
- {
- 'label': ['Repair'],
- 'items': ['Asset Repair']
- },
- {
'label': ['Movement'],
'items': ['Asset Movement']
}
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 52039c1..a0d7603 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -9,6 +9,7 @@
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset
from erpnext.assets.doctype.asset.asset import make_sales_invoice
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice as make_invoice
class TestAsset(unittest.TestCase):
@@ -558,81 +559,6 @@
self.assertEqual(gle, expected_gle)
- def test_gle_with_cwip_toggling(self):
- # TEST: purchase an asset with cwip enabled and then disable cwip and try submitting the asset
- frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
-
- pr = make_purchase_receipt(item_code="Macbook Pro",
- qty=1, rate=5000, do_not_submit=True, location="Test Location")
- pr.set('taxes', [{
- 'category': 'Total',
- 'add_deduct_tax': 'Add',
- 'charge_type': 'On Net Total',
- 'account_head': '_Test Account Service Tax - _TC',
- 'description': '_Test Account Service Tax',
- 'cost_center': 'Main - _TC',
- 'rate': 5.0
- }, {
- 'category': 'Valuation and Total',
- 'add_deduct_tax': 'Add',
- 'charge_type': 'On Net Total',
- 'account_head': '_Test Account Shipping Charges - _TC',
- 'description': '_Test Account Shipping Charges',
- 'cost_center': 'Main - _TC',
- 'rate': 5.0
- }])
- pr.submit()
- expected_gle = (
- ("Asset Received But Not Billed - _TC", 0.0, 5250.0),
- ("CWIP Account - _TC", 5250.0, 0.0)
- )
- pr_gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
- where voucher_type='Purchase Receipt' and voucher_no = %s
- order by account""", pr.name)
- self.assertEqual(pr_gle, expected_gle)
-
- pi = make_invoice(pr.name)
- pi.submit()
- expected_gle = (
- ("_Test Account Service Tax - _TC", 250.0, 0.0),
- ("_Test Account Shipping Charges - _TC", 250.0, 0.0),
- ("Asset Received But Not Billed - _TC", 5250.0, 0.0),
- ("Creditors - _TC", 0.0, 5500.0),
- ("Expenses Included In Asset Valuation - _TC", 0.0, 250.0),
- )
- pi_gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
- where voucher_type='Purchase Invoice' and voucher_no = %s
- order by account""", pi.name)
- self.assertEqual(pi_gle, expected_gle)
-
- asset = frappe.db.get_value('Asset', {'purchase_receipt': pr.name, 'docstatus': 0}, 'name')
- asset_doc = frappe.get_doc('Asset', asset)
- month_end_date = get_last_day(nowdate())
- asset_doc.available_for_use_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
- self.assertEqual(asset_doc.gross_purchase_amount, 5250.0)
- asset_doc.append("finance_books", {
- "expected_value_after_useful_life": 200,
- "depreciation_method": "Straight Line",
- "total_number_of_depreciations": 3,
- "frequency_of_depreciation": 10,
- "depreciation_start_date": month_end_date
- })
-
- # disable cwip and try submitting
- frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0)
- asset_doc.submit()
- # asset should have gl entries even if cwip is disabled
- expected_gle = (
- ("_Test Fixed Asset - _TC", 5250.0, 0.0),
- ("CWIP Account - _TC", 0.0, 5250.0)
- )
- gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
- where voucher_type='Asset' and voucher_no = %s
- order by account""", asset_doc.name)
- self.assertEqual(gle, expected_gle)
-
- frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
-
def test_expense_head(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=2, rate=200000.0, location="Test Location")
@@ -640,6 +566,74 @@
doc = make_invoice(pr.name)
self.assertEquals('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"])
+ cwip_acc = "CWIP Account - _TC"
+
+ frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0)
+ frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", "")
+ frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", "")
+
+ # case 0 -- PI with cwip disable, Asset with cwip disabled, No cwip account set
+ pi = make_purchase_invoice(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location", update_stock=1)
+ asset = frappe.db.get_value('Asset', {'purchase_invoice': pi.name, 'docstatus': 0}, 'name')
+ asset_doc = frappe.get_doc('Asset', asset)
+ asset_doc.available_for_use_date = nowdate()
+ asset_doc.calculate_depreciation = 0
+ asset_doc.submit()
+ gle = frappe.db.sql("""select name from `tabGL Entry` where voucher_type='Asset' and voucher_no = %s""", asset_doc.name)
+ self.assertFalse(gle)
+
+ # case 1 -- PR with cwip disabled, Asset with cwip enabled
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location")
+ frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
+ frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
+ asset = frappe.db.get_value('Asset', {'purchase_receipt': pr.name, 'docstatus': 0}, 'name')
+ asset_doc = frappe.get_doc('Asset', asset)
+ asset_doc.available_for_use_date = nowdate()
+ asset_doc.calculate_depreciation = 0
+ asset_doc.submit()
+ gle = frappe.db.sql("""select name from `tabGL Entry` where voucher_type='Asset' and voucher_no = %s""", asset_doc.name)
+ self.assertFalse(gle)
+
+ # case 2 -- PR with cwip enabled, Asset with cwip disabled
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location")
+ frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0)
+ asset = frappe.db.get_value('Asset', {'purchase_receipt': pr.name, 'docstatus': 0}, 'name')
+ asset_doc = frappe.get_doc('Asset', asset)
+ asset_doc.available_for_use_date = nowdate()
+ asset_doc.calculate_depreciation = 0
+ asset_doc.submit()
+ gle = frappe.db.sql("""select name from `tabGL Entry` where voucher_type='Asset' and voucher_no = %s""", asset_doc.name)
+ self.assertTrue(gle)
+
+ # case 3 -- PI with cwip disabled, Asset with cwip enabled
+ pi = make_purchase_invoice(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location", update_stock=1)
+ frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
+ asset = frappe.db.get_value('Asset', {'purchase_invoice': pi.name, 'docstatus': 0}, 'name')
+ asset_doc = frappe.get_doc('Asset', asset)
+ asset_doc.available_for_use_date = nowdate()
+ asset_doc.calculate_depreciation = 0
+ asset_doc.submit()
+ gle = frappe.db.sql("""select name from `tabGL Entry` where voucher_type='Asset' and voucher_no = %s""", asset_doc.name)
+ self.assertFalse(gle)
+
+ # case 4 -- PI with cwip enabled, Asset with cwip disabled
+ pi = make_purchase_invoice(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location", update_stock=1)
+ frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0)
+ asset = frappe.db.get_value('Asset', {'purchase_invoice': pi.name, 'docstatus': 0}, 'name')
+ asset_doc = frappe.get_doc('Asset', asset)
+ asset_doc.available_for_use_date = nowdate()
+ asset_doc.calculate_depreciation = 0
+ asset_doc.submit()
+ gle = frappe.db.sql("""select name from `tabGL Entry` where voucher_type='Asset' and voucher_no = %s""", asset_doc.name)
+ self.assertTrue(gle)
+
+ frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", cwip)
+ 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)
def create_asset_data():
if not frappe.db.exists("Asset Category", "Computers"):
diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json
index 7483b41..a25f546 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.json
+++ b/erpnext/assets/doctype/asset_category/asset_category.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:asset_category_name",
@@ -64,7 +65,8 @@
"label": "Enable Capital Work in Progress Accounting"
}
],
- "modified": "2019-10-11 12:19:59.759136",
+ "links": [],
+ "modified": "2021-02-24 15:05:38.621803",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category",
@@ -111,5 +113,6 @@
],
"show_name_in_global_search": 1,
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 9a33fc1..46620d5 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import cint
+from frappe.utils import cint, get_link_to_form
from frappe.model.document import Document
class AssetCategory(Document):
@@ -13,6 +13,7 @@
self.validate_finance_books()
self.validate_account_types()
self.validate_account_currency()
+ self.valide_cwip_account()
def validate_finance_books(self):
for d in self.finance_books:
@@ -58,6 +59,21 @@
frappe.throw(_("Row #{}: {} of {} should be {}. Please modify the account or select a different account.")
.format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_type)),
title=_("Invalid Account"))
+
+ def valide_cwip_account(self):
+ if self.enable_cwip_accounting:
+ missing_cwip_accounts_for_company = []
+ for d in self.accounts:
+ if (not d.capital_work_in_progress_account and
+ not frappe.db.get_value("Company", d.company_name, "capital_work_in_progress_account")):
+ missing_cwip_accounts_for_company.append(get_link_to_form("Company", d.company_name))
+
+ if missing_cwip_accounts_for_company:
+ msg = _("""To enable Capital Work in Progress Accounting, """)
+ msg += _("""you must select Capital Work in Progress Account in accounts table""")
+ msg += "<br><br>"
+ msg += _("You can also set default CWIP account in Company {}").format(", ".join(missing_cwip_accounts_for_company))
+ frappe.throw(msg, title=_("Missing Account"))
@frappe.whitelist()
diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.py b/erpnext/assets/doctype/asset_category/test_asset_category.py
index b32f9b5..39b79d6 100644
--- a/erpnext/assets/doctype/asset_category/test_asset_category.py
+++ b/erpnext/assets/doctype/asset_category/test_asset_category.py
@@ -26,4 +26,22 @@
asset_category.insert()
except frappe.DuplicateEntryError:
pass
-
\ No newline at end of file
+
+ def test_cwip_accounting(self):
+ company_cwip_acc = frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account")
+ frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "")
+
+ asset_category = frappe.new_doc("Asset Category")
+ asset_category.asset_category_name = "Computers"
+ asset_category.enable_cwip_accounting = 1
+
+ asset_category.total_number_of_depreciations = 3
+ asset_category.frequency_of_depreciation = 3
+ asset_category.append("accounts", {
+ "company_name": "_Test Company",
+ "fixed_asset_account": "_Test Fixed Asset - _TC",
+ "accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
+ "depreciation_expense_account": "_Test Depreciations - _TC"
+ })
+
+ self.assertRaises(frappe.ValidationError, asset_category.insert)
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index 79fcb95..d9b7b69 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -50,12 +50,11 @@
"reqd": 1
},
{
- "depends_on": "eval:parent.doctype == 'Asset'",
"fieldname": "depreciation_start_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Depreciation Posting Date",
- "reqd": 1
+ "mandatory_depends_on": "eval:parent.doctype == 'Asset'"
},
{
"default": "0",
@@ -86,7 +85,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-09-16 12:11:30.631788",
+ "modified": "2020-11-05 16:30:09.213479",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 001fc26..70b8654 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -40,14 +40,13 @@
if(!r.message) {
return;
}
- var section = frm.dashboard.add_section(`<h5 style="margin-top: 0px;">
- ${ __("Maintenance Log") }</a></h5>`);
+ const section = frm.dashboard.add_section('', __("Maintenance Log"));
var rows = $('<div></div>').appendTo(section);
// show
(r.message || []).forEach(function(d) {
$(`<div class='row' style='margin-bottom: 10px;'>
<div class='col-sm-3 small'>
- <a onclick="frappe.set_route('List', 'Asset Maintenance Log',
+ <a onclick="frappe.set_route('List', 'Asset Maintenance Log',
{'asset_name': '${d.asset_name}','maintenance_status': '${d.maintenance_status}' });">
${d.maintenance_status} <span class="badge">${d.count}</span>
</a>
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index 60c528b..a506dee 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -108,7 +108,7 @@
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_team_members(doctype, txt, searchfield, start, page_len, filters):
- return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") })
+ return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") }, "team_member")
@frappe.whitelist()
def get_maintenance_log(asset_name):
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
index 7395bec..7d33176 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
@@ -18,15 +18,13 @@
"task_name",
"maintenance_type",
"periodicity",
- "assign_to_name",
- "column_break_6",
- "due_date",
- "completion_date",
- "maintenance_status",
- "section_break_12",
"has_certificate",
"certificate_attachement",
- "section_break_6",
+ "column_break_6",
+ "maintenance_status",
+ "assign_to_name",
+ "due_date",
+ "completion_date",
"description",
"column_break_9",
"actions_performed",
@@ -70,7 +68,8 @@
},
{
"fieldname": "section_break_5",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Maintenance Details"
},
{
"fieldname": "task",
@@ -124,10 +123,6 @@
"reqd": 1
},
{
- "fieldname": "section_break_12",
- "fieldtype": "Section Break"
- },
- {
"default": "0",
"fetch_from": "task.certificate_required",
"fieldname": "has_certificate",
@@ -141,10 +136,6 @@
"label": "Certificate"
},
{
- "fieldname": "section_break_6",
- "fieldtype": "Column Break"
- },
- {
"fetch_from": "task.description",
"fieldname": "description",
"fieldtype": "Read Only",
@@ -179,9 +170,10 @@
"read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-05-28 20:51:48.238397",
+ "modified": "2021-01-22 12:33:45.888124",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance Log",
diff --git a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json
index e2aa548..ffa04e5 100644
--- a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json
+++ b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json
@@ -1,282 +1,87 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:maintenance_team_name",
- "beta": 0,
- "creation": "2017-10-20 11:43:47.712616",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "field:maintenance_team_name",
+ "creation": "2017-10-20 11:43:47.712616",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "maintenance_team_name",
+ "maintenance_manager",
+ "maintenance_manager_name",
+ "column_break_2",
+ "company",
+ "section_break_2",
+ "maintenance_team_members"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maintenance_team_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": "Maintenance Team 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": 0
- },
+ "fieldname": "maintenance_team_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Maintenance Team Name",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maintenance_manager",
- "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": "Maintenance Manager",
- "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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "maintenance_manager",
+ "fieldtype": "Link",
+ "label": "Maintenance Manager",
+ "options": "User"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "maintenance_manager.full_name",
- "fieldname": "maintenance_manager_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": "Maintenance Manager Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "maintenance_manager_name",
+ "fieldtype": "Read Only",
+ "label": "Maintenance Manager Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "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_2",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_2",
- "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_2",
+ "fieldtype": "Section Break",
+ "label": "Team"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maintenance_team_members",
- "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": "Maintenance Team Members",
- "length": 0,
- "no_copy": 0,
- "options": "Maintenance Team Member",
- "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": "maintenance_team_members",
+ "fieldtype": "Table",
+ "label": "Maintenance Team Members",
+ "options": "Maintenance Team Member",
+ "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": 0,
- "max_attachments": 0,
- "modified": "2018-05-16 22:43:24.195349",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Maintenance Team",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-01-22 15:09:03.347345",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Maintenance Team",
+ "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": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "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/assets/doctype/asset_movement/asset_movement.json b/erpnext/assets/doctype/asset_movement/asset_movement.json
index 3472ab5..bdce639 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.json
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "format:ACC-ASM-{YYYY}-{#####}",
"creation": "2016-04-25 18:00:23.559973",
@@ -91,8 +92,10 @@
"fieldtype": "Column Break"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
- "modified": "2019-11-23 13:28:47.256935",
+ "links": [],
+ "modified": "2021-01-22 12:30:55.295670",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Movement",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index 6df6e27..d338fc0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -1,763 +1,208 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2017-10-23 11:38:54.004355",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2017-10-23 11:38:54.004355",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "asset_name",
+ "column_break_2",
+ "item_code",
+ "item_name",
+ "section_break_5",
+ "failure_date",
+ "assign_to",
+ "assign_to_name",
+ "column_break_6",
+ "completion_date",
+ "repair_status",
+ "repair_cost",
+ "section_break_9",
+ "description",
+ "column_break_9",
+ "actions_performed",
+ "section_break_17",
+ "downtime",
+ "column_break_19",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "fieldname": "asset_name",
- "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": "Asset Name",
- "length": 0,
- "no_copy": 0,
- "options": "Asset",
- "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": "asset_name",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Asset",
+ "options": "Asset",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "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": "Series",
- "length": 0,
- "no_copy": 0,
- "options": "ACC-ASR-.YYYY.-",
- "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": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "ACC-ASR-.YYYY.-",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "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_2",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "asset_name.item_code",
- "fieldname": "item_code",
- "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": "Item Code",
- "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
- },
+ "fetch_from": "asset_name.item_code",
+ "fieldname": "item_code",
+ "fieldtype": "Read Only",
+ "label": "Item Code"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "asset_name.item_name",
- "fieldname": "item_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": "Item Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "asset_name.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Read Only",
+ "label": "Item Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "label": "Repair Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "fieldname": "failure_date",
- "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": "Failure 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
- },
+ "columns": 1,
+ "fieldname": "failure_date",
+ "fieldtype": "Datetime",
+ "label": "Failure Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "assign_to",
- "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": "Assign To",
- "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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "assign_to",
+ "fieldtype": "Link",
+ "label": "Assign To",
+ "options": "User"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "assign_to.full_name",
- "fieldname": "assign_to_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": "Assign To Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fetch_from": "assign_to.full_name",
+ "fieldname": "assign_to_name",
+ "fieldtype": "Read Only",
+ "label": "Assign To Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_6",
- "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_6",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "completion_date",
- "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": "Completion 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "completion_date",
+ "fieldtype": "Datetime",
+ "label": "Completion Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Pending",
- "fieldname": "repair_status",
- "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": "Repair Status",
- "length": 0,
- "no_copy": 1,
- "options": "Pending\nCompleted\nCancelled",
- "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,
- "width": ""
- },
+ "allow_on_submit": 1,
+ "default": "Pending",
+ "fieldname": "repair_status",
+ "fieldtype": "Select",
+ "label": "Repair Status",
+ "no_copy": 1,
+ "options": "Pending\nCompleted\nCancelled",
+ "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_9",
- "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_9",
+ "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": "description",
- "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": "Error Description",
- "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": "description",
+ "fieldtype": "Long Text",
+ "label": "Error Description",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "actions_performed",
- "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": "Actions performed",
- "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_on_submit": 1,
+ "fieldname": "actions_performed",
+ "fieldtype": "Long Text",
+ "label": "Actions performed"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_17",
- "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_17",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "downtime",
- "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": "Downtime",
- "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_on_submit": 1,
+ "fieldname": "downtime",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Downtime",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_19",
- "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_19",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "repair_cost",
- "fieldtype": "Currency",
- "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": "Repair Cost",
- "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_on_submit": 1,
+ "fieldname": "repair_cost",
+ "fieldtype": "Currency",
+ "label": "Repair Cost"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Asset Repair",
- "permlevel": 0,
- "print_hide": 1,
- "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": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Asset Repair",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 14:44:27.181876",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Repair",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-01-22 15:08:12.495850",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Repair",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Quality Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Quality Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "",
- "track_changes": 1,
- "track_seen": 1,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 1
}
\ No newline at end of file
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 a6e6974..79c8861 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Asset Value Adjustment', {
setup: function(frm) {
frm.add_fetch('company', 'cost_center', 'cost_center');
@@ -13,11 +15,19 @@
}
});
},
+
onload: function(frm) {
if(frm.is_new() && frm.doc.asset) {
frm.trigger("set_current_asset_value");
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
asset: function(frm) {
frm.trigger("set_current_asset_value");
},
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
index 3236e72..57e04e2 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2018-05-11 00:22:43.695151",
"doctype": "DocType",
"editable_grid": 1,
@@ -7,14 +8,16 @@
"company",
"asset",
"asset_category",
- "finance_book",
- "journal_entry",
"column_break_4",
"date",
+ "finance_book",
+ "amended_from",
+ "value_details_section",
"current_asset_value",
"new_asset_value",
+ "column_break_11",
"difference_amount",
- "amended_from",
+ "journal_entry",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break"
@@ -108,10 +111,21 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "value_details_section",
+ "fieldtype": "Section Break",
+ "label": "Value Details"
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
- "modified": "2019-11-22 14:09:25.800375",
+ "links": [],
+ "modified": "2021-01-22 14:10:23.085181",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Value Adjustment",
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 fd702c7..1430827 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -13,19 +13,16 @@
class AssetValueAdjustment(Document):
def validate(self):
self.validate_date()
- self.set_difference_amount()
self.set_current_asset_value()
+ self.set_difference_amount()
def on_submit(self):
self.make_depreciation_entry()
self.reschedule_depreciations(self.new_asset_value)
def on_cancel(self):
- if self.journal_entry:
- frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry))
-
self.reschedule_depreciations(self.current_asset_value)
-
+
def validate_date(self):
asset_purchase_date = frappe.db.get_value('Asset', self.asset, 'purchase_date')
if getdate(self.date) < getdate(asset_purchase_date):
@@ -53,6 +50,7 @@
je.posting_date = self.date
je.company = self.company
je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
+ je.finance_book = self.finance_book
credit_entry = {
"account": accumulated_depreciation_account,
@@ -78,7 +76,7 @@
debit_entry.update({
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
})
-
+
je.append("accounts", credit_entry)
je.append("accounts", debit_entry)
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 af08a2a..d1457b9 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -75,24 +75,23 @@
for asset in assets_record:
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
- flt(depreciation_amount_map.get(asset.name))
- if asset_value:
- row = {
- "asset_id": asset.asset_id,
- "asset_name": asset.asset_name,
- "status": asset.status,
- "department": asset.department,
- "cost_center": asset.cost_center,
- "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
- "gross_purchase_amount": asset.gross_purchase_amount,
- "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
- "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
- "available_for_use_date": asset.available_for_use_date,
- "location": asset.location,
- "asset_category": asset.asset_category,
- "purchase_date": asset.purchase_date,
- "asset_value": asset_value
- }
- data.append(row)
+ row = {
+ "asset_id": asset.asset_id,
+ "asset_name": asset.asset_name,
+ "status": asset.status,
+ "department": asset.department,
+ "cost_center": asset.cost_center,
+ "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
+ "gross_purchase_amount": asset.gross_purchase_amount,
+ "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
+ "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
+ "available_for_use_date": asset.available_for_use_date,
+ "location": asset.location,
+ "asset_category": asset.asset_category,
+ "purchase_date": asset.purchase_date,
+ "asset_value": asset_value
+ }
+ data.append(row)
return data
diff --git a/erpnext/assets/workspace/assets/assets.json b/erpnext/assets/workspace/assets/assets.json
new file mode 100644
index 0000000..c401581
--- /dev/null
+++ b/erpnext/assets/workspace/assets/assets.json
@@ -0,0 +1,193 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Asset Value Analytics",
+ "label": "Asset Value Analytics"
+ }
+ ],
+ "creation": "2020-03-02 15:43:27.634865",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "assets",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Assets",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assets",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset",
+ "link_to": "Asset",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Location",
+ "link_to": "Location",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Category",
+ "link_to": "Asset Category",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Movement",
+ "link_to": "Asset Movement",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Maintenance Team",
+ "link_to": "Asset Maintenance Team",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Asset Maintenance Team",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Maintenance",
+ "link_to": "Asset Maintenance",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Asset Maintenance",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Maintenance Log",
+ "link_to": "Asset Maintenance Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Asset",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Value Adjustment",
+ "link_to": "Asset Value Adjustment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Asset",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Repair",
+ "link_to": "Asset Repair",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Asset",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Asset Depreciation Ledger",
+ "link_to": "Asset Depreciation Ledger",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Asset",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Asset Depreciations and Balances",
+ "link_to": "Asset Depreciations and Balances",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Asset Maintenance",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Asset Maintenance",
+ "link_to": "Asset Maintenance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:37.977119",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Assets",
+ "onboarding": "Assets",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "label": "Asset",
+ "link_to": "Asset",
+ "type": "DocType"
+ },
+ {
+ "label": "Asset Category",
+ "link_to": "Asset Category",
+ "type": "DocType"
+ },
+ {
+ "label": "Fixed Asset Register",
+ "link_to": "Fixed Asset Register",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Asset",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/buying/desk_page/buying/buying.json b/erpnext/buying/desk_page/buying/buying.json
deleted file mode 100644
index 565d39c..0000000
--- a/erpnext/buying/desk_page/buying/buying.json
+++ /dev/null
@@ -1,113 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Buying",
- "links": "[ \n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Request for purchase.\",\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Purchase Orders given to Suppliers.\",\n \"label\": \"Purchase Order\",\n \"name\": \"Purchase Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Request for quotation.\",\n \"label\": \"Request for Quotation\",\n \"name\": \"Request for Quotation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Quotations received from Suppliers.\",\n \"label\": \"Supplier Quotation\",\n \"name\": \"Supplier Quotation\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Items & Pricing",
- "links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Multiple Item prices.\",\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"onboard\": 1,\n \"route\": \"#Report/Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Price List master.\",\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bundle items at time of sale.\",\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Item Groups.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying different promotional schemes.\",\n \"label\": \"Promotional Scheme\",\n \"name\": \"Promotional Scheme\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying pricing and discount.\",\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"description\": \"Default settings for buying transactions.\",\n \"label\": \"Buying Settings\",\n \"name\": \"Buying Settings\",\n \"settings\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Supplier",
- "links": "[\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier Group master.\",\n \"label\": \"Supplier Group\",\n \"name\": \"Supplier Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Addresses.\",\n \"label\": \"Address\",\n \"name\": \"Address\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Supplier Scorecard",
- "links": "[\n {\n \"description\": \"All Supplier scorecards.\",\n \"label\": \"Supplier Scorecard\",\n \"name\": \"Supplier Scorecard\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier scorecard variables.\",\n \"label\": \"Supplier Scorecard Variable\",\n \"name\": \"Supplier Scorecard Variable\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier scorecard criteria.\",\n \"label\": \"Supplier Scorecard Criteria\",\n \"name\": \"Supplier Scorecard Criteria\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier standings.\",\n \"label\": \"Supplier Scorecard Standing\",\n \"name\": \"Supplier Scorecard Standing\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Key Reports",
- "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Analytics\",\n \"name\": \"Purchase Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Analysis\",\n \"name\": \"Purchase Order Analysis\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier-Wise Sales Analytics\",\n \"name\": \"Supplier-Wise Sales Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Stock Ledger Entry\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Requested Items to Order\",\n \"name\": \"Requested Items to Order\",\n \"onboard\": 1,\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Trends\",\n \"name\": \"Purchase Order Trends\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Procurement Tracker\",\n \"name\": \"Procurement Tracker\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Other Reports",
- "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Receipt Trends\",\n \"name\": \"Purchase Receipt Trends\",\n \"reference_doctype\": \"Purchase Receipt\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"reference_doctype\": \"Purchase Invoice\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Raw Materials To Be Transferred\",\n \"name\": \"Subcontracted Raw Materials To Be Transferred\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Item To Be Received\",\n \"name\": \"Subcontracted Item To Be Received\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Quoted Item Comparison\",\n \"name\": \"Quoted Item Comparison\",\n \"onboard\": 1,\n \"reference_doctype\": \"Supplier Quotation\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Regional",
- "links": "[\n {\n \"description\": \"Import Italian Purchase Invoices\",\n \"label\": \"Import Supplier Invoice\",\n \"name\": \"Import Supplier Invoice\",\n \"type\": \"doctype\"\n } \n]"
- }
- ],
- "cards_label": "",
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Purchase Order Trends",
- "label": "Purchase Order Trends"
- }
- ],
- "charts_label": "",
- "creation": "2020-01-28 11:50:26.195467",
- "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": "Buying",
- "modified": "2020-06-29 19:30:24.983050",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Buying",
- "onboarding": "Buying",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Available",
- "label": "Item",
- "link_to": "Item",
- "stats_filter": "{\n \"disabled\": 0\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Pending",
- "label": "Material Request",
- "link_to": "Material Request",
- "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Pending\"\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} To Receive",
- "label": "Purchase Order",
- "link_to": "Purchase Order",
- "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\":[\"in\", [\"To Receive\", \"To Receive and Bill\"]]\n}",
- "type": "DocType"
- },
- {
- "label": "Purchase Analytics",
- "link_to": "Purchase Analytics",
- "type": "Report"
- },
- {
- "label": "Purchase Order Analysis",
- "link_to": "Purchase Order Analysis",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Buying",
- "type": "Dashboard"
- }
- ],
- "shortcuts_label": ""
-}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index a0ab2a0..248cb9a 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -46,26 +46,26 @@
{
"fieldname": "po_required",
"fieldtype": "Select",
- "label": "Purchase Order Required for Purchase Invoice & Receipt Creation",
+ "label": "Is Purchase Order Required for Purchase Invoice & Receipt Creation?",
"options": "No\nYes"
},
{
"fieldname": "pr_required",
"fieldtype": "Select",
- "label": "Purchase Receipt Required for Purchase Invoice Creation",
+ "label": "Is Purchase Receipt Required for Purchase Invoice Creation?",
"options": "No\nYes"
},
{
"default": "0",
"fieldname": "maintain_same_rate",
"fieldtype": "Check",
- "label": "Maintain same rate throughout purchase cycle"
+ "label": "Maintain Same Rate Throughout the Purchase Cycle"
},
{
"default": "0",
"fieldname": "allow_multiple_items",
"fieldtype": "Check",
- "label": "Allow Item to be added multiple times in a transaction"
+ "label": "Allow Item To Be Added Multiple Times in a Transaction"
},
{
"fieldname": "subcontract",
@@ -93,9 +93,10 @@
],
"icon": "fa fa-cog",
"idx": 1,
+ "index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-05-15 14:49:32.513611",
+ "modified": "2021-03-02 17:34:04.190677",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
@@ -112,5 +113,6 @@
}
],
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 9f2b971..dd0f065 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.buying");
-
+frappe.provide("erpnext.accounts.dimensions");
{% include 'erpnext/public/js/controllers/buying.js' %};
frappe.ui.form.on("Purchase Order", {
@@ -30,6 +30,10 @@
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm) {
set_schedule_date(frm);
if (!frm.doc.transaction_date){
@@ -39,6 +43,8 @@
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
}
});
@@ -58,8 +64,8 @@
erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
setup: function() {
this.frm.custom_make_buttons = {
- 'Purchase Receipt': 'Receipt',
- 'Purchase Invoice': 'Invoice',
+ 'Purchase Receipt': 'Purchase Receipt',
+ 'Purchase Invoice': 'Purchase Invoice',
'Stock Entry': 'Material to Supplier',
'Payment Entry': 'Payment',
}
@@ -90,6 +96,11 @@
this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship);
if(doc.docstatus == 1) {
+ this.frm.fields_dict.items_section.wrapper.addClass("hide-border");
+ if(!this.frm.doc.set_warehouse) {
+ this.frm.fields_dict.items_section.wrapper.removeClass("hide-border");
+ }
+
if(!in_list(["Closed", "Delivered"], doc.status)) {
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) {
this.frm.add_custom_button(__('Update Items'), () => {
@@ -126,16 +137,25 @@
if(doc.status != "Closed") {
if (doc.status != "On Hold") {
if(flt(doc.per_received) < 100 && allow_receipt) {
- cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
+ cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
cur_frm.add_custom_button(__('Material to Supplier'),
function() { me.make_stock_entry(); }, __("Transfer"));
}
}
if(flt(doc.per_billed) < 100)
- cur_frm.add_custom_button(__('Invoice'),
+ cur_frm.add_custom_button(__('Purchase Invoice'),
this.make_purchase_invoice, __('Create'));
+ if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
+ cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
+ }
+
+ if(flt(doc.per_billed)==0) {
+ this.frm.add_custom_button(__('Payment Request'),
+ function() { me.make_payment_request() }, __('Create'));
+ }
+
if(!doc.auto_repeat) {
cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(doc.doctype, doc.name)
@@ -144,25 +164,19 @@
if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
let me = this;
- frappe.model.with_doc("Supplier", me.frm.doc.supplier, () => {
- let supplier = frappe.model.get_doc("Supplier", me.frm.doc.supplier);
- let internal = supplier.is_internal_supplier;
- let disabled = supplier.disabled;
- if (internal === 1 && disabled === 0) {
- me.frm.add_custom_button("Inter Company Order", function() {
- me.make_inter_company_order(me.frm);
- }, __('Create'));
- }
- });
+ let internal = me.frm.doc.is_internal_supplier;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Sales Order" :
+ "Inter Company Sales Order";
+
+ me.frm.add_custom_button(button_label, function() {
+ me.make_inter_company_order(me.frm);
+ }, __('Create'));
+ }
+
}
}
- if(flt(doc.per_billed)==0) {
- this.frm.add_custom_button(__('Payment Request'),
- function() { me.make_payment_request() }, __('Create'));
- }
- if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
- cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
- }
+
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
}
} else if(doc.docstatus===0) {
@@ -299,7 +313,7 @@
if(me.values) {
me.values.sub_con_rm_items.map((row,i) => {
if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
- frappe.throw(__("Item Code, warehouse, quantity are required on row" + (i+1)));
+ frappe.throw(__("Item Code, warehouse, quantity are required on row {0}", [i+1]));
}
})
me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
@@ -339,7 +353,8 @@
make_purchase_receipt: function() {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
- frm: cur_frm
+ frm: cur_frm,
+ freeze_message: __("Creating Purchase Receipt ...")
})
},
@@ -358,15 +373,19 @@
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request",
target: me.frm,
- setters: {},
+ setters: {
+ schedule_date: undefined,
+ status: undefined
+ },
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
+ per_ordered: ["<", 100],
+ company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
this.frm.add_custom_button(__('Supplier Quotation'),
function() {
@@ -375,16 +394,17 @@
source_doctype: "Supplier Quotation",
target: me.frm,
setters: {
- supplier: me.frm.doc.supplier
+ supplier: me.frm.doc.supplier,
+ valid_till: undefined
},
get_query_filters: {
docstatus: 1,
- status: ["!=", "Stopped"],
+ status: ["not in", ["Stopped", "Expired"]],
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
- this.frm.add_custom_button(__('Update rate as per last purchase'),
+ this.frm.add_custom_button(__('Update Rate as per Last Purchase'),
function() {
frappe.call({
"method": "get_last_purchase_rate",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index d1063b1..ee2beea 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
@@ -30,8 +31,8 @@
"customer_contact_email",
"section_addresses",
"supplier_address",
- "contact_person",
"address_display",
+ "contact_person",
"contact_display",
"contact_mobile",
"contact_email",
@@ -49,12 +50,14 @@
"plc_conversion_rate",
"ignore_pricing_rule",
"sec_warehouse",
- "set_warehouse",
- "col_break_warehouse",
"is_subcontracted",
+ "col_break_warehouse",
"supplier_warehouse",
- "items_section",
+ "before_items_section",
"scan_barcode",
+ "items_col_break",
+ "set_warehouse",
+ "items_section",
"items",
"sb_last_purchase",
"total_qty",
@@ -108,18 +111,13 @@
"payment_terms_template",
"payment_schedule",
"tracking_section",
- "per_billed",
+ "status",
"column_break_75",
+ "per_billed",
"per_received",
"terms_section_break",
"tc_name",
"terms",
- "more_info",
- "status",
- "ref_sq",
- "column_break_74",
- "party_account_currency",
- "inter_company_order_reference",
"column_break5",
"letter_head",
"select_print_heading",
@@ -131,7 +129,14 @@
"to_date",
"column_break_97",
"auto_repeat",
- "update_auto_repeat_reference"
+ "update_auto_repeat_reference",
+ "more_info",
+ "ref_sq",
+ "column_break_74",
+ "party_account_currency",
+ "is_internal_supplier",
+ "represents_company",
+ "inter_company_order_reference"
],
"fields": [
{
@@ -165,6 +170,7 @@
"bold": 1,
"fieldname": "supplier",
"fieldtype": "Link",
+ "in_global_search": 1,
"in_standard_filter": 1,
"label": "Supplier",
"oldfieldname": "supplier",
@@ -313,34 +319,34 @@
{
"fieldname": "supplier_address",
"fieldtype": "Link",
- "label": "Select Supplier Address",
+ "label": "Supplier Address",
"options": "Address",
"print_hide": 1
},
{
"fieldname": "contact_person",
"fieldtype": "Link",
- "label": "Contact Person",
+ "label": "Supplier Contact",
"options": "Contact",
"print_hide": 1
},
{
"fieldname": "address_display",
"fieldtype": "Small Text",
- "label": "Address",
+ "label": "Supplier Address Details",
"read_only": 1
},
{
"fieldname": "contact_display",
"fieldtype": "Small Text",
"in_global_search": 1,
- "label": "Contact",
+ "label": "Contact Name",
"read_only": 1
},
{
"fieldname": "contact_mobile",
"fieldtype": "Small Text",
- "label": "Mobile No",
+ "label": "Contact Mobile No",
"read_only": 1
},
{
@@ -358,14 +364,14 @@
{
"fieldname": "shipping_address",
"fieldtype": "Link",
- "label": "Select Shipping Address",
+ "label": "Company Shipping Address",
"options": "Address",
"print_hide": 1
},
{
"fieldname": "shipping_address_display",
"fieldtype": "Small Text",
- "label": "Shipping Address",
+ "label": "Shipping Address Details",
"print_hide": 1,
"read_only": 1
},
@@ -433,7 +439,8 @@
},
{
"fieldname": "sec_warehouse",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Subcontracting"
},
{
"description": "Sets 'Warehouse' in each row of the Items table.",
@@ -466,6 +473,7 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -598,7 +606,8 @@
},
{
"fieldname": "section_break_52",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1
},
{
"fieldname": "taxes",
@@ -626,10 +635,12 @@
{
"fieldname": "totals",
"fieldtype": "Section Break",
+ "label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
{
+ "depends_on": "base_taxes_and_charges_added",
"fieldname": "base_taxes_and_charges_added",
"fieldtype": "Currency",
"label": "Taxes and Charges Added (Company Currency)",
@@ -640,6 +651,7 @@
"read_only": 1
},
{
+ "depends_on": "base_taxes_and_charges_deducted",
"fieldname": "base_taxes_and_charges_deducted",
"fieldtype": "Currency",
"label": "Taxes and Charges Deducted (Company Currency)",
@@ -650,6 +662,7 @@
"read_only": 1
},
{
+ "depends_on": "base_total_taxes_and_charges",
"fieldname": "base_total_taxes_and_charges",
"fieldtype": "Currency",
"label": "Total Taxes and Charges (Company Currency)",
@@ -665,6 +678,7 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "taxes_and_charges_added",
"fieldname": "taxes_and_charges_added",
"fieldtype": "Currency",
"label": "Taxes and Charges Added",
@@ -675,6 +689,7 @@
"read_only": 1
},
{
+ "depends_on": "taxes_and_charges_deducted",
"fieldname": "taxes_and_charges_deducted",
"fieldtype": "Currency",
"label": "Taxes and Charges Deducted",
@@ -685,6 +700,7 @@
"read_only": 1
},
{
+ "depends_on": "total_taxes_and_charges",
"fieldname": "total_taxes_and_charges",
"fieldtype": "Currency",
"label": "Total Taxes and Charges",
@@ -694,7 +710,7 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
+ "collapsible_depends_on": "apply_discount_on",
"fieldname": "discount_section",
"fieldtype": "Section Break",
"label": "Additional Discount"
@@ -734,7 +750,8 @@
},
{
"fieldname": "totals_section",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Totals"
},
{
"fieldname": "base_grand_total",
@@ -902,12 +919,12 @@
},
{
"fieldname": "ref_sq",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Ref SQ",
+ "fieldtype": "Link",
+ "label": "Supplier Quotation",
"no_copy": 1,
"oldfieldname": "ref_sq",
"oldfieldtype": "Data",
+ "options": "Supplier Quotation",
"print_hide": 1,
"read_only": 1
},
@@ -1061,7 +1078,7 @@
"collapsible": 1,
"fieldname": "tracking_section",
"fieldtype": "Section Break",
- "label": "Tracking"
+ "label": "Order Status"
},
{
"fieldname": "column_break_75",
@@ -1070,13 +1087,36 @@
{
"fieldname": "billing_address",
"fieldtype": "Link",
- "label": "Select Billing Address",
+ "label": "Company Billing Address",
"options": "Address"
},
{
"fieldname": "billing_address_display",
"fieldtype": "Small Text",
- "label": "Billing Address",
+ "label": "Billing Address Details",
+ "read_only": 1
+ },
+ {
+ "fieldname": "before_items_section",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "items_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fetch_from": "supplier.is_internal_supplier",
+ "fieldname": "is_internal_supplier",
+ "fieldtype": "Check",
+ "label": "Is Internal Supplier"
+ },
+ {
+ "fetch_from": "supplier.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
"read_only": 1
}
],
@@ -1084,7 +1124,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2020-09-14 14:36:12.418690",
+ "modified": "2021-01-20 22:07:23.487138",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
@@ -1130,11 +1170,11 @@
"write": 1
}
],
- "search_fields": "status, transaction_date, supplier,grand_total",
+ "search_fields": "status, transaction_date, supplier, grand_total",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"timeline_field": "supplier",
- "title_field": "supplier",
+ "title_field": "supplier_name",
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index c7efb8a..d32e98e 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -123,8 +123,8 @@
if self.is_subcontracted == "Yes":
for item in self.items:
if not item.bom:
- frappe.throw(_("BOM is not specified for subcontracting item {0} at row {1}"\
- .format(item.item_code, item.idx)))
+ frappe.throw(_("BOM is not specified for subcontracting item {0} at row {1}")
+ .format(item.item_code, item.idx))
def get_schedule_dates(self):
for d in self.get('items'):
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 158799c..604c886 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -19,6 +19,8 @@
from erpnext.controllers.status_updater import OverAllowanceError
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
+from erpnext.stock.doctype.batch.test_batch import make_new_batch
+from erpnext.controllers.buying_controller import get_backflushed_subcontracted_raw_materials
class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_receipt(self):
@@ -203,9 +205,39 @@
frappe.set_user("Administrator")
def test_update_child_with_tax_template(self):
- tax_template = "_Test Account Excise Duty @ 10"
- item = "_Test Item Home Desktop 100"
+ """
+ Test Action: Create a PO with one item having its tax account head already in the PO.
+ Add the same item + new item with tax template via Update Items.
+ Expected result: First Item's tax row is updated. New tax row is added for second Item.
+ """
+ if not frappe.db.exists("Item", "Test Item with Tax"):
+ make_item("Test Item with Tax", {
+ 'is_stock_item': 1,
+ })
+ if not frappe.db.exists("Item Tax Template", {"title": 'Test Update Items Template'}):
+ frappe.get_doc({
+ 'doctype': 'Item Tax Template',
+ 'title': 'Test Update Items Template',
+ 'company': '_Test Company',
+ 'taxes': [
+ {
+ 'tax_type': "_Test Account Service Tax - _TC",
+ 'tax_rate': 10,
+ }
+ ]
+ }).insert()
+
+ new_item_with_tax = frappe.get_doc("Item", "Test Item with Tax")
+
+ new_item_with_tax.append("taxes", {
+ "item_tax_template": "Test Update Items Template - _TC",
+ "valid_from": nowdate()
+ })
+ new_item_with_tax.save()
+
+ tax_template = "_Test Account Excise Duty @ 10 - _TC"
+ item = "_Test Item Home Desktop 100"
if not frappe.db.exists("Item Tax", {"parent":item, "item_tax_template":tax_template}):
item_doc = frappe.get_doc("Item", item)
item_doc.append("taxes", {
@@ -237,17 +269,25 @@
items = json.dumps([
{'item_code' : item, 'rate' : 500, 'qty' : 1, 'docname': po.items[0].name},
- {'item_code' : item, 'rate' : 100, 'qty' : 1} # added item
+ {'item_code' : item, 'rate' : 100, 'qty' : 1}, # added item whose tax account head already exists in PO
+ {'item_code' : new_item_with_tax.name, 'rate' : 100, 'qty' : 1} # added item whose tax account head is missing in PO
])
update_child_qty_rate('Purchase Order', items, po.name)
po.reload()
- self.assertEqual(po.taxes[0].tax_amount, 60)
- self.assertEqual(po.taxes[0].total, 660)
+ self.assertEqual(po.taxes[0].tax_amount, 70)
+ self.assertEqual(po.taxes[0].total, 770)
+ self.assertEqual(po.taxes[1].account_head, "_Test Account Service Tax - _TC")
+ self.assertEqual(po.taxes[1].tax_amount, 70)
+ self.assertEqual(po.taxes[1].total, 840)
+ # teardown
frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = NULL
- where parent = %(item)s and item_tax_template = %(tax)s""",
- {"item": item, "tax": tax_template})
+ where parent = %(item)s and item_tax_template = %(tax)s""", {"item": item, "tax": tax_template})
+ po.cancel()
+ po.delete()
+ new_item_with_tax.delete()
+ frappe.get_doc("Item Tax Template", "Test Update Items Template - _TC").delete()
def test_update_child_uom_conv_factor_change(self):
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
@@ -648,15 +688,15 @@
def test_exploded_items_in_subcontracted(self):
item_code = "_Test Subcontracted FG Item 1"
- make_subcontracted_item(item_code)
+ make_subcontracted_item(item_code=item_code)
po = create_purchase_order(item_code=item_code, qty=1,
- is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
+ is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", include_exploded_items=1)
name = frappe.db.get_value('BOM', {'item': item_code}, 'name')
bom = frappe.get_doc('BOM', name)
- exploded_items = sorted([d.item_code for d in bom.exploded_items])
+ exploded_items = sorted([d.item_code for d in bom.exploded_items if not d.get('sourced_by_supplier')])
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
self.assertEquals(exploded_items, supplied_items)
@@ -664,13 +704,13 @@
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", include_exploded_items=0)
supplied_items1 = sorted([d.rm_item_code for d in po1.supplied_items])
- bom_items = sorted([d.item_code for d in bom.items])
+ bom_items = sorted([d.item_code for d in bom.items if not d.get('sourced_by_supplier')])
self.assertEquals(supplied_items1, bom_items)
def test_backflush_based_on_stock_entry(self):
item_code = "_Test Subcontracted FG Item 1"
- make_subcontracted_item(item_code)
+ make_subcontracted_item(item_code=item_code)
make_item('Sub Contracted Raw Material 1', {
'is_stock_item': 1,
'is_sub_contracted_item': 1
@@ -683,7 +723,7 @@
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
make_stock_entry(target="_Test Warehouse - _TC",
- item_code="_Test Item Home Desktop 100", qty=10, basic_rate=100)
+ item_code="_Test Item Home Desktop 100", qty=20, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
item_code = "Test Extra Item 1", qty=100, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
@@ -729,6 +769,133 @@
update_backflush_based_on("BOM")
+ def test_backflushed_based_on_for_multiple_batches(self):
+ item_code = "_Test Subcontracted FG Item 2"
+ make_item('Sub Contracted Raw Material 2', {
+ 'is_stock_item': 1,
+ 'is_sub_contracted_item': 1
+ })
+
+ make_subcontracted_item(item_code=item_code, has_batch_no=1, create_new_batch=1,
+ raw_materials=["Sub Contracted Raw Material 2"])
+
+ update_backflush_based_on("Material Transferred for Subcontract")
+
+ order_qty = 500
+ po = create_purchase_order(item_code=item_code, qty=order_qty,
+ is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
+
+ make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Sub Contracted Raw Material 2", qty=552, basic_rate=100)
+
+ rm_items = [
+ {"item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 2","item_name":"_Test Item",
+ "qty":552,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos"}]
+
+ rm_item_string = json.dumps(rm_items)
+ se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
+ se.submit()
+
+ for batch in ["ABCD1", "ABCD2", "ABCD3", "ABCD4"]:
+ make_new_batch(batch_id=batch, item_code=item_code)
+
+ pr = make_purchase_receipt(po.name)
+
+ # partial receipt
+ pr.get('items')[0].qty = 30
+ pr.get('items')[0].batch_no = "ABCD1"
+
+ purchase_order = po.name
+ purchase_order_item = po.items[0].name
+
+ for batch_no, qty in {"ABCD2": 60, "ABCD3": 70, "ABCD4":40}.items():
+ pr.append("items", {
+ "item_code": pr.get('items')[0].item_code,
+ "item_name": pr.get('items')[0].item_name,
+ "uom": pr.get('items')[0].uom,
+ "stock_uom": pr.get('items')[0].stock_uom,
+ "warehouse": pr.get('items')[0].warehouse,
+ "conversion_factor": pr.get('items')[0].conversion_factor,
+ "cost_center": pr.get('items')[0].cost_center,
+ "rate": pr.get('items')[0].rate,
+ "qty": qty,
+ "batch_no": batch_no,
+ "purchase_order": purchase_order,
+ "purchase_order_item": purchase_order_item
+ })
+
+ pr.submit()
+
+ pr1 = make_purchase_receipt(po.name)
+ pr1.get('items')[0].qty = 300
+ pr1.get('items')[0].batch_no = "ABCD1"
+ pr1.save()
+
+ pr_key = ("Sub Contracted Raw Material 2", po.name)
+ consumed_qty = get_backflushed_subcontracted_raw_materials([po.name]).get(pr_key)
+
+ self.assertTrue(pr1.supplied_items[0].consumed_qty > 0)
+ self.assertTrue(pr1.supplied_items[0].consumed_qty, flt(552.0) - flt(consumed_qty))
+
+ update_backflush_based_on("BOM")
+
+ def test_supplied_qty_against_subcontracted_po(self):
+ item_code = "_Test Subcontracted FG Item 5"
+ make_item('Sub Contracted Raw Material 4', {
+ 'is_stock_item': 1,
+ 'is_sub_contracted_item': 1
+ })
+
+ make_subcontracted_item(item_code=item_code, raw_materials=["Sub Contracted Raw Material 4"])
+
+ update_backflush_based_on("Material Transferred for Subcontract")
+
+ order_qty = 250
+ po = create_purchase_order(item_code=item_code, qty=order_qty,
+ is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", do_not_save=True)
+
+ # Add same subcontracted items multiple times
+ po.append("items", {
+ "item_code": item_code,
+ "qty": order_qty,
+ "schedule_date": add_days(nowdate(), 1),
+ "warehouse": "_Test Warehouse - _TC"
+ })
+
+ po.set_missing_values()
+ po.submit()
+
+ # Material receipt entry for the raw materials which will be send to supplier
+ make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Sub Contracted Raw Material 4", qty=500, basic_rate=100)
+
+ rm_items = [
+ {
+ "item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 4","item_name":"_Test Item",
+ "qty":250,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos", "name": po.supplied_items[0].name
+ },
+ {
+ "item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 4","item_name":"_Test Item",
+ "qty":250,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos"
+ },
+ ]
+
+ # Raw Materials transfer entry from stores to supplier's warehouse
+ rm_item_string = json.dumps(rm_items)
+ se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
+ se.submit()
+
+ # Test po_detail field has value or not
+ for item_row in se.items:
+ self.assertEqual(item_row.po_detail, po.supplied_items[item_row.idx - 1].name)
+
+ po_doc = frappe.get_doc("Purchase Order", po.name)
+ for row in po_doc.supplied_items:
+ # Valid that whether transferred quantity is matching with supplied qty or not in the purchase order
+ self.assertEqual(row.supplied_qty, 250.0)
+
+ update_backflush_based_on("BOM")
+
def test_advance_payment_entry_unlink_against_purchase_order(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
frappe.db.set_value("Accounts Settings", "Accounts Settings",
@@ -801,27 +968,33 @@
pr.submit()
return pr
-def make_subcontracted_item(item_code):
+def make_subcontracted_item(**args):
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
- if not frappe.db.exists('Item', item_code):
- make_item(item_code, {
+ args = frappe._dict(args)
+
+ if not frappe.db.exists('Item', args.item_code):
+ make_item(args.item_code, {
'is_stock_item': 1,
- 'is_sub_contracted_item': 1
+ 'is_sub_contracted_item': 1,
+ 'has_batch_no': args.get("has_batch_no") or 0
})
- if not frappe.db.exists('Item', "Test Extra Item 1"):
- make_item("Test Extra Item 1", {
- 'is_stock_item': 1,
- })
+ if not args.raw_materials:
+ if not frappe.db.exists('Item', "Test Extra Item 1"):
+ make_item("Test Extra Item 1", {
+ 'is_stock_item': 1,
+ })
- if not frappe.db.exists('Item', "Test Extra Item 2"):
- make_item("Test Extra Item 2", {
- 'is_stock_item': 1,
- })
+ if not frappe.db.exists('Item', "Test Extra Item 2"):
+ make_item("Test Extra Item 2", {
+ 'is_stock_item': 1,
+ })
- if not frappe.db.get_value('BOM', {'item': item_code}, 'name'):
- make_bom(item = item_code, raw_materials = ['_Test FG Item', 'Test Extra Item 1'])
+ args.raw_materials = ['_Test FG Item', 'Test Extra Item 1']
+
+ if not frappe.db.get_value('BOM', {'item': args.item_code}, 'name'):
+ make_bom(item = args.item_code, raw_materials = args.get("raw_materials"))
def update_backflush_based_on(based_on):
doc = frappe.get_doc('Buying Settings')
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 7a52c28..5baf693 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -24,13 +24,20 @@
"col_break2",
"uom",
"conversion_factor",
+ "stock_qty",
"sec_break1",
"price_list_rate",
+ "last_purchase_rate",
+ "col_break3",
+ "base_price_list_rate",
+ "discount_and_margin_section",
+ "margin_type",
+ "margin_rate_or_amount",
+ "rate_with_margin",
+ "column_break_28",
"discount_percentage",
"discount_amount",
- "col_break3",
- "last_purchase_rate",
- "base_price_list_rate",
+ "base_rate_with_margin",
"sec_break2",
"rate",
"amount",
@@ -39,6 +46,7 @@
"base_rate",
"base_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_29",
"net_rate",
@@ -46,11 +54,8 @@
"column_break_32",
"base_net_rate",
"base_net_amount",
- "billed_amt",
"warehouse_and_reference",
"warehouse",
- "delivered_by_supplier",
- "project",
"material_request",
"material_request_item",
"sales_order",
@@ -58,36 +63,37 @@
"supplier_quotation",
"supplier_quotation_item",
"col_break5",
+ "delivered_by_supplier",
"against_blanket_order",
"blanket_order",
"blanket_order_rate",
"item_group",
"brand",
- "bom",
- "include_exploded_items",
"section_break_56",
- "stock_qty",
- "column_break_60",
"received_qty",
"returned_qty",
- "manufacture_details",
- "manufacturer",
- "column_break_14",
- "manufacturer_part_no",
- "more_info_section_break",
- "is_fixed_asset",
- "item_tax_rate",
+ "column_break_60",
+ "billed_amt",
"accounting_details",
"expense_account",
- "column_break_68",
+ "manufacture_details",
+ "manufacturer",
+ "manufacturer_part_no",
+ "column_break_14",
+ "bom",
+ "include_exploded_items",
"item_weight_details",
"weight_per_unit",
"total_weight",
"column_break_40",
"weight_uom",
"accounting_dimensions_section",
- "cost_center",
+ "project",
"dimension_col_break",
+ "cost_center",
+ "more_info_section_break",
+ "is_fixed_asset",
+ "item_tax_rate",
"section_break_72",
"page_break"
],
@@ -346,6 +352,7 @@
},
{
"default": "0",
+ "depends_on": "is_free_item",
"fieldname": "is_free_item",
"fieldtype": "Check",
"label": "Is Free Item",
@@ -508,9 +515,10 @@
},
{
"default": "0",
+ "depends_on": "delivered_by_supplier",
"fieldname": "delivered_by_supplier",
"fieldtype": "Check",
- "label": "To be delivered to customer",
+ "label": "To be Delivered to Customer",
"print_hide": 1,
"read_only": 1
},
@@ -558,6 +566,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.is_subcontracted == 'Yes'",
"fieldname": "bom",
"fieldtype": "Link",
"label": "BOM",
@@ -574,21 +583,21 @@
},
{
"fieldname": "section_break_56",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Billed, Received & Returned"
},
{
"fieldname": "stock_qty",
"fieldtype": "Float",
- "label": "Qty as per Stock UOM",
+ "label": "Qty in Stock UOM",
"no_copy": 1,
- "oldfieldname": "stock_qty",
- "oldfieldtype": "Currency",
"print_hide": 1,
"print_width": "100px",
"read_only": 1,
"width": "100px"
},
{
+ "depends_on": "received_qty",
"fieldname": "received_qty",
"fieldtype": "Float",
"label": "Received Qty",
@@ -612,9 +621,10 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "billed_amt",
"fieldname": "billed_amt",
"fieldtype": "Currency",
- "label": "Billed Amt",
+ "label": "Billed Amount",
"no_copy": 1,
"options": "currency",
"print_hide": 1,
@@ -633,6 +643,7 @@
"report_hide": 1
},
{
+ "collapsible": 1,
"fieldname": "accounting_details",
"fieldtype": "Section Break",
"label": "Accounting Details"
@@ -645,10 +656,6 @@
"print_hide": 1
},
{
- "fieldname": "column_break_68",
- "fieldtype": "Column Break"
- },
- {
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
@@ -715,6 +722,7 @@
},
{
"default": "0",
+ "depends_on": "is_fixed_asset",
"fetch_from": "item_code.is_fixed_asset",
"fieldname": "is_fixed_asset",
"fieldtype": "Check",
@@ -725,12 +733,65 @@
"fieldname": "more_info_section_break",
"fieldtype": "Section Break",
"label": "More Information"
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "discount_and_margin_section",
+ "fieldtype": "Section Break",
+ "label": "Discount and Margin"
+ },
+ {
+ "depends_on": "price_list_rate",
+ "fieldname": "margin_type",
+ "fieldtype": "Select",
+ "label": "Margin Type",
+ "options": "\nPercentage\nAmount",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate",
+ "fieldname": "margin_rate_or_amount",
+ "fieldtype": "Float",
+ "label": "Margin Rate or Amount",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "rate_with_margin",
+ "fieldtype": "Currency",
+ "label": "Rate With Margin",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_28",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "label": "Rate With Margin (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-21 11:55:58.643393",
+ "modified": "2021-02-23 01:00:27.132705",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
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 b711e36..8bdcd47 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py
@@ -6,11 +6,8 @@
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
-
class PurchaseOrderItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
def on_doctype_update():
frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])
\ No newline at end of file
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index 4a937f7..b76c378 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -22,8 +22,6 @@
},
onload: function(frm) {
- frm.add_fetch('email_template', 'response', 'message_for_supplier');
-
if(!frm.doc.message_for_supplier) {
frm.set_value("message_for_supplier", __("Please supply the specified items at the best possible rates"))
}
@@ -31,14 +29,12 @@
refresh: function(frm, cdt, cdn) {
if (frm.doc.docstatus === 1) {
- frm.add_custom_button(__('Create'),
- function(){ frm.trigger("make_suppplier_quotation") }, __("Supplier Quotation"));
- frm.add_custom_button(__("View"),
- function(){ frappe.set_route('List', 'Supplier Quotation',
- {'request_for_quotation': frm.doc.name}) }, __("Supplier Quotation"));
+ frm.add_custom_button(__('Supplier Quotation'),
+ function(){ frm.trigger("make_suppplier_quotation") }, __("Create"));
- frm.add_custom_button(__("Send Supplier Emails"), function() {
+
+ frm.add_custom_button(__("Send Emails to Suppliers"), function() {
frappe.call({
method: 'erpnext.buying.doctype.request_for_quotation.request_for_quotation.send_supplier_emails',
freeze: true,
@@ -49,11 +45,273 @@
frm.reload_doc();
}
});
- });
+ }, __("Tools"));
+
+ frm.add_custom_button(__('Download PDF'), () => {
+ var suppliers = [];
+ const fields = [{
+ fieldtype: 'Link',
+ label: __('Select a Supplier'),
+ fieldname: 'supplier',
+ options: 'Supplier',
+ reqd: 1,
+ get_query: () => {
+ return {
+ filters: [
+ ["Supplier", "name", "in", frm.doc.suppliers.map((row) => {return row.supplier;})]
+ ]
+ }
+ }
+ }];
+
+ frappe.prompt(fields, data => {
+ var child = locals[cdt][cdn]
+
+ var w = window.open(
+ frappe.urllib.get_full_url("/api/method/erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_pdf?"
+ +"doctype="+encodeURIComponent(frm.doc.doctype)
+ +"&name="+encodeURIComponent(frm.doc.name)
+ +"&supplier="+encodeURIComponent(data.supplier)
+ +"&no_letterhead=0"));
+ if(!w) {
+ frappe.msgprint(__("Please enable pop-ups")); return;
+ }
+ },
+ 'Download PDF for Supplier',
+ 'Download');
+ },
+ __("Tools"));
+
+ frm.page.set_inner_btn_group_as_primary(__('Create'));
}
},
+ make_suppplier_quotation: function(frm) {
+ var doc = frm.doc;
+ var dialog = new frappe.ui.Dialog({
+ title: __("Create Supplier Quotation"),
+ fields: [
+ { "fieldtype": "Select", "label": __("Supplier"),
+ "fieldname": "supplier",
+ "options": doc.suppliers.map(d => d.supplier),
+ "reqd": 1,
+ "default": doc.suppliers.length === 1 ? doc.suppliers[0].supplier_name : "" },
+ ],
+ primary_action_label: __("Create"),
+ primary_action: (args) => {
+ if(!args) return;
+ dialog.hide();
+
+ return frappe.call({
+ type: "GET",
+ method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation_from_rfq",
+ args: {
+ "source_name": doc.name,
+ "for_supplier": args.supplier
+ },
+ freeze: true,
+ callback: function(r) {
+ if(!r.exc) {
+ var doc = frappe.model.sync(r.message);
+ frappe.set_route("Form", r.message.doctype, r.message.name);
+ }
+ }
+ });
+ }
+ });
+
+ dialog.show()
+ },
+
+ preview: (frm) => {
+ let dialog = new frappe.ui.Dialog({
+ title: __('Preview Email'),
+ fields: [
+ {
+ label: __('Supplier'),
+ fieldtype: 'Select',
+ fieldname: 'supplier',
+ options: frm.doc.suppliers.map(row => row.supplier),
+ reqd: 1
+ },
+ {
+ fieldtype: 'Column Break',
+ fieldname: 'col_break_1',
+ },
+ {
+ label: __('Subject'),
+ fieldtype: 'Data',
+ fieldname: 'subject',
+ read_only: 1,
+ depends_on: 'subject'
+ },
+ {
+ fieldtype: 'Section Break',
+ fieldname: 'sec_break_1',
+ hide_border: 1
+ },
+ {
+ label: __('Email'),
+ fieldtype: 'HTML',
+ fieldname: 'email_preview'
+ },
+ {
+ fieldtype: 'Section Break',
+ fieldname: 'sec_break_2'
+ },
+ {
+ label: __('Note'),
+ fieldtype: 'HTML',
+ fieldname: 'note'
+ }
+ ]
+ });
+
+ dialog.fields_dict['supplier'].df.onchange = () => {
+ var supplier = dialog.get_value('supplier');
+ frm.call('get_supplier_email_preview', {supplier: supplier}).then(result => {
+ dialog.fields_dict.email_preview.$wrapper.empty();
+ dialog.fields_dict.email_preview.$wrapper.append(result.message);
+ });
+
+ }
+
+ dialog.fields_dict.note.$wrapper.append(`<p class="small text-muted">This is a preview of the email to be sent. A PDF of the document will
+ automatically be attached with the email.</p>`);
+
+ dialog.set_value("subject", frm.doc.subject);
+ dialog.show();
+ }
+})
+
+frappe.ui.form.on("Request for Quotation Supplier",{
+ supplier: function(frm, cdt, cdn) {
+ var d = locals[cdt][cdn]
+ frappe.call({
+ method:"erpnext.accounts.party.get_party_details",
+ args:{
+ party: d.supplier,
+ party_type: 'Supplier'
+ },
+ callback: function(r){
+ if(r.message){
+ frappe.model.set_value(cdt, cdn, 'contact', r.message.contact_person)
+ frappe.model.set_value(cdt, cdn, 'email_id', r.message.contact_email)
+ }
+ }
+ })
+ },
+
+})
+
+erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({
+ refresh: function() {
+ var me = this;
+ this._super();
+ if (this.frm.doc.docstatus===0) {
+ this.frm.add_custom_button(__('Material Request'),
+ function() {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation",
+ source_doctype: "Material Request",
+ target: me.frm,
+ setters: {
+ schedule_date: undefined,
+ status: undefined
+ },
+ get_query_filters: {
+ material_request_type: "Purchase",
+ docstatus: 1,
+ status: ["!=", "Stopped"],
+ per_ordered: ["<", 100],
+ company: me.frm.doc.company
+ }
+ })
+ }, __("Get Items From"));
+
+ // Get items from Opportunity
+ this.frm.add_custom_button(__('Opportunity'),
+ function() {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.crm.doctype.opportunity.opportunity.make_request_for_quotation",
+ source_doctype: "Opportunity",
+ target: me.frm,
+ setters: {
+ party_name: undefined,
+ opportunity_from: undefined,
+ status: undefined
+ },
+ get_query_filters: {
+ status: ["not in", ["Closed", "Lost"]],
+ company: me.frm.doc.company
+ }
+ })
+ }, __("Get Items From"));
+
+ // Get items from open Material Requests based on supplier
+ this.frm.add_custom_button(__('Possible Supplier'), function() {
+ // Create a dialog window for the user to pick their supplier
+ var dialog = new frappe.ui.Dialog({
+ title: __('Select Possible Supplier'),
+ fields: [
+ {
+ fieldname: 'supplier',
+ fieldtype:'Link',
+ options:'Supplier',
+ label:'Supplier',
+ reqd:1,
+ description: __("Get Items from Material Requests against this Supplier")
+ }
+ ],
+ primary_action_label: __("Get Items"),
+ primary_action: (args) => {
+ if(!args) return;
+ dialog.hide();
+
+ erpnext.utils.map_current_doc({
+ method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_item_from_material_requests_based_on_supplier",
+ source_name: args.supplier,
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
+ get_query_filters: {
+ material_request_type: "Purchase",
+ docstatus: 1,
+ status: ["!=", "Stopped"],
+ per_ordered: ["<", 100]
+ }
+ });
+ dialog.hide();
+ }
+ });
+
+ dialog.show();
+ }, __("Get Items From"));
+
+ // Link Material Requests
+ this.frm.add_custom_button(__('Link to Material Requests'),
+ function() {
+ erpnext.buying.link_to_mrs(me.frm);
+ }, __("Tools"));
+
+ // Get Suppliers
+ this.frm.add_custom_button(__('Get Suppliers'),
+ function() {
+ me.get_suppliers_button(me.frm);
+ }, __("Tools"));
+ }
+ },
+
+ calculate_taxes_and_totals: function() {
+ return;
+ },
+
+ tc_name: function() {
+ this.get_terms();
+ },
+
get_suppliers_button: function (frm) {
var doc = frm.doc;
var dialog = new frappe.ui.Dialog({
@@ -62,7 +320,7 @@
{
"fieldtype": "Select", "label": __("Get Suppliers By"),
"fieldname": "search_type",
- "options": ["Tag","Supplier Group"],
+ "options": ["Supplier Group", "Tag"],
"reqd": 1,
onchange() {
if(dialog.get_value('search_type') == 'Tag'){
@@ -86,258 +344,74 @@
"fieldname": "tag",
"reqd": 0,
"depends_on": "eval:doc.search_type == 'Tag'",
- },
- {
- "fieldtype": "Button", "label": __("Add All Suppliers"),
- "fieldname": "add_suppliers"
- },
- ]
- });
-
- dialog.fields_dict.add_suppliers.$input.click(function() {
- var args = dialog.get_values();
- if(!args) return;
- dialog.hide();
-
- //Remove blanks
- for (var j = 0; j < frm.doc.suppliers.length; j++) {
- if(!frm.doc.suppliers[j].hasOwnProperty("supplier")) {
- frm.get_field("suppliers").grid.grid_rows[j].remove();
}
- }
+ ],
+ primary_action_label: __("Add Suppliers"),
+ primary_action : (args) => {
+ if(!args) return;
+ dialog.hide();
- function load_suppliers(r) {
- if(r.message) {
- for (var i = 0; i < r.message.length; i++) {
- var exists = false;
- if (r.message[i].constructor === Array){
- var supplier = r.message[i][0];
- } else {
- var supplier = r.message[i].name;
- }
+ //Remove blanks
+ for (var j = 0; j < frm.doc.suppliers.length; j++) {
+ if(!frm.doc.suppliers[j].hasOwnProperty("supplier")) {
+ frm.get_field("suppliers").grid.grid_rows[j].remove();
+ }
+ }
- for (var j = 0; j < doc.suppliers.length;j++) {
- if (supplier === doc.suppliers[j].supplier) {
- exists = true;
+ function load_suppliers(r) {
+ if(r.message) {
+ for (var i = 0; i < r.message.length; i++) {
+ var exists = false;
+ if (r.message[i].constructor === Array){
+ var supplier = r.message[i][0];
+ } else {
+ var supplier = r.message[i].name;
+ }
+
+ for (var j = 0; j < doc.suppliers.length;j++) {
+ if (supplier === doc.suppliers[j].supplier) {
+ exists = true;
+ }
+ }
+ if(!exists) {
+ var d = frm.add_child('suppliers');
+ d.supplier = supplier;
+ frm.script_manager.trigger("supplier", d.doctype, d.name);
}
}
- if(!exists) {
- var d = frm.add_child('suppliers');
- d.supplier = supplier;
- frm.script_manager.trigger("supplier", d.doctype, d.name);
- }
}
- }
- frm.refresh_field("suppliers");
- }
-
- if (args.search_type === "Tag" && args.tag) {
- return frappe.call({
- type: "GET",
- method: "frappe.desk.doctype.tag.tag.get_tagged_docs",
- args: {
- "doctype": "Supplier",
- "tag": args.tag
- },
- callback: load_suppliers
- });
- } else if (args.supplier_group) {
- return frappe.call({
- method: "frappe.client.get_list",
- args: {
- doctype: "Supplier",
- order_by: "name",
- fields: ["name"],
- filters: [["Supplier", "supplier_group", "=", args.supplier_group]]
-
- },
- callback: load_suppliers
- });
- }
- });
- dialog.show();
-
- },
- make_suppplier_quotation: function(frm) {
- var doc = frm.doc;
- var dialog = new frappe.ui.Dialog({
- title: __("For Supplier"),
- fields: [
- { "fieldtype": "Select", "label": __("Supplier"),
- "fieldname": "supplier",
- "options": doc.suppliers.map(d => d.supplier),
- "reqd": 1,
- "default": doc.suppliers.length === 1 ? doc.suppliers[0].supplier_name : "" },
- { "fieldtype": "Button", "label": __('Create Supplier Quotation'),
- "fieldname": "make_supplier_quotation", "cssClass": "btn-primary" },
- ]
- });
-
- dialog.fields_dict.make_supplier_quotation.$input.click(function() {
- var args = dialog.get_values();
- if(!args) return;
- dialog.hide();
- return frappe.call({
- type: "GET",
- method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation",
- args: {
- "source_name": doc.name,
- "for_supplier": args.supplier
- },
- freeze: true,
- callback: function(r) {
- if(!r.exc) {
- var doc = frappe.model.sync(r.message);
- frappe.set_route("Form", r.message.doctype, r.message.name);
- }
- }
- });
- });
- dialog.show()
- }
-})
-
-frappe.ui.form.on("Request for Quotation Supplier",{
- supplier: function(frm, cdt, cdn) {
- var d = locals[cdt][cdn]
- frappe.call({
- method:"erpnext.accounts.party.get_party_details",
- args:{
- party: d.supplier,
- party_type: 'Supplier'
- },
- callback: function(r){
- if(r.message){
- frappe.model.set_value(cdt, cdn, 'contact', r.message.contact_person)
- frappe.model.set_value(cdt, cdn, 'email_id', r.message.contact_email)
- }
- }
- })
- },
-
- download_pdf: function(frm, cdt, cdn) {
- var child = locals[cdt][cdn]
-
- var w = window.open(
- frappe.urllib.get_full_url("/api/method/erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_pdf?"
- +"doctype="+encodeURIComponent(frm.doc.doctype)
- +"&name="+encodeURIComponent(frm.doc.name)
- +"&supplier_idx="+encodeURIComponent(child.idx)
- +"&no_letterhead=0"));
- if(!w) {
- frappe.msgprint(__("Please enable pop-ups")); return;
- }
- },
- no_quote: function(frm, cdt, cdn) {
- var d = locals[cdt][cdn];
- if (d.no_quote) {
- if (d.quote_status != __('Received')) {
- frappe.model.set_value(cdt, cdn, 'quote_status', 'No Quote');
- } else {
- frappe.msgprint(__("Cannot set a received RFQ to No Quote"));
- frappe.model.set_value(cdt, cdn, 'no_quote', 0);
- }
- } else {
- d.quote_status = __('Pending');
- frm.call({
- method:"update_rfq_supplier_status",
- doc: frm.doc,
- args: {
- sup_name: d.supplier
- },
- callback: function(r) {
frm.refresh_field("suppliers");
}
- });
- }
- }
-})
-erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({
- refresh: function() {
- var me = this;
- this._super();
- if (this.frm.doc.docstatus===0) {
- this.frm.add_custom_button(__('Material Request'),
- function() {
- erpnext.utils.map_current_doc({
- method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation",
- source_doctype: "Material Request",
- target: me.frm,
- setters: {
- company: me.frm.doc.company
+ if (args.search_type === "Tag" && args.tag) {
+ return frappe.call({
+ type: "GET",
+ method: "frappe.desk.doctype.tag.tag.get_tagged_docs",
+ args: {
+ "doctype": "Supplier",
+ "tag": args.tag
},
- get_query_filters: {
- material_request_type: "Purchase",
- docstatus: 1,
- status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99]
- }
- })
- }, __("Get items from"));
- // Get items from Opportunity
- this.frm.add_custom_button(__('Opportunity'),
- function() {
- erpnext.utils.map_current_doc({
- method: "erpnext.crm.doctype.opportunity.opportunity.make_request_for_quotation",
- source_doctype: "Opportunity",
- target: me.frm,
- setters: {
- company: me.frm.doc.company
+ callback: load_suppliers
+ });
+ } else if (args.supplier_group) {
+ return frappe.call({
+ method: "frappe.client.get_list",
+ args: {
+ doctype: "Supplier",
+ order_by: "name",
+ fields: ["name"],
+ filters: [["Supplier", "supplier_group", "=", args.supplier_group]]
+
},
- })
- }, __("Get items from"));
- // Get items from open Material Requests based on supplier
- this.frm.add_custom_button(__('Possible Supplier'), function() {
- // Create a dialog window for the user to pick their supplier
- var d = new frappe.ui.Dialog({
- title: __('Select Possible Supplier'),
- fields: [
- {fieldname: 'supplier', fieldtype:'Link', options:'Supplier', label:'Supplier', reqd:1},
- {fieldname: 'ok_button', fieldtype:'Button', label:'Get Items from Material Requests'},
- ]
- });
-
- // On the user clicking the ok button
- d.fields_dict.ok_button.input.onclick = function() {
- var btn = d.fields_dict.ok_button.input;
- var v = d.get_values();
- if(v) {
- $(btn).set_working();
-
- erpnext.utils.map_current_doc({
- method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_item_from_material_requests_based_on_supplier",
- source_name: v.supplier,
- target: me.frm,
- setters: {
- company: me.frm.doc.company
- },
- get_query_filters: {
- material_request_type: "Purchase",
- docstatus: 1,
- status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99]
- }
- });
- $(btn).done_working();
- d.hide();
- }
+ callback: load_suppliers
+ });
}
- d.show();
- }, __("Get items from"));
+ }
+ });
- }
+ dialog.show();
},
-
- calculate_taxes_and_totals: function() {
- return;
- },
-
- tc_name: function() {
- this.get_terms();
- }
});
-
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.buying.RequestforQuotationController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
index 5cd8e6f..4ce4100 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
@@ -1,5 +1,5 @@
{
- "actions": "",
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2016-02-25 01:24:07.224790",
@@ -12,25 +12,26 @@
"vendor",
"column_break1",
"transaction_date",
+ "status",
+ "amended_from",
"suppliers_section",
"suppliers",
- "get_suppliers_button",
"items_section",
"items",
- "link_to_mrs",
"supplier_response_section",
+ "salutation",
+ "subject",
+ "col_break_email_1",
"email_template",
+ "preview",
+ "sec_break_email_2",
"message_for_supplier",
"terms_section_break",
"tc_name",
"terms",
"printing_settings",
"select_print_heading",
- "letter_head",
- "more_info",
- "status",
- "column_break3",
- "amended_from"
+ "letter_head"
],
"fields": [
{
@@ -78,6 +79,7 @@
"width": "50%"
},
{
+ "default": "Today",
"fieldname": "transaction_date",
"fieldtype": "Date",
"in_list_view": 1,
@@ -94,17 +96,12 @@
{
"fieldname": "suppliers",
"fieldtype": "Table",
- "label": "Supplier Detail",
+ "label": "Suppliers",
"options": "Request for Quotation Supplier",
"print_hide": 1,
"reqd": 1
},
{
- "fieldname": "get_suppliers_button",
- "fieldtype": "Button",
- "label": "Get Suppliers"
- },
- {
"fieldname": "items_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
@@ -120,14 +117,9 @@
"reqd": 1
},
{
- "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
- "fieldname": "link_to_mrs",
- "fieldtype": "Button",
- "label": "Link to Material Requests"
- },
- {
"fieldname": "supplier_response_section",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Email Details"
},
{
"fieldname": "email_template",
@@ -137,6 +129,9 @@
"print_hide": 1
},
{
+ "allow_on_submit": 1,
+ "fetch_from": "email_template.response",
+ "fetch_if_empty": 1,
"fieldname": "message_for_supplier",
"fieldtype": "Text Editor",
"in_list_view": 1,
@@ -198,14 +193,6 @@
"print_hide": 1
},
{
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text"
- },
- {
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
@@ -219,10 +206,6 @@
"search_index": 1
},
{
- "fieldname": "column_break3",
- "fieldtype": "Column Break"
- },
- {
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
@@ -230,12 +213,46 @@
"options": "Request for Quotation",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fetch_from": "email_template.subject",
+ "fetch_if_empty": 1,
+ "fieldname": "subject",
+ "fieldtype": "Data",
+ "label": "Subject",
+ "print_hide": 1
+ },
+ {
+ "description": "Select a greeting for the receiver. E.g. Mr., Ms., etc.",
+ "fieldname": "salutation",
+ "fieldtype": "Link",
+ "label": "Salutation",
+ "no_copy": 1,
+ "options": "Salutation",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "col_break_email_1",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:!doc.docstatus==1",
+ "fieldname": "preview",
+ "fieldtype": "Button",
+ "label": "Preview Email"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "sec_break_email_2",
+ "fieldtype": "Section Break",
+ "hide_border": 1
}
],
"icon": "fa fa-shopping-cart",
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-06-25 14:37:21.140194",
+ "modified": "2020-11-05 22:04:29.017134",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation",
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 b54a585..7cf22f8 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -28,6 +28,10 @@
super(RequestforQuotation, self).set_qty_as_per_stock_uom()
self.update_email_id()
+ if self.docstatus < 1:
+ # after amend and save, status still shows as cancelled, until submit
+ frappe.db.set(self, 'status', 'Draft')
+
def validate_duplicate_supplier(self):
supplier_list = [d.supplier for d in self.suppliers]
if len(supplier_list) != len(set(supplier_list)):
@@ -51,7 +55,7 @@
def validate_email_id(self, args):
if not args.email_id:
- frappe.throw(_("Row {0}: For Supplier {0}, Email Address is Required to Send Email").format(args.idx, args.supplier))
+ frappe.throw(_("Row {0}: For Supplier {1}, Email Address is Required to send an email").format(args.idx, frappe.bold(args.supplier)))
def on_submit(self):
frappe.db.set(self, 'status', 'Submitted')
@@ -62,43 +66,58 @@
def on_cancel(self):
frappe.db.set(self, 'status', 'Cancelled')
+ def get_supplier_email_preview(self, supplier):
+ """Returns formatted email preview as string."""
+ rfq_suppliers = list(filter(lambda row: row.supplier == supplier, self.suppliers))
+ rfq_supplier = rfq_suppliers[0]
+
+ self.validate_email_id(rfq_supplier)
+
+ message = self.supplier_rfq_mail(rfq_supplier, '', self.get_link(), True)
+
+ return message
+
def send_to_supplier(self):
+ """Sends RFQ mail to involved suppliers."""
for rfq_supplier in self.suppliers:
if rfq_supplier.send_email:
self.validate_email_id(rfq_supplier)
# make new user if required
- update_password_link = self.update_supplier_contact(rfq_supplier, self.get_link())
+ update_password_link, contact = self.update_supplier_contact(rfq_supplier, self.get_link())
- self.update_supplier_part_no(rfq_supplier)
+ self.update_supplier_part_no(rfq_supplier.supplier)
self.supplier_rfq_mail(rfq_supplier, update_password_link, self.get_link())
rfq_supplier.email_sent = 1
+ if not rfq_supplier.contact:
+ rfq_supplier.contact = contact
rfq_supplier.save()
def get_link(self):
# RFQ link for supplier portal
return get_url("/rfq/" + self.name)
- def update_supplier_part_no(self, args):
- self.vendor = args.supplier
+ def update_supplier_part_no(self, supplier):
+ self.vendor = supplier
for item in self.items:
item.supplier_part_no = frappe.db.get_value('Item Supplier',
- {'parent': item.item_code, 'supplier': args.supplier}, 'supplier_part_no')
+ {'parent': item.item_code, 'supplier': supplier}, 'supplier_part_no')
def update_supplier_contact(self, rfq_supplier, link):
'''Create a new user for the supplier if not set in contact'''
- update_password_link = ''
+ update_password_link, contact = '', ''
if frappe.db.exists("User", rfq_supplier.email_id):
user = frappe.get_doc("User", rfq_supplier.email_id)
else:
user, update_password_link = self.create_user(rfq_supplier, link)
- self.update_contact_of_supplier(rfq_supplier, user)
+ contact = self.link_supplier_contact(rfq_supplier, user)
- return update_password_link
+ return update_password_link, contact
- def update_contact_of_supplier(self, rfq_supplier, user):
+ def link_supplier_contact(self, rfq_supplier, user):
+ """If no Contact, create a new contact against Supplier. If Contact exists, check if email and user id set."""
if rfq_supplier.contact:
contact = frappe.get_doc("Contact", rfq_supplier.contact)
else:
@@ -108,6 +127,10 @@
'link_doctype': 'Supplier',
'link_name': rfq_supplier.supplier
})
+ contact.append('email_ids', {
+ 'email_id': user.name,
+ 'is_primary': 1
+ })
if not contact.email_id and not contact.user:
contact.email_id = user.name
@@ -115,6 +138,10 @@
contact.save(ignore_permissions=True)
+ if not rfq_supplier.contact:
+ # return contact to later update, RFQ supplier row's contact
+ return contact.name
+
def create_user(self, rfq_supplier, link):
user = frappe.get_doc({
'doctype': 'User',
@@ -129,22 +156,36 @@
return user, update_password_link
- def supplier_rfq_mail(self, data, update_password_link, rfq_link):
+ def supplier_rfq_mail(self, data, update_password_link, rfq_link, preview=False):
full_name = get_user_fullname(frappe.session['user'])
if full_name == "Guest":
full_name = "Administrator"
+ # send document dict and some important data from suppliers row
+ # to render message_for_supplier from any template
+ doc_args = self.as_dict()
+ doc_args.update({
+ 'supplier': data.get('supplier'),
+ 'supplier_name': data.get('supplier_name')
+ })
+
args = {
'update_password_link': update_password_link,
- 'message': frappe.render_template(self.message_for_supplier, data.as_dict()),
+ 'message': frappe.render_template(self.message_for_supplier, doc_args),
'rfq_link': rfq_link,
- 'user_fullname': full_name
+ 'user_fullname': full_name,
+ 'supplier_name' : data.get('supplier_name'),
+ 'supplier_salutation' : self.salutation or 'Dear Mx.',
}
- subject = _("Request for Quotation")
+ subject = self.subject or _("Request for Quotation")
template = "templates/emails/request_for_quotation.html"
sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None
message = frappe.get_template(template).render(args)
+
+ if preview:
+ return message
+
attachments = self.get_attachments()
self.send_email(data, sender, subject, message, attachments)
@@ -164,23 +205,22 @@
def update_rfq_supplier_status(self, sup_name=None):
for supplier in self.suppliers:
if sup_name == None or supplier.supplier == sup_name:
- if supplier.quote_status != _('No Quote'):
- quote_status = _('Received')
- for item in self.items:
- sqi_count = frappe.db.sql("""
- SELECT
- COUNT(sqi.name) as count
- FROM
- `tabSupplier Quotation Item` as sqi,
- `tabSupplier Quotation` as sq
- WHERE sq.supplier = %(supplier)s
- AND sqi.docstatus = 1
- AND sqi.request_for_quotation_item = %(rqi)s
- AND sqi.parent = sq.name""",
- {"supplier": supplier.supplier, "rqi": item.name}, as_dict=1)[0]
- if (sqi_count.count) == 0:
- quote_status = _('Pending')
- supplier.quote_status = quote_status
+ quote_status = _('Received')
+ for item in self.items:
+ sqi_count = frappe.db.sql("""
+ SELECT
+ COUNT(sqi.name) as count
+ FROM
+ `tabSupplier Quotation Item` as sqi,
+ `tabSupplier Quotation` as sq
+ WHERE sq.supplier = %(supplier)s
+ AND sqi.docstatus = 1
+ AND sqi.request_for_quotation_item = %(rqi)s
+ AND sqi.parent = sq.name""",
+ {"supplier": supplier.supplier, "rqi": item.name}, as_dict=1)[0]
+ if (sqi_count.count) == 0:
+ quote_status = _('Pending')
+ supplier.quote_status = quote_status
@frappe.whitelist()
@@ -214,14 +254,14 @@
and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
limit %(start)s, %(page_len)s""", {"start": start, "page_len":page_len, "txt": "%%%s%%" % txt, "name": filters.get('supplier')})
-# This method is used to make supplier quotation from material request form.
@frappe.whitelist()
-def make_supplier_quotation(source_name, for_supplier, target_doc=None):
+def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier=None):
def postprocess(source, target_doc):
- target_doc.supplier = for_supplier
- args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True)
- target_doc.currency = args.currency or get_party_account_currency('Supplier', for_supplier, source.company)
- target_doc.buying_price_list = args.buying_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list')
+ if for_supplier:
+ target_doc.supplier = for_supplier
+ args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True)
+ target_doc.currency = args.currency or get_party_account_currency('Supplier', for_supplier, source.company)
+ target_doc.buying_price_list = args.buying_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list')
set_missing_values(source, target_doc)
doclist = get_mapped_doc("Request for Quotation", source_name, {
@@ -289,16 +329,15 @@
})
@frappe.whitelist()
-def get_pdf(doctype, name, supplier_idx):
- doc = get_rfq_doc(doctype, name, supplier_idx)
+def get_pdf(doctype, name, supplier):
+ doc = get_rfq_doc(doctype, name, supplier)
if doc:
download_pdf(doctype, name, doc=doc)
-def get_rfq_doc(doctype, name, supplier_idx):
- if cint(supplier_idx):
+def get_rfq_doc(doctype, name, supplier):
+ if supplier:
doc = frappe.get_doc(doctype, name)
- args = doc.get('suppliers')[cint(supplier_idx) - 1]
- doc.update_supplier_part_no(args)
+ doc.update_supplier_part_no(supplier)
return doc
@frappe.whitelist()
@@ -354,3 +393,32 @@
frappe.cache().hset("Supplier", "Tags", tags)
return frappe.cache().hget("Supplier", "Tags")
+
+@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
+def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filters):
+ conditions = ""
+ if txt:
+ conditions += "and rfq.name like '%%"+txt+"%%' "
+
+ if filters.get("transaction_date"):
+ conditions += "and rfq.transaction_date = '{0}'".format(filters.get("transaction_date"))
+
+ rfq_data = frappe.db.sql("""
+ select
+ distinct rfq.name, rfq.transaction_date,
+ rfq.company
+ from
+ `tabRequest for Quotation` rfq, `tabRequest for Quotation Supplier` rfq_supplier
+ where
+ rfq.name = rfq_supplier.parent
+ and rfq_supplier.supplier = '{0}'
+ and rfq.docstatus = 1
+ and rfq.company = '{1}'
+ {2}
+ order by rfq.transaction_date ASC
+ limit %(page_len)s offset %(start)s """ \
+ .format(filters.get("supplier"), filters.get("company"), conditions),
+ {"page_len": page_len, "start": start}, as_dict=1)
+
+ return rfq_data
\ No newline at end of file
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 019cefc..36f87b0 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
@@ -9,7 +9,7 @@
from frappe.utils import nowdate
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.templates.pages.rfq import check_supplier_has_docname_access
-from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
+from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation_from_rfq
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation
from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity
from erpnext.crm.doctype.opportunity.opportunity import make_request_for_quotation as make_rfq
@@ -22,25 +22,21 @@
self.assertEqual(rfq.get('suppliers')[1].quote_status, 'Pending')
# Submit the first supplier quotation
- sq = make_supplier_quotation(rfq.name, rfq.get('suppliers')[0].supplier)
+ sq = make_supplier_quotation_from_rfq(rfq.name, for_supplier=rfq.get('suppliers')[0].supplier)
sq.submit()
- # No Quote first supplier quotation
- rfq.get('suppliers')[1].no_quote = 1
- rfq.get('suppliers')[1].quote_status = 'No Quote'
-
rfq.update_rfq_supplier_status() #rfq.get('suppliers')[1].supplier)
self.assertEqual(rfq.get('suppliers')[0].quote_status, 'Received')
- self.assertEqual(rfq.get('suppliers')[1].quote_status, 'No Quote')
+ self.assertEqual(rfq.get('suppliers')[1].quote_status, 'Pending')
def test_make_supplier_quotation(self):
rfq = make_request_for_quotation()
- sq = make_supplier_quotation(rfq.name, rfq.get('suppliers')[0].supplier)
+ sq = make_supplier_quotation_from_rfq(rfq.name, for_supplier=rfq.get('suppliers')[0].supplier)
sq.submit()
- sq1 = make_supplier_quotation(rfq.name, rfq.get('suppliers')[1].supplier)
+ sq1 = make_supplier_quotation_from_rfq(rfq.name, for_supplier=rfq.get('suppliers')[1].supplier)
sq1.submit()
self.assertEqual(sq.supplier, rfq.get('suppliers')[0].supplier)
@@ -62,7 +58,7 @@
rfq = make_request_for_quotation(supplier_data=supplier_wt_appos)
- sq = make_supplier_quotation(rfq.name, supplier_wt_appos[0].get("supplier"))
+ sq = make_supplier_quotation_from_rfq(rfq.name, for_supplier=supplier_wt_appos[0].get("supplier"))
sq.submit()
frappe.form_dict = frappe.local("form_dict")
diff --git a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js
index 1a9cd35..2e1652d 100644
--- a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js
+++ b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation_for_status.js
@@ -84,9 +84,6 @@
cur_frm.fields_dict.suppliers.grid.grid_rows[0].toggle_view();
},
() => frappe.timeout(1),
- () => {
- frappe.click_check('No Quote');
- },
() => frappe.timeout(1),
() => {
cur_frm.cur_grid.toggle_view();
@@ -125,7 +122,6 @@
() => frappe.timeout(1),
() => {
assert.ok(cur_frm.fields_dict.suppliers.grid.grid_rows[1].doc.quote_status == "Received");
- assert.ok(cur_frm.fields_dict.suppliers.grid.grid_rows[0].doc.no_quote == 1);
},
() => done()
]);
diff --git a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json
index 408f49f..e07f462 100644
--- a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json
+++ b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json
@@ -27,10 +27,11 @@
"stock_qty",
"warehouse_and_reference",
"warehouse",
- "project_name",
"col_break4",
"material_request",
"material_request_item",
+ "section_break_24",
+ "project_name",
"section_break_23",
"page_break"
],
@@ -161,7 +162,7 @@
{
"fieldname": "project_name",
"fieldtype": "Link",
- "label": "Project Name",
+ "label": "Project",
"options": "Project",
"print_hide": 1
},
@@ -249,11 +250,18 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_24",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-06-12 19:10:36.333441",
+ "modified": "2020-09-24 17:26:46.276934",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation Item",
diff --git a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json
index 61ad336..534cd90 100644
--- a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json
+++ b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json
@@ -1,362 +1,99 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-03-29 05:59:11.896885",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2016-03-29 05:59:11.896885",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "supplier",
+ "contact",
+ "quote_status",
+ "column_break_3",
+ "supplier_name",
+ "email_id",
+ "send_email",
+ "email_sent"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "send_email",
- "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": "Send Email",
- "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_on_submit": 1,
+ "columns": 2,
+ "default": "1",
+ "fieldname": "send_email",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Send Email"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "depends_on": "eval:doc.docstatus >= 1",
- "fieldname": "email_sent",
- "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": "Email Sent",
- "length": 0,
- "no_copy": 1,
- "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_on_submit": 1,
+ "default": "0",
+ "depends_on": "eval:doc.docstatus >= 1",
+ "fieldname": "email_sent",
+ "fieldtype": "Check",
+ "label": "Email Sent",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 4,
- "fieldname": "supplier",
- "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": "Supplier",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier",
- "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": 2,
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Supplier",
+ "options": "Supplier",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 3,
- "fieldname": "contact",
- "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": "Contact",
- "length": 0,
- "no_copy": 1,
- "options": "Contact",
- "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_on_submit": 1,
+ "columns": 2,
+ "fieldname": "contact",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Contact",
+ "no_copy": 1,
+ "options": "Contact"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.docstatus >= 1 && doc.quote_status != 'Received'",
- "fieldname": "no_quote",
- "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": "No Quote",
- "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_on_submit": 1,
+ "depends_on": "eval:doc.docstatus >= 1",
+ "fieldname": "quote_status",
+ "fieldtype": "Select",
+ "label": "Quote Status",
+ "options": "Pending\nReceived",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.docstatus >= 1 && !doc.no_quote",
- "fieldname": "quote_status",
- "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": "Quote Status",
- "length": 0,
- "no_copy": 0,
- "options": "Pending\nReceived\nNo Quote",
- "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": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
+ "bold": 1,
"fetch_from": "supplier.supplier_name",
- "fieldname": "supplier_name",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Supplier Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "supplier_name",
+ "fieldtype": "Read Only",
+ "in_global_search": 1,
+ "label": "Supplier Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 3,
+ "columns": 3,
"fetch_from": "contact.email_id",
- "fieldname": "email_id",
- "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": "Email Id",
- "length": 0,
- "no_copy": 1,
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "download_pdf",
- "fieldtype": "Button",
- "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": "Download PDF",
- "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": "email_id",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Email Id",
+ "no_copy": 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-05-16 22:43:30.212408",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Request for Quotation Supplier",
- "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": 1,
- "track_seen": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-11-04 22:01:43.832942",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Request for Quotation Supplier",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 40362b1..4cc5753 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -26,7 +26,6 @@
"supplier_group",
"supplier_type",
"pan",
- "language",
"allow_purchase_invoice_creation_without_purchase_order",
"allow_purchase_invoice_creation_without_purchase_receipt",
"disabled",
@@ -57,6 +56,7 @@
"website",
"supplier_details",
"column_break_30",
+ "language",
"is_frozen"
],
"fields": [
@@ -384,7 +384,7 @@
"idx": 370,
"image_field": "image",
"links": [],
- "modified": "2020-06-17 23:18:20",
+ "modified": "2021-01-06 19:51:40.939087",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index df143ee..edeb135 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -49,6 +49,15 @@
msgprint(_("Series is mandatory"), raise_exception=1)
validate_party_accounts(self)
+ self.validate_internal_supplier()
+
+ def validate_internal_supplier(self):
+ internal_supplier = frappe.db.get_value("Supplier",
+ {"is_internal_supplier": 1, "represents_company": self.represents_company, "name": ("!=", self.name)}, "name")
+
+ if internal_supplier:
+ frappe.throw(_("Internal Supplier for company {0} already exists").format(
+ frappe.bold(self.represents_company)))
def on_trash(self):
delete_contact_and_address('Supplier', self.name)
diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py
index a377ec9..f9c8d35 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.py
+++ b/erpnext/buying/doctype/supplier/test_supplier.py
@@ -120,3 +120,20 @@
# Rollback
address.delete()
+
+def create_supplier(**args):
+ args = frappe._dict(args)
+
+ try:
+ doc = frappe.get_doc({
+ "doctype": "Supplier",
+ "supplier_name": args.supplier_name,
+ "supplier_group": args.supplier_group or "Services",
+ "supplier_type": args.supplier_type or "Company",
+ "tax_withholding_category": args.tax_withholding_category
+ }).insert()
+
+ return doc
+
+ except frappe.DuplicateEntryError:
+ return frappe.get_doc("Supplier", args.supplier_name)
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index 1b8b404..a0187b0 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -8,8 +8,7 @@
setup: function() {
this.frm.custom_make_buttons = {
'Purchase Order': 'Purchase Order',
- 'Quotation': 'Quotation',
- 'Subscription': 'Subscription'
+ 'Quotation': 'Quotation'
}
this._super();
@@ -28,12 +27,6 @@
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
cur_frm.add_custom_button(__("Quotation"), this.make_quotation,
__('Create'));
-
- if(!this.frm.doc.auto_repeat) {
- cur_frm.add_custom_button(__('Subscription'), function() {
- erpnext.utils.make_subscription(me.frm.doc.doctype, me.frm.doc.name)
- }, __('Create'))
- }
}
else if (this.frm.doc.docstatus===0) {
@@ -44,16 +37,45 @@
source_doctype: "Material Request",
target: me.frm,
setters: {
- company: me.frm.doc.company
+ schedule_date: undefined,
+ status: undefined
},
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99]
+ per_ordered: ["<", 100],
+ company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
+
+ // Link Material Requests
+ this.frm.add_custom_button(__('Link to Material Requests'),
+ function() {
+ erpnext.buying.link_to_mrs(me.frm);
+ }, __("Tools"));
+
+ this.frm.add_custom_button(__("Request for Quotation"),
+ function() {
+ if (!me.frm.doc.supplier) {
+ frappe.throw({message:__("Please select a Supplier"), title:__("Mandatory")})
+ }
+ erpnext.utils.map_current_doc({
+ method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation_from_rfq",
+ source_doctype: "Request for Quotation",
+ target: me.frm,
+ setters: {
+ transaction_date: null
+ },
+ get_query_filters: {
+ supplier: me.frm.doc.supplier,
+ company: me.frm.doc.company
+ },
+ get_query_method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_rfq_containing_supplier"
+
+ })
+ }, __("Get Items From"));
}
},
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 660dcff..40fbe2c 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:45",
@@ -34,7 +35,6 @@
"ignore_pricing_rule",
"items_section",
"items",
- "link_to_mrs",
"pricing_rule_details",
"pricing_rules",
"section_break_22",
@@ -159,6 +159,7 @@
"default": "Today",
"fieldname": "transaction_date",
"fieldtype": "Date",
+ "in_list_view": 1,
"label": "Date",
"oldfieldname": "transaction_date",
"oldfieldtype": "Date",
@@ -321,12 +322,6 @@
"reqd": 1
},
{
- "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
- "fieldname": "link_to_mrs",
- "fieldtype": "Button",
- "label": "Link to material requests"
- },
- {
"fieldname": "pricing_rule_details",
"fieldtype": "Section Break",
"label": "Pricing Rules"
@@ -798,14 +793,16 @@
{
"fieldname": "valid_till",
"fieldtype": "Date",
+ "in_list_view": 1,
"label": "Valid Till"
}
],
"icon": "fa fa-shopping-cart",
"idx": 29,
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-07-18 05:10:45.556792",
+ "modified": "2020-12-03 15:18:29.073368",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index baf2457..6a4c02c 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -71,7 +71,7 @@
doc_sup = doc_sup[0] if doc_sup else None
if not doc_sup:
frappe.throw(_("Supplier {0} not found in {1}").format(self.supplier,
- "<a href='desk#Form/Request for Quotation/{0}'> Request for Quotation {0} </a>".format(doc.name)))
+ "<a href='desk/app/Form/Request for Quotation/{0}'> Request for Quotation {0} </a>".format(doc.name)))
quote_status = _('Received')
for item in doc.items:
@@ -91,12 +91,7 @@
for my_item in self.items) if include_me else 0
if (sqi_count.count + self_count) == 0:
quote_status = _('Pending')
- if quote_status == _('Received') and doc_sup.quote_status == _('No Quote'):
- frappe.msgprint(_("{0} indicates that {1} will not provide a quotation, but all items \
- have been quoted. Updating the RFQ quote status.").format(doc.name, self.supplier))
- frappe.db.set_value('Request for Quotation Supplier', doc_sup.name, 'quote_status', quote_status)
- frappe.db.set_value('Request for Quotation Supplier', doc_sup.name, 'no_quote', 0)
- elif doc_sup.quote_status != _('No Quote'):
+
frappe.db.set_value('Request for Quotation Supplier', doc_sup.name, 'quote_status', quote_status)
def get_list_context(context=None):
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
index 9f4fece..5ab6c98 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
@@ -4,9 +4,9 @@
if(doc.status==="Ordered") {
return [__("Ordered"), "green", "status,=,Ordered"];
} else if(doc.status==="Rejected") {
- return [__("Lost"), "darkgrey", "status,=,Lost"];
+ return [__("Lost"), "gray", "status,=,Lost"];
} else if(doc.status==="Expired") {
- return [__("Expired"), "darkgrey", "status,=,Expired"];
+ return [__("Expired"), "gray", "status,=,Expired"];
}
}
};
diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
index b50e834..638cde0 100644
--- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
+++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
@@ -12,6 +12,8 @@
"item_name",
"column_break_3",
"lead_time_days",
+ "expected_delivery_date",
+ "is_free_item",
"section_break_5",
"description",
"item_group",
@@ -19,20 +21,18 @@
"col_break1",
"image",
"image_view",
- "manufacture_details",
- "manufacturer",
- "column_break_15",
- "manufacturer_part_no",
"quantity_and_rate",
"qty",
"stock_uom",
- "price_list_rate",
- "discount_percentage",
- "discount_amount",
"col_break2",
"uom",
"conversion_factor",
"stock_qty",
+ "sec_break_price_list",
+ "price_list_rate",
+ "discount_percentage",
+ "discount_amount",
+ "col_break_price_list",
"base_price_list_rate",
"sec_break1",
"rate",
@@ -42,7 +42,6 @@
"base_rate",
"base_amount",
"pricing_rules",
- "is_free_item",
"section_break_24",
"net_rate",
"net_amount",
@@ -56,7 +55,6 @@
"weight_uom",
"warehouse_and_reference",
"warehouse",
- "project",
"prevdoc_doctype",
"material_request",
"sales_order",
@@ -65,13 +63,19 @@
"material_request_item",
"request_for_quotation_item",
"item_tax_rate",
+ "manufacture_details",
+ "manufacturer",
+ "column_break_15",
+ "manufacturer_part_no",
+ "ad_sec_break",
+ "project",
"section_break_44",
"page_break"
],
"fields": [
{
"bold": 1,
- "columns": 4,
+ "columns": 2,
"fieldname": "item_code",
"fieldtype": "Link",
"in_list_view": 1,
@@ -107,7 +111,7 @@
{
"fieldname": "lead_time_days",
"fieldtype": "Int",
- "label": "Lead Time in days"
+ "label": "Supplier Lead Time (days)"
},
{
"collapsible": 1,
@@ -162,7 +166,6 @@
{
"fieldname": "stock_uom",
"fieldtype": "Link",
- "in_list_view": 1,
"label": "Stock UOM",
"options": "UOM",
"print_hide": 1,
@@ -196,6 +199,7 @@
{
"fieldname": "uom",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "UOM",
"options": "UOM",
"print_hide": 1,
@@ -237,7 +241,7 @@
"fieldname": "rate",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "Rate ",
+ "label": "Rate",
"oldfieldname": "import_rate",
"oldfieldtype": "Currency",
"options": "currency"
@@ -290,14 +294,6 @@
"read_only": 1
},
{
- "default": "0",
- "fieldname": "is_free_item",
- "fieldtype": "Check",
- "label": "Is Free Item",
- "print_hide": 1,
- "read_only": 1
- },
- {
"fieldname": "section_break_24",
"fieldtype": "Section Break"
},
@@ -528,12 +524,43 @@
{
"fieldname": "column_break_15",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "sec_break_price_list",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "col_break_price_list",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "ad_sec_break",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "default": "0",
+ "depends_on": "is_free_item",
+ "fieldname": "is_free_item",
+ "fieldtype": "Check",
+ "label": "Is Free Item",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "bold": 1,
+ "fieldname": "expected_delivery_date",
+ "fieldtype": "Date",
+ "label": "Expected Delivery Date"
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-07 18:35:51.175947",
+ "modified": "2020-10-19 12:36:26.913211",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",
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 f24e5be..64dda87 100644
--- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py
+++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py
@@ -6,8 +6,5 @@
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
-
class SupplierQuotationItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js
index c50916e..dc5474e 100644
--- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js
@@ -10,7 +10,7 @@
if (doc.indicator_color) {
return [__(doc.status), doc.indicator_color.toLowerCase(), "status,=," + doc.status];
} else {
- return [__("Unknown"), "darkgrey", "status,=,''"];
+ return [__("Unknown"), "gray", "status,=,''"];
}
},
diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
index 88a865f..beeca09 100644
--- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
@@ -143,7 +143,7 @@
conditions = ""
if filters.get("company"):
- conditions += " AND par.company=%s" % frappe.db.escape(filters.get('company'))
+ conditions += " AND parent.company=%s" % frappe.db.escape(filters.get('company'))
if filters.get("cost_center") or filters.get("project"):
conditions += """
@@ -151,10 +151,10 @@
""" % (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
if filters.get("from_date"):
- conditions += " AND par.transaction_date>='%s'" % filters.get('from_date')
+ conditions += " AND parent.transaction_date>='%s'" % filters.get('from_date')
if filters.get("to_date"):
- conditions += " AND par.transaction_date<='%s'" % filters.get('to_date')
+ conditions += " AND parent.transaction_date<='%s'" % filters.get('to_date')
return conditions
def get_data(filters):
@@ -198,21 +198,23 @@
mr_records = {}
mr_details = frappe.db.sql("""
SELECT
- par.transaction_date,
- par.per_ordered,
- par.owner,
+ parent.transaction_date,
+ parent.per_ordered,
+ parent.owner,
child.name,
child.parent,
child.amount,
child.qty,
child.item_code,
child.uom,
- par.status
- FROM `tabMaterial Request` par, `tabMaterial Request Item` child
+ parent.status,
+ child.project,
+ child.cost_center
+ FROM `tabMaterial Request` parent, `tabMaterial Request Item` child
WHERE
- par.per_ordered>=0
- AND par.name=child.parent
- AND par.docstatus=1
+ parent.per_ordered>=0
+ AND parent.name=child.parent
+ AND parent.docstatus=1
{conditions}
""".format(conditions=conditions), as_dict=1) #nosec
@@ -232,7 +234,9 @@
status=record.status,
actual_cost=0,
purchase_order_amt=0,
- purchase_order_amt_in_company_currency=0
+ purchase_order_amt_in_company_currency=0,
+ project = record.project,
+ cost_center = record.cost_center
)
procurement_record_against_mr.append(procurement_record_details)
return mr_records, procurement_record_against_mr
@@ -280,16 +284,16 @@
child.amount,
child.base_amount,
child.schedule_date,
- par.transaction_date,
- par.supplier,
- par.status,
- par.owner
- FROM `tabPurchase Order` par, `tabPurchase Order Item` child
+ parent.transaction_date,
+ parent.supplier,
+ parent.status,
+ parent.owner
+ FROM `tabPurchase Order` parent, `tabPurchase Order Item` child
WHERE
- par.docstatus = 1
- AND par.name = child.parent
- AND par.status not in ("Closed","Completed","Cancelled")
+ parent.docstatus = 1
+ AND parent.name = child.parent
+ AND parent.status not in ("Closed","Completed","Cancelled")
{conditions}
GROUP BY
- par.name, child.item_code
+ parent.name, child.item_code
""".format(conditions=conditions), as_dict=1) #nosec
\ No newline at end of file
diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.js b/erpnext/buying/report/purchase_analytics/purchase_analytics.js
index e17973c..ba8535a 100644
--- a/erpnext/buying/report/purchase_analytics/purchase_analytics.js
+++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.js
@@ -75,62 +75,70 @@
return Object.assign(options, {
checkboxColumn: true,
events: {
- onCheckRow: function(data) {
+ onCheckRow: function (data) {
+ if (!data) return;
+
+ const data_doctype = $(
+ data[2].html
+ )[0].attributes.getNamedItem("data-doctype").value;
+ const tree_type = frappe.query_report.filters[0].value;
+ if (data_doctype != tree_type) return;
+
row_name = data[2].content;
length = data.length;
- var tree_type = frappe.query_report.filters[0].value;
-
- if(tree_type == "Supplier" || tree_type == "Item") {
- row_values = data.slice(4,length-1).map(function (column) {
- return column.content;
- })
- }
- else {
- row_values = data.slice(3,length-1).map(function (column) {
- return column.content;
- })
+ if (tree_type == "Supplier") {
+ row_values = data
+ .slice(4, length - 1)
+ .map(function (column) {
+ return column.content;
+ });
+ } else if (tree_type == "Item") {
+ row_values = data
+ .slice(5, length - 1)
+ .map(function (column) {
+ return column.content;
+ });
+ } else {
+ row_values = data
+ .slice(3, length - 1)
+ .map(function (column) {
+ return column.content;
+ });
}
- entry = {
- 'name':row_name,
- 'values':row_values
- }
+ entry = {
+ name: row_name,
+ values: row_values,
+ };
let raw_data = frappe.query_report.chart.data;
let new_datasets = raw_data.datasets;
- var found = false;
-
- for(var i=0; i < new_datasets.length;i++){
- if(new_datasets[i].name == row_name){
- found = true;
- new_datasets.splice(i,1);
- break;
+ let element_found = new_datasets.some((element, index, array)=>{
+ if(element.name == row_name){
+ array.splice(index, 1)
+ return true
}
- }
+ return false
+ })
- if(!found){
+ if (!element_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)
+ datasets: new_datasets,
+ };
+ chart_options = {
+ data: new_data,
+ type: "line",
+ };
+ frappe.query_report.render_chart(chart_options);
frappe.query_report.raw_chart_data = new_data;
},
- }
+ },
});
}
}
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.json b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.json
deleted file mode 100644
index 23b3ace..0000000
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "add_total_row": 0,
- "apply_user_permissions": 1,
- "creation": "2016-07-21 08:31:05.890362",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 2,
- "is_standard": "Yes",
- "modified": "2017-02-24 20:04:58.784351",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Quoted Item Comparison",
- "owner": "Administrator",
- "ref_doctype": "Supplier Quotation",
- "report_name": "Quoted Item Comparison",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Manufacturing Manager"
- },
- {
- "role": "Purchase Manager"
- },
- {
- "role": "Purchase User"
- },
- {
- "role": "Stock User"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/buying/report/quoted_item_comparison/__init__.py b/erpnext/buying/report/supplier_quotation_comparison/__init__.py
similarity index 100%
rename from erpnext/buying/report/quoted_item_comparison/__init__.py
rename to erpnext/buying/report/supplier_quotation_comparison/__init__.py
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.html b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.html
similarity index 100%
rename from erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.html
rename to erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.html
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js
similarity index 90%
rename from erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
rename to erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js
index 518d665..80e521a 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js
@@ -1,7 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.query_reports["Quoted Item Comparison"] = {
+frappe.query_reports["Supplier Quotation Comparison"] = {
filters: [
{
fieldtype: "Link",
@@ -79,6 +79,13 @@
}
},
{
+ "fieldname":"group_by",
+ "label": __("Group by"),
+ "fieldtype": "Select",
+ "options": [__("Group by Supplier"), __("Group by Item")],
+ "default": __("Group by Supplier")
+ },
+ {
fieldtype: "Check",
label: __("Include Expired"),
fieldname: "include_expired",
@@ -98,6 +105,9 @@
}
}
+ if(column.fieldname === "price_per_unit" && data.price_per_unit && data.min && data.min === 1){
+ value = `<div style="color:green">${value}</div>`;
+ }
return value;
},
diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.json b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.json
new file mode 100644
index 0000000..886e5b8
--- /dev/null
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.json
@@ -0,0 +1,32 @@
+{
+ "add_total_row": 0,
+ "apply_user_permissions": 1,
+ "creation": "2016-07-21 08:31:05.890362",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 2,
+ "is_standard": "Yes",
+ "modified": "2017-02-24 20:04:58.784351",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Quotation Comparison",
+ "owner": "Administrator",
+ "ref_doctype": "Supplier Quotation",
+ "report_name": "Supplier Quotation Comparison",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Manufacturing Manager"
+ },
+ {
+ "role": "Purchase Manager"
+ },
+ {
+ "role": "Purchase User"
+ },
+ {
+ "role": "Stock User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
similarity index 68%
rename from erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
rename to erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
index 4426560..2b37191 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
@@ -12,9 +12,9 @@
if not filters:
return [], []
+ columns = get_columns(filters)
conditions = get_conditions(filters)
supplier_quotation_data = get_data(filters, conditions)
- columns = get_columns()
data, chart_data = prepare_data(supplier_quotation_data, filters)
message = get_message()
@@ -41,9 +41,13 @@
return conditions
def get_data(filters, conditions):
- supplier_quotation_data = frappe.db.sql("""SELECT
- sqi.parent, sqi.item_code, sqi.qty, sqi.rate, sqi.uom, sqi.request_for_quotation,
- sqi.lead_time_days, sq.supplier, sq.valid_till
+ supplier_quotation_data = frappe.db.sql("""
+ SELECT
+ sqi.parent, sqi.item_code,
+ sqi.qty, sqi.stock_qty, sqi.amount,
+ sqi.uom, sqi.stock_uom,
+ sqi.request_for_quotation,
+ sqi.lead_time_days, sq.supplier as supplier_name, sq.valid_till
FROM
`tabSupplier Quotation Item` sqi,
`tabSupplier Quotation` sq
@@ -58,16 +62,18 @@
return supplier_quotation_data
def prepare_data(supplier_quotation_data, filters):
- out, suppliers, qty_list, chart_data = [], [], [], []
- supplier_wise_map = defaultdict(list)
+ out, groups, qty_list, suppliers, chart_data = [], [], [], [], []
+ group_wise_map = defaultdict(list)
supplier_qty_price_map = {}
+ group_by_field = "supplier_name" if filters.get("group_by") == "Group by Supplier" else "item_code"
company_currency = frappe.db.get_default("currency")
float_precision = cint(frappe.db.get_default("float_precision")) or 2
for data in supplier_quotation_data:
- supplier = data.get("supplier")
- supplier_currency = frappe.db.get_value("Supplier", data.get("supplier"), "default_currency")
+ group = data.get(group_by_field) # get item or supplier value for this row
+
+ supplier_currency = frappe.db.get_value("Supplier", data.get("supplier_name"), "default_currency")
if supplier_currency:
exchange_rate = get_exchange_rate(supplier_currency, company_currency)
@@ -75,38 +81,55 @@
exchange_rate = 1
row = {
- "item_code": data.get('item_code'),
+ "item_code": "" if group_by_field=="item_code" else data.get("item_code"), # leave blank if group by field
+ "supplier_name": "" if group_by_field=="supplier_name" else data.get("supplier_name"),
"quotation": data.get("parent"),
"qty": data.get("qty"),
- "price": flt(data.get("rate") * exchange_rate, float_precision),
+ "price": flt(data.get("amount") * exchange_rate, float_precision),
"uom": data.get("uom"),
+ "stock_uom": data.get('stock_uom'),
"request_for_quotation": data.get("request_for_quotation"),
"valid_till": data.get('valid_till'),
"lead_time_days": data.get('lead_time_days')
}
+ row["price_per_unit"] = flt(row["price"]) / (flt(data.get("stock_qty")) or 1)
- # map for report view of form {'supplier1':[{},{},...]}
- supplier_wise_map[supplier].append(row)
+ # map for report view of form {'supplier1'/'item1':[{},{},...]}
+ group_wise_map[group].append(row)
# map for chart preparation of the form {'supplier1': {'qty': 'price'}}
+ supplier = data.get("supplier_name")
if filters.get("item_code"):
if not supplier in supplier_qty_price_map:
supplier_qty_price_map[supplier] = {}
supplier_qty_price_map[supplier][row["qty"]] = row["price"]
+ groups.append(group)
suppliers.append(supplier)
qty_list.append(data.get("qty"))
+ groups = list(set(groups))
suppliers = list(set(suppliers))
qty_list = list(set(qty_list))
+ highlight_min_price = group_by_field == "item_code" or filters.get("item_code")
+
# final data format for report view
- for supplier in suppliers:
- supplier_wise_map[supplier][0].update({"supplier_name": supplier})
- for entry in supplier_wise_map[supplier]:
+ for group in groups:
+ group_entries = group_wise_map[group] # all entries pertaining to item/supplier
+ group_entries[0].update({group_by_field : group}) # Add item/supplier name in first group row
+
+ if highlight_min_price:
+ prices = [group_entry["price_per_unit"] for group_entry in group_entries]
+ min_price = min(prices)
+
+ for entry in group_entries:
+ if highlight_min_price and entry["price_per_unit"] == min_price:
+ entry["min"] = 1
out.append(entry)
if filters.get("item_code"):
+ # render chart only for one item comparison
chart_data = prepare_chart_data(suppliers, qty_list, supplier_qty_price_map)
return out, chart_data
@@ -145,8 +168,9 @@
return chart_data
-def get_columns():
- columns = [{
+def get_columns(filters):
+ group_by_columns = [
+ {
"fieldname": "supplier_name",
"label": _("Supplier"),
"fieldtype": "Link",
@@ -158,8 +182,10 @@
"label": _("Item"),
"fieldtype": "Link",
"options": "Item",
- "width": 200
- },
+ "width": 150
+ }]
+
+ columns = [
{
"fieldname": "uom",
"label": _("UOM"),
@@ -181,6 +207,20 @@
"width": 110
},
{
+ "fieldname": "stock_uom",
+ "label": _("Stock UOM"),
+ "fieldtype": "Link",
+ "options": "UOM",
+ "width": 90
+ },
+ {
+ "fieldname": "price_per_unit",
+ "label": _("Price per Unit (Stock UOM)"),
+ "fieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "width": 120
+ },
+ {
"fieldname": "quotation",
"label": _("Supplier Quotation"),
"fieldtype": "Link",
@@ -205,9 +245,12 @@
"fieldtype": "Link",
"options": "Request for Quotation",
"width": 150
- }
- ]
+ }]
+ if filters.get("group_by") == "Group by Item":
+ group_by_columns.reverse()
+
+ columns[0:0] = group_by_columns # add positioned group by columns to the report
return columns
def get_message():
diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py
index 47b4866..a73cb0d 100644
--- a/erpnext/buying/utils.py
+++ b/erpnext/buying/utils.py
@@ -35,9 +35,10 @@
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
# update last purchsae rate
- if last_purchase_rate:
- frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
- (flt(last_purchase_rate), d.item_code))
+ frappe.db.set_value('Item', d.item_code, 'last_purchase_rate', flt(last_purchase_rate))
+
+
+
def validate_for_items(doc):
items = []
diff --git a/erpnext/buying/workspace/buying/buying.json b/erpnext/buying/workspace/buying/buying.json
new file mode 100644
index 0000000..6c9c0f3
--- /dev/null
+++ b/erpnext/buying/workspace/buying/buying.json
@@ -0,0 +1,520 @@
+{
+ "cards_label": "",
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Purchase Order Trends",
+ "label": "Purchase Order Trends"
+ }
+ ],
+ "charts_label": "",
+ "creation": "2020-01-28 11:50:26.195467",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "buying",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Buying",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Buying",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Material Request",
+ "link_to": "Material Request",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Supplier",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Purchase Order",
+ "link_to": "Purchase Order",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Supplier",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Purchase Invoice",
+ "link_to": "Purchase Invoice",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Supplier",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Request for Quotation",
+ "link_to": "Request for Quotation",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Supplier",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Quotation",
+ "link_to": "Supplier Quotation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Items & Pricing",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item",
+ "link_to": "Item",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Price",
+ "link_to": "Item Price",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Price List",
+ "link_to": "Price List",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Product Bundle",
+ "link_to": "Product Bundle",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Group",
+ "link_to": "Item Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Promotional Scheme",
+ "link_to": "Promotional Scheme",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Pricing Rule",
+ "link_to": "Pricing Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Buying Settings",
+ "link_to": "Buying Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Purchase Taxes and Charges Template",
+ "link_to": "Purchase Taxes and Charges Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Terms and Conditions Template",
+ "link_to": "Terms and Conditions",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier",
+ "link_to": "Supplier",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Group",
+ "link_to": "Supplier Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Contact",
+ "link_to": "Contact",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Address",
+ "link_to": "Address",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Scorecard",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Scorecard",
+ "link_to": "Supplier Scorecard",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Scorecard Variable",
+ "link_to": "Supplier Scorecard Variable",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Scorecard Criteria",
+ "link_to": "Supplier Scorecard Criteria",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier Scorecard Standing",
+ "link_to": "Supplier Scorecard Standing",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Key Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Analytics",
+ "link_to": "Purchase Analytics",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Order Analysis",
+ "link_to": "Purchase Order Analysis",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Supplier-Wise Sales Analytics",
+ "link_to": "Supplier-Wise Sales Analytics",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Items to Order and Receive",
+ "link_to": "Requested Items to Order and Receive",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Order Trends",
+ "link_to": "Purchase Order Trends",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Procurement Tracker",
+ "link_to": "Procurement Tracker",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Other Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Items To Be Requested",
+ "link_to": "Items To Be Requested",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item-wise Purchase History",
+ "link_to": "Item-wise Purchase History",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Receipt Trends",
+ "link_to": "Purchase Receipt Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Invoice Trends",
+ "link_to": "Purchase Invoice Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Subcontracted Raw Materials To Be Transferred",
+ "link_to": "Subcontracted Raw Materials To Be Transferred",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Subcontracted Item To Be Received",
+ "link_to": "Subcontracted Item To Be Received",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Supplier Quotation Comparison",
+ "link_to": "Supplier Quotation Comparison",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Material Requests for which Supplier Quotations are not created",
+ "link_to": "Material Requests for which Supplier Quotations are not created",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Supplier Addresses And Contacts",
+ "link_to": "Address And Contacts",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Regional",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Import Supplier Invoice",
+ "link_to": "Import Supplier Invoice",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:38.615167",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Buying",
+ "onboarding": "Buying",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Green",
+ "format": "{} Available",
+ "label": "Item",
+ "link_to": "Item",
+ "stats_filter": "{\n \"disabled\": 0\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} Pending",
+ "label": "Material Request",
+ "link_to": "Material Request",
+ "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Pending\"\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} To Receive",
+ "label": "Purchase Order",
+ "link_to": "Purchase Order",
+ "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\":[\"in\", [\"To Receive\", \"To Receive and Bill\"]]\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Purchase Analytics",
+ "link_to": "Purchase Analytics",
+ "type": "Report"
+ },
+ {
+ "label": "Purchase Order Analysis",
+ "link_to": "Purchase Order Analysis",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Buying",
+ "type": "Dashboard"
+ }
+ ],
+ "shortcuts_label": ""
+}
\ No newline at end of file
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
deleted file mode 100644
index b31b757..0000000
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ /dev/null
@@ -1,98 +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
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from erpnext.crm.doctype.utils import get_scheduled_employees_for_popup, strip_number
-from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
-from erpnext.crm.doctype.lead.lead import get_lead_with_phone_number
-
-class CallLog(Document):
- def before_insert(self):
- number = strip_number(self.get('from'))
- self.contact = get_contact_with_phone_number(number)
- self.lead = get_lead_with_phone_number(number)
-
- contact = frappe.get_doc("Contact", self.contact)
- self.customer = contact.get_link_for("Customer")
-
- def after_insert(self):
- self.trigger_call_popup()
-
- def on_update(self):
- doc_before_save = self.get_doc_before_save()
- if not doc_before_save: return
- if doc_before_save.status in ['Ringing'] and self.status in ['Missed', 'Completed']:
- frappe.publish_realtime('call_{id}_disconnected'.format(id=self.id), self)
- elif doc_before_save.to != self.to:
- self.trigger_call_popup()
-
- def trigger_call_popup(self):
- scheduled_employees = get_scheduled_employees_for_popup(self.medium)
- employee_emails = get_employees_with_number(self.to)
-
- # check if employees with matched number are scheduled to receive popup
- emails = set(scheduled_employees).intersection(employee_emails)
-
- # # if no employee found with matching phone number then show popup to scheduled employees
- # emails = emails or scheduled_employees if employee_emails
-
- for email in emails:
- frappe.publish_realtime('show_call_popup', self, user=email)
-
-@frappe.whitelist()
-def add_call_summary(call_log, summary):
- doc = frappe.get_doc('Call Log', call_log)
- doc.add_comment('Comment', frappe.bold(_('Call Summary')) + '<br><br>' + summary)
-
-def get_employees_with_number(number):
- number = strip_number(number)
- if not number: return []
-
- employee_emails = frappe.cache().hget('employees_with_number', number)
- if employee_emails: return employee_emails
-
- employees = frappe.get_all('Employee', filters={
- 'cell_number': ['like', '%{}%'.format(number)],
- 'user_id': ['!=', '']
- }, fields=['user_id'])
-
- employee_emails = [employee.user_id for employee in employees]
- frappe.cache().hset('employees_with_number', number, employee_emails)
-
- return employee_emails
-
-def set_caller_information(doc, state):
- '''Called from hooks on creation of Lead or Contact'''
- if doc.doctype not in ['Lead', 'Contact']: return
-
- numbers = [doc.get('phone'), doc.get('mobile_no')]
- # contact for Contact and lead for Lead
- fieldname = doc.doctype.lower()
-
- # contact_name or lead_name
- display_name_field = '{}_name'.format(fieldname)
-
- # Contact now has all the nos saved in child table
- if doc.doctype == 'Contact':
- numbers = [d.phone for d in doc.phone_nos]
-
- for number in numbers:
- number = strip_number(number)
- if not number: continue
-
- filters = frappe._dict({
- 'from': ['like', '%{}'.format(number)],
- fieldname: ''
- })
-
- logs = frappe.get_all('Call Log', filters=filters)
-
- for log in logs:
- frappe.db.set_value('Call Log', log.name, {
- fieldname: doc.name,
- display_name_field: doc.get_title()
- }, update_modified=False)
diff --git a/erpnext/communication/doctype/communication_medium/communication_medium.json b/erpnext/communication/doctype/communication_medium/communication_medium.json
index f009b38..1e1fe3b 100644
--- a/erpnext/communication/doctype/communication_medium/communication_medium.json
+++ b/erpnext/communication/doctype/communication_medium/communication_medium.json
@@ -1,12 +1,14 @@
{
+ "actions": [],
"autoname": "Prompt",
"creation": "2019-06-05 11:48:30.572795",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
+ "communication_channel",
"communication_medium_type",
- "catch_all",
"column_break_3",
+ "catch_all",
"provider",
"disabled",
"timeslots_section",
@@ -54,9 +56,16 @@
"fieldtype": "Table",
"label": "Timeslots",
"options": "Communication Medium Timeslot"
+ },
+ {
+ "fieldname": "communication_channel",
+ "fieldtype": "Select",
+ "label": "Communication Channel",
+ "options": "\nExotel"
}
],
- "modified": "2019-06-05 11:49:30.769006",
+ "links": [],
+ "modified": "2020-10-27 16:22:08.068542",
"modified_by": "Administrator",
"module": "Communication",
"name": "Communication Medium",
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
deleted file mode 100644
index 839c4ad..0000000
--- a/erpnext/config/accounts.py
+++ /dev/null
@@ -1,626 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-import frappe
-
-
-def get_data():
- config = [
- {
- "label": _("Accounts Receivable"),
- "items": [
- {
- "type": "doctype",
- "name": "Sales Invoice",
- "description": _("Bills raised to Customers."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Customer",
- "description": _("Customer database."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Payment Entry",
- "description": _("Bank/Cash transactions against party or for internal transfer")
- },
- {
- "type": "doctype",
- "name": "Payment Request",
- "description": _("Payment Request"),
- },
- {
- "type": "report",
- "name": "Accounts Receivable",
- "doctype": "Sales Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Accounts Receivable Summary",
- "doctype": "Sales Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Sales Register",
- "doctype": "Sales Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Item-wise Sales Register",
- "is_query_report": True,
- "doctype": "Sales Invoice"
- },
- {
- "type": "report",
- "name": "Ordered Items To Be Billed",
- "is_query_report": True,
- "doctype": "Sales Invoice"
- },
- {
- "type": "report",
- "name": "Delivered Items To Be Billed",
- "is_query_report": True,
- "doctype": "Sales Invoice"
- },
- ]
- },
- {
- "label": _("Accounts Payable"),
- "items": [
- {
- "type": "doctype",
- "name": "Purchase Invoice",
- "description": _("Bills raised by Suppliers."),
- "onboard": 1
- },
- {
- "type": "doctype",
- "name": "Supplier",
- "description": _("Supplier database."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Payment Entry",
- "description": _("Bank/Cash transactions against party or for internal transfer")
- },
- {
- "type": "report",
- "name": "Accounts Payable",
- "doctype": "Purchase Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Accounts Payable Summary",
- "doctype": "Purchase Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Purchase Register",
- "doctype": "Purchase Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Item-wise Purchase Register",
- "is_query_report": True,
- "doctype": "Purchase Invoice"
- },
- {
- "type": "report",
- "name": "Purchase Order Items To Be Billed",
- "is_query_report": True,
- "doctype": "Purchase Invoice"
- },
- {
- "type": "report",
- "name": "Received Items To Be Billed",
- "is_query_report": True,
- "doctype": "Purchase Invoice"
- },
- ]
- },
- {
- "label": _("Accounting Masters"),
- "items": [
- {
- "type": "doctype",
- "name": "Company",
- "description": _("Company (not Customer or Supplier) master."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Account",
- "icon": "fa fa-sitemap",
- "label": _("Chart of Accounts"),
- "route": "#Tree/Account",
- "description": _("Tree of financial accounts."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Accounts Settings",
- },
- {
- "type": "doctype",
- "name": "Fiscal Year",
- "description": _("Financial / accounting year.")
- },
- {
- "type": "doctype",
- "name": "Accounting Dimension",
- },
- {
- "type": "doctype",
- "name": "Finance Book",
- },
- {
- "type": "doctype",
- "name": "Accounting Period",
- },
- {
- "type": "doctype",
- "name": "Payment Term",
- "description": _("Payment Terms based on conditions")
- },
- ]
- },
- {
- "label": _("Banking and Payments"),
- "items": [
- {
- "type": "doctype",
- "label": _("Match Payments with Invoices"),
- "name": "Payment Reconciliation",
- "description": _("Match non-linked Invoices and Payments.")
- },
- {
- "type": "doctype",
- "label": _("Update Bank Clearance Dates"),
- "name": "Bank Clearance",
- "description": _("Update bank payment dates with journals.")
- },
- {
- "type": "doctype",
- "label": _("Invoice Discounting"),
- "name": "Invoice Discounting",
- },
- {
- "type": "report",
- "name": "Bank Reconciliation Statement",
- "is_query_report": True,
- "doctype": "Journal Entry"
- },{
- "type": "page",
- "name": "bank-reconciliation",
- "label": _("Bank Reconciliation"),
- "icon": "fa fa-bar-chart"
- },
- {
- "type": "report",
- "name": "Bank Clearance Summary",
- "is_query_report": True,
- "doctype": "Journal Entry"
- },
- {
- "type": "doctype",
- "name": "Bank Guarantee"
- },
- {
- "type": "doctype",
- "name": "Cheque Print Template",
- "description": _("Setup cheque dimensions for printing")
- },
- ]
- },
- {
- "label": _("General Ledger"),
- "items": [
- {
- "type": "doctype",
- "name": "Journal Entry",
- "description": _("Accounting journal entries.")
- },
- {
- "type": "report",
- "name": "General Ledger",
- "doctype": "GL Entry",
- "is_query_report": True,
- },
- {
- "type": "report",
- "name": "Customer Ledger Summary",
- "doctype": "Sales Invoice",
- "is_query_report": True,
- },
- {
- "type": "report",
- "name": "Supplier Ledger Summary",
- "doctype": "Sales Invoice",
- "is_query_report": True,
- },
- {
- "type": "doctype",
- "name": "Process Deferred Accounting"
- }
- ]
- },
- {
- "label": _("Taxes"),
- "items": [
- {
- "type": "doctype",
- "name": "Sales Taxes and Charges Template",
- "description": _("Tax template for selling transactions.")
- },
- {
- "type": "doctype",
- "name": "Purchase Taxes and Charges Template",
- "description": _("Tax template for buying transactions.")
- },
- {
- "type": "doctype",
- "name": "Item Tax Template",
- "description": _("Tax template for item tax rates.")
- },
- {
- "type": "doctype",
- "name": "Tax Category",
- "description": _("Tax Category for overriding tax rates.")
- },
- {
- "type": "doctype",
- "name": "Tax Rule",
- "description": _("Tax Rule for transactions.")
- },
- {
- "type": "doctype",
- "name": "Tax Withholding Category",
- "description": _("Tax Withholding rates to be applied on transactions.")
- },
- ]
- },
- {
- "label": _("Cost Center and Budgeting"),
- "items": [
- {
- "type": "doctype",
- "name": "Cost Center",
- "icon": "fa fa-sitemap",
- "label": _("Chart of Cost Centers"),
- "route": "#Tree/Cost Center",
- "description": _("Tree of financial Cost Centers."),
- },
- {
- "type": "doctype",
- "name": "Budget",
- "description": _("Define budget for a financial year.")
- },
- {
- "type": "doctype",
- "name": "Accounting Dimension",
- },
- {
- "type": "report",
- "name": "Budget Variance Report",
- "is_query_report": True,
- "doctype": "Cost Center"
- },
- {
- "type": "doctype",
- "name": "Monthly Distribution",
- "description": _("Seasonality for setting budgets, targets etc.")
- },
- ]
- },
- {
- "label": _("Financial Statements"),
- "items": [
- {
- "type": "report",
- "name": "Trial Balance",
- "doctype": "GL Entry",
- "is_query_report": True,
- },
- {
- "type": "report",
- "name": "Profit and Loss Statement",
- "doctype": "GL Entry",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Balance Sheet",
- "doctype": "GL Entry",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Cash Flow",
- "doctype": "GL Entry",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Consolidated Financial Statement",
- "doctype": "GL Entry",
- "is_query_report": True
- },
- ]
- },
- {
- "label": _("Opening and Closing"),
- "items": [
- {
- "type": "doctype",
- "name": "Opening Invoice Creation Tool",
- },
- {
- "type": "doctype",
- "name": "Chart of Accounts Importer",
- },
- {
- "type": "doctype",
- "name": "Period Closing Voucher",
- "description": _("Close Balance Sheet and book Profit or Loss.")
- },
- ]
-
- },
- {
- "label": _("Multi Currency"),
- "items": [
- {
- "type": "doctype",
- "name": "Currency",
- "description": _("Enable / disable currencies.")
- },
- {
- "type": "doctype",
- "name": "Currency Exchange",
- "description": _("Currency exchange rate master.")
- },
- {
- "type": "doctype",
- "name": "Exchange Rate Revaluation",
- "description": _("Exchange Rate Revaluation master.")
- },
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-cog",
- "items": [
- {
- "type": "doctype",
- "name": "Payment Gateway Account",
- "description": _("Setup Gateway accounts.")
- },
- {
- "type": "doctype",
- "name": "Terms and Conditions",
- "label": _("Terms and Conditions Template"),
- "description": _("Template of terms or contract.")
- },
- {
- "type": "doctype",
- "name": "Mode of Payment",
- "description": _("e.g. Bank, Cash, Credit Card")
- },
- ]
- },
- {
- "label": _("Subscription Management"),
- "items": [
- {
- "type": "doctype",
- "name": "Subscriber",
- },
- {
- "type": "doctype",
- "name": "Subscription Plan",
- },
- {
- "type": "doctype",
- "name": "Subscription"
- },
- {
- "type": "doctype",
- "name": "Subscription Settings"
- }
- ]
- },
- {
- "label": _("Bank Statement"),
- "items": [
- {
- "type": "doctype",
- "label": _("Bank"),
- "name": "Bank",
- },
- {
- "type": "doctype",
- "label": _("Bank Account"),
- "name": "Bank Account",
- },
- {
- "type": "doctype",
- "name": "Bank Statement Transaction Entry",
- },
- {
- "type": "doctype",
- "label": _("Bank Statement Settings"),
- "name": "Bank Statement Settings",
- },
- ]
- },
- {
- "label": _("Profitability"),
- "items": [
- {
- "type": "report",
- "name": "Gross Profit",
- "doctype": "Sales Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Profitability Analysis",
- "doctype": "GL Entry",
- "is_query_report": True,
- },
- {
- "type": "report",
- "name": "Sales Invoice Trends",
- "is_query_report": True,
- "doctype": "Sales Invoice"
- },
- {
- "type": "report",
- "name": "Purchase Invoice Trends",
- "is_query_report": True,
- "doctype": "Purchase Invoice"
- },
- ]
- },
- {
- "label": _("Reports"),
- "icon": "fa fa-table",
- "items": [
- {
- "type": "report",
- "name": "Trial Balance for Party",
- "doctype": "GL Entry",
- "is_query_report": True,
- },
- {
- "type": "report",
- "name": "Payment Period Based On Invoice Date",
- "is_query_report": True,
- "doctype": "Journal Entry"
- },
- {
- "type": "report",
- "name": "Sales Partners Commission",
- "is_query_report": True,
- "doctype": "Sales Invoice"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Customer Credit Balance",
- "doctype": "Customer"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Payment Summary",
- "doctype": "Sales Invoice"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Address And Contacts",
- "doctype": "Address"
- }
- ]
- },
- {
- "label": _("Share Management"),
- "icon": "fa fa-microchip ",
- "items": [
- {
- "type": "doctype",
- "name": "Shareholder",
- "description": _("List of available Shareholders with folio numbers")
- },
- {
- "type": "doctype",
- "name": "Share Transfer",
- "description": _("List of all share transactions"),
- },
- {
- "type": "report",
- "name": "Share Ledger",
- "doctype": "Share Transfer",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Share Balance",
- "doctype": "Share Transfer",
- "is_query_report": True
- }
- ]
- },
-
- ]
-
- gst = {
- "label": _("Goods and Services Tax (GST India)"),
- "items": [
- {
- "type": "doctype",
- "name": "GST Settings",
- },
- {
- "type": "doctype",
- "name": "GST HSN Code",
- },
- {
- "type": "report",
- "name": "GSTR-1",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GSTR-2",
- "is_query_report": True
- },
- {
- "type": "doctype",
- "name": "GSTR 3B Report",
- },
- {
- "type": "report",
- "name": "GST Sales Register",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Purchase Register",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Itemised Sales Register",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Itemised Purchase Register",
- "is_query_report": True
- },
- {
- "type": "doctype",
- "name": "C-Form",
- "description": _("C-Form records"),
- "country": "India"
- },
- ]
- }
-
-
- countries = frappe.get_all("Company", fields="country")
- countries = [country["country"] for country in countries]
- if "India" in countries:
- config.insert(9, gst)
- domains = frappe.get_active_domains()
- return config
diff --git a/erpnext/config/agriculture.py b/erpnext/config/agriculture.py
deleted file mode 100644
index 937d76e..0000000
--- a/erpnext/config/agriculture.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Crops & Lands"),
- "items": [
- {
- "type": "doctype",
- "name": "Crop",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Crop Cycle",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Location",
- "onboard": 1,
- }
- ]
- },
- {
- "label": _("Diseases & Fertilizers"),
- "items": [
- {
- "type": "doctype",
- "name": "Disease",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Fertilizer",
- "onboard": 1,
- }
- ]
- },
- {
- "label": _("Analytics"),
- "items": [
- {
- "type": "doctype",
- "name": "Plant Analysis",
- },
- {
- "type": "doctype",
- "name": "Soil Analysis",
- },
- {
- "type": "doctype",
- "name": "Water Analysis",
- },
- {
- "type": "doctype",
- "name": "Soil Texture",
- },
- {
- "type": "doctype",
- "name": "Weather",
- },
- {
- "type": "doctype",
- "name": "Agriculture Analysis Criteria",
- }
- ]
- },
- ]
\ No newline at end of file
diff --git a/erpnext/config/assets.py b/erpnext/config/assets.py
deleted file mode 100644
index 4cf7cf0..0000000
--- a/erpnext/config/assets.py
+++ /dev/null
@@ -1,94 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Assets"),
- "items": [
- {
- "type": "doctype",
- "name": "Asset",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Location",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Asset Category",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Asset Movement",
- "description": _("Transfer an asset from one warehouse to another")
- },
- ]
- },
- {
- "label": _("Maintenance"),
- "items": [
- {
- "type": "doctype",
- "name": "Asset Maintenance Team",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Asset Maintenance",
- "onboard": 1,
- "dependencies": ["Asset Maintenance Team"],
- },
- {
- "type": "doctype",
- "name": "Asset Maintenance Tasks",
- "onboard": 1,
- "dependencies": ["Asset Maintenance"],
- },
- {
- "type": "doctype",
- "name": "Asset Maintenance Log",
- "dependencies": ["Asset Maintenance"],
- },
- {
- "type": "doctype",
- "name": "Asset Value Adjustment",
- "dependencies": ["Asset"],
- },
- {
- "type": "doctype",
- "name": "Asset Repair",
- "dependencies": ["Asset"],
- },
- ]
- },
- {
- "label": _("Reports"),
- "icon": "fa fa-table",
- "items": [
- {
- "type": "report",
- "name": "Asset Depreciation Ledger",
- "doctype": "Asset",
- "is_query_report": True,
- "dependencies": ["Asset"],
- },
- {
- "type": "report",
- "name": "Asset Depreciations and Balances",
- "doctype": "Asset",
- "is_query_report": True,
- "dependencies": ["Asset"],
- },
- {
- "type": "report",
- "name": "Asset Maintenance",
- "doctype": "Asset Maintenance",
- "dependencies": ["Asset Maintenance"]
- },
- ]
- }
- ]
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
deleted file mode 100644
index b06bb76..0000000
--- a/erpnext/config/buying.py
+++ /dev/null
@@ -1,264 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-
-def get_data():
- config = [
- {
- "label": _("Purchasing"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "Material Request",
- "onboard": 1,
- "dependencies": ["Item"],
- "description": _("Request for purchase."),
- },
- {
- "type": "doctype",
- "name": "Purchase Order",
- "onboard": 1,
- "dependencies": ["Item", "Supplier"],
- "description": _("Purchase Orders given to Suppliers."),
- },
- {
- "type": "doctype",
- "name": "Purchase Invoice",
- "onboard": 1,
- "dependencies": ["Item", "Supplier"]
- },
- {
- "type": "doctype",
- "name": "Request for Quotation",
- "onboard": 1,
- "dependencies": ["Item", "Supplier"],
- "description": _("Request for quotation."),
- },
- {
- "type": "doctype",
- "name": "Supplier Quotation",
- "dependencies": ["Item", "Supplier"],
- "description": _("Quotations received from Suppliers."),
- },
- ]
- },
- {
- "label": _("Items and Pricing"),
- "items": [
- {
- "type": "doctype",
- "name": "Item",
- "onboard": 1,
- "description": _("All Products or Services."),
- },
- {
- "type": "doctype",
- "name": "Item Price",
- "description": _("Multiple Item prices."),
- "onboard": 1,
- "route": "#Report/Item Price"
- },
- {
- "type": "doctype",
- "name": "Price List",
- "description": _("Price List master.")
- },
- {
- "type": "doctype",
- "name": "Pricing Rule",
- "description": _("Rules for applying pricing and discount.")
- },
- {
- "type": "doctype",
- "name": "Product Bundle",
- "description": _("Bundle items at time of sale."),
- },
- {
- "type": "doctype",
- "name": "Item Group",
- "icon": "fa fa-sitemap",
- "label": _("Item Group"),
- "link": "Tree/Item Group",
- "description": _("Tree of Item Groups."),
- },
- {
- "type": "doctype",
- "name": "Promotional Scheme",
- "description": _("Rules for applying different promotional schemes.")
- }
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-cog",
- "items": [
- {
- "type": "doctype",
- "name": "Buying Settings",
- "settings": 1,
- "description": _("Default settings for buying transactions.")
- },
- {
- "type": "doctype",
- "name": "Purchase Taxes and Charges Template",
- "description": _("Tax template for buying transactions.")
- },
- {
- "type": "doctype",
- "name":"Terms and Conditions",
- "label": _("Terms and Conditions Template"),
- "description": _("Template of terms or contract.")
- },
- ]
- },
- {
- "label": _("Supplier"),
- "items": [
- {
- "type": "doctype",
- "name": "Supplier",
- "onboard": 1,
- "description": _("Supplier database."),
- },
- {
- "type": "doctype",
- "name": "Supplier Group",
- "description": _("Supplier Group master.")
- },
- {
- "type": "doctype",
- "name": "Contact",
- "description": _("All Contacts."),
- },
- {
- "type": "doctype",
- "name": "Address",
- "description": _("All Addresses."),
- },
-
- ]
- },
- {
- "label": _("Key Reports"),
- "icon": "fa fa-table",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Purchase Analytics",
- "reference_doctype": "Purchase Order",
- "onboard": 1
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Purchase Order Trends",
- "reference_doctype": "Purchase Order",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Procurement Tracker",
- "reference_doctype": "Purchase Order",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Requested Items To Order",
- "reference_doctype": "Material Request",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Address And Contacts",
- "label": _("Supplier Addresses And Contacts"),
- "reference_doctype": "Address",
- "route_options": {
- "party_type": "Supplier"
- }
- }
- ]
- },
- {
- "label": _("Supplier Scorecard"),
- "items": [
- {
- "type": "doctype",
- "name": "Supplier Scorecard",
- "description": _("All Supplier scorecards."),
- },
- {
- "type": "doctype",
- "name": "Supplier Scorecard Variable",
- "description": _("Templates of supplier scorecard variables.")
- },
- {
- "type": "doctype",
- "name": "Supplier Scorecard Criteria",
- "description": _("Templates of supplier scorecard criteria."),
- },
- {
- "type": "doctype",
- "name": "Supplier Scorecard Standing",
- "description": _("Templates of supplier standings."),
- },
-
- ]
- },
- {
- "label": _("Other Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Items To Be Requested",
- "reference_doctype": "Item",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Item-wise Purchase History",
- "reference_doctype": "Item",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Supplier-Wise Sales Analytics",
- "reference_doctype": "Stock Ledger Entry",
- "onboard": 1
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Material Requests for which Supplier Quotations are not created",
- "reference_doctype": "Material Request"
- }
- ]
- },
-
- ]
-
- regional = {
- "label": _("Regional"),
- "items": [
- {
- "type": "doctype",
- "name": "Import Supplier Invoice",
- "description": _("Import Italian Supplier Invoice."),
- "onboard": 1,
- }
- ]
- }
-
- countries = frappe.get_all("Company", fields="country")
- countries = [country["country"] for country in countries]
- if "Italy" in countries:
- config.append(regional)
- return config
\ No newline at end of file
diff --git a/erpnext/config/crm.py b/erpnext/config/crm.py
deleted file mode 100644
index 09c2a65..0000000
--- a/erpnext/config/crm.py
+++ /dev/null
@@ -1,236 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Sales Pipeline"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "Lead",
- "description": _("Database of potential customers."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Opportunity",
- "description": _("Potential opportunities for selling."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Customer",
- "description": _("Customer database."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Contact",
- "description": _("All Contacts."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Communication",
- "description": _("Record of all communications of type email, phone, chat, visit, etc."),
- },
- {
- "type": "doctype",
- "name": "Lead Source",
- "description": _("Track Leads by Lead Source.")
- },
- {
- "type": "doctype",
- "name": "Contract",
- "description": _("Helps you keep tracks of Contracts based on Supplier, Customer and Employee"),
- },
- {
- "type": "doctype",
- "name": "Appointment",
- "description" : _("Helps you manage appointments with your leads"),
- },
- {
- "type": "doctype",
- "name": "Newsletter",
- "label": _("Newsletter"),
- }
- ]
- },
- {
- "label": _("Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Lead Details",
- "doctype": "Lead",
- "onboard": 1,
- },
- {
- "type": "page",
- "name": "sales-funnel",
- "label": _("Sales Funnel"),
- "icon": "fa fa-bar-chart",
- "onboard": 1,
- },
- {
- "type": "report",
- "name": "Prospects Engaged But Not Converted",
- "doctype": "Lead",
- "is_query_report": True,
- "onboard": 1,
- },
- {
- "type": "report",
- "name": "Minutes to First Response for Opportunity",
- "doctype": "Opportunity",
- "is_query_report": True,
- "dependencies": ["Opportunity"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Customer Addresses And Contacts",
- "doctype": "Contact",
- "dependencies": ["Customer"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Inactive Customers",
- "doctype": "Sales Order",
- "dependencies": ["Sales Order"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Campaign Efficiency",
- "doctype": "Lead",
- "dependencies": ["Lead"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Lead Owner Efficiency",
- "doctype": "Lead",
- "dependencies": ["Lead"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Territory-wise Sales",
- "doctype": "Opportunity",
- "dependencies": ["Opportunity"]
- }
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-cog",
- "items": [
- {
- "type": "doctype",
- "label": _("Customer Group"),
- "name": "Customer Group",
- "icon": "fa fa-sitemap",
- "link": "Tree/Customer Group",
- "description": _("Manage Customer Group Tree."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "label": _("Territory"),
- "name": "Territory",
- "icon": "fa fa-sitemap",
- "link": "Tree/Territory",
- "description": _("Manage Territory Tree."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "label": _("Sales Person"),
- "name": "Sales Person",
- "icon": "fa fa-sitemap",
- "link": "Tree/Sales Person",
- "description": _("Manage Sales Person Tree."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Campaign",
- "description": _("Sales campaigns."),
- },
- {
- "type": "doctype",
- "name": "Email Campaign",
- "description": _("Sends Mails to lead or contact based on a Campaign schedule"),
- },
- {
- "type": "doctype",
- "name": "SMS Center",
- "description":_("Send mass SMS to your contacts"),
- },
- {
- "type": "doctype",
- "name": "SMS Log",
- "description":_("Logs for maintaining sms delivery status"),
- },
- {
- "type": "doctype",
- "name": "SMS Settings",
- "description": _("Setup SMS gateway settings")
- },
- {
- "type": "doctype",
- "label": _("Email Group"),
- "name": "Email Group",
- }
- ]
- },
- {
- "label": _("Maintenance"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "Maintenance Schedule",
- "description": _("Plan for maintenance visits."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Maintenance Visit",
- "description": _("Visit report for maintenance call."),
- },
- {
- "type": "report",
- "name": "Maintenance Schedules",
- "is_query_report": True,
- "doctype": "Maintenance Schedule"
- },
- {
- "type": "doctype",
- "name": "Warranty Claim",
- "description": _("Warranty Claim against Serial No."),
- },
- ]
- },
- # {
- # "label": _("Help"),
- # "items": [
- # {
- # "type": "help",
- # "label": _("Lead to Quotation"),
- # "youtube_id": "TxYX4r4JAKA"
- # },
- # {
- # "type": "help",
- # "label": _("Newsletters"),
- # "youtube_id": "muLKsCrrDRo"
- # },
- # ]
- # },
- ]
diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py
deleted file mode 100644
index ce7c245..0000000
--- a/erpnext/config/desktop.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# coding=utf-8
-
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- # Modules
- {
- "module_name": "Getting Started",
- "category": "Modules",
- "label": _("Getting Started"),
- "color": "#1abc9c",
- "icon": "fa fa-check-square-o",
- "type": "module",
- "disable_after_onboard": 1,
- "description": "Dive into the basics for your organisation's needs.",
- "onboard_present": 1
- },
- {
- "module_name": "Accounts",
- "category": "Modules",
- "label": _("Accounting"),
- "color": "#3498db",
- "icon": "octicon octicon-repo",
- "type": "module",
- "description": "Accounts, billing, payments, cost center and budgeting."
- },
- {
- "module_name": "Selling",
- "category": "Modules",
- "label": _("Selling"),
- "color": "#1abc9c",
- "icon": "octicon octicon-tag",
- "type": "module",
- "description": "Sales orders, quotations, customers and items."
- },
- {
- "module_name": "Buying",
- "category": "Modules",
- "label": _("Buying"),
- "color": "#c0392b",
- "icon": "octicon octicon-briefcase",
- "type": "module",
- "description": "Purchasing, suppliers, material requests, and items."
- },
- {
- "module_name": "Stock",
- "category": "Modules",
- "label": _("Stock"),
- "color": "#f39c12",
- "icon": "octicon octicon-package",
- "type": "module",
- "description": "Stock transactions, reports, serial numbers and batches."
- },
- {
- "module_name": "Assets",
- "category": "Modules",
- "label": _("Assets"),
- "color": "#4286f4",
- "icon": "octicon octicon-database",
- "type": "module",
- "description": "Asset movement, maintainance and tools."
- },
- {
- "module_name": "Projects",
- "category": "Modules",
- "label": _("Projects"),
- "color": "#8e44ad",
- "icon": "octicon octicon-rocket",
- "type": "module",
- "description": "Updates, Timesheets and Activities."
- },
- {
- "module_name": "CRM",
- "category": "Modules",
- "label": _("CRM"),
- "color": "#EF4DB6",
- "icon": "octicon octicon-broadcast",
- "type": "module",
- "description": "Sales pipeline, leads, opportunities and customers."
- },
- {
- "module_name": "Loan Management",
- "category": "Modules",
- "label": _("Loan Management"),
- "color": "#EF4DB6",
- "icon": "octicon octicon-repo",
- "type": "module",
- "description": "Loan Management for Customer and Employees"
- },
- {
- "module_name": "Support",
- "category": "Modules",
- "label": _("Support"),
- "color": "#1abc9c",
- "icon": "fa fa-check-square-o",
- "type": "module",
- "description": "User interactions, support issues and knowledge base."
- },
- {
- "module_name": "HR",
- "category": "Modules",
- "label": _("Human Resources"),
- "color": "#2ecc71",
- "icon": "octicon octicon-organization",
- "type": "module",
- "description": "Employees, attendance, payroll, leaves and shifts."
- },
- {
- "module_name": "Quality Management",
- "category": "Modules",
- "label": _("Quality"),
- "color": "#1abc9c",
- "icon": "fa fa-check-square-o",
- "type": "module",
- "description": "Quality goals, procedures, reviews and action."
- },
-
-
- # Category: "Domains"
- {
- "module_name": "Manufacturing",
- "category": "Domains",
- "label": _("Manufacturing"),
- "color": "#7f8c8d",
- "icon": "octicon octicon-tools",
- "type": "module",
- "description": "BOMS, work orders, operations, and timesheets."
- },
- {
- "module_name": "Retail",
- "category": "Domains",
- "label": _("Retail"),
- "color": "#7f8c8d",
- "icon": "octicon octicon-credit-card",
- "type": "module",
- "description": "Point of Sale and cashier closing."
- },
- {
- "module_name": "Education",
- "category": "Domains",
- "label": _("Education"),
- "color": "#428B46",
- "icon": "octicon octicon-mortar-board",
- "type": "module",
- "description": "Student admissions, fees, courses and scores."
- },
-
- {
- "module_name": "Healthcare",
- "category": "Domains",
- "label": _("Healthcare"),
- "color": "#FF888B",
- "icon": "fa fa-heartbeat",
- "type": "module",
- "description": "Patient appointments, procedures and tests."
- },
- {
- "module_name": "Agriculture",
- "category": "Domains",
- "label": _("Agriculture"),
- "color": "#8BC34A",
- "icon": "octicon octicon-globe",
- "type": "module",
- "description": "Crop cycles, land areas, soil and plant analysis."
- },
- {
- "module_name": "Hotels",
- "category": "Domains",
- "label": _("Hotels"),
- "color": "#EA81E8",
- "icon": "fa fa-bed",
- "type": "module",
- "description": "Hotel rooms, pricing, reservation and amenities."
- },
-
- {
- "module_name": "Non Profit",
- "category": "Domains",
- "label": _("Non Profit"),
- "color": "#DE2B37",
- "icon": "octicon octicon-heart",
- "type": "module",
- "description": "Volunteers, memberships, grants and chapters."
- },
- {
- "module_name": "Restaurant",
- "category": "Domains",
- "label": _("Restaurant"),
- "color": "#EA81E8",
- "icon": "fa fa-cutlery",
- "_doctype": "Restaurant",
- "type": "module",
- "link": "List/Restaurant",
- "description": "Menu, Orders and Table Reservations."
- },
-
- {
- "module_name": "Help",
- "category": "Administration",
- "label": _("Learn"),
- "color": "#FF888B",
- "icon": "octicon octicon-device-camera-video",
- "type": "module",
- "is_help": True,
- "description": "Explore Help Articles and Videos."
- },
- {
- "module_name": 'Marketplace',
- "category": "Places",
- "label": _('Marketplace'),
- "icon": "octicon octicon-star",
- "type": 'link',
- "link": '#marketplace/home',
- "color": '#FF4136',
- 'standard': 1,
- "description": "Publish items to other ERPNext users."
- },
- ]
diff --git a/erpnext/config/docs.py b/erpnext/config/docs.py
deleted file mode 100644
index 85e6006..0000000
--- a/erpnext/config/docs.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from __future__ import unicode_literals
-
-source_link = "https://github.com/erpnext/foundation"
diff --git a/erpnext/config/education.py b/erpnext/config/education.py
index 4efaaa6..1c8ab10 100644
--- a/erpnext/config/education.py
+++ b/erpnext/config/education.py
@@ -173,7 +173,7 @@
{
"type": "doctype",
"name": "Course Schedule",
- "route": "#List/Course Schedule/Calendar"
+ "route": "/app/List/Course Schedule/Calendar"
},
{
"type": "doctype",
diff --git a/erpnext/config/getting_started.py b/erpnext/config/getting_started.py
deleted file mode 100644
index fa84b1c..0000000
--- a/erpnext/config/getting_started.py
+++ /dev/null
@@ -1,268 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-
-active_domains = frappe.get_active_domains()
-
-def get_data():
- return [
- {
- "label": _("Accounting"),
- "items": [
- {
- "type": "doctype",
- "name": "Item",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Customer",
- "description": _("Customer database."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Supplier",
- "description": _("Supplier database."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Company",
- "description": _("Company (not Customer or Supplier) master."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Account",
- "icon": "fa fa-sitemap",
- "label": _("Chart of Accounts"),
- "route": "#Tree/Account",
- "description": _("Tree of financial accounts."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Opening Invoice Creation Tool",
- "description": _("Create Opening Sales and Purchase Invoices"),
- "onboard": 1,
- },
- ]
- },
- {
- "label": _("Data Import and Settings"),
- "items": [
- {
- "type": "doctype",
- "name": "Data Import",
- "label": _("Import Data"),
- "icon": "octicon octicon-cloud-upload",
- "description": _("Import Data from CSV / Excel files."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Chart of Accounts Importer",
- "labe": _("Chart Of Accounts Importer"),
- "description": _("Import Chart Of Accounts from CSV / Excel files"),
- "onboard": 1
- },
- {
- "type": "doctype",
- "name": "Letter Head",
- "description": _("Letter Heads for print templates."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Email Account",
- "description": _("Add / Manage Email Accounts."),
- "onboard": 1,
- },
-
- ]
- },
- {
- "label": _("Stock"),
- "items": [
- {
- "type": "doctype",
- "name": "Warehouse",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Brand",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "UOM",
- "label": _("Unit of Measure") + " (UOM)",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Stock Reconciliation",
- "onboard": 1,
- },
- ]
- },
- {
- "label": _("CRM"),
- "items": [
- {
- "type": "doctype",
- "name": "Lead",
- "description": _("Database of potential customers."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "label": _("Customer Group"),
- "name": "Customer Group",
- "icon": "fa fa-sitemap",
- "link": "Tree/Customer Group",
- "description": _("Manage Customer Group Tree."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "label": _("Territory"),
- "name": "Territory",
- "icon": "fa fa-sitemap",
- "link": "Tree/Territory",
- "description": _("Manage Territory Tree."),
- "onboard": 1,
- },
- ]
- },
- {
- "label": _("Human Resources"),
- "items": [
- {
- "type": "doctype",
- "name": "Employee",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Employee Attendance Tool",
- "hide_count": True,
- "onboard": 1,
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Salary Structure",
- "onboard": 1,
- },
- ]
- },
- {
- "label": _("Education"),
- "condition": "Education" in active_domains,
- "items": [
- {
- "type": "doctype",
- "name": "Student",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Course",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Instructor",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Room",
- "onboard": 1,
- },
- ]
- },
- {
- "label": _("Healthcare"),
- "condition": "Healthcare" in active_domains,
- "items": [
- {
- "type": "doctype",
- "name": "Patient",
- "label": _("Patient"),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Physician",
- "label": _("Physician"),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Diagnosis",
- "label": _("Diagnosis"),
- "onboard": 1,
- }
- ]
- },
- {
- "label": _("Agriculture"),
- "condition": "Agriculture" in active_domains,
- "items": [
- {
- "type": "doctype",
- "name": "Crop",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Crop Cycle",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Location",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Fertilizer",
- "onboard": 1,
- }
- ]
- },
- {
- "label": _("Non Profit"),
- "condition": "Non Profit" in active_domains,
- "items": [
- {
- "type": "doctype",
- "name": "Member",
- "description": _("Member information."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Volunteer",
- "description": _("Volunteer information."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Chapter",
- "description": _("Chapter information."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Donor",
- "description": _("Donor information."),
- "onboard": 1,
- },
- ]
- }
- ]
\ No newline at end of file
diff --git a/erpnext/config/healthcare.py b/erpnext/config/healthcare.py
deleted file mode 100644
index da24d11..0000000
--- a/erpnext/config/healthcare.py
+++ /dev/null
@@ -1,254 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Masters"),
- "items": [
- {
- "type": "doctype",
- "name": "Patient",
- "label": _("Patient"),
- "onboard": 1
- },
- {
- "type": "doctype",
- "name": "Healthcare Practitioner",
- "label": _("Healthcare Practitioner"),
- "onboard": 1
- },
- {
- "type": "doctype",
- "name": "Practitioner Schedule",
- "label": _("Practitioner Schedule"),
- "onboard": 1
- },
- {
- "type": "doctype",
- "name": "Medical Department",
- "label": _("Medical Department"),
- },
- {
- "type": "doctype",
- "name": "Healthcare Service Unit Type",
- "label": _("Healthcare Service Unit Type")
- },
- {
- "type": "doctype",
- "name": "Healthcare Service Unit",
- "label": _("Healthcare Service Unit")
- },
- {
- "type": "doctype",
- "name": "Medical Code Standard",
- "label": _("Medical Code Standard")
- },
- {
- "type": "doctype",
- "name": "Medical Code",
- "label": _("Medical Code")
- }
- ]
- },
- {
- "label": _("Consultation Setup"),
- "items": [
- {
- "type": "doctype",
- "name": "Appointment Type",
- "label": _("Appointment Type"),
- },
- {
- "type": "doctype",
- "name": "Clinical Procedure Template",
- "label": _("Clinical Procedure Template")
- },
- {
- "type": "doctype",
- "name": "Prescription Dosage",
- "label": _("Prescription Dosage")
- },
- {
- "type": "doctype",
- "name": "Prescription Duration",
- "label": _("Prescription Duration")
- },
- {
- "type": "doctype",
- "name": "Antibiotic",
- "label": _("Antibiotic")
- }
- ]
- },
- {
- "label": _("Consultation"),
- "items": [
- {
- "type": "doctype",
- "name": "Patient Appointment",
- "label": _("Patient Appointment")
- },
- {
- "type": "doctype",
- "name": "Clinical Procedure",
- "label": _("Clinical Procedure")
- },
- {
- "type": "doctype",
- "name": "Patient Encounter",
- "label": _("Patient Encounter")
- },
- {
- "type": "doctype",
- "name": "Vital Signs",
- "label": _("Vital Signs")
- },
- {
- "type": "doctype",
- "name": "Complaint",
- "label": _("Complaint")
- },
- {
- "type": "doctype",
- "name": "Diagnosis",
- "label": _("Diagnosis")
- },
- {
- "type": "doctype",
- "name": "Fee Validity",
- "label": _("Fee Validity")
- }
- ]
- },
- {
- "label": _("Settings"),
- "items": [
- {
- "type": "doctype",
- "name": "Healthcare Settings",
- "label": _("Healthcare Settings"),
- "onboard": 1
- }
- ]
- },
- {
- "label": _("Laboratory Setup"),
- "items": [
- {
- "type": "doctype",
- "name": "Lab Test Template",
- "label": _("Lab Test Template")
- },
- {
- "type": "doctype",
- "name": "Lab Test Sample",
- "label": _("Lab Test Sample")
- },
- {
- "type": "doctype",
- "name": "Lab Test UOM",
- "label": _("Lab Test UOM")
- },
- {
- "type": "doctype",
- "name": "Sensitivity",
- "label": _("Sensitivity")
- }
- ]
- },
- {
- "label": _("Laboratory"),
- "items": [
- {
- "type": "doctype",
- "name": "Lab Test",
- "label": _("Lab Test")
- },
- {
- "type": "doctype",
- "name": "Sample Collection",
- "label": _("Sample Collection")
- },
- {
- "type": "doctype",
- "name": "Dosage Form",
- "label": _("Dosage Form")
- }
- ]
- },
- {
- "label": _("Records and History"),
- "items": [
- {
- "type": "page",
- "name": "patient_history",
- "label": _("Patient History"),
- },
- {
- "type": "doctype",
- "name": "Patient Medical Record",
- "label": _("Patient Medical Record")
- },
- {
- "type": "doctype",
- "name": "Inpatient Record",
- "label": _("Inpatient Record")
- }
- ]
- },
- {
- "label": _("Reports"),
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Patient Appointment Analytics",
- "doctype": "Patient Appointment"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Lab Test Report",
- "doctype": "Lab Test",
- "label": _("Lab Test Report")
- }
- ]
- },
- {
- "label": _("Rehabilitation"),
- "icon": "icon-cog",
- "items": [
- {
- "type": "doctype",
- "name": "Exercise Type",
- "label": _("Exercise Type")
- },
- {
- "type": "doctype",
- "name": "Exercise Difficulty Level",
- "label": _("Exercise Difficulty Level")
- },
- {
- "type": "doctype",
- "name": "Therapy Type",
- "label": _("Therapy Type")
- },
- {
- "type": "doctype",
- "name": "Therapy Plan",
- "label": _("Therapy Plan")
- },
- {
- "type": "doctype",
- "name": "Therapy Session",
- "label": _("Therapy Session")
- },
- {
- "type": "doctype",
- "name": "Motor Assessment Scale",
- "label": _("Motor Assessment Scale")
- }
- ]
- }
- ]
diff --git a/erpnext/config/help.py b/erpnext/config/help.py
deleted file mode 100644
index 922afb4..0000000
--- a/erpnext/config/help.py
+++ /dev/null
@@ -1,273 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("General"),
- "items": [
- {
- "type": "help",
- "label": _("Navigating"),
- "youtube_id": "YDoI2DF4Lmc"
- },
- {
- "type": "help",
- "label": _("Setup Wizard"),
- "youtube_id": "oIOf_zCFWKQ"
- },
- {
- "type": "help",
- "label": _("Customizing Forms"),
- "youtube_id": "pJhL9mmxV_U"
- },
- {
- "type": "help",
- "label": _("Report Builder"),
- "youtube_id": "TxJGUNarcQs"
- },
- ]
-
- },
- {
- "label": _("Settings"),
- "items": [
- {
- "type": "help",
- "label": _("Data Import and Export"),
- "youtube_id": "6wiriRKPhmg"
- },
- {
- "type": "help",
- "label": _("Opening Stock Balance"),
- "youtube_id": "nlHX0ZZ84Lw"
- },
- {
- "type": "help",
- "label": _("Setting up Email Account"),
- "youtube_id": "YFYe0DrB95o"
- },
- {
- "type": "help",
- "label": _("Printing and Branding"),
- "youtube_id": "cKZHcx1znMc"
- },
- {
- "type": "help",
- "label": _("Users and Permissions"),
- "youtube_id": "8Slw1hsTmUI"
- },
- {
- "type": "help",
- "label": _("Workflow"),
- "youtube_id": "yObJUg9FxFs"
- },
- {
- "type": "help",
- "label": _("File Manager"),
- "youtube_id": "4-osLW3E_Rk"
- },
- ]
- },
- {
- "label": _("Accounting"),
- "items": [
- {
- "type": "help",
- "label": _("Chart of Accounts"),
- "youtube_id": "DyR-DST-PyA"
- },
- {
- "type": "help",
- "label": _("Setting up Taxes"),
- "youtube_id": "nQ1zZdPgdaQ"
- },
- {
- "type": "help",
- "label": _("Opening Accounting Balance"),
- "youtube_id": "kdgM20Q-q68"
- },
- {
- "type": "help",
- "label": _("Advance Payments"),
- "youtube_id": "J46-6qtyZ9U"
- },
- ]
- },
- {
- "label": _("CRM"),
- "items": [
- {
- "type": "help",
- "label": _("Lead to Quotation"),
- "youtube_id": "TxYX4r4JAKA"
- },
- {
- "type": "help",
- "label": _("Newsletters"),
- "youtube_id": "muLKsCrrDRo"
- },
- ]
- },
- {
- "label": _("Selling"),
- "items": [
- {
- "type": "help",
- "label": _("Customer and Supplier"),
- "youtube_id": "anoGi_RpQ20"
- },
- {
- "type": "help",
- "label": _("Sales Order to Payment"),
- "youtube_id": "1eP90MWoDQM"
- },
- {
- "type": "help",
- "label": _("Point-of-Sale"),
- "youtube_id": "4WkelWkbP_c"
- },
- {
- "type": "help",
- "label": _("Product Bundle"),
- "youtube_id": "yk3kPrRyRRc"
- },
- {
- "type": "help",
- "label": _("Drop Ship"),
- "youtube_id": "hUc0hu_XLdo"
- },
- ]
- },
- {
- "label": _("Stock"),
- "items": [
- {
- "type": "help",
- "label": _("Items and Pricing"),
- "youtube_id": "qXaEwld4_Ps"
- },
- {
- "type": "help",
- "label": _("Item Variants"),
- "youtube_id": "OGBETlCzU5o"
- },
- {
- "type": "help",
- "label": _("Opening Stock Balance"),
- "youtube_id": "0yPgrtfeCTs"
- },
- {
- "type": "help",
- "label": _("Making Stock Entries"),
- "youtube_id": "Njt107hlY3I"
- },
- {
- "type": "help",
- "label": _("Serialized Inventory"),
- "youtube_id": "gvOVlEwFDAk"
- },
- {
- "type": "help",
- "label": _("Batch Inventory"),
- "youtube_id": "J0QKl7ABPKM"
- },
- {
- "type": "help",
- "label": _("Managing Subcontracting"),
- "youtube_id": "ThiMCC2DtKo"
- },
- {
- "type": "help",
- "label": _("Quality Inspection"),
- "youtube_id": "WmtcF3Y40Fs"
- },
- ]
- },
- {
- "label": _("Buying"),
- "items": [
- {
- "type": "help",
- "label": _("Customer and Supplier"),
- "youtube_id": "anoGi_RpQ20"
- },
- {
- "type": "help",
- "label": _("Material Request to Purchase Order"),
- "youtube_id": "55Gk2j7Q8Zw"
- },
- {
- "type": "help",
- "label": _("Purchase Order to Payment"),
- "youtube_id": "efFajTTQBa8"
- },
- {
- "type": "help",
- "label": _("Managing Subcontracting"),
- "youtube_id": "ThiMCC2DtKo"
- },
- ]
- },
- {
- "label": _("Manufacturing"),
- "items": [
- {
- "type": "help",
- "label": _("Bill of Materials"),
- "youtube_id": "hDV0c1OeWLo"
- },
- {
- "type": "help",
- "label": _("Work Order"),
- "youtube_id": "ZotgLyp2YFY"
- },
-
- ]
- },
- {
- "label": _("Human Resource"),
- "items": [
- {
- "type": "help",
- "label": _("Setting up Employees"),
- "youtube_id": "USfIUdZlUhw"
- },
- {
- "type": "help",
- "label": _("Leave Management"),
- "youtube_id": "fc0p_AXebc8"
- },
- {
- "type": "help",
- "label": _("Expense Claims"),
- "youtube_id": "5SZHJF--ZFY"
- }
- ]
- },
- {
- "label": _("Projects"),
- "items": [
- {
- "type": "help",
- "label": _("Managing Projects"),
- "youtube_id": "gCzShu9Niu4"
- },
- ]
- },
- {
- "label": _("Website"),
- "items": [
- {
- "type": "help",
- "label": _("Publish Items on Website"),
- "youtube_id": "W31LBBNzbgc"
- },
- {
- "type": "help",
- "label": _("Shopping Cart"),
- "youtube_id": "xkrYO-KFukM"
- },
- ]
- },
- ]
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
deleted file mode 100644
index 9855a11..0000000
--- a/erpnext/config/hr.py
+++ /dev/null
@@ -1,470 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Employee"),
- "items": [
- {
- "type": "doctype",
- "name": "Employee",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Employment Type",
- },
- {
- "type": "doctype",
- "name": "Branch",
- },
- {
- "type": "doctype",
- "name": "Department",
- },
- {
- "type": "doctype",
- "name": "Designation",
- },
- {
- "type": "doctype",
- "name": "Employee Grade",
- },
- {
- "type": "doctype",
- "name": "Employee Group",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Health Insurance"
- },
- ]
- },
- {
- "label": _("Attendance"),
- "items": [
- {
- "type": "doctype",
- "name": "Employee Attendance Tool",
- "hide_count": True,
- "onboard": 1,
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Attendance",
- "onboard": 1,
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Attendance Request",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Upload Attendance",
- "hide_count": True,
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Checkin",
- "hide_count": True,
- "dependencies": ["Employee"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Monthly Attendance Sheet",
- "doctype": "Attendance"
- },
- ]
- },
- {
- "label": _("Leaves"),
- "items": [
- {
- "type": "doctype",
- "name": "Leave Application",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Leave Allocation",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Leave Policy",
- "dependencies": ["Leave Type"]
- },
- {
- "type": "doctype",
- "name": "Leave Period",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name":"Leave Type",
- },
- {
- "type": "doctype",
- "name": "Holiday List",
- },
- {
- "type": "doctype",
- "name": "Compensatory Leave Request",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Leave Encashment",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Leave Block List",
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Employee Leave Balance",
- "doctype": "Leave Application"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Leave Ledger Entry",
- "doctype": "Leave Ledger Entry"
- },
- ]
- },
- {
- "label": _("Payroll"),
- "items": [
- {
- "type": "doctype",
- "name": "Salary Structure",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Salary Structure Assignment",
- "onboard": 1,
- "dependencies": ["Salary Structure", "Employee"],
- },
- {
- "type": "doctype",
- "name": "Payroll Entry",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Salary Slip",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Payroll Period",
- },
- {
- "type": "doctype",
- "name": "Income Tax Slab",
- },
- {
- "type": "doctype",
- "name": "Salary Component",
- },
- {
- "type": "doctype",
- "name": "Additional Salary",
- },
- {
- "type": "doctype",
- "name": "Retention Bonus",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Incentive",
- "dependencies": ["Employee"]
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Salary Register",
- "doctype": "Salary Slip"
- },
- ]
- },
- {
- "label": _("Employee Tax and Benefits"),
- "items": [
- {
- "type": "doctype",
- "name": "Employee Tax Exemption Declaration",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Tax Exemption Proof Submission",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Other Income",
- },
- {
- "type": "doctype",
- "name": "Employee Benefit Application",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Benefit Claim",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Tax Exemption Category",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Tax Exemption Sub Category",
- "dependencies": ["Employee"]
- },
- ]
- },
- {
- "label": _("Employee Lifecycle"),
- "items": [
- {
- "type": "doctype",
- "name": "Employee Onboarding",
- "dependencies": ["Job Applicant"],
- },
- {
- "type": "doctype",
- "name": "Employee Skill Map",
- "dependencies": ["Employee"],
- },
- {
- "type": "doctype",
- "name": "Employee Promotion",
- "dependencies": ["Employee"],
- },
- {
- "type": "doctype",
- "name": "Employee Transfer",
- "dependencies": ["Employee"],
- },
- {
- "type": "doctype",
- "name": "Employee Separation",
- "dependencies": ["Employee"],
- },
- {
- "type": "doctype",
- "name": "Employee Onboarding Template",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Separation Template",
- "dependencies": ["Employee"]
- },
- ]
- },
- {
- "label": _("Recruitment"),
- "items": [
- {
- "type": "doctype",
- "name": "Job Opening",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Job Applicant",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Job Offer",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Appointment Letter",
- },
- {
- "type": "doctype",
- "name": "Staffing Plan",
- },
- ]
- },
- {
- "label": _("Training"),
- "items": [
- {
- "type": "doctype",
- "name": "Training Program"
- },
- {
- "type": "doctype",
- "name": "Training Event"
- },
- {
- "type": "doctype",
- "name": "Training Result"
- },
- {
- "type": "doctype",
- "name": "Training Feedback"
- },
- ]
- },
- {
- "label": _("Performance"),
- "items": [
- {
- "type": "doctype",
- "name": "Appraisal",
- },
- {
- "type": "doctype",
- "name": "Appraisal Template",
- },
- {
- "type": "doctype",
- "name": "Energy Point Rule",
- },
- {
- "type": "doctype",
- "name": "Energy Point Log",
- },
- {
- "type": "link",
- "doctype": "Energy Point Log",
- "label": _("Energy Point Leaderboard"),
- "route": "#social/users"
- },
- ]
- },
- {
- "label": _("Expense Claims"),
- "items": [
- {
- "type": "doctype",
- "name": "Expense Claim",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Employee Advance",
- "dependencies": ["Employee"]
- },
- ]
- },
- {
- "label": _("Loans"),
- "items": [
- {
- "type": "doctype",
- "name": "Loan Application",
- "dependencies": ["Employee"]
- },
- {
- "type": "doctype",
- "name": "Loan"
- },
- {
- "type": "doctype",
- "name": "Loan Type",
- },
- ]
- },
- {
- "label": _("Shift Management"),
- "items": [
- {
- "type": "doctype",
- "name": "Shift Type",
- },
- {
- "type": "doctype",
- "name": "Shift Request",
- },
- {
- "type": "doctype",
- "name": "Shift Assignment",
- },
- ]
- },
- {
- "label": _("Fleet Management"),
- "items": [
- {
- "type": "doctype",
- "name": "Vehicle"
- },
- {
- "type": "doctype",
- "name": "Vehicle Log"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Vehicle Expenses",
- "doctype": "Vehicle"
- },
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-cog",
- "items": [
- {
- "type": "doctype",
- "name": "HR Settings",
- },
- {
- "type": "doctype",
- "name": "Daily Work Summary Group"
- },
- {
- "type": "page",
- "name": "team-updates",
- "label": _("Team Updates")
- },
- ]
- },
- {
- "label": _("Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Employee Birthday",
- "doctype": "Employee"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Employees working on a holiday",
- "doctype": "Employee"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Department Analytics",
- "doctype": "Employee"
- },
- ]
- },
- ]
diff --git a/erpnext/config/hub_node.py b/erpnext/config/hub_node.py
deleted file mode 100644
index 0afdeb5..0000000
--- a/erpnext/config/hub_node.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Settings"),
- "items": [
- {
- "type": "doctype",
- "name": "Marketplace Settings"
- },
- ]
- },
- {
- "label": _("Marketplace"),
- "items": [
- {
- "type": "page",
- "name": "marketplace/home"
- },
- ]
- },
- ]
\ No newline at end of file
diff --git a/erpnext/config/integrations.py b/erpnext/config/integrations.py
deleted file mode 100644
index f8b3257..0000000
--- a/erpnext/config/integrations.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Payments"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "GoCardless Settings",
- "description": _("GoCardless payment gateway settings"),
- },
- {
- "type": "doctype",
- "name": "GoCardless Mandate",
- "description": _("GoCardless SEPA Mandate"),
- }
- ]
- },
- {
- "label": _("Settings"),
- "items": [
- {
- "type": "doctype",
- "name": "Woocommerce Settings"
- },
- {
- "type": "doctype",
- "name": "Shopify Settings",
- "description": _("Connect Shopify with ERPNext"),
- },
- {
- "type": "doctype",
- "name": "Amazon MWS Settings",
- "description": _("Connect Amazon with ERPNext"),
- },
- {
- "type": "doctype",
- "name": "Plaid Settings",
- "description": _("Connect your bank accounts to ERPNext"),
- },
- {
- "type": "doctype",
- "name": "Exotel Settings",
- "description": _("Connect your Exotel Account to ERPNext and track call logs"),
- }
- ]
- }
- ]
diff --git a/erpnext/config/loan_management.py b/erpnext/config/loan_management.py
deleted file mode 100644
index a84f13a..0000000
--- a/erpnext/config/loan_management.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-import frappe
-
-
-def get_data():
- return [
- {
- "label": _("Loan"),
- "items": [
- {
- "type": "doctype",
- "name": "Loan Type",
- "description": _("Loan Type for interest and penalty rates"),
- },
- {
- "type": "doctype",
- "name": "Loan Application",
- "description": _("Loan Applications from customers and employees."),
- },
- {
- "type": "doctype",
- "name": "Loan",
- "description": _("Loans provided to customers and employees."),
- },
-
- ]
- },
- {
- "label": _("Loan Security"),
- "items": [
- {
- "type": "doctype",
- "name": "Loan Security Type",
- },
- {
- "type": "doctype",
- "name": "Loan Security Price",
- },
- {
- "type": "doctype",
- "name": "Loan Security",
- },
- {
- "type": "doctype",
- "name": "Loan Security Pledge",
- },
- {
- "type": "doctype",
- "name": "Loan Security Unpledge",
- },
- {
- "type": "doctype",
- "name": "Loan Security Shortfall",
- },
- ]
- },
- {
- "label": _("Disbursement and Repayment"),
- "items": [
- {
- "type": "doctype",
- "name": "Loan Disbursement",
- },
- {
- "type": "doctype",
- "name": "Loan Repayment",
- },
- {
- "type": "doctype",
- "name": "Loan Interest Accrual"
- }
- ]
- },
- {
- "label": _("Loan Processes"),
- "items": [
- {
- "type": "doctype",
- "name": "Process Loan Security Shortfall",
- },
- {
- "type": "doctype",
- "name": "Process Loan Interest Accrual",
- }
- ]
- },
- {
- "label": _("Reports"),
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Loan Repayment and Closure",
- "route": "#query-report/Loan Repayment and Closure",
- "doctype": "Loan Repayment",
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Loan Security Status",
- "route": "#query-report/Loan Security Status",
- "doctype": "Loan Security Pledge",
- }
- ]
- }
- ]
\ No newline at end of file
diff --git a/erpnext/config/manufacturing.py b/erpnext/config/manufacturing.py
deleted file mode 100644
index 012f1ca..0000000
--- a/erpnext/config/manufacturing.py
+++ /dev/null
@@ -1,168 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Bill of Materials"),
- "items": [
- {
- "type": "doctype",
- "name": "Item",
- "description": _("All Products or Services."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "BOM",
- "description": _("Bill of Materials (BOM)"),
- "label": _("Bill of Materials"),
- "onboard": 1,
- "dependencies": ["Item"]
- },
- {
- "type": "doctype",
- "name": "BOM Browser",
- "icon": "fa fa-sitemap",
- "label": _("BOM Browser"),
- "description": _("Tree of Bill of Materials"),
- "link": "Tree/BOM",
- "onboard": 1,
- "dependencies": ["Item"]
- },
-
- {
- "type": "doctype",
- "name": "Workstation",
- "description": _("Where manufacturing operations are carried."),
- },
- {
- "type": "doctype",
- "name": "Operation",
- "description": _("Details of the operations carried out."),
- },
- {
- "type": "doctype",
- "name": "Routing"
- }
-
- ]
- },
- {
- "label": _("Production"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "Work Order",
- "description": _("Orders released for production."),
- "onboard": 1,
- "dependencies": ["Item", "BOM"]
- },
- {
- "type": "doctype",
- "name": "Production Plan",
- "description": _("Generate Material Requests (MRP) and Work Orders."),
- "onboard": 1,
- "dependencies": ["Item", "BOM"]
- },
- {
- "type": "doctype",
- "name": "Stock Entry",
- "onboard": 1,
- "dependencies": ["Item"]
- },
- {
- "type": "doctype",
- "name": "Timesheet",
- "description": _("Time Sheet for manufacturing."),
- "onboard": 1,
- "dependencies": ["Activity Type"]
- },
- {
- "type": "doctype",
- "name": "Job Card"
- }
- ]
- },
- {
- "label": _("Tools"),
- "icon": "fa fa-wrench",
- "items": [
- {
- "type": "doctype",
- "name": "BOM Update Tool",
- "description": _("Replace BOM and update latest price in all BOMs"),
- },
- {
- "type": "page",
- "label": _("BOM Comparison Tool"),
- "name": "bom-comparison-tool",
- "description": _("Compare BOMs for changes in Raw Materials and Operations"),
- "data_doctype": "BOM"
- },
- ]
- },
- {
- "label": _("Settings"),
- "items": [
- {
- "type": "doctype",
- "name": "Manufacturing Settings",
- "description": _("Global settings for all manufacturing processes."),
- }
- ]
- },
- {
- "label": _("Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Work Order Summary",
- "doctype": "Work Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Issued Items Against Work Order",
- "doctype": "Work Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Production Analytics",
- "doctype": "Work Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "BOM Search",
- "doctype": "BOM"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "BOM Stock Report",
- "doctype": "BOM"
- }
- ]
- },
- {
- "label": _("Help"),
- "icon": "fa fa-facetime-video",
- "items": [
- {
- "type": "help",
- "label": _("Bill of Materials"),
- "youtube_id": "hDV0c1OeWLo"
- },
- {
- "type": "help",
- "label": _("Work Order"),
- "youtube_id": "ZotgLyp2YFY"
- },
- ]
- }
- ]
diff --git a/erpnext/config/non_profit.py b/erpnext/config/non_profit.py
deleted file mode 100644
index 42ec9d3..0000000
--- a/erpnext/config/non_profit.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Chapter"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "Chapter",
- "description": _("Chapter information."),
- "onboard": 1,
- }
- ]
- },
- {
- "label": _("Membership"),
- "items": [
- {
- "type": "doctype",
- "name": "Member",
- "description": _("Member information."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Membership",
- "description": _("Memebership Details"),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Membership Type",
- "description": _("Memebership Type Details"),
- },
- ]
- },
- {
- "label": _("Volunteer"),
- "items": [
- {
- "type": "doctype",
- "name": "Volunteer",
- "description": _("Volunteer information."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Volunteer Type",
- "description": _("Volunteer Type information."),
- }
- ]
- },
- {
- "label": _("Donor"),
- "items": [
- {
- "type": "doctype",
- "name": "Donor",
- "description": _("Donor information."),
- },
- {
- "type": "doctype",
- "name": "Donor Type",
- "description": _("Donor Type information."),
- }
- ]
- },
- {
- "label": _("Loan Management"),
- "icon": "icon-list",
- "items": [
- {
- "type": "doctype",
- "name": "Loan Type",
- "description": _("Define various loan types")
- },
- {
- "type": "doctype",
- "name": "Loan Application",
- "description": _("Loan Application")
- },
- {
- "type": "doctype",
- "name": "Loan"
- },
- ]
- },
- {
- "label": _("Grant Application"),
- "items": [
- {
- "type": "doctype",
- "name": "Grant Application",
- "description": _("Grant information."),
- }
- ]
- }
- ]
diff --git a/erpnext/config/projects.py b/erpnext/config/projects.py
index 47700d1..ab4db96 100644
--- a/erpnext/config/projects.py
+++ b/erpnext/config/projects.py
@@ -16,13 +16,13 @@
{
"type": "doctype",
"name": "Task",
- "route": "#List/Task",
+ "route": "/app/List/Task",
"description": _("Project activity / task."),
"onboard": 1,
},
{
"type": "report",
- "route": "#List/Task/Gantt",
+ "route": "/app/List/Task/Gantt",
"doctype": "Task",
"name": "Gantt Chart",
"description": _("Gantt chart of all tasks."),
@@ -97,5 +97,5 @@
},
]
},
-
+
]
diff --git a/erpnext/config/quality_management.py b/erpnext/config/quality_management.py
deleted file mode 100644
index 35acdfa..0000000
--- a/erpnext/config/quality_management.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Goal and Procedure"),
- "items": [
- {
- "type": "doctype",
- "name": "Quality Goal",
- "description":_("Quality Goal."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Quality Procedure",
- "description":_("Quality Procedure."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Quality Procedure",
- "icon": "fa fa-sitemap",
- "label": _("Tree of Procedures"),
- "route": "#Tree/Quality Procedure",
- "description": _("Tree of Quality Procedures."),
- },
- ]
- },
- {
- "label": _("Review and Action"),
- "items": [
- {
- "type": "doctype",
- "name": "Quality Review",
- "description":_("Quality Review"),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Quality Action",
- "description":_("Quality Action"),
- }
- ]
- },
- {
- "label": _("Meeting"),
- "items": [
- {
- "type": "doctype",
- "name": "Quality Meeting",
- "description":_("Quality Meeting"),
- }
- ]
- },
- {
- "label": _("Feedback"),
- "items": [
- {
- "type": "doctype",
- "name": "Quality Feedback",
- "description":_("Quality Feedback"),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Quality Feedback Template",
- "description":_("Quality Feedback Template"),
- }
- ]
- },
- ]
\ No newline at end of file
diff --git a/erpnext/config/retail.py b/erpnext/config/retail.py
deleted file mode 100644
index 738be7e..0000000
--- a/erpnext/config/retail.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Retail Operations"),
- "items": [
- {
- "type": "doctype",
- "name": "POS Profile",
- "label": _("Point-of-Sale Profile"),
- "description": _("Setup default values for POS Invoices"),
- "onboard": 1,
- },
- {
- "type": "page",
- "name": "pos",
- "label": _("POS"),
- "description": _("Point of Sale"),
- "onboard": 1,
- "dependencies": ["POS Profile"]
- },
- {
- "type": "doctype",
- "name": "Cashier Closing",
- "description": _("Cashier Closing"),
- },
- {
- "type": "doctype",
- "name": "POS Settings",
- "description": _("Setup mode of POS (Online / Offline)")
- },
- {
- "type": "doctype",
- "name": "Loyalty Program",
- "label": _("Loyalty Program"),
- "description": _("To make Customer based incentive schemes.")
- },
- {
- "type": "doctype",
- "name": "Loyalty Point Entry",
- "label": _("Loyalty Point Entry"),
- "description": _("To view logs of Loyalty Points assigned to a Customer.")
- }
- ]
- }
- ]
\ No newline at end of file
diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py
deleted file mode 100644
index 5db4cc2..0000000
--- a/erpnext/config/selling.py
+++ /dev/null
@@ -1,320 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Sales"),
- "icon": "fa fa-star",
- "items": [
- {
- "type": "doctype",
- "name": "Customer",
- "description": _("Customer Database."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Quotation",
- "description": _("Quotes to Leads or Customers."),
- "onboard": 1,
- "dependencies": ["Item", "Customer"],
- },
- {
- "type": "doctype",
- "name": "Sales Order",
- "description": _("Confirmed orders from Customers."),
- "onboard": 1,
- "dependencies": ["Item", "Customer"],
- },
- {
- "type": "doctype",
- "name": "Sales Invoice",
- "description": _("Invoices for Costumers."),
- "onboard": 1,
- "dependencies": ["Item", "Customer"],
- },
- {
- "type": "doctype",
- "name": "Blanket Order",
- "description": _("Blanket Orders from Costumers."),
- "onboard": 1,
- "dependencies": ["Item", "Customer"],
- },
- {
- "type": "doctype",
- "name": "Sales Partner",
- "description": _("Manage Sales Partners."),
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "label": _("Sales Person"),
- "name": "Sales Person",
- "icon": "fa fa-sitemap",
- "link": "Tree/Sales Person",
- "description": _("Manage Sales Person Tree."),
- "dependencies": ["Item", "Customer"],
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Territory Target Variance (Item Group-Wise)",
- "route": "#query-report/Territory Target Variance Item Group-Wise",
- "doctype": "Territory",
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Person Target Variance (Item Group-Wise)",
- "route": "#query-report/Sales Person Target Variance Item Group-Wise",
- "doctype": "Sales Person",
- "dependencies": ["Sales Person"],
- },
- ]
- },
- {
- "label": _("Items and Pricing"),
- "items": [
- {
- "type": "doctype",
- "name": "Item",
- "description": _("All Products or Services."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Item Price",
- "description": _("Multiple Item prices."),
- "route": "#Report/Item Price",
- "dependencies": ["Item", "Price List"],
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Price List",
- "description": _("Price List master."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Item Group",
- "icon": "fa fa-sitemap",
- "label": _("Item Group"),
- "link": "Tree/Item Group",
- "description": _("Tree of Item Groups."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Product Bundle",
- "description": _("Bundle items at time of sale."),
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Promotional Scheme",
- "description": _("Rules for applying different promotional schemes.")
- },
- {
- "type": "doctype",
- "name": "Pricing Rule",
- "description": _("Rules for applying pricing and discount."),
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Shipping Rule",
- "description": _("Rules for adding shipping costs."),
- },
- {
- "type": "doctype",
- "name": "Coupon Code",
- "description": _("Define coupon codes."),
- }
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-cog",
- "items": [
- {
- "type": "doctype",
- "name": "Selling Settings",
- "description": _("Default settings for selling transactions."),
- "settings": 1,
- },
- {
- "type": "doctype",
- "name":"Terms and Conditions",
- "label": _("Terms and Conditions Template"),
- "description": _("Template of terms or contract."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Sales Taxes and Charges Template",
- "description": _("Tax template for selling transactions."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Lead Source",
- "description": _("Track Leads by Lead Source.")
- },
- {
- "type": "doctype",
- "label": _("Customer Group"),
- "name": "Customer Group",
- "icon": "fa fa-sitemap",
- "link": "Tree/Customer Group",
- "description": _("Manage Customer Group Tree."),
- },
- {
- "type": "doctype",
- "name": "Contact",
- "description": _("All Contacts."),
- },
- {
- "type": "doctype",
- "name": "Address",
- "description": _("All Addresses."),
- },
- {
- "type": "doctype",
- "label": _("Territory"),
- "name": "Territory",
- "icon": "fa fa-sitemap",
- "link": "Tree/Territory",
- "description": _("Manage Territory Tree."),
- },
- {
- "type": "doctype",
- "name": "Campaign",
- "description": _("Sales campaigns."),
- },
- ]
- },
- {
- "label": _("Key Reports"),
- "icon": "fa fa-table",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Analytics",
- "doctype": "Sales Order",
- "onboard": 1,
- },
- {
- "type": "page",
- "name": "sales-funnel",
- "label": _("Sales Funnel"),
- "icon": "fa fa-bar-chart",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Customer Acquisition and Loyalty",
- "doctype": "Customer",
- "icon": "fa fa-bar-chart",
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Inactive Customers",
- "doctype": "Sales Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Ordered Items To Be Delivered",
- "doctype": "Sales Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Person-wise Transaction Summary",
- "doctype": "Sales Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Item-wise Sales History",
- "doctype": "Item"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Quotation Trends",
- "doctype": "Quotation"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Order Trends",
- "doctype": "Sales Order"
- },
- ]
- },
- {
- "label": _("Other Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Lead Details",
- "doctype": "Lead"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Address And Contacts",
- "label": _("Customer Addresses And Contacts"),
- "doctype": "Address",
- "route_options": {
- "party_type": "Customer"
- }
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "BOM Search",
- "doctype": "BOM"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Available Stock for Packing Items",
- "doctype": "Item",
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Pending SO Items For Purchase Request",
- "doctype": "Sales Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Customer Credit Balance",
- "doctype": "Customer"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Customers Without Any Sales Transactions",
- "doctype": "Customer"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Sales Partners Commission",
- "doctype": "Customer"
- }
- ]
- },
-
- ]
diff --git a/erpnext/config/settings.py b/erpnext/config/settings.py
deleted file mode 100644
index 323683a..0000000
--- a/erpnext/config/settings.py
+++ /dev/null
@@ -1,117 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-from frappe.desk.moduleview import add_setup_section
-
-def get_data():
- data = [
- {
- "label": _("Settings"),
- "icon": "fa fa-wrench",
- "items": [
- {
- "type": "doctype",
- "name": "Global Defaults",
- "label": _("ERPNext Settings"),
- "description": _("Set Default Values like Company, Currency, Current Fiscal Year, etc."),
- "hide_count": True,
- "settings": 1,
- }
- ]
- },
- {
- "label": _("Printing"),
- "icon": "fa fa-print",
- "items": [
- {
- "type": "doctype",
- "name": "Letter Head",
- "description": _("Letter Heads for print templates."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Print Heading",
- "description": _("Titles for print templates e.g. Proforma Invoice.")
- },
- {
- "type": "doctype",
- "name": "Address Template",
- "description": _("Country wise default Address Templates")
- },
- {
- "type": "doctype",
- "name": "Terms and Conditions",
- "description": _("Standard contract terms for Sales or Purchase.")
- },
- ]
- },
- {
- "label": _("Help"),
- "items": [
- {
- "type": "help",
- "name": _("Data Import and Export"),
- "youtube_id": "6wiriRKPhmg"
- },
- {
- "type": "help",
- "label": _("Setting up Email"),
- "youtube_id": "YFYe0DrB95o"
- },
- {
- "type": "help",
- "label": _("Printing and Branding"),
- "youtube_id": "cKZHcx1znMc"
- },
- {
- "type": "help",
- "label": _("Users and Permissions"),
- "youtube_id": "8Slw1hsTmUI"
- },
- {
- "type": "help",
- "label": _("Workflow"),
- "youtube_id": "yObJUg9FxFs"
- },
- ]
- },
- {
- "label": _("Customize"),
- "icon": "fa fa-glass",
- "items": [
- {
- "type": "doctype",
- "name": "Authorization Rule",
- "description": _("Create rules to restrict transactions based on values.")
- }
- ]
- },
- {
- "label": _("Email"),
- "icon": "fa fa-envelope",
- "items": [
- {
- "type": "doctype",
- "name": "Email Digest",
- "description": _("Create and manage daily, weekly and monthly email digests.")
- },
- {
- "type": "doctype",
- "name": "SMS Settings",
- "description": _("Setup SMS gateway settings")
- },
- ]
- }
- ]
-
- for module, label, icon in (
- ("accounts", _("Accounting"), "fa fa-money"),
- ("stock", _("Stock"), "fa fa-truck"),
- ("selling", _("Selling"), "fa fa-tag"),
- ("buying", _("Buying"), "fa fa-shopping-cart"),
- ("hr", _("Human Resources"), "fa fa-group"),
- ("support", _("Support"), "fa fa-phone")):
-
- add_setup_section(data, "erpnext", module, label, icon)
-
- return data
diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py
deleted file mode 100644
index dd35f5a..0000000
--- a/erpnext/config/stock.py
+++ /dev/null
@@ -1,361 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Stock Transactions"),
- "items": [
- {
- "type": "doctype",
- "name": "Stock Entry",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Delivery Note",
- "onboard": 1,
- "dependencies": ["Item", "Customer"],
- },
- {
- "type": "doctype",
- "name": "Purchase Receipt",
- "onboard": 1,
- "dependencies": ["Item", "Supplier"],
- },
- {
- "type": "doctype",
- "name": "Material Request",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Pick List",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Delivery Trip"
- },
- ]
- },
- {
- "label": _("Stock Reports"),
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Stock Ledger",
- "doctype": "Stock Ledger Entry",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Stock Balance",
- "doctype": "Stock Ledger Entry",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Stock Projected Qty",
- "doctype": "Item",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "page",
- "name": "stock-balance",
- "label": _("Stock Summary"),
- "dependencies": ["Item"],
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Stock Ageing",
- "doctype": "Item",
- "dependencies": ["Item"],
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Item Price Stock",
- "doctype": "Item",
- "dependencies": ["Item"],
- }
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-cog",
- "items": [
- {
- "type": "doctype",
- "name": "Stock Settings",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Warehouse",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "UOM",
- "label": _("Unit of Measure") + " (UOM)",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Brand",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Item Attribute",
- },
- {
- "type": "doctype",
- "name": "Item Variant Settings",
- },
- ]
- },
- {
- "label": _("Items and Pricing"),
- "items": [
- {
- "type": "doctype",
- "name": "Item",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Product Bundle",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Item Group",
- "icon": "fa fa-sitemap",
- "label": _("Item Group"),
- "link": "Tree/Item Group",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Price List",
- },
- {
- "type": "doctype",
- "name": "Item Price",
- },
- {
- "type": "doctype",
- "name": "Shipping Rule",
- },
- {
- "type": "doctype",
- "name": "Pricing Rule",
- },
- {
- "type": "doctype",
- "name": "Item Alternative",
- },
- {
- "type": "doctype",
- "name": "Item Manufacturer",
- },
- {
- "type": "doctype",
- "name": "Item Variant Settings",
- },
- ]
- },
- {
- "label": _("Serial No and Batch"),
- "items": [
- {
- "type": "doctype",
- "name": "Serial No",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Batch",
- "onboard": 1,
- "dependencies": ["Item"],
- },
- {
- "type": "doctype",
- "name": "Installation Note",
- "dependencies": ["Item"],
- },
- {
- "type": "report",
- "name": "Serial No Service Contract Expiry",
- "doctype": "Serial No"
- },
- {
- "type": "report",
- "name": "Serial No Status",
- "doctype": "Serial No"
- },
- {
- "type": "report",
- "name": "Serial No Warranty Expiry",
- "doctype": "Serial No"
- },
- ]
- },
- {
- "label": _("Tools"),
- "icon": "fa fa-wrench",
- "items": [
- {
- "type": "doctype",
- "name": "Stock Reconciliation",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Landed Cost Voucher",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Packing Slip",
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Quality Inspection",
- },
- {
- "type": "doctype",
- "name": "Quality Inspection Template",
- },
- {
- "type": "doctype",
- "name": "Quick Stock Balance",
- },
- ]
- },
- {
- "label": _("Key Reports"),
- "icon": "fa fa-table",
- "items": [
- {
- "type": "report",
- "is_query_report": False,
- "name": "Item-wise Price List Rate",
- "doctype": "Item Price",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Stock Analytics",
- "doctype": "Stock Entry",
- "onboard": 1,
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Delivery Note Trends",
- "doctype": "Delivery Note"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Purchase Receipt Trends",
- "doctype": "Purchase Receipt"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Ordered Items To Be Delivered",
- "doctype": "Delivery Note"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Purchase Order Items To Be Received",
- "doctype": "Purchase Receipt"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Item Shortage Report",
- "doctype": "Bin"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Batch-Wise Balance History",
- "doctype": "Batch"
- },
- ]
- },
- {
- "label": _("Other Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "report",
- "is_query_report": True,
- "name": "Requested Items To Be Transferred",
- "doctype": "Material Request"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Batch Item Expiry Status",
- "doctype": "Stock Ledger Entry"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Item Prices",
- "doctype": "Price List"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Itemwise Recommended Reorder Level",
- "doctype": "Item"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Item Variant Details",
- "doctype": "Item"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Subcontracted Raw Materials To Be Transferred",
- "doctype": "Purchase Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Subcontracted Item To Be Received",
- "doctype": "Purchase Order"
- },
- {
- "type": "report",
- "is_query_report": True,
- "name": "Stock and Account Value Comparison",
- "doctype": "Stock Ledger Entry"
- }
- ]
- },
-
- ]
diff --git a/erpnext/config/support.py b/erpnext/config/support.py
deleted file mode 100644
index 151c4f7..0000000
--- a/erpnext/config/support.py
+++ /dev/null
@@ -1,105 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Issues"),
- "items": [
- {
- "type": "doctype",
- "name": "Issue",
- "description": _("Support queries from customers."),
- "onboard": 1,
- },
- {
- "type": "doctype",
- "name": "Issue Type",
- "description": _("Issue Type."),
- },
- {
- "type": "doctype",
- "name": "Issue Priority",
- "description": _("Issue Priority."),
- }
- ]
- },
- {
- "label": _("Warranty"),
- "items": [
- {
- "type": "doctype",
- "name": "Warranty Claim",
- "description": _("Warranty Claim against Serial No."),
- },
- {
- "type": "doctype",
- "name": "Serial No",
- "description": _("Single unit of an Item."),
- },
- ]
- },
- {
- "label": _("Service Level Agreement"),
- "items": [
- {
- "type": "doctype",
- "name": "Service Level",
- "description": _("Service Level."),
- },
- {
- "type": "doctype",
- "name": "Service Level Agreement",
- "description": _("Service Level Agreement."),
- }
- ]
- },
- {
- "label": _("Maintenance"),
- "items": [
- {
- "type": "doctype",
- "name": "Maintenance Schedule",
- },
- {
- "type": "doctype",
- "name": "Maintenance Visit",
- },
- ]
- },
- {
- "label": _("Reports"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "page",
- "name": "support-analytics",
- "label": _("Support Analytics"),
- "icon": "fa fa-bar-chart"
- },
- {
- "type": "report",
- "name": "Minutes to First Response for Issues",
- "doctype": "Issue",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Support Hours",
- "doctype": "Issue",
- "is_query_report": True
- },
- ]
- },
- {
- "label": _("Settings"),
- "icon": "fa fa-list",
- "items": [
- {
- "type": "doctype",
- "name": "Support Settings",
- "label": _("Support Settings"),
- },
- ]
- },
- ]
\ No newline at end of file
diff --git a/erpnext/config/website.py b/erpnext/config/website.py
deleted file mode 100644
index d31b057..0000000
--- a/erpnext/config/website.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-
-def get_data():
- return [
- {
- "label": _("Portal"),
- "items": [
- {
- "type": "doctype",
- "name": "Homepage",
- "description": _("Settings for website homepage"),
- },
- {
- "type": "doctype",
- "name": "Homepage Section",
- "description": _("Add cards or custom sections on homepage"),
- },
- {
- "type": "doctype",
- "name": "Products Settings",
- "description": _("Settings for website product listing"),
- },
- {
- "type": "doctype",
- "name": "Shopping Cart Settings",
- "label": _("Shopping Cart Settings"),
- "description": _("Settings for online shopping cart such as shipping rules, price list etc."),
- "hide_count": True
- }
- ]
- }
- ]
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index f1c96de..477ad6a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -22,13 +22,30 @@
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
from erpnext.stock.get_item_details import get_item_warehouse, _get_item_tax_template, get_item_tax_map
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
+from erpnext.controllers.print_settings import set_print_templates_for_item_table, set_print_templates_for_taxes
-force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
+class AccountMissingError(frappe.ValidationError): pass
+
+force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate",
+ "pricing_rules", "weight_per_unit", "weight_uom", "total_weight")
class AccountsController(TransactionBase):
def __init__(self, *args, **kwargs):
super(AccountsController, self).__init__(*args, **kwargs)
+ def get_print_settings(self):
+ print_setting_fields = []
+ items_field = self.meta.get_field('items')
+
+ if items_field and items_field.fieldtype == 'Table':
+ print_setting_fields += ['compact_item_print', 'print_uom_after_quantity']
+
+ taxes_field = self.meta.get_field('taxes')
+ if taxes_field and taxes_field.fieldtype == 'Table':
+ print_setting_fields += ['print_taxes_with_zero_amount']
+
+ return print_setting_fields
+
@property
def company_currency(self):
if not hasattr(self, "__company_currency"):
@@ -73,6 +90,9 @@
self.ensure_supplier_is_not_blocked()
self.validate_date_with_fiscal_year()
+ self.validate_inter_company_reference()
+
+ self.set_incoming_rate()
if self.meta.get_field("currency"):
self.calculate_taxes_and_totals()
@@ -105,10 +125,24 @@
else:
self.validate_deferred_start_and_end_date()
+ self.set_inter_company_account()
+
validate_regional(self)
+
+ validate_einvoice_fields(self)
+
if self.doctype != 'Material Request':
apply_pricing_rule_on_transaction(self)
+ def before_cancel(self):
+ validate_einvoice_fields(self)
+
+ def on_trash(self):
+ # delete sl and gl entries on deletion of transaction
+ if frappe.db.get_single_value('Accounts Settings', 'delete_linked_ledger_entries'):
+ frappe.db.sql("delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name))
+ frappe.db.sql("delete from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name))
+
def validate_deferred_start_and_end_date(self):
for d in self.items:
if d.get("enable_deferred_revenue") or d.get("enable_deferred_expense"):
@@ -138,7 +172,7 @@
elif self.doctype in ("Quotation", "Purchase Order", "Sales Order"):
self.validate_non_invoice_documents_schedule()
- def before_print(self):
+ def before_print(self, settings=None):
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
if self.get("group_same_items"):
@@ -151,6 +185,9 @@
else:
df.set("print_hide", 1)
+ set_print_templates_for_item_table(self, settings)
+ set_print_templates_for_taxes(self, settings)
+
def calculate_paid_amount(self):
if hasattr(self, "is_pos") or hasattr(self, "is_paid"):
is_paid = self.get("is_pos") or self.get("is_paid")
@@ -196,6 +233,17 @@
validate_fiscal_year(self.get(date_field), self.fiscal_year, self.company,
self.meta.get_label(date_field), self)
+ def validate_inter_company_reference(self):
+ if self.doctype not in ('Purchase Invoice', 'Purchase Receipt', 'Purchase Order'):
+ return
+
+ if self.is_internal_transfer():
+ if not (self.get('inter_company_reference') or self.get('inter_company_invoice_reference')
+ or self.get('inter_company_order_reference')):
+ msg = _("Internal Sale or Delivery Reference missing. ")
+ msg += _("Please create purchase from internal sale or delivery document itself")
+ frappe.throw(msg, title=_("Internal Sales Reference Missing"))
+
def validate_due_date(self):
if self.get('is_pos'): return
@@ -263,6 +311,7 @@
if self.doctype == "Quotation" and self.quotation_to == "Customer" and parent_dict.get("party_name"):
parent_dict.update({"customer": parent_dict.get("party_name")})
+ self.pricing_rules = []
for item in self.get("items"):
if item.get("item_code"):
args = parent_dict.copy()
@@ -271,6 +320,7 @@
args["doctype"] = self.doctype
args["name"] = self.name
args["child_docname"] = item.name
+ args["ignore_pricing_rule"] = self.ignore_pricing_rule if hasattr(self, 'ignore_pricing_rule') else 0
if not args.get("transaction_date"):
args["transaction_date"] = args.get("posting_date")
@@ -301,6 +351,7 @@
if ret.get("pricing_rules"):
self.apply_pricing_rule_on_items(item, ret)
+ self.set_pricing_rule_details(item, ret)
if self.doctype == "Purchase Invoice":
self.set_expense_account(for_validate)
@@ -322,6 +373,9 @@
if item.get('discount_amount'):
item.rate = item.price_list_rate - item.discount_amount
+ if item.get("apply_discount_on_discounted_rate") and pricing_rule_args.get("rate"):
+ item.rate = pricing_rule_args.get("rate")
+
elif pricing_rule_args.get('free_item_data'):
apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data'))
@@ -335,6 +389,18 @@
frappe.msgprint(_("Row {0}: user has not applied the rule {1} on the item {2}")
.format(item.idx, frappe.bold(title), frappe.bold(item.item_code)))
+ def set_pricing_rule_details(self, item_row, args):
+ pricing_rules = get_applied_pricing_rules(args.get("pricing_rules"))
+ if not pricing_rules: return
+
+ for pricing_rule in pricing_rules:
+ self.append("pricing_rules", {
+ "pricing_rule": pricing_rule,
+ "item_code": item_row.item_code,
+ "child_docname": item_row.name,
+ "rule_applied": True
+ })
+
def set_taxes(self):
if not self.meta.get_field("taxes"):
return
@@ -421,8 +487,10 @@
account_currency = get_account_currency(gl_dict.account)
if gl_dict.account and self.doctype not in ["Journal Entry",
- "Period Closing Voucher", "Payment Entry"]:
+ "Period Closing Voucher", "Payment Entry", "Purchase Receipt", "Purchase Invoice", "Stock Entry"]:
self.validate_account_currency(gl_dict.account, account_currency)
+
+ if gl_dict.account and self.doctype not in ["Journal Entry", "Period Closing Voucher", "Payment Entry"]:
set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"),
self.company_currency)
@@ -605,8 +673,6 @@
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
- if self.is_return: return
-
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
unlink_ref_doc_from_payment_entries(self)
@@ -720,6 +786,21 @@
return self._abbr
+ def raise_missing_debit_credit_account_error(self, party_type, party):
+ """Raise an error if debit to/credit to account does not exist."""
+ db_or_cr = frappe.bold("Debit To") if self.doctype == "Sales Invoice" else frappe.bold("Credit To")
+ rec_or_pay = "Receivable" if self.doctype == "Sales Invoice" else "Payable"
+
+ link_to_party = frappe.utils.get_link_to_form(party_type, party)
+ link_to_company = frappe.utils.get_link_to_form("Company", self.company)
+
+ message = _("{0} Account not found against Customer {1}.").format(db_or_cr, frappe.bold(party) or '')
+ message += "<br>" + _("Please set one of the following:") + "<br>"
+ message += "<br><ul><li>" + _("'Account' in the Accounting section of Customer {0}").format(link_to_party) + "</li>"
+ message += "<li>" + _("'Default {0} Account' in Company {1}").format(rec_or_pay, link_to_company) + "</li></ul>"
+
+ frappe.throw(message, title=_("Account Missing"), exc=AccountMissingError)
+
def validate_party(self):
party_type, party = self.get_party()
validate_party_frozen_disabled(party_type, party)
@@ -900,6 +981,38 @@
else:
return frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
+ def set_inter_company_account(self):
+ """
+ Set intercompany account for inter warehouse transactions
+ This account will be used in case billing company and internal customer's
+ representation company is same
+ """
+
+ if self.is_internal_transfer() and not self.unrealized_profit_loss_account:
+ unrealized_profit_loss_account = frappe.db.get_value('Company', self.company, 'unrealized_profit_loss_account')
+
+ if not unrealized_profit_loss_account:
+ msg = _("Please select Unrealized Profit / Loss account or add default Unrealized Profit / Loss account account for company {0}").format(
+ frappe.bold(self.company))
+ frappe.throw(msg)
+
+ self.unrealized_profit_loss_account = unrealized_profit_loss_account
+
+ def is_internal_transfer(self):
+ """
+ It will an internal transfer if its an internal customer and representation
+ company is same as billing company
+ """
+ if self.doctype in ('Sales Invoice', 'Delivery Note', 'Sales Order'):
+ internal_party_field = 'is_internal_customer'
+ elif self.doctype in ('Purchase Invoice', 'Purchase Receipt', 'Purchase Order'):
+ internal_party_field = 'is_internal_supplier'
+
+ if self.get(internal_party_field) and (self.represents_company == self.company):
+ return True
+
+ return False
+
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
@@ -948,8 +1061,10 @@
company_currency = frappe.get_cached_value('Company', company, "default_currency")
if not conversion_rate:
- throw(_("{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}.").format(
- conversion_rate_label, currency, company_currency))
+ throw(
+ _("{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}.")
+ .format(conversion_rate_label, currency, company_currency)
+ )
def validate_taxes_and_charges(tax):
@@ -1170,46 +1285,56 @@
if child_item.get("item_tax_template"):
child_item.item_tax_rate = get_item_tax_map(parent_doc.get('company'), child_item.item_tax_template, as_json=True)
-def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
+def add_taxes_from_tax_template(child_item, parent_doc):
+ add_taxes_from_item_tax_template = frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template")
+
+ if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template:
+ tax_map = json.loads(child_item.get("item_tax_rate"))
+ for tax_type in tax_map:
+ tax_rate = flt(tax_map[tax_type])
+ taxes = parent_doc.get('taxes') or []
+ # add new row for tax head only if missing
+ found = any(tax.account_head == tax_type for tax in taxes)
+ if not found:
+ tax_row = parent_doc.append("taxes", {})
+ tax_row.update({
+ "description" : str(tax_type).split(' - ')[0],
+ "charge_type" : "On Net Total",
+ "account_head" : tax_type,
+ "rate" : tax_rate
+ })
+ if parent_doc.doctype == "Purchase Order":
+ tax_row.update({
+ "category" : "Total",
+ "add_deduct_tax" : "Add"
+ })
+ tax_row.db_insert()
+
+def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item):
"""
- Returns a Sales Order Item child item containing the default values
+ Returns a Sales/Purchase Order Item child item containing the default values
"""
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
- child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
+ child_item = frappe.new_doc(child_doctype, p_doc, child_docname)
item = frappe.get_doc("Item", trans_item.get('item_code'))
- child_item.item_code = item.item_code
- child_item.item_name = item.item_name
- child_item.description = item.description
- child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
- child_item.uom = trans_item.get("uom") or item.stock_uom
- conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
- child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
- set_child_tax_template_and_map(item, child_item, p_doc)
- child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
- if not child_item.warehouse:
- frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
- .format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
- return child_item
-
-
-def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
- """
- Returns a Purchase Order Item child item containing the default values
- """
- p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
- child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
- item = frappe.get_doc("Item", trans_item.get('item_code'))
- child_item.item_code = item.item_code
- child_item.item_name = item.item_name
- child_item.description = item.description
- child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
+ for field in ("item_code", "item_name", "description", "item_group"):
+ child_item.update({field: item.get(field)})
+ date_fieldname = "delivery_date" if child_doctype == "Sales Order Item" else "schedule_date"
+ child_item.update({date_fieldname: trans_item.get(date_fieldname) or p_doc.get(date_fieldname)})
child_item.uom = trans_item.get("uom") or item.stock_uom
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
- child_item.base_rate = 1 # Initiallize value will update in parent validation
- child_item.base_amount = 1 # Initiallize value will update in parent validation
+ if child_doctype == "Purchase Order Item":
+ child_item.base_rate = 1 # Initiallize value will update in parent validation
+ child_item.base_amount = 1 # Initiallize value will update in parent validation
+ if child_doctype == "Sales Order Item":
+ child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
+ if not child_item.warehouse:
+ frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
+ .format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
set_child_tax_template_and_map(item, child_item, p_doc)
+ add_taxes_from_tax_template(child_item, p_doc)
return child_item
def validate_and_delete_children(parent, data):
@@ -1282,8 +1407,8 @@
)
def get_new_child_item(item_row):
- new_child_function = set_sales_order_defaults if parent_doctype == "Sales Order" else set_purchase_order_defaults
- return new_child_function(parent_doctype, parent_doctype_name, child_docname, item_row)
+ child_doctype = "Sales Order Item" if parent_doctype == "Sales Order" else "Purchase Order Item"
+ return set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, item_row)
def validate_quantity(child_item, d):
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
@@ -1331,24 +1456,26 @@
validate_quantity(child_item, d)
child_item.qty = flt(d.get("qty"))
- precision = child_item.precision("rate") or 2
+ rate_precision = child_item.precision("rate") or 2
+ conv_fac_precision = child_item.precision("conversion_factor") or 2
+ qty_precision = child_item.precision("qty") or 2
- if flt(child_item.billed_amt, precision) > flt(flt(d.get("rate")) * flt(d.get("qty")), precision):
+ if flt(child_item.billed_amt, rate_precision) > flt(flt(d.get("rate"), rate_precision) * flt(d.get("qty"), qty_precision), rate_precision):
frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
.format(child_item.idx, child_item.item_code))
else:
- child_item.rate = flt(d.get("rate"))
+ child_item.rate = flt(d.get("rate"), rate_precision)
if d.get("conversion_factor"):
if child_item.stock_uom == child_item.uom:
child_item.conversion_factor = 1
else:
- child_item.conversion_factor = flt(d.get('conversion_factor'))
+ child_item.conversion_factor = flt(d.get('conversion_factor'), conv_fac_precision)
if d.get("uom"):
child_item.uom = d.get("uom")
conversion_factor = flt(get_conversion_factor(child_item.item_code, child_item.uom).get("conversion_factor"))
- child_item.conversion_factor = flt(d.get('conversion_factor')) or conversion_factor
+ child_item.conversion_factor = flt(d.get('conversion_factor'), conv_fac_precision) or conversion_factor
if d.get("delivery_date") and parent_doctype == 'Sales Order':
child_item.delivery_date = d.get('delivery_date')
@@ -1390,6 +1517,7 @@
parent.flags.ignore_validate_update_after_submit = True
parent.set_qty_as_per_stock_uom()
parent.calculate_taxes_and_totals()
+ parent.set_total_in_words()
if parent_doctype == "Sales Order":
make_packing_list(parent)
parent.set_gross_profit()
@@ -1433,3 +1561,7 @@
@erpnext.allow_regional
def validate_regional(doc):
pass
+
+@erpnext.allow_regional
+def validate_einvoice_fields(doc):
+ pass
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index ac567b7..219d529 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -5,7 +5,7 @@
import frappe
from frappe import _, msgprint
from frappe.utils import flt,cint, cstr, getdate
-
+from six import iteritems
from erpnext.accounts.party import get_party_details
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.buying.utils import validate_for_items, update_last_purchase_rate
@@ -16,18 +16,10 @@
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
from erpnext.controllers.stock_controller import StockController
+from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
+from erpnext.stock.utils import get_incoming_rate
class BuyingController(StockController):
- def __setup__(self):
- if hasattr(self, "taxes"):
- self.flags.print_taxes_with_zero_amount = cint(frappe.db.get_single_value("Print Settings",
- "print_taxes_with_zero_amount"))
- self.flags.show_inclusive_tax_in_print = self.is_inclusive_tax()
-
- self.print_templates = {
- "total": "templates/print_formats/includes/total.html",
- "taxes": "templates/print_formats/includes/taxes.html"
- }
def get_feed(self):
if self.get("supplier_name"):
@@ -62,7 +54,7 @@
self.set_landed_cost_voucher_amount()
if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
- self.update_valuation_rate("items")
+ self.update_valuation_rate()
def set_missing_values(self, for_validate=False):
super(BuyingController, self).set_missing_values(for_validate)
@@ -94,13 +86,18 @@
def validate_stock_or_nonstock_items(self):
if self.meta.get_field("taxes") and not self.get_stock_items() and not self.get_asset_items():
- tax_for_valuation = [d for d in self.get("taxes")
+ msg = _('Tax Category has been changed to "Total" because all the Items are non-stock items')
+ self.update_tax_category(msg)
+
+ def update_tax_category(self, msg):
+ tax_for_valuation = [d for d in self.get("taxes")
if d.category in ["Valuation", "Valuation and Total"]]
- if tax_for_valuation:
- for d in tax_for_valuation:
- d.category = 'Total'
- msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
+ if tax_for_valuation:
+ for d in tax_for_valuation:
+ d.category = 'Total'
+
+ msgprint(msg)
def validate_asset_return(self):
if self.doctype not in ['Purchase Receipt', 'Purchase Invoice'] or not self.is_return:
@@ -112,8 +109,8 @@
"docstatus": 1
})]
if self.is_return and len(not_cancelled_asset):
- frappe.throw(_("{} has submitted assets linked to it. You need to cancel the assets to create purchase return.".format(self.return_against)),
- title=_("Not Allowed"))
+ frappe.throw(_("{} has submitted assets linked to it. You need to cancel the assets to create purchase return.")
+ .format(self.return_against), title=_("Not Allowed"))
def get_asset_items(self):
if self.doctype not in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']:
@@ -166,7 +163,7 @@
self.in_words = money_in_words(amount, self.currency)
# update valuation rate
- def update_valuation_rate(self, parentfield):
+ def update_valuation_rate(self, reset_outgoing_rate=True):
"""
item_tax_amount is the total tax amount applied on that item
stored for valuation
@@ -177,7 +174,7 @@
stock_and_asset_items_qty, stock_and_asset_items_amount = 0, 0
last_item_idx = 1
- for d in self.get(parentfield):
+ for d in self.get("items"):
if d.item_code and d.item_code in stock_and_asset_items:
stock_and_asset_items_qty += flt(d.qty)
stock_and_asset_items_amount += flt(d.base_net_amount)
@@ -187,7 +184,7 @@
if d.category in ["Valuation", "Valuation and Total"]])
valuation_amount_adjustment = total_valuation_amount
- for i, item in enumerate(self.get(parentfield)):
+ for i, item in enumerate(self.get("items")):
if item.item_code and item.qty and item.item_code in stock_and_asset_items:
item_proportion = flt(item.base_net_amount) / stock_and_asset_items_amount if stock_and_asset_items_amount \
else flt(item.qty) / stock_and_asset_items_qty
@@ -205,23 +202,83 @@
item.conversion_factor = get_conversion_factor(item.item_code, item.uom).get("conversion_factor") or 1.0
qty_in_stock_uom = flt(item.qty * item.conversion_factor)
- rm_supp_cost = flt(item.rm_supp_cost) if self.doctype in ["Purchase Receipt", "Purchase Invoice"] else 0.0
-
- landed_cost_voucher_amount = flt(item.landed_cost_voucher_amount) \
- if self.doctype in ["Purchase Receipt", "Purchase Invoice"] else 0.0
-
- item.valuation_rate = ((item.base_net_amount + item.item_tax_amount + rm_supp_cost
- + landed_cost_voucher_amount) / qty_in_stock_uom)
+ item.rm_supp_cost = self.get_supplied_items_cost(item.name, reset_outgoing_rate)
+ item.valuation_rate = ((item.base_net_amount + item.item_tax_amount + item.rm_supp_cost
+ + flt(item.landed_cost_voucher_amount)) / qty_in_stock_uom)
else:
item.valuation_rate = 0.0
+ def set_incoming_rate(self):
+ if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Purchase Order"):
+ return
+
+ ref_doctype_map = {
+ "Purchase Order": "Sales Order Item",
+ "Purchase Receipt": "Delivery Note Item",
+ "Purchase Invoice": "Sales Invoice Item",
+ }
+
+ ref_doctype = ref_doctype_map.get(self.doctype)
+ items = self.get("items")
+ for d in items:
+ if not cint(self.get("is_return")):
+ # Get outgoing rate based on original item cost based on valuation method
+
+ if not d.get(frappe.scrub(ref_doctype)):
+ outgoing_rate = get_incoming_rate({
+ "item_code": d.item_code,
+ "warehouse": d.get('from_warehouse'),
+ "posting_date": self.get('posting_date') or self.get('transation_date'),
+ "posting_time": self.get('posting_time'),
+ "qty": -1 * flt(d.get('stock_qty')),
+ "serial_no": d.get('serial_no'),
+ "company": self.company,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "allow_zero_valuation": d.get("allow_zero_valuation")
+ }, raise_error_if_no_rate=False)
+
+ rate = flt(outgoing_rate * d.conversion_factor, d.precision('rate'))
+ else:
+ rate = frappe.db.get_value(ref_doctype, d.get(frappe.scrub(ref_doctype)), 'rate')
+
+ if self.is_internal_transfer():
+ if rate != d.rate:
+ d.rate = rate
+ d.discount_percentage = 0
+ d.discount_amount = 0
+ frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
+ .format(d.idx), alert=1)
+
+ def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
+ supplied_items_cost = 0.0
+ for d in self.get("supplied_items"):
+ if d.reference_name == item_row_id:
+ if reset_outgoing_rate and frappe.db.get_value('Item', d.rm_item_code, 'is_stock_item'):
+ rate = get_incoming_rate({
+ "item_code": d.rm_item_code,
+ "warehouse": self.supplier_warehouse,
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "qty": -1 * d.consumed_qty,
+ "serial_no": d.serial_no
+ })
+
+ if rate > 0:
+ d.rate = rate
+
+ d.amount = flt(flt(d.consumed_qty) * flt(d.rate), d.precision("amount"))
+ supplied_items_cost += flt(d.amount)
+
+ return supplied_items_cost
+
def validate_for_subcontracting(self):
if not self.is_subcontracted and self.sub_contracted_items:
frappe.throw(_("Please enter 'Is Subcontracted' as Yes or No"))
if self.is_subcontracted == "Yes":
if self.doctype in ["Purchase Receipt", "Purchase Invoice"] and not self.supplier_warehouse:
- frappe.throw(_("Supplier Warehouse mandatory for sub-contracted Purchase Receipt"))
+ frappe.throw(_("Supplier Warehouse mandatory for sub-contracted {0}").format(self.doctype))
for item in self.get("items"):
if item in self.sub_contracted_items and not item.bom:
@@ -298,14 +355,14 @@
title=_("Limit Crossed"))
transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
- backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
+ # backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
for raw_material in transferred_raw_materials + non_stock_items:
- rm_item_key = '{}{}'.format(raw_material.rm_item_code, item.purchase_order)
+ rm_item_key = (raw_material.rm_item_code, item.item_code, item.purchase_order)
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
consumed_qty = raw_material_data.get('qty', 0)
- consumed_serial_nos = raw_material_data.get('serial_nos', '')
+ consumed_serial_nos = raw_material_data.get('serial_no', '')
consumed_batch_nos = raw_material_data.get('batch_nos', '')
transferred_qty = raw_material.qty
@@ -330,8 +387,10 @@
set_serial_nos(raw_material, consumed_serial_nos, qty)
if raw_material.batch_nos:
+ backflushed_batch_qty_map = raw_material_data.get('consumed_batch', {})
+
batches_qty = get_batches_with_qty(raw_material.rm_item_code, raw_material.main_item_code,
- qty, transferred_batch_qty_map, backflushed_batch_qty_map)
+ qty, transferred_batch_qty_map, backflushed_batch_qty_map, item.purchase_order)
for batch_data in batches_qty:
qty = batch_data['qty']
raw_material.batch_no = batch_data['batch']
@@ -339,31 +398,17 @@
else:
self.append_raw_material_to_be_backflushed(item, raw_material, qty)
- def append_raw_material_to_be_backflushed(self, fg_item_doc, raw_material_data, qty):
+ def append_raw_material_to_be_backflushed(self, fg_item_row, raw_material_data, qty):
rm = self.append('supplied_items', {})
rm.update(raw_material_data)
+ if not rm.main_item_code:
+ rm.main_item_code = fg_item_row.item_code
+
+ rm.reference_name = fg_item_row.name
rm.required_qty = qty
rm.consumed_qty = qty
- if not raw_material_data.get('non_stock_item'):
- from erpnext.stock.utils import get_incoming_rate
- rm.rate = get_incoming_rate({
- "item_code": raw_material_data.rm_item_code,
- "warehouse": self.supplier_warehouse,
- "posting_date": self.posting_date,
- "posting_time": self.posting_time,
- "qty": -1 * qty,
- "serial_no": rm.serial_no
- })
-
- if not rm.rate:
- rm.rate = get_valuation_rate(raw_material_data.rm_item_code, self.supplier_warehouse,
- self.doctype, self.name, currency=self.company_currency, company=self.company)
-
- rm.amount = qty * flt(rm.rate)
- fg_item_doc.rm_supp_cost += rm.amount
-
def update_raw_materials_supplied_based_on_bom(self, item, raw_material_table):
exploded_item = 1
if hasattr(item, 'include_exploded_items'):
@@ -372,7 +417,7 @@
bom_items = get_items_from_bom(item.item_code, item.bom, exploded_item)
used_alternative_items = []
- if self.doctype == 'Purchase Receipt' and item.purchase_order:
+ if self.doctype in ["Purchase Receipt", "Purchase Invoice"] and item.purchase_order:
used_alternative_items = get_used_alternative_items(purchase_order = item.purchase_order)
raw_materials_cost = 0
@@ -389,7 +434,7 @@
reserve_warehouse = None
conversion_factor = item.conversion_factor
- if (self.doctype == 'Purchase Receipt' and item.purchase_order and
+ if (self.doctype in ["Purchase Receipt", "Purchase Invoice"] and item.purchase_order and
bom_item.item_code in used_alternative_items):
alternative_item_data = used_alternative_items.get(bom_item.item_code)
bom_item.item_code = alternative_item_data.item_code
@@ -417,9 +462,7 @@
rm.rm_item_code = bom_item.item_code
rm.stock_uom = bom_item.stock_uom
rm.required_qty = required_qty
- if self.doctype == "Purchase Order" and not rm.reserve_warehouse:
- rm.reserve_warehouse = reserve_warehouse
-
+ rm.rate = bom_item.rate
rm.conversion_factor = conversion_factor
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
@@ -427,29 +470,8 @@
rm.description = bom_item.description
if item.batch_no and frappe.db.get_value("Item", rm.rm_item_code, "has_batch_no") and not rm.batch_no:
rm.batch_no = item.batch_no
-
- # get raw materials rate
- if self.doctype == "Purchase Receipt":
- from erpnext.stock.utils import get_incoming_rate
- rm.rate = get_incoming_rate({
- "item_code": bom_item.item_code,
- "warehouse": self.supplier_warehouse,
- "posting_date": self.posting_date,
- "posting_time": self.posting_time,
- "qty": -1 * required_qty,
- "serial_no": rm.serial_no
- })
- if not rm.rate:
- rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
- self.doctype, self.name, currency=self.company_currency, company = self.company)
- else:
- rm.rate = bom_item.rate
-
- rm.amount = required_qty * flt(rm.rate)
- raw_materials_cost += flt(rm.amount)
-
- if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
- item.rm_supp_cost = raw_materials_cost
+ elif not rm.reserve_warehouse:
+ rm.reserve_warehouse = reserve_warehouse
def cleanup_raw_materials_supplied(self, parent_items, raw_material_table):
"""Remove all those child items which are no longer present in main item table"""
@@ -491,6 +513,10 @@
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
+ if self.doctype=="Purchase Receipt" and d.meta.get_field("received_stock_qty"):
+ # Set Received Qty in Stock UOM
+ d.received_stock_qty = flt(d.received_qty) * flt(d.conversion_factor, d.precision("conversion_factor"))
+
def validate_purchase_return(self):
for d in self.get("items"):
if self.is_return and flt(d.rejected_qty) != 0:
@@ -558,7 +584,10 @@
or (cint(self.is_return) and self.docstatus==2)):
from_warehouse_sle = self.get_sl_entries(d, {
"actual_qty": -1 * pr_qty,
- "warehouse": d.from_warehouse
+ "warehouse": d.from_warehouse,
+ "outgoing_rate": d.rate,
+ "recalculate_rate": 1,
+ "dependant_sle_voucher_detail_no": d.name
})
sl_entries.append(from_warehouse_sle)
@@ -568,28 +597,20 @@
"serial_no": cstr(d.serial_no).strip()
})
if self.is_return:
- filters = {
- "voucher_type": self.doctype,
- "voucher_no": self.return_against,
- "item_code": d.item_code
- }
-
- if (self.doctype == "Purchase Invoice" and self.update_stock
- and d.get("purchase_invoice_item")):
- filters["voucher_detail_no"] = d.purchase_invoice_item
- elif self.doctype == "Purchase Receipt" and d.get("purchase_receipt_item"):
- filters["voucher_detail_no"] = d.purchase_receipt_item
-
- original_incoming_rate = frappe.db.get_value("Stock Ledger Entry", filters, "incoming_rate")
+ outgoing_rate = get_rate_for_return(self.doctype, self.name, d.item_code, self.return_against, item_row=d)
sle.update({
- "outgoing_rate": original_incoming_rate
+ "outgoing_rate": outgoing_rate,
+ "recalculate_rate": 1
})
+ if d.from_warehouse:
+ sle.dependant_sle_voucher_detail_no = d.name
else:
val_rate_db_precision = 6 if cint(self.precision("valuation_rate", d)) <= 6 else 9
incoming_rate = flt(d.valuation_rate, val_rate_db_precision)
sle.update({
- "incoming_rate": incoming_rate
+ "incoming_rate": incoming_rate,
+ "recalculate_rate": 1 if (self.is_subcontracted and d.bom) or d.from_warehouse else 0
})
sl_entries.append(sle)
@@ -597,7 +618,8 @@
or (cint(self.is_return) and self.docstatus==1)):
from_warehouse_sle = self.get_sl_entries(d, {
"actual_qty": -1 * pr_qty,
- "warehouse": d.from_warehouse
+ "warehouse": d.from_warehouse,
+ "recalculate_rate": 1
})
sl_entries.append(from_warehouse_sle)
@@ -645,6 +667,7 @@
"item_code": d.rm_item_code,
"warehouse": self.supplier_warehouse,
"actual_qty": -1*flt(d.consumed_qty),
+ "dependant_sle_voucher_detail_no": d.reference_name
}))
def on_submit(self):
@@ -792,8 +815,8 @@
asset.set(field, None)
asset.supplier = None
if asset.docstatus == 1 and delete_asset:
- frappe.throw(_('Cannot cancel this document as it is linked with submitted asset {0}.\
- Please cancel the it to continue.').format(frappe.utils.get_link_to_form('Asset', asset.name)))
+ frappe.throw(_('Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.')
+ .format(frappe.utils.get_link_to_form('Asset', asset.name)))
asset.flags.ignore_validate_update_after_submit = True
asset.flags.ignore_mandatory = True
@@ -836,6 +859,7 @@
else:
validate_item_type(self, "is_purchase_item", "purchase")
+
def get_items_from_bom(item_code, bom, exploded_item=1):
doctype = "BOM Item" if not exploded_item else "BOM Explosion Item"
@@ -847,6 +871,7 @@
where
t2.parent = t1.name and t1.item = %s
and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s
+ and t2.sourced_by_supplier = 0
and t2.item_code = t3.name""".format(doctype),
(item_code, bom), as_dict=1)
@@ -872,7 +897,7 @@
AND se.purpose='Send to Subcontractor'
AND se.purchase_order = %s
AND IFNULL(sed.t_warehouse, '') != ''
- AND sed.subcontracted_item = %s
+ AND IFNULL(sed.subcontracted_item, '') in ('', %s)
GROUP BY sed.item_code, sed.subcontracted_item
"""
raw_materials = frappe.db.multisql({
@@ -889,39 +914,49 @@
return raw_materials
def get_backflushed_subcontracted_raw_materials(purchase_orders):
- common_query = """
- SELECT
- CONCAT(prsi.rm_item_code, pri.purchase_order) AS item_key,
- SUM(prsi.consumed_qty) AS qty,
- {serial_no_concat_syntax} AS serial_nos,
- {batch_no_concat_syntax} AS batch_nos
- FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri, `tabPurchase Receipt Item Supplied` prsi
- WHERE
- pr.name = pri.parent
- AND pr.name = prsi.parent
- AND pri.purchase_order IN %s
- AND pri.item_code = prsi.main_item_code
- AND pr.docstatus = 1
- GROUP BY prsi.rm_item_code, pri.purchase_order
- """
+ purchase_receipts = frappe.get_all("Purchase Receipt Item",
+ fields = ["purchase_order", "item_code", "name", "parent"],
+ filters={"docstatus": 1, "purchase_order": ("in", list(purchase_orders))})
- backflushed_raw_materials = frappe.db.multisql({
- 'mariadb': common_query.format(
- serial_no_concat_syntax="GROUP_CONCAT(prsi.serial_no)",
- batch_no_concat_syntax="GROUP_CONCAT(prsi.batch_no)"
- ),
- 'postgres': common_query.format(
- serial_no_concat_syntax="STRING_AGG(prsi.serial_no, ',')",
- batch_no_concat_syntax="STRING_AGG(prsi.batch_no, ',')"
- )
- }, (purchase_orders, ), as_dict=1)
+ distinct_purchase_receipts = {}
+ for pr in purchase_receipts:
+ key = (pr.purchase_order, pr.item_code, pr.parent)
+ distinct_purchase_receipts.setdefault(key, []).append(pr.name)
backflushed_raw_materials_map = frappe._dict()
- for item in backflushed_raw_materials:
- backflushed_raw_materials_map.setdefault(item.item_key, item)
+ for args, references in iteritems(distinct_purchase_receipts):
+ purchase_receipt_supplied_items = get_supplied_items(args[1], args[2], references)
+
+ for data in purchase_receipt_supplied_items:
+ pr_key = (data.rm_item_code, data.main_item_code, args[0])
+ if pr_key not in backflushed_raw_materials_map:
+ backflushed_raw_materials_map.setdefault(pr_key, frappe._dict({
+ "qty": 0.0,
+ "serial_no": [],
+ "batch_no": [],
+ "consumed_batch": {}
+ }))
+
+ row = backflushed_raw_materials_map.get(pr_key)
+ row.qty += data.consumed_qty
+
+ for field in ["serial_no", "batch_no"]:
+ if data.get(field):
+ row[field].append(data.get(field))
+
+ if data.get("batch_no"):
+ if data.get("batch_no") in row.consumed_batch:
+ row.consumed_batch[data.get("batch_no")] += data.consumed_qty
+ else:
+ row.consumed_batch[data.get("batch_no")] = data.consumed_qty
return backflushed_raw_materials_map
+def get_supplied_items(item_code, purchase_receipt, references):
+ return frappe.get_all("Purchase Receipt Item Supplied",
+ fields=["rm_item_code", "main_item_code", "consumed_qty", "serial_no", "batch_no"],
+ filters={"main_item_code": item_code, "parent": purchase_receipt, "reference_name": ("in", references)})
+
def get_asset_item_details(asset_items):
asset_items_data = {}
for d in frappe.get_all('Item', fields = ["name", "auto_create_assets", "asset_naming_series"],
@@ -1003,14 +1038,15 @@
SELECT
sed.batch_no,
SUM(sed.qty) AS qty,
- sed.item_code
+ sed.item_code,
+ sed.subcontracted_item
FROM `tabStock Entry` se,`tabStock Entry Detail` sed
WHERE
se.name = sed.parent
AND se.docstatus=1
AND se.purpose='Send to Subcontractor'
AND se.purchase_order = %s
- AND sed.subcontracted_item = %s
+ AND ifnull(sed.subcontracted_item, '') in ('', %s)
AND sed.batch_no IS NOT NULL
GROUP BY
sed.batch_no,
@@ -1018,8 +1054,10 @@
""", (purchase_order, fg_item), as_dict=1)
for batch_data in transferred_batches:
- transferred_batch_qty_map.setdefault((batch_data.item_code, fg_item), {})
- transferred_batch_qty_map[(batch_data.item_code, fg_item)][batch_data.batch_no] = batch_data.qty
+ key = ((batch_data.item_code, fg_item)
+ if batch_data.subcontracted_item else (batch_data.item_code, purchase_order))
+ transferred_batch_qty_map.setdefault(key, {})
+ transferred_batch_qty_map[key][batch_data.batch_no] = batch_data.qty
return transferred_batch_qty_map
@@ -1056,10 +1094,11 @@
return backflushed_batch_qty_map
-def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty_map, backflushed_batch_qty_map):
+def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty_map, backflushed_batches, po):
# Returns available batches to be backflushed based on requirements
transferred_batches = transferred_batch_qty_map.get((item_code, fg_item), {})
- backflushed_batches = backflushed_batch_qty_map.get((item_code, fg_item), {})
+ if not transferred_batches:
+ transferred_batches = transferred_batch_qty_map.get((item_code, po), {})
available_batches = []
diff --git a/erpnext/controllers/print_settings.py b/erpnext/controllers/print_settings.py
index c41db25..e08c400 100644
--- a/erpnext/controllers/print_settings.py
+++ b/erpnext/controllers/print_settings.py
@@ -5,20 +5,34 @@
import frappe
from frappe.utils import cint
-def print_settings_for_item_table(doc):
-
+def set_print_templates_for_item_table(doc, settings):
doc.print_templates = {
- "qty": "templates/print_formats/includes/item_table_qty.html"
+ "items": "templates/print_formats/includes/items.html",
}
- doc.hide_in_print_layout = ["uom", "stock_uom"]
- doc.flags.compact_item_print = cint(frappe.db.get_single_value("Print Settings", "compact_item_print"))
+ doc.child_print_templates = {
+ "items": {
+ "qty": "templates/print_formats/includes/item_table_qty.html",
+ }
+ }
- if doc.flags.compact_item_print:
- doc.print_templates["description"] = "templates/print_formats/includes/item_table_description.html"
- doc.flags.compact_item_fields = ["description", "qty", "rate", "amount"]
+ if doc.meta.get_field("items"):
+ doc.meta.get_field("items").hide_in_print_layout = ["uom", "stock_uom"]
+
+ doc.flags.compact_item_fields = ["description", "qty", "rate", "amount"]
+
+ if settings.compact_item_print:
+ doc.child_print_templates["items"]["description"] =\
+ "templates/print_formats/includes/item_table_description.html"
doc.flags.format_columns = format_columns
+def set_print_templates_for_taxes(doc, settings):
+ doc.flags.show_inclusive_tax_in_print = doc.is_inclusive_tax()
+ doc.print_templates.update({
+ "total": "templates/print_formats/includes/total.html",
+ "taxes": "templates/print_formats/includes/taxes.html"
+ })
+
def format_columns(display_columns, compact_fields):
compact_fields = compact_fields + ["image", "item_code", "item_name"]
final_columns = []
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index efd4944..81f0ad3 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -368,13 +368,17 @@
searchfields = meta.get_search_fields()
search_columns = ''
+ search_cond = ''
+
if searchfields:
search_columns = ", " + ", ".join(searchfields)
+ search_cond = " or " + " or ".join([field + " like %(txt)s" for field in searchfields])
if args.get('warehouse'):
searchfields = ['batch.' + field for field in searchfields]
if searchfields:
search_columns = ", " + ", ".join(searchfields)
+ search_cond = " or " + " or ".join([field + " like %(txt)s" for field in searchfields])
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom,
concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
@@ -387,7 +391,8 @@
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
or batch.expiry_date like %(txt)s
- or batch.manufacturing_date like %(txt)s)
+ or batch.manufacturing_date like %(txt)s
+ {search_cond})
and batch.docstatus < 2
{cond}
{match_conditions}
@@ -397,7 +402,8 @@
search_columns = search_columns,
cond=cond,
match_conditions=get_match_cond(doctype),
- having_clause = having_clause
+ having_clause = having_clause,
+ search_cond = search_cond
), args)
return batch_nos
@@ -409,12 +415,15 @@
and item = %(item_code)s
and (name like %(txt)s
or expiry_date like %(txt)s
- or manufacturing_date like %(txt)s)
+ or manufacturing_date like %(txt)s
+ {search_cond})
and docstatus < 2
{0}
{match_conditions}
+
order by expiry_date, name desc
- limit %(start)s, %(page_len)s""".format(cond, search_columns = search_columns, match_conditions=get_match_cond(doctype)), args)
+ limit %(start)s, %(page_len)s""".format(cond, search_columns = search_columns,
+ search_cond = search_cond, match_conditions=get_match_cond(doctype)), args)
@frappe.whitelist()
@@ -484,6 +493,41 @@
'company': filters.get("company", "")
})
+@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
+def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters):
+ from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import get_dimension_filter_map
+ dimension_filters = get_dimension_filter_map()
+ dimension_filters = dimension_filters.get((filters.get('dimension'),filters.get('account')))
+ query_filters = []
+
+ meta = frappe.get_meta(doctype)
+ if meta.is_tree:
+ query_filters.append(['is_group', '=', 0])
+
+ if meta.has_field('company'):
+ query_filters.append(['company', '=', filters.get('company')])
+
+ if txt:
+ query_filters.append([searchfield, 'LIKE', "%%%s%%" % txt])
+
+ if dimension_filters:
+ if dimension_filters['allow_or_restrict'] == 'Allow':
+ query_selector = 'in'
+ else:
+ query_selector = 'not in'
+
+ if len(dimension_filters['allowed_dimensions']) == 1:
+ dimensions = tuple(dimension_filters['allowed_dimensions'] * 2)
+ else:
+ dimensions = tuple(dimension_filters['allowed_dimensions'])
+
+ query_filters.append(['name', query_selector, dimensions])
+
+ output = frappe.get_all(doctype, filters=query_filters)
+ result = [d.name for d in output]
+
+ return [(d,) for d in set(result)]
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
@@ -613,6 +657,34 @@
@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):
item_doc = frappe.get_cached_doc('Item', filters.get('item_code'))
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index afc5f81..de61b35 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -203,10 +203,40 @@
return items
+def get_returned_qty_map_for_row(row_name, doctype):
+ child_doctype = doctype + " Item"
+ reference_field = "dn_detail" if doctype == "Delivery Note" else frappe.scrub(child_doctype)
+
+ fields = [
+ "sum(abs(`tab{0}`.qty)) as qty".format(child_doctype),
+ "sum(abs(`tab{0}`.stock_qty)) as stock_qty".format(child_doctype)
+ ]
+
+ if doctype in ("Purchase Receipt", "Purchase Invoice"):
+ fields += [
+ "sum(abs(`tab{0}`.rejected_qty)) as rejected_qty".format(child_doctype),
+ "sum(abs(`tab{0}`.received_qty)) as received_qty".format(child_doctype)
+ ]
+
+ if doctype == "Purchase Receipt":
+ fields += ["sum(abs(`tab{0}`.received_stock_qty)) as received_stock_qty".format(child_doctype)]
+
+ data = frappe.db.get_list(doctype,
+ fields = fields,
+ filters = [
+ [doctype, "docstatus", "=", 1],
+ [doctype, "is_return", "=", 1],
+ [child_doctype, reference_field, "=", row_name]
+ ])
+
+ return data[0]
+
def make_return_doc(doctype, source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
company = frappe.db.get_value("Delivery Note", source_name, "company")
default_warehouse_for_sales_return = frappe.db.get_value("Company", company, "default_warehouse_for_sales_return")
+
def set_missing_values(source, target):
doc = frappe.get_doc(target)
doc.is_return = 1
@@ -230,6 +260,7 @@
if doc.get("is_return"):
if doc.doctype == 'Sales Invoice' or doc.doctype == 'POS Invoice':
+ doc.consolidated_invoice = ""
doc.set('payments', [])
for data in source.payments:
paid_amount = 0.00
@@ -261,30 +292,48 @@
doc.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
- target_doc.qty = -1* source_doc.qty
+ target_doc.qty = -1 * source_doc.qty
+
+ if source_doc.serial_no:
+ returned_serial_nos = get_returned_serial_nos(source_doc, source_parent)
+ serial_nos = list(set(get_serial_nos(source_doc.serial_no)) - set(returned_serial_nos))
+ if serial_nos:
+ target_doc.serial_no = '\n'.join(serial_nos)
+
if doctype == "Purchase Receipt":
- target_doc.received_qty = -1* source_doc.received_qty
- target_doc.rejected_qty = -1* source_doc.rejected_qty
- target_doc.qty = -1* source_doc.qty
- target_doc.stock_qty = -1 * source_doc.stock_qty
+ returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
+ target_doc.received_qty = -1 * flt(source_doc.received_qty - (returned_qty_map.get('received_qty') or 0))
+ target_doc.rejected_qty = -1 * flt(source_doc.rejected_qty - (returned_qty_map.get('rejected_qty') or 0))
+ target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
+
+ target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
+ target_doc.received_stock_qty = -1 * flt(source_doc.received_stock_qty - (returned_qty_map.get('received_stock_qty') or 0))
+
target_doc.purchase_order = source_doc.purchase_order
target_doc.purchase_order_item = source_doc.purchase_order_item
target_doc.rejected_warehouse = source_doc.rejected_warehouse
target_doc.purchase_receipt_item = source_doc.name
elif doctype == "Purchase Invoice":
- target_doc.received_qty = -1* source_doc.received_qty
- target_doc.rejected_qty = -1* source_doc.rejected_qty
- target_doc.qty = -1* source_doc.qty
- target_doc.stock_qty = -1 * source_doc.stock_qty
+ returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
+ target_doc.received_qty = -1 * flt(source_doc.received_qty - (returned_qty_map.get('received_qty') or 0))
+ target_doc.rejected_qty = -1 * flt(source_doc.rejected_qty - (returned_qty_map.get('rejected_qty') or 0))
+ target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
+
+ target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
target_doc.purchase_order = source_doc.purchase_order
target_doc.purchase_receipt = source_doc.purchase_receipt
target_doc.rejected_warehouse = source_doc.rejected_warehouse
target_doc.po_detail = source_doc.po_detail
target_doc.pr_detail = source_doc.pr_detail
target_doc.purchase_invoice_item = source_doc.name
+ target_doc.price_list_rate = 0
elif doctype == "Delivery Note":
+ returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
+ target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
+ target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
+
target_doc.against_sales_order = source_doc.against_sales_order
target_doc.against_sales_invoice = source_doc.against_sales_invoice
target_doc.so_detail = source_doc.so_detail
@@ -294,12 +343,22 @@
if default_warehouse_for_sales_return:
target_doc.warehouse = default_warehouse_for_sales_return
elif doctype == "Sales Invoice" or doctype == "POS Invoice":
+ returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
+ target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
+ target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
+
target_doc.sales_order = source_doc.sales_order
target_doc.delivery_note = source_doc.delivery_note
target_doc.so_detail = source_doc.so_detail
target_doc.dn_detail = source_doc.dn_detail
target_doc.expense_account = source_doc.expense_account
- target_doc.sales_invoice_item = source_doc.name
+
+ if doctype == "Sales Invoice":
+ target_doc.sales_invoice_item = source_doc.name
+ else:
+ target_doc.pos_invoice_item = source_doc.name
+
+ target_doc.price_list_rate = 0
if default_warehouse_for_sales_return:
target_doc.warehouse = default_warehouse_for_sales_return
@@ -329,3 +388,63 @@
}, target_doc, set_missing_values)
return doclist
+
+def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None, item_row=None, voucher_detail_no=None):
+ if not return_against:
+ return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against")
+
+ return_against_item_field = get_return_against_item_fields(voucher_type)
+
+ filters = get_filters(voucher_type, voucher_no, voucher_detail_no,
+ return_against, item_code, return_against_item_field, item_row)
+
+ if voucher_type in ("Purchase Receipt", "Purchase Invoice"):
+ select_field = "incoming_rate"
+ else:
+ select_field = "abs(stock_value_difference / actual_qty)"
+
+ return flt(frappe.db.get_value("Stock Ledger Entry", filters, select_field))
+
+def get_return_against_item_fields(voucher_type):
+ return_against_item_fields = {
+ "Purchase Receipt": "purchase_receipt_item",
+ "Purchase Invoice": "purchase_invoice_item",
+ "Delivery Note": "dn_detail",
+ "Sales Invoice": "sales_invoice_item"
+ }
+ return return_against_item_fields[voucher_type]
+
+def get_filters(voucher_type, voucher_no, voucher_detail_no, return_against, item_code, return_against_item_field, item_row):
+ filters = {
+ "voucher_type": voucher_type,
+ "voucher_no": return_against,
+ "item_code": item_code
+ }
+
+ if item_row:
+ reference_voucher_detail_no = item_row.get(return_against_item_field)
+ else:
+ reference_voucher_detail_no = frappe.db.get_value(voucher_type + " Item", voucher_detail_no, return_against_item_field)
+
+ if reference_voucher_detail_no:
+ filters["voucher_detail_no"] = reference_voucher_detail_no
+
+ return filters
+
+def get_returned_serial_nos(child_doc, parent_doc):
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+ return_ref_field = frappe.scrub(child_doc.doctype)
+ if child_doc.doctype == "Delivery Note Item":
+ return_ref_field = "dn_detail"
+
+ serial_nos = []
+
+ fields = ["`{0}`.`serial_no`".format("tab" + child_doc.doctype)]
+
+ filters = [[parent_doc.doctype, "return_against", "=", parent_doc.name], [parent_doc.doctype, "is_return", "=", 1],
+ [child_doc.doctype, return_ref_field, "=", child_doc.name], [parent_doc.doctype, "docstatus", "=", 1]]
+
+ for row in frappe.get_all(parent_doc.doctype, fields = fields, filters=filters):
+ serial_nos.extend(get_serial_nos(row.serial_no))
+
+ return serial_nos
\ No newline at end of file
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 7f7aae3..edc40c4 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -3,27 +3,19 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cint, flt, cstr, comma_or
+from frappe.utils import cint, flt, cstr, get_link_to_form, nowtime
from frappe import _, throw
from erpnext.stock.get_item_details import get_bin_details
from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.doctype.item.item import set_item_default
from frappe.contacts.doctype.address.address import get_address_display
+from erpnext.controllers.accounts_controller import get_taxes_and_charges
from erpnext.controllers.stock_controller import StockController
+from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
class SellingController(StockController):
- def __setup__(self):
- if hasattr(self, "taxes"):
- self.flags.print_taxes_with_zero_amount = cint(frappe.db.get_single_value("Print Settings",
- "print_taxes_with_zero_amount"))
- self.flags.show_inclusive_tax_in_print = self.is_inclusive_tax()
-
- self.print_templates = {
- "total": "templates/print_formats/includes/total.html",
- "taxes": "templates/print_formats/includes/taxes.html"
- }
def get_feed(self):
return _("To {0} | {1} {2}").format(self.customer_name, self.currency,
@@ -41,7 +33,7 @@
self.validate_max_discount()
self.validate_selling_price()
self.set_qty_as_per_stock_uom()
- self.set_po_nos()
+ self.set_po_nos(for_validate=True)
self.set_gross_profit()
set_default_income_account_for_item(self)
self.set_customer_address()
@@ -53,10 +45,10 @@
super(SellingController, self).set_missing_values(for_validate)
# set contact and address details for customer, if they are not mentioned
- self.set_missing_lead_customer_details()
+ self.set_missing_lead_customer_details(for_validate=for_validate)
self.set_price_list_and_item_details(for_validate=for_validate)
- def set_missing_lead_customer_details(self):
+ def set_missing_lead_customer_details(self, for_validate=False):
customer, lead = None, None
if getattr(self, "customer", None):
customer = self.customer
@@ -94,6 +86,11 @@
posting_date=self.get('transaction_date') or self.get('posting_date'),
company=self.company))
+ if self.get('taxes_and_charges') and not self.get('taxes') and not for_validate:
+ taxes = get_taxes_and_charges('Sales Taxes and Charges Template', self.taxes_and_charges)
+ for tax in taxes:
+ self.append('taxes', tax)
+
def set_price_list_and_item_details(self, for_validate=False):
self.set_price_list_currency("Selling")
self.set_missing_item_details(for_validate=for_validate)
@@ -145,6 +142,11 @@
self.base_net_total * sales_person.allocated_percentage / 100.0,
self.precision("allocated_amount", sales_person))
+ if sales_person.commission_rate:
+ sales_person.incentives = flt(
+ sales_person.allocated_amount * flt(sales_person.commission_rate) / 100.0,
+ self.precision("incentives", sales_person))
+
total += sales_person.allocated_percentage
if sales_team and total != 100.0:
@@ -167,12 +169,16 @@
def validate_selling_price(self):
def throw_message(idx, item_name, rate, ref_rate_field):
- frappe.throw(_("""Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {}""")
- .format(idx, item_name, ref_rate_field, rate))
+ bold_net_rate = frappe.bold("net rate")
+ msg = (_("""Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {}""")
+ .format(idx, frappe.bold(item_name), frappe.bold(ref_rate_field), bold_net_rate, frappe.bold(rate)))
+ msg += "<br><br>"
+ msg += (_("""You can alternatively disable selling price validation in {} to bypass this validation.""")
+ .format(get_link_to_form("Selling Settings", "Selling Settings")))
+ frappe.throw(msg, title=_("Invalid Selling Price"))
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
return
-
if hasattr(self, "is_return") and self.is_return:
return
@@ -181,8 +187,8 @@
continue
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
- last_purchase_rate_in_sales_uom = last_purchase_rate / (it.conversion_factor or 1)
- if flt(it.base_rate) < flt(last_purchase_rate_in_sales_uom):
+ last_purchase_rate_in_sales_uom = last_purchase_rate * (it.conversion_factor or 1)
+ if flt(it.base_net_rate) < flt(last_purchase_rate_in_sales_uom):
throw_message(it.idx, frappe.bold(it.item_name), last_purchase_rate_in_sales_uom, "last purchase rate")
last_valuation_rate = frappe.db.sql("""
@@ -191,8 +197,8 @@
ORDER BY posting_date DESC, posting_time DESC, creation DESC LIMIT 1
""", (it.item_code, it.warehouse))
if last_valuation_rate:
- last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] / (it.conversion_factor or 1)
- if is_stock_item and flt(it.base_rate) < flt(last_valuation_rate_in_sales_uom) \
+ last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] * (it.conversion_factor or 1)
+ if is_stock_item and flt(it.base_net_rate) < flt(last_valuation_rate_in_sales_uom) \
and not self.get('is_internal_customer'):
throw_message(it.idx, frappe.bold(it.item_name), last_valuation_rate_in_sales_uom, "valuation rate")
@@ -220,7 +226,8 @@
'voucher_type': self.doctype,
'allow_zero_valuation': d.allow_zero_valuation_rate,
'sales_invoice_item': d.get("sales_invoice_item"),
- 'delivery_note_item': d.get("dn_detail")
+ 'dn_detail': d.get("dn_detail"),
+ 'incoming_rate': p.get("incoming_rate")
}))
else:
il.append(frappe._dict({
@@ -238,7 +245,8 @@
'voucher_type': self.doctype,
'allow_zero_valuation': d.allow_zero_valuation_rate,
'sales_invoice_item': d.get("sales_invoice_item"),
- 'delivery_note_item': d.get("dn_detail")
+ 'dn_detail': d.get("dn_detail"),
+ 'incoming_rate': d.get("incoming_rate")
}))
return il
@@ -297,77 +305,130 @@
sales_order.update_reserved_qty(so_item_rows)
+ def set_incoming_rate(self):
+ if self.doctype not in ("Delivery Note", "Sales Invoice", "Sales Order"):
+ return
+
+ items = self.get("items") + (self.get("packed_items") or [])
+ for d in items:
+ if not cint(self.get("is_return")):
+ # Get incoming rate based on original item cost based on valuation method
+ d.incoming_rate = get_incoming_rate({
+ "item_code": d.item_code,
+ "warehouse": d.warehouse,
+ "posting_date": self.get('posting_date') or self.get('transaction_date'),
+ "posting_time": self.get('posting_time') or nowtime(),
+ "qty": -1 * flt(d.get('stock_qty') or d.get('actual_qty')),
+ "serial_no": d.get('serial_no'),
+ "company": self.company,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "allow_zero_valuation": d.get("allow_zero_valuation")
+ }, raise_error_if_no_rate=False)
+
+ # For internal transfers use incoming rate as the valuation rate
+ if self.is_internal_transfer():
+ rate = flt(d.incoming_rate * d.conversion_factor, d.precision('rate'))
+ if d.rate != rate:
+ d.rate = rate
+ d.discount_percentage = 0
+ d.discount_amount = 0
+ frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
+ .format(d.idx), alert=1)
+
+ elif self.get("return_against"):
+ # Get incoming rate of return entry from reference document
+ # based on original item cost as per valuation method
+ d.incoming_rate = get_rate_for_return(self.doctype, self.name, d.item_code, self.return_against, item_row=d)
+
def update_stock_ledger(self):
self.update_reserved_qty()
sl_entries = []
+ # Loop over items and packed items table
for d in self.get_item_list():
if frappe.get_cached_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
if flt(d.conversion_factor)==0.0:
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
- return_rate = 0
- if cint(self.is_return) and self.return_against and self.docstatus==1:
- against_document_no = (d.get("sales_invoice_item")
- if self.doctype == "Sales Invoice" else d.get("delivery_note_item"))
- return_rate = self.get_incoming_rate_for_return(d.item_code,
- self.return_against, against_document_no)
-
- # On cancellation or if return entry submission, make stock ledger entry for
+ # On cancellation or return entry submission, make stock ledger entry for
# target warehouse first, to update serial no values properly
if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
or (cint(self.is_return) and self.docstatus==2)):
- sl_entries.append(self.get_sl_entries(d, {
- "actual_qty": -1*flt(d.qty),
- "incoming_rate": return_rate
- }))
+ sl_entries.append(self.get_sle_for_source_warehouse(d))
if d.target_warehouse:
- target_warehouse_sle = self.get_sl_entries(d, {
- "actual_qty": flt(d.qty),
- "warehouse": d.target_warehouse
- })
-
- if self.docstatus == 1:
- if not cint(self.is_return):
- args = frappe._dict({
- "item_code": d.item_code,
- "warehouse": d.warehouse,
- "posting_date": self.posting_date,
- "posting_time": self.posting_time,
- "qty": -1*flt(d.qty),
- "serial_no": d.serial_no,
- "company": d.company,
- "voucher_type": d.voucher_type,
- "voucher_no": d.name,
- "allow_zero_valuation": d.allow_zero_valuation
- })
- target_warehouse_sle.update({
- "incoming_rate": get_incoming_rate(args)
- })
- else:
- target_warehouse_sle.update({
- "outgoing_rate": return_rate
- })
- sl_entries.append(target_warehouse_sle)
+ sl_entries.append(self.get_sle_for_target_warehouse(d))
if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
or (cint(self.is_return) and self.docstatus==1)):
- sl_entries.append(self.get_sl_entries(d, {
- "actual_qty": -1*flt(d.qty),
- "incoming_rate": return_rate
- }))
+ sl_entries.append(self.get_sle_for_source_warehouse(d))
+
self.make_sl_entries(sl_entries)
- def set_po_nos(self):
- if self.doctype in ("Delivery Note", "Sales Invoice") and hasattr(self, "items"):
- ref_fieldname = "against_sales_order" if self.doctype == "Delivery Note" else "sales_order"
- sales_orders = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
- if sales_orders:
- po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)})
- if po_nos and po_nos[0].get('po_no'):
- self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no])))
+ def get_sle_for_source_warehouse(self, item_row):
+ sle = self.get_sl_entries(item_row, {
+ "actual_qty": -1*flt(item_row.qty),
+ "incoming_rate": item_row.incoming_rate,
+ "recalculate_rate": cint(self.is_return)
+ })
+ if item_row.target_warehouse and not cint(self.is_return):
+ sle.dependant_sle_voucher_detail_no = item_row.name
+
+ return sle
+
+ def get_sle_for_target_warehouse(self, item_row):
+ sle = self.get_sl_entries(item_row, {
+ "actual_qty": flt(item_row.qty),
+ "warehouse": item_row.target_warehouse
+ })
+
+ if self.docstatus == 1:
+ if not cint(self.is_return):
+ sle.update({
+ "incoming_rate": item_row.incoming_rate,
+ "recalculate_rate": 1
+ })
+ else:
+ sle.update({
+ "outgoing_rate": item_row.incoming_rate
+ })
+ if item_row.warehouse:
+ sle.dependant_sle_voucher_detail_no = item_row.name
+
+ return sle
+
+ def set_po_nos(self, for_validate=False):
+ if self.doctype == 'Sales Invoice' and hasattr(self, "items"):
+ if for_validate and self.po_no:
+ return
+ self.set_pos_for_sales_invoice()
+ if self.doctype == 'Delivery Note' and hasattr(self, "items"):
+ if for_validate and self.po_no:
+ return
+ self.set_pos_for_delivery_note()
+
+ def set_pos_for_sales_invoice(self):
+ po_nos = []
+ if self.po_no:
+ po_nos.append(self.po_no)
+ self.get_po_nos('Sales Order', 'sales_order', po_nos)
+ self.get_po_nos('Delivery Note', 'delivery_note', po_nos)
+ self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
+
+ def set_pos_for_delivery_note(self):
+ po_nos = []
+ if self.po_no:
+ po_nos.append(self.po_no)
+ self.get_po_nos('Sales Order', 'against_sales_order', po_nos)
+ self.get_po_nos('Sales Invoice', 'against_sales_invoice', po_nos)
+ self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
+
+ def get_po_nos(self, ref_doctype, ref_fieldname, po_nos):
+ doc_list = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
+ if doc_list:
+ po_nos += [d.po_no for d in frappe.get_all(ref_doctype, 'po_no', filters = {'name': ('in', doc_list)}) if d.get('po_no')]
def set_gross_profit(self):
if self.doctype in ["Sales Order", "Quotation"]:
@@ -390,28 +451,38 @@
check_list, chk_dupl_itm = [], []
if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
return
+ if self.doctype == "Sales Invoice" and self.is_consolidated:
+ return
+ if self.doctype == "POS Invoice":
+ return
for d in self.get('items'):
if self.doctype == "Sales Invoice":
- e = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
- f = [d.item_code, d.description, d.sales_order or d.delivery_note]
+ stock_items = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
+ non_stock_items = [d.item_code, d.description, d.sales_order or d.delivery_note]
elif self.doctype == "Delivery Note":
- e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
- f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
+ stock_items = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
+ non_stock_items = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
elif self.doctype in ["Sales Order", "Quotation"]:
- e = [d.item_code, d.description, d.warehouse, '']
- f = [d.item_code, d.description]
+ stock_items = [d.item_code, d.description, d.warehouse, '']
+ non_stock_items = [d.item_code, d.description]
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
- if e in check_list:
- frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+ duplicate_items_msg = _("Item {0} entered multiple times.").format(frappe.bold(d.item_code))
+ duplicate_items_msg += "<br><br>"
+ duplicate_items_msg += _("Please enable {} in {} to allow same item in multiple rows").format(
+ frappe.bold("Allow Item to Be Added Multiple Times in a Transaction"),
+ get_link_to_form("Selling Settings", "Selling Settings")
+ )
+ if stock_items in check_list:
+ frappe.throw(duplicate_items_msg)
else:
- check_list.append(e)
+ check_list.append(stock_items)
else:
- if f in chk_dupl_itm:
- frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+ if non_stock_items in chk_dupl_itm:
+ frappe.throw(duplicate_items_msg)
else:
- chk_dupl_itm.append(f)
+ chk_dupl_itm.append(non_stock_items)
def validate_target_warehouse(self):
items = self.get("items") + (self.get("packed_items") or [])
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 9feac78..0987d09 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -58,6 +58,7 @@
"Delivery Note": [
["Draft", None],
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
+ ["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],
["Closed", "eval:self.status=='Closed'"],
@@ -65,6 +66,7 @@
"Purchase Receipt": [
["Draft", None],
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
+ ["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],
["Closed", "eval:self.status=='Closed'"],
@@ -91,6 +93,12 @@
["Open", "eval:self.docstatus == 1 and not self.pos_closing_entry"],
["Closed", "eval:self.docstatus == 1 and self.pos_closing_entry"],
["Cancelled", "eval:self.docstatus == 2"],
+ ],
+ "POS Closing Entry": [
+ ["Draft", None],
+ ["Submitted", "eval:self.docstatus == 1"],
+ ["Queued", "eval:self.status == 'Queued'"],
+ ["Cancelled", "eval:self.docstatus == 2"],
]
}
@@ -232,7 +240,7 @@
self._update_children(args, update_modified)
- if "percent_join_field" in args:
+ if "percent_join_field" in args or "percent_join_field_parent" in args:
self._update_percent_field_in_targets(args, update_modified)
def _update_children(self, args, update_modified):
@@ -252,33 +260,43 @@
if not args.get("second_source_extra_cond"):
args["second_source_extra_cond"] = ""
- args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
+ args['second_source_condition'] = frappe.db.sql(""" select ifnull((select sum(%(second_source_field)s)
from `tab%(second_source_dt)s`
where `%(second_join_field)s`="%(detail_id)s"
- and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s FOR UPDATE), 0)""" % args
+ and (`tab%(second_source_dt)s`.docstatus=1)
+ %(second_source_extra_cond)s), 0) """ % args)[0][0]
if args['detail_id']:
if not args.get("extra_cond"): args["extra_cond"] = ""
- frappe.db.sql("""update `tab%(target_dt)s`
- set %(target_field)s = (
+ args["source_dt_value"] = frappe.db.sql("""
(select ifnull(sum(%(source_field)s), 0)
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
and (docstatus=1 %(cond)s) %(extra_cond)s)
- %(second_source_condition)s
- )
- %(update_modified)s
+ """ % args)[0][0] or 0.0
+
+ if args['second_source_condition']:
+ args["source_dt_value"] += flt(args['second_source_condition'])
+
+ frappe.db.sql("""update `tab%(target_dt)s`
+ set %(target_field)s = %(source_dt_value)s %(update_modified)s
where name='%(detail_id)s'""" % args)
def _update_percent_field_in_targets(self, args, update_modified=True):
"""Update percent field in parent transaction"""
- distinct_transactions = set([d.get(args['percent_join_field'])
- for d in self.get_all_children(args['source_dt'])])
+ if args.get('percent_join_field_parent'):
+ # if reference to target doc where % is to be updated, is
+ # in source doc's parent form, consider percent_join_field_parent
+ args['name'] = self.get(args['percent_join_field_parent'])
+ self._update_percent_field(args, update_modified)
+ else:
+ distinct_transactions = set([d.get(args['percent_join_field'])
+ for d in self.get_all_children(args['source_dt'])])
- for name in distinct_transactions:
- if name:
- args['name'] = name
- self._update_percent_field(args, update_modified)
+ for name in distinct_transactions:
+ if name:
+ args['name'] = name
+ self._update_percent_field(args, update_modified)
def _update_percent_field(self, args, update_modified=True):
"""Update percent field in parent transaction"""
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 394883d..f352bae 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -6,7 +6,8 @@
from frappe.utils import cint, flt, cstr, get_link_to_form, today, getdate
from frappe import _
import frappe.defaults
-from erpnext.accounts.utils import get_fiscal_year
+from collections import defaultdict
+from erpnext.accounts.utils import get_fiscal_year, check_if_stock_and_account_balance_synced
from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries, process_gl_map
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.stock.stock_ledger import get_valuation_rate
@@ -23,8 +24,11 @@
self.validate_inspection()
self.validate_serialized_batch()
self.validate_customer_provided_item()
+ self.set_rate_of_stock_uom()
+ self.validate_internal_transfer()
+ self.validate_putaway_capacity()
- def make_gl_entries(self, gl_entries=None):
+ def make_gl_entries(self, gl_entries=None, from_repost=False):
if self.docstatus == 2:
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
@@ -34,12 +38,12 @@
if self.docstatus==1:
if not gl_entries:
gl_entries = self.get_gl_entries(warehouse_account)
- make_gl_entries(gl_entries)
+ make_gl_entries(gl_entries, from_repost=from_repost)
elif self.doctype in ['Purchase Receipt', 'Purchase Invoice'] and self.docstatus == 1:
gl_entries = []
gl_entries = self.get_asset_gl_entry(gl_entries)
- make_gl_entries(gl_entries)
+ make_gl_entries(gl_entries, from_repost=from_repost)
def validate_serialized_batch(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -52,7 +56,7 @@
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
.format(d.idx, serial_no_data.name, d.batch_no))
- if d.qty > 0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
+ if flt(d.qty) > 0.0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
if expiry_date and getdate(expiry_date) < getdate(self.posting_date):
@@ -70,14 +74,14 @@
gl_list = []
warehouse_with_no_account = []
-
- precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
+ precision = self.get_debit_field_precision()
for item_row in voucher_details:
+
sle_list = sle_map.get(item_row.name)
if sle_list:
for sle in sle_list:
if warehouse_account.get(sle.warehouse):
- # from warehouse account/ target warehouse account
+ # from warehouse account
self.check_expense_account(item_row)
@@ -92,9 +96,16 @@
sle = self.update_stock_ledger_entries(sle)
+ # expense account/ target_warehouse / source_warehouse
+ if item_row.get('target_warehouse'):
+ warehouse = item_row.get('target_warehouse')
+ expense_account = warehouse_account[warehouse]["account"]
+ else:
+ expense_account = item_row.expense_account
+
gl_list.append(self.get_gl_dict({
"account": warehouse_account[sle.warehouse]["account"],
- "against": item_row.expense_account,
+ "against": expense_account,
"cost_center": item_row.cost_center,
"project": item_row.project or self.get('project'),
"remarks": self.get("remarks") or "Accounting Entry for Stock",
@@ -102,9 +113,8 @@
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
- # expense account
gl_list.append(self.get_gl_dict({
- "account": item_row.expense_account,
+ "account": expense_account,
"against": warehouse_account[sle.warehouse]["account"],
"cost_center": item_row.cost_center,
"project": item_row.project or self.get('project'),
@@ -119,9 +129,15 @@
if warehouse_with_no_account:
for wh in warehouse_with_no_account:
if frappe.db.get_value("Warehouse", wh, "company"):
- frappe.throw(_("Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}.").format(wh, self.company))
+ frappe.throw(_("Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}.").format(wh, self.company))
- return process_gl_map(gl_list)
+ return process_gl_map(gl_list, precision=precision)
+
+ def get_debit_field_precision(self):
+ if not frappe.flags.debit_field_precision:
+ frappe.flags.debit_field_precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
+
+ return frappe.flags.debit_field_precision
def update_stock_ledger_entries(self, sle):
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
@@ -211,7 +227,7 @@
""", (self.doctype, self.name), as_dict=True)
for sle in stock_ledger_entries:
- stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
+ stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
return stock_ledger
def make_batches(self, warehouse_field):
@@ -229,12 +245,12 @@
def check_expense_account(self, item):
if not item.get("expense_account"):
- frappe.throw(_("Row #{0}: Expense Account not set for Item {1}. Please set an Expense \
- Account in the Items table").format(item.idx, frappe.bold(item.item_code)),
- title=_("Expense Account Missing"))
+ msg = _("Please set an Expense Account in the Items table")
+ frappe.throw(_("Row #{0}: Expense Account not set for the Item {1}. {2}")
+ .format(item.idx, frappe.bold(item.item_code), msg), title=_("Expense Account Missing"))
else:
- is_expense_account = frappe.db.get_value("Account",
+ is_expense_account = frappe.get_cached_value("Account",
item.get("expense_account"), "report_type")=="Profit and Loss"
if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Stock Reconciliation", "Stock Entry") and not is_expense_account:
frappe.throw(_("Expense / Difference account ({0}) must be a 'Profit or Loss' account")
@@ -247,7 +263,9 @@
for d in self.items:
if not d.batch_no: continue
- serial_nos = [sr.name for sr in frappe.get_all("Serial No", {'batch_no': d.batch_no})]
+ serial_nos = [sr.name for sr in frappe.get_all("Serial No",
+ {'batch_no': d.batch_no, 'status': 'Inactive'})]
+
if serial_nos:
frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None)
@@ -301,25 +319,8 @@
return serialized_items
- def get_incoming_rate_for_return(self, item_code, against_document, against_document_no=None):
- incoming_rate = 0.0
- cond = ''
- if against_document and item_code:
- if against_document_no:
- cond = " and voucher_detail_no = %s" %(frappe.db.escape(against_document_no))
-
- incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
- from `tabStock Ledger Entry`
- where voucher_type = %s and voucher_no = %s
- and item_code = %s {0} limit 1""".format(cond),
- (self.doctype, against_document, item_code))
-
- incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
-
- return incoming_rate
-
def validate_warehouse(self):
- from erpnext.stock.utils import validate_warehouse_company
+ from erpnext.stock.utils import validate_warehouse_company, validate_disabled_warehouse
warehouses = list(set([d.warehouse for d in
self.get("items") if getattr(d, "warehouse", None)]))
@@ -335,14 +336,19 @@
warehouses.extend(from_warehouse)
for w in warehouses:
+ validate_disabled_warehouse(w)
validate_warehouse_company(w, self.company)
def update_billing_percentage(self, update_modified=True):
+ target_ref_field = "amount"
+ if self.doctype == "Delivery Note":
+ target_ref_field = "amount - (returned_qty * rate)"
+
self._update_percent_field({
"target_dt": self.doctype + " Item",
"target_parent_dt": self.doctype,
"target_parent_field": "per_billed",
- "target_ref_field": "amount",
+ "target_ref_field": target_ref_field,
"target_field": "billed_amt",
"name": self.name,
}, update_modified)
@@ -397,19 +403,160 @@
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1
-def compare_existing_and_expected_gle(existing_gle, expected_gle):
- matched = True
- for entry in expected_gle:
- account_existed = False
- for e in existing_gle:
- if entry.account == e.account:
- account_existed = True
- if entry.account == e.account and entry.against_account == e.against_account \
- and (not entry.cost_center or not e.cost_center or entry.cost_center == e.cost_center) \
- and (entry.debit != e.debit or entry.credit != e.credit):
- matched = False
- break
- if not account_existed:
- matched = False
- break
- return matched
+ def set_rate_of_stock_uom(self):
+ if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
+ for d in self.get("items"):
+ if d.conversion_factor:
+ d.stock_uom_rate = d.rate / d.conversion_factor
+
+ def validate_internal_transfer(self):
+ if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
+ and self.is_internal_transfer():
+ self.validate_in_transit_warehouses()
+ self.validate_multi_currency()
+ self.validate_packed_items()
+
+ def validate_in_transit_warehouses(self):
+ if (self.doctype == 'Sales Invoice' and self.get('update_stock')) or self.doctype == 'Delivery Note':
+ for item in self.get('items'):
+ if not item.target_warehouse:
+ frappe.throw(_("Row {0}: Target Warehouse is mandatory for internal transfers").format(item.idx))
+
+ if (self.doctype == 'Purchase Invoice' and self.get('update_stock')) or self.doctype == 'Purchase Receipt':
+ for item in self.get('items'):
+ if not item.from_warehouse:
+ frappe.throw(_("Row {0}: From Warehouse is mandatory for internal transfers").format(item.idx))
+
+ def validate_multi_currency(self):
+ if self.currency != self.company_currency:
+ frappe.throw(_("Internal transfers can only be done in company's default currency"))
+
+ def validate_packed_items(self):
+ if self.doctype in ('Sales Invoice', 'Delivery Note Item') and self.get('packed_items'):
+ frappe.throw(_("Packed Items cannot be transferred internally"))
+
+ def validate_putaway_capacity(self):
+ # if over receipt is attempted while 'apply putaway rule' is disabled
+ # and if rule was applied on the transaction, validate it.
+ from erpnext.stock.doctype.putaway_rule.putaway_rule import get_available_putaway_capacity
+ valid_doctype = self.doctype in ("Purchase Receipt", "Stock Entry", "Purchase Invoice",
+ "Stock Reconciliation")
+
+ if self.doctype == "Purchase Invoice" and self.get("update_stock") == 0:
+ valid_doctype = False
+
+ if valid_doctype:
+ rule_map = defaultdict(dict)
+ for item in self.get("items"):
+ warehouse_field = "t_warehouse" if self.doctype == "Stock Entry" else "warehouse"
+ rule = frappe.db.get_value("Putaway Rule",
+ {
+ "item_code": item.get("item_code"),
+ "warehouse": item.get(warehouse_field)
+ },
+ ["name", "disable"], as_dict=True)
+ if rule:
+ if rule.get("disabled"): continue # dont validate for disabled rule
+
+ if self.doctype == "Stock Reconciliation":
+ stock_qty = flt(item.qty)
+ else:
+ stock_qty = flt(item.transfer_qty) if self.doctype == "Stock Entry" else flt(item.stock_qty)
+
+ rule_name = rule.get("name")
+ if not rule_map[rule_name]:
+ rule_map[rule_name]["warehouse"] = item.get(warehouse_field)
+ rule_map[rule_name]["item"] = item.get("item_code")
+ rule_map[rule_name]["qty_put"] = 0
+ rule_map[rule_name]["capacity"] = get_available_putaway_capacity(rule_name)
+ rule_map[rule_name]["qty_put"] += flt(stock_qty)
+
+ for rule, values in rule_map.items():
+ if flt(values["qty_put"]) > flt(values["capacity"]):
+ message = self.prepare_over_receipt_message(rule, values)
+ frappe.throw(msg=message, title=_("Over Receipt"))
+
+ def prepare_over_receipt_message(self, rule, values):
+ message = _("{0} qty of Item {1} is being received into Warehouse {2} with capacity {3}.") \
+ .format(
+ frappe.bold(values["qty_put"]), frappe.bold(values["item"]),
+ frappe.bold(values["warehouse"]), frappe.bold(values["capacity"])
+ )
+ message += "<br><br>"
+ rule_link = frappe.utils.get_link_to_form("Putaway Rule", rule)
+ message += _(" Please adjust the qty or edit {0} to proceed.").format(rule_link)
+ return message
+
+ def repost_future_sle_and_gle(self):
+ args = frappe._dict({
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "company": self.company
+ })
+ if future_sle_exists(args):
+ create_repost_item_valuation_entry(args)
+ elif not is_reposting_pending():
+ check_if_stock_and_account_balance_synced(self.posting_date,
+ self.company, self.doctype, self.name)
+
+def is_reposting_pending():
+ return frappe.db.exists("Repost Item Valuation",
+ {'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
+
+
+def future_sle_exists(args):
+ sl_entries = frappe.get_all("Stock Ledger Entry",
+ filters={"voucher_type": args.voucher_type, "voucher_no": args.voucher_no},
+ fields=["item_code", "warehouse"],
+ order_by="creation asc")
+
+ if not sl_entries:
+ return
+
+ warehouse_items_map = {}
+ for entry in sl_entries:
+ if entry.warehouse not in warehouse_items_map:
+ warehouse_items_map[entry.warehouse] = set()
+
+ warehouse_items_map[entry.warehouse].add(entry.item_code)
+
+ or_conditions = []
+ for warehouse, items in warehouse_items_map.items():
+ or_conditions.append(
+ "warehouse = '{}' and item_code in ({})".format(
+ warehouse,
+ ", ".join(frappe.db.escape(item) for item in items)
+ )
+ )
+
+ return frappe.db.sql("""
+ select name
+ from `tabStock Ledger Entry`
+ where
+ ({})
+ and timestamp(posting_date, posting_time)
+ >= timestamp(%(posting_date)s, %(posting_time)s)
+ and voucher_no != %(voucher_no)s
+ and is_cancelled = 0
+ limit 1
+ """.format(" or ".join(or_conditions)), args)
+
+def create_repost_item_valuation_entry(args):
+ args = frappe._dict(args)
+ repost_entry = frappe.new_doc("Repost Item Valuation")
+ repost_entry.based_on = args.based_on
+ if not args.based_on:
+ repost_entry.based_on = 'Transaction' if args.voucher_no else "Item and Warehouse"
+ repost_entry.voucher_type = args.voucher_type
+ repost_entry.voucher_no = args.voucher_no
+ repost_entry.item_code = args.item_code
+ repost_entry.warehouse = args.warehouse
+ repost_entry.posting_date = args.posting_date
+ repost_entry.posting_time = args.posting_time
+ repost_entry.company = args.company
+ repost_entry.allow_zero_rate = args.allow_zero_rate
+ repost_entry.flags.ignore_links = True
+ repost_entry.save()
+ repost_entry.submit()
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 92cfdb7..e329b32 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -10,10 +10,13 @@
validate_taxes_and_charges, validate_inclusive_tax
from erpnext.stock.get_item_details import _get_item_tax_template
from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
+from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate
class calculate_taxes_and_totals(object):
def __init__(self, doc):
self.doc = doc
+ frappe.flags.round_off_applicable_accounts = []
+ get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts)
self.calculate()
def calculate(self):
@@ -106,11 +109,14 @@
elif item.discount_amount and item.pricing_rules:
item.rate = item.price_list_rate - item.discount_amount
- if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item']:
+ if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item', 'POS Invoice Item', 'Purchase Invoice Item', 'Purchase Order Item', 'Purchase Receipt Item']:
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
if flt(item.rate_with_margin) > 0:
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
- item.discount_amount = item.rate_with_margin - item.rate
+ if not item.discount_amount:
+ item.discount_amount = item.rate_with_margin - item.rate
+ elif not item.discount_percentage:
+ item.rate -= item.discount_amount
elif flt(item.price_list_rate) > 0:
item.discount_amount = item.price_list_rate - item.rate
elif flt(item.price_list_rate) > 0 and not item.discount_amount:
@@ -238,9 +244,6 @@
self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"])
- if self.doc.doctype == 'Sales Invoice' and self.doc.is_pos:
- self.doc.pos_total_qty = self.doc.total_qty
-
def calculate_taxes(self):
self.doc.rounding_adjustment = 0
# maintain actual tax rate based on idx
@@ -334,10 +337,18 @@
elif tax.charge_type == "On Item Quantity":
current_tax_amount = tax_rate * item.qty
+ current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
return current_tax_amount
+ def get_final_current_tax_amount(self, tax, current_tax_amount):
+ # Some countries need individual tax components to be rounded
+ # Handeled via regional doctypess
+ if tax.account_head in frappe.flags.round_off_applicable_accounts:
+ current_tax_amount = round(current_tax_amount, 0)
+ return current_tax_amount
+
def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount):
# store tax breakup for each item
key = item.item_code or item.item_name
@@ -519,6 +530,17 @@
if self.doc.docstatus == 0:
self.calculate_outstanding_amount()
+ def is_internal_invoice(self):
+ """
+ Checks if its an internal transfer invoice
+ and decides if to calculate any out standing amount or not
+ """
+
+ if self.doc.doctype in ('Sales Invoice', 'Purchase Invoice') and self.doc.is_internal_transfer():
+ return True
+
+ return False
+
def calculate_outstanding_amount(self):
# NOTE:
# write_off_amount is only for POS Invoice
@@ -526,7 +548,8 @@
if self.doc.doctype == "Sales Invoice":
self.calculate_paid_amount()
- if self.doc.is_return and self.doc.return_against and not self.doc.get('is_pos'): return
+ if self.doc.is_return and self.doc.return_against and not self.doc.get('is_pos') or \
+ self.is_internal_invoice(): return
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
self._set_in_company_currency(self.doc, ['write_off_amount'])
@@ -603,21 +626,23 @@
self.doc.precision("base_write_off_amount"))
def calculate_margin(self, item):
-
rate_with_margin = 0.0
base_rate_with_margin = 0.0
if item.price_list_rate:
if item.pricing_rules and not self.doc.ignore_pricing_rule:
+ has_margin = False
for d in get_applied_pricing_rules(item.pricing_rules):
pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
- if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\
- or (pricing_rule.margin_type == 'Percentage'):
+ if pricing_rule.margin_rate_or_amount and ((pricing_rule.currency == self.doc.currency and
+ pricing_rule.margin_type in ['Amount', 'Percentage']) or pricing_rule.margin_type == 'Percentage'):
item.margin_type = pricing_rule.margin_type
item.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
- else:
- item.margin_type = None
- item.margin_rate_or_amount = 0.0
+ has_margin = True
+
+ if not has_margin:
+ item.margin_type = None
+ item.margin_rate_or_amount = 0.0
if item.margin_type and item.margin_rate_or_amount:
margin_value = item.margin_rate_or_amount if item.margin_type == 'Amount' else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
@@ -638,7 +663,8 @@
if default_mode_of_payment:
self.doc.append('payments', {
'mode_of_payment': default_mode_of_payment.mode_of_payment,
- 'amount': total_amount_to_pay
+ 'amount': total_amount_to_pay,
+ 'default': 1
})
else:
self.doc.is_pos = 0
@@ -680,6 +706,15 @@
)
)
+@frappe.whitelist()
+def get_round_off_applicable_accounts(company, account_list):
+ account_list = get_regional_round_off_accounts(company, account_list)
+
+ return account_list
+
+@erpnext.allow_regional
+def get_regional_round_off_accounts(company, account_list):
+ pass
@erpnext.allow_regional
def update_itemised_tax_data(doc):
@@ -742,3 +777,35 @@
for taxes in itemised_tax.values():
for tax_account in taxes:
taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision)
+
+class init_landed_taxes_and_totals(object):
+ def __init__(self, doc):
+ self.doc = doc
+ self.tax_field = 'taxes' if self.doc.doctype == 'Landed Cost Voucher' else 'additional_costs'
+ self.set_account_currency()
+ self.set_exchange_rate()
+ self.set_amounts_in_company_currency()
+
+ def set_account_currency(self):
+ company_currency = erpnext.get_company_currency(self.doc.company)
+ for d in self.doc.get(self.tax_field):
+ if not d.account_currency:
+ account_currency = frappe.db.get_value('Account', d.expense_account, 'account_currency')
+ d.account_currency = account_currency or company_currency
+
+ def set_exchange_rate(self):
+ company_currency = erpnext.get_company_currency(self.doc.company)
+ for d in self.doc.get(self.tax_field):
+ if d.account_currency == company_currency:
+ d.exchange_rate = 1
+ elif not d.exchange_rate:
+ d.exchange_rate = get_exchange_rate(self.doc.posting_date, account=d.expense_account,
+ account_currency=d.account_currency, company=self.doc.company)
+
+ if not d.exchange_rate:
+ frappe.throw(_("Row {0}: Exchange Rate is mandatory").format(d.idx))
+
+ def set_amounts_in_company_currency(self):
+ for d in self.doc.get(self.tax_field):
+ d.amount = flt(d.amount, d.precision("amount"))
+ d.base_amount = flt(d.amount * flt(d.exchange_rate), d.precision("base_amount"))
\ No newline at end of file
diff --git a/erpnext/controllers/tests/test_item_variant.py b/erpnext/controllers/tests/test_item_variant.py
index c257215..813f0a0 100644
--- a/erpnext/controllers/tests/test_item_variant.py
+++ b/erpnext/controllers/tests/test_item_variant.py
@@ -6,6 +6,7 @@
from erpnext.stock.doctype.item.test_item import set_item_variant_settings
from erpnext.controllers.item_variant import copy_attributes_to_variant, make_variant_item_code
+from erpnext.stock.doctype.quality_inspection.test_quality_inspection import create_quality_inspection_parameter
from six import string_types
@@ -56,6 +57,8 @@
qc = frappe.new_doc("Quality Inspection Template")
qc.quality_inspection_template_name = qc_template
+
+ create_quality_inspection_parameter("Moisture")
qc.append('item_quality_inspection_parameter', {
"specification": "Moisture",
"value": "< 5%",
diff --git a/erpnext/crm/desk_page/crm/crm.json b/erpnext/crm/desk_page/crm/crm.json
deleted file mode 100644
index d974beb..0000000
--- a/erpnext/crm/desk_page/crm/crm.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Sales Pipeline",
- "links": "[\n {\n \"description\": \"Database of potential customers.\",\n \"label\": \"Lead\",\n \"name\": \"Lead\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Potential opportunities for selling.\",\n \"label\": \"Opportunity\",\n \"name\": \"Opportunity\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Record of all communications of type email, phone, chat, visit, etc.\",\n \"label\": \"Communication\",\n \"name\": \"Communication\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Track Leads by Lead Source.\",\n \"label\": \"Lead Source\",\n \"name\": \"Lead Source\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Helps you keep tracks of Contracts based on Supplier, Customer and Employee\",\n \"label\": \"Contract\",\n \"name\": \"Contract\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Helps you manage appointments with your leads\",\n \"label\": \"Appointment\",\n \"name\": \"Appointment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Sales Funnel\",\n \"name\": \"sales-funnel\",\n \"onboard\": 1,\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Prospects Engaged But Not Converted\",\n \"name\": \"Prospects Engaged But Not Converted\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Opportunity\"\n ],\n \"doctype\": \"Opportunity\",\n \"is_query_report\": true,\n \"label\": \"First Response Time for Opportunity\",\n \"name\": \"First Response Time for Opportunity\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Inactive Customers\",\n \"name\": \"Inactive Customers\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Campaign Efficiency\",\n \"name\": \"Campaign Efficiency\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Owner Efficiency\",\n \"name\": \"Lead Owner Efficiency\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Maintenance",
- "links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Campaign",
- "links": "[\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Create and Schedule social media posts\",\n \"label\": \"Social Media Post\",\n \"name\": \"Social Media Post\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Twitter Settings\",\n \"name\": \"Twitter Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"LinkedIn Settings\",\n \"name\": \"LinkedIn Settings\",\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Territory Wise Sales"
- }
- ],
- "creation": "2020-01-23 14:48:30.183272",
- "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": "CRM",
- "modified": "2020-08-11 18:55:18.238900",
- "modified_by": "Administrator",
- "module": "CRM",
- "name": "CRM",
- "onboarding": "CRM",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#ffe8cd",
- "format": "{} Open",
- "label": "Lead",
- "link_to": "Lead",
- "stats_filter": "{\"status\":\"Open\"}",
- "type": "DocType"
- },
- {
- "color": "#cef6d1",
- "format": "{} Assigned",
- "label": "Opportunity",
- "link_to": "Opportunity",
- "stats_filter": "{\"_assign\": [\"like\", '%' + frappe.session.user + '%']}",
- "type": "DocType"
- },
- {
- "label": "Customer",
- "link_to": "Customer",
- "type": "DocType"
- },
- {
- "label": "Sales Analytics",
- "link_to": "Sales Analytics",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "CRM",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py
index 63efeb3..2009ebf 100644
--- a/erpnext/crm/doctype/appointment/appointment.py
+++ b/erpnext/crm/doctype/appointment/appointment.py
@@ -126,7 +126,7 @@
add_assignemnt({
'doctype': self.doctype,
'name': self.name,
- 'assign_to': existing_assignee
+ 'assign_to': [existing_assignee]
})
return
if self._assign:
@@ -139,7 +139,7 @@
add_assignemnt({
'doctype': self.doctype,
'name': self.name,
- 'assign_to': agent
+ 'assign_to': [agent]
})
break
diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
index 99b8214..dc3ae8b 100644
--- a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
+++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
@@ -4,7 +4,7 @@
let from_time = Date.parse('01/01/2019 ' + d.from_time);
let to_time = Date.parse('01/01/2019 ' + d.to_time);
if (from_time > to_time) {
- frappe.throw(__(`In row ${i + 1} of Appointment Booking Slots : "To Time" must be later than "From Time"`));
+ frappe.throw(__('In row {0} of Appointment Booking Slots: "To Time" must be later than "From Time".', [i + 1]));
}
});
}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/contract/contract.js b/erpnext/crm/doctype/contract/contract.js
index ee9e895..9968855 100644
--- a/erpnext/crm/doctype/contract/contract.js
+++ b/erpnext/crm/doctype/contract/contract.js
@@ -1,23 +1,31 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-cur_frm.add_fetch("contract_template", "contract_terms", "contract_terms");
-cur_frm.add_fetch("contract_template", "requires_fulfilment", "requires_fulfilment");
-
-// Add fulfilment terms from contract template into contract
frappe.ui.form.on("Contract", {
contract_template: function (frm) {
- // Populate the fulfilment terms table from a contract template, if any
if (frm.doc.contract_template) {
- frappe.model.with_doc("Contract Template", frm.doc.contract_template, function () {
- var tabletransfer = frappe.model.get_doc("Contract Template", frm.doc.contract_template);
-
- frm.doc.fulfilment_terms = [];
- $.each(tabletransfer.fulfilment_terms, function (index, row) {
- var d = frm.add_child("fulfilment_terms");
- d.requirement = row.requirement;
- frm.refresh_field("fulfilment_terms");
- });
+ frappe.call({
+ method: 'erpnext.crm.doctype.contract_template.contract_template.get_contract_template',
+ args: {
+ template_name: frm.doc.contract_template,
+ doc: frm.doc
+ },
+ callback: function(r) {
+ if (r && r.message) {
+ let contract_template = r.message.contract_template;
+ frm.set_value("contract_terms", r.message.contract_terms);
+ frm.set_value("requires_fulfilment", contract_template.requires_fulfilment);
+
+ if (frm.doc.requires_fulfilment) {
+ // Populate the fulfilment terms table from a contract template, if any
+ r.message.contract_template.fulfilment_terms.forEach(element => {
+ let d = frm.add_child("fulfilment_terms");
+ d.requirement = element.requirement;
+ });
+ frm.refresh_field("fulfilment_terms");
+ }
+ }
+ }
});
}
}
diff --git a/erpnext/crm/doctype/contract/contract.json b/erpnext/crm/doctype/contract/contract.json
index 0026e4a..de3230f 100755
--- a/erpnext/crm/doctype/contract/contract.json
+++ b/erpnext/crm/doctype/contract/contract.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"creation": "2018-04-12 06:32:04.582486",
@@ -247,7 +248,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-03-30 06:56:07.257932",
+ "modified": "2020-12-07 11:15:58.385521",
"modified_by": "Administrator",
"module": "CRM",
"name": "Contract",
diff --git a/erpnext/crm/doctype/contract/contract_list.js b/erpnext/crm/doctype/contract/contract_list.js
index 2ef5900..26a2907 100644
--- a/erpnext/crm/doctype/contract/contract_list.js
+++ b/erpnext/crm/doctype/contract/contract_list.js
@@ -1,12 +1,12 @@
frappe.listview_settings['Contract'] = {
- add_fields: ["status"],
- get_indicator: function (doc) {
- if (doc.status == "Unsigned") {
- return [__(doc.status), "red", "status,=," + doc.status];
- } else if (doc.status == "Active") {
- return [__(doc.status), "green", "status,=," + doc.status];
- } else if (doc.status == "Inactive") {
- return [__(doc.status), "darkgrey", "status,=," + doc.status];
- }
- },
+ add_fields: ["status"],
+ get_indicator: function (doc) {
+ if (doc.status == "Unsigned") {
+ return [__(doc.status), "red", "status,=," + doc.status];
+ } else if (doc.status == "Active") {
+ return [__(doc.status), "green", "status,=," + doc.status];
+ } else if (doc.status == "Inactive") {
+ return [__(doc.status), "gray", "status,=," + doc.status];
+ }
+ },
};
\ No newline at end of file
diff --git a/erpnext/crm/doctype/contract_template/contract_template.json b/erpnext/crm/doctype/contract_template/contract_template.json
index ef9974f..7cc5ec1 100644
--- a/erpnext/crm/doctype/contract_template/contract_template.json
+++ b/erpnext/crm/doctype/contract_template/contract_template.json
@@ -11,7 +11,9 @@
"contract_terms",
"sb_fulfilment",
"requires_fulfilment",
- "fulfilment_terms"
+ "fulfilment_terms",
+ "section_break_6",
+ "contract_template_help"
],
"fields": [
{
@@ -23,8 +25,7 @@
{
"fieldname": "contract_terms",
"fieldtype": "Text Editor",
- "label": "Contract Terms and Conditions",
- "read_only": 1
+ "label": "Contract Terms and Conditions"
},
{
"fieldname": "sb_fulfilment",
@@ -42,10 +43,20 @@
"fieldtype": "Table",
"label": "Fulfilment Terms and Conditions",
"options": "Contract Template Fulfilment Terms"
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "contract_template_help",
+ "fieldtype": "HTML",
+ "label": "Contract Template Help",
+ "options": "<h4>Contract Template Example</h4>\n\n<pre>Contract for Customer {{ party_name }}\n\n-Valid From : {{ start_date }} \n-Valid To : {{ end_date }}\n</pre>\n\n<h4>How to get fieldnames</h4>\n\n<p>The field names you can use in your Contract Template are the fields in the Contract for which you are creating the template. You can find out the fields of any documents via Setup > Customize Form View and selecting the document type (e.g. Contract)</p>\n\n<h4>Templating</h4>\n\n<p>Templates are compiled using the Jinja Templating Language. To learn more about Jinja, <a class=\"strong\" href=\"http://jinja.pocoo.org/docs/dev/templates/\">read this documentation.</a></p>"
}
],
"links": [],
- "modified": "2020-06-03 00:24:58.179816",
+ "modified": "2020-12-07 10:44:22.587047",
"modified_by": "Administrator",
"module": "CRM",
"name": "Contract Template",
diff --git a/erpnext/crm/doctype/contract_template/contract_template.py b/erpnext/crm/doctype/contract_template/contract_template.py
index 601ee9a..69fd86f 100644
--- a/erpnext/crm/doctype/contract_template/contract_template.py
+++ b/erpnext/crm/doctype/contract_template/contract_template.py
@@ -5,6 +5,27 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe.utils.jinja import validate_template
+from six import string_types
+import json
class ContractTemplate(Document):
- pass
+ def validate(self):
+ if self.contract_terms:
+ validate_template(self.contract_terms)
+
+@frappe.whitelist()
+def get_contract_template(template_name, doc):
+ if isinstance(doc, string_types):
+ doc = json.loads(doc)
+
+ contract_template = frappe.get_doc("Contract Template", template_name)
+ contract_terms = None
+
+ if contract_template.contract_terms:
+ contract_terms = frappe.render_template(contract_template.contract_terms, doc)
+
+ return {
+ 'contract_template': contract_template,
+ 'contract_terms': contract_terms
+ }
\ No newline at end of file
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index f5f8b4e..1b33fd7 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -49,6 +49,7 @@
"phone",
"mobile_no",
"fax",
+ "website",
"more_info",
"type",
"market_segment",
@@ -56,8 +57,8 @@
"request_type",
"column_break3",
"company",
- "website",
"territory",
+ "language",
"unsubscribed",
"blog_subscriber",
"title"
@@ -241,6 +242,7 @@
},
{
"depends_on": "eval: doc.__islocal",
+ "description": "Home, Work, etc.",
"fieldname": "address_title",
"fieldtype": "Data",
"label": "Address Title"
@@ -249,7 +251,8 @@
"depends_on": "eval: doc.__islocal",
"fieldname": "address_line1",
"fieldtype": "Data",
- "label": "Address Line 1"
+ "label": "Address Line 1",
+ "mandatory_depends_on": "eval: doc.address_title && doc.address_type"
},
{
"depends_on": "eval: doc.__islocal",
@@ -261,7 +264,8 @@
"depends_on": "eval: doc.__islocal",
"fieldname": "city",
"fieldtype": "Data",
- "label": "City/Town"
+ "label": "City/Town",
+ "mandatory_depends_on": "eval: doc.address_title && doc.address_type"
},
{
"depends_on": "eval: doc.__islocal",
@@ -280,6 +284,7 @@
"fieldname": "country",
"fieldtype": "Link",
"label": "Country",
+ "mandatory_depends_on": "eval: doc.address_title && doc.address_type",
"options": "Country"
},
{
@@ -443,13 +448,19 @@
"fieldtype": "Select",
"label": "Address Type",
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther"
+ },
+ {
+ "fieldname": "language",
+ "fieldtype": "Link",
+ "label": "Print Language",
+ "options": "Language"
}
],
"icon": "fa fa-user",
"idx": 5,
"image_field": "image",
"links": [],
- "modified": "2020-06-18 14:39:41.835416",
+ "modified": "2021-01-06 19:39:58.748978",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead",
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 99fa703..d1d0968 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -22,7 +22,8 @@
load_address_and_contact(self)
def before_insert(self):
- self.address_doc = self.create_address()
+ if self.address_title and self.address_type:
+ self.address_doc = self.create_address()
self.contact_doc = self.create_contact()
def after_insert(self):
@@ -133,15 +134,6 @@
# skipping country since the system auto-sets it from system defaults
address = frappe.new_doc("Address")
- mandatory_fields = [ df.fieldname for df in address.meta.fields if df.reqd ]
-
- if not all([self.get(field) for field in mandatory_fields]):
- frappe.msgprint(_('Missing mandatory fields in address. \
- {0} to create address' ).format("<a href='desk#Form/Address/New Address 1' \
- > Click here </a>"),
- alert=True, indicator='yellow')
- return
-
address.update({addr_field: self.get(addr_field) for addr_field in address_fields})
address.update({info_field: self.get(info_field) for info_field in info_fields})
address.insert()
@@ -184,13 +176,13 @@
"phone": self.mobile_no
})
- contact.insert()
+ contact.insert(ignore_permissions=True)
return contact
def update_links(self):
# update address links
- if self.address_doc:
+ if hasattr(self, 'address_doc'):
self.address_doc.append("links", {
"link_doctype": "Lead",
"link_name": self.name,
@@ -360,7 +352,7 @@
leads = frappe.get_all('Lead', or_filters={
'phone': ['like', '%{}'.format(number)],
'mobile_no': ['like', '%{}'.format(number)]
- }, limit=1)
+ }, limit=1, order_by="creation DESC")
lead = leads[0].name if leads else None
@@ -369,4 +361,4 @@
def daily_open_lead():
leads = frappe.get_all("Lead", filters = [["contact_date", "Between", [nowdate(), nowdate()]]])
for lead in leads:
- frappe.db.set_value("Lead", lead.name, "status", "Open")
\ No newline at end of file
+ frappe.db.set_value("Lead", lead.name, "status", "Open")
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index 08958b7..ac374a9 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -24,6 +24,12 @@
frm.trigger('set_contact_link');
}
},
+ contact_date: function(frm) {
+ if(frm.doc.contact_date < frappe.datetime.now_datetime()){
+ frm.set_value("contact_date", "");
+ frappe.throw(__("Next follow up date should be greater than now."))
+ }
+ },
onload_post_render: function(frm) {
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json
index eee13f7..2e09a76 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.json
+++ b/erpnext/crm/doctype/opportunity/opportunity.json
@@ -54,6 +54,7 @@
"campaign",
"column_break1",
"transaction_date",
+ "language",
"amended_from",
"lost_reasons"
],
@@ -419,12 +420,18 @@
"fieldtype": "Duration",
"label": "First Response Time",
"read_only": 1
+ },
+ {
+ "fieldname": "language",
+ "fieldtype": "Link",
+ "label": "Print Language",
+ "options": "Language"
}
],
"icon": "fa fa-info-sign",
"idx": 195,
"links": [],
- "modified": "2020-08-12 17:34:35.066961",
+ "modified": "2021-01-06 19:42:46.190051",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity",
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 47b05f3..0522ace 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -248,7 +248,6 @@
"doctype": "Quotation",
"field_map": {
"opportunity_from": "quotation_to",
- "opportunity_type": "order_type",
"name": "enq_no",
}
},
diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py
index 885ef05..f244daf 100644
--- a/erpnext/crm/doctype/utils.py
+++ b/erpnext/crm/doctype/utils.py
@@ -78,7 +78,9 @@
def strip_number(number):
if not number: return
- # strip 0 from the start of the number for proper number comparisions
+ # strip + and 0 from the start of the number for proper number comparisions
+ # eg. +7888383332 should match with 7888383332
# eg. 07888383332 should match with 7888383332
+ number = number.lstrip('+')
number = number.lstrip('0')
- return number
\ No newline at end of file
+ return number
diff --git a/erpnext/crm/onboarding_step/create_opportunity/create_opportunity.json b/erpnext/crm/onboarding_step/create_opportunity/create_opportunity.json
index 9f996d9..0ee9317 100644
--- a/erpnext/crm/onboarding_step/create_opportunity/create_opportunity.json
+++ b/erpnext/crm/onboarding_step/create_opportunity/create_opportunity.json
@@ -8,12 +8,12 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 17:38:27.496696",
+ "modified": "2021-01-21 15:28:52.483839",
"modified_by": "Administrator",
"name": "Create Opportunity",
"owner": "Administrator",
"reference_document": "Opportunity",
- "show_full_form": 0,
+ "show_full_form": 1,
"title": "Create Opportunity",
"validate_action": 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 b538a58..3a9d57d 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
@@ -19,15 +19,50 @@
if not filters.get('lead_age'): filters["lead_age"] = 60
def get_columns():
- return [
- _("Lead") + ":Link/Lead:100",
- _("Name") + "::100",
- _("Organization") + "::100",
- _("Reference Document") + "::150",
- _("Reference Name") + ":Dynamic Link/"+_("Reference Document")+":120",
- _("Last Communication") + ":Data:200",
- _("Last Communication Date") + ":Date:180"
- ]
+ columns = [{
+ "label": _("Lead"),
+ "fieldname": "lead",
+ "fieldtype": "Link",
+ "options": "Lead",
+ "width": 130
+ },
+ {
+ "label": _("Name"),
+ "fieldname": "name",
+ "width": 120
+ },
+ {
+ "label": _("Organization"),
+ "fieldname": "organization",
+ "width": 120
+ },
+ {
+ "label": _("Reference Document Type"),
+ "fieldname": "reference_document_type",
+ "fieldtype": "Link",
+ "options": "Doctype",
+ "width": 100
+ },
+ {
+ "label": _("Reference Name"),
+ "fieldname": "reference_name",
+ "fieldtype": "Dynamic Link",
+ "options": "reference_document_type",
+ "width": 140
+ },
+ {
+ "label": _("Last Communication"),
+ "fieldname": "last_communication",
+ "fieldtype": "Data",
+ "width": 200
+ },
+ {
+ "label": _("Last Communication Date"),
+ "fieldname": "last_communication_date",
+ "fieldtype": "Date",
+ "width": 100
+ }]
+ return columns
def get_data(filters):
lead_details = []
diff --git a/erpnext/crm/workspace/crm/crm.json b/erpnext/crm/workspace/crm/crm.json
new file mode 100644
index 0000000..b4fb7d8
--- /dev/null
+++ b/erpnext/crm/workspace/crm/crm.json
@@ -0,0 +1,407 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Territory Wise Sales"
+ }
+ ],
+ "creation": "2020-01-23 14:48:30.183272",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "crm",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "CRM",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Pipeline",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lead",
+ "link_to": "Lead",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Opportunity",
+ "link_to": "Opportunity",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer",
+ "link_to": "Customer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Contact",
+ "link_to": "Contact",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Communication",
+ "link_to": "Communication",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lead Source",
+ "link_to": "Lead Source",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Contract",
+ "link_to": "Contract",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Appointment",
+ "link_to": "Appointment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Newsletter",
+ "link_to": "Newsletter",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Lead",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Lead Details",
+ "link_to": "Lead Details",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Funnel",
+ "link_to": "sales-funnel",
+ "link_type": "Page",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Lead",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Prospects Engaged But Not Converted",
+ "link_to": "Prospects Engaged But Not Converted",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Opportunity",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "First Response Time for Opportunity",
+ "link_to": "First Response Time for Opportunity",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Inactive Customers",
+ "link_to": "Inactive Customers",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Lead",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Campaign Efficiency",
+ "link_to": "Campaign Efficiency",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Lead",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Lead Owner Efficiency",
+ "link_to": "Lead Owner Efficiency",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance Schedule",
+ "link_to": "Maintenance Schedule",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance Visit",
+ "link_to": "Maintenance Visit",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Warranty Claim",
+ "link_to": "Warranty Claim",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Campaign",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Campaign",
+ "link_to": "Campaign",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Email Campaign",
+ "link_to": "Email Campaign",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Social Media Post",
+ "link_to": "Social Media Post",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer Group",
+ "link_to": "Customer Group",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Territory",
+ "link_to": "Territory",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Person",
+ "link_to": "Sales Person",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "SMS Center",
+ "link_to": "SMS Center",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "SMS Log",
+ "link_to": "SMS Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "SMS Settings",
+ "link_to": "SMS Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Email Group",
+ "link_to": "Email Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Twitter Settings",
+ "link_to": "Twitter Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "LinkedIn Settings",
+ "link_to": "LinkedIn Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:36.871352",
+ "modified_by": "Administrator",
+ "module": "CRM",
+ "name": "CRM",
+ "onboarding": "CRM",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Blue",
+ "format": "{} Open",
+ "label": "Lead",
+ "link_to": "Lead",
+ "stats_filter": "{\"status\":\"Open\"}",
+ "type": "DocType"
+ },
+ {
+ "color": "Blue",
+ "format": "{} Assigned",
+ "label": "Opportunity",
+ "link_to": "Opportunity",
+ "stats_filter": "{\"_assign\": [\"like\", '%' + frappe.session.user + '%']}",
+ "type": "DocType"
+ },
+ {
+ "label": "Customer",
+ "link_to": "Customer",
+ "type": "DocType"
+ },
+ {
+ "label": "Sales Analytics",
+ "link_to": "Sales Analytics",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "CRM",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/demo/data/asset.json b/erpnext/demo/data/asset.json
index 23029ca..44db2ae 100644
--- a/erpnext/demo/data/asset.json
+++ b/erpnext/demo/data/asset.json
@@ -4,48 +4,55 @@
"item_code": "Computer",
"gross_purchase_amount": 100000,
"asset_owner": "Company",
- "available_for_use_date": "2017-01-02"
+ "available_for_use_date": "2017-01-02",
+ "location": "Main Location"
},
{
"asset_name": "Macbook Air - 1",
"item_code": "Computer",
"gross_purchase_amount": 60000,
"asset_owner": "Company",
- "available_for_use_date": "2017-10-02"
+ "available_for_use_date": "2017-10-02",
+ "location": "Avg Location"
},
{
"asset_name": "Conferrence Table",
"item_code": "Table",
"gross_purchase_amount": 30000,
"asset_owner": "Company",
- "available_for_use_date": "2018-10-02"
+ "available_for_use_date": "2018-10-02",
+ "location": "Zany Location"
},
{
"asset_name": "Lunch Table",
"item_code": "Table",
"gross_purchase_amount": 20000,
"asset_owner": "Company",
- "available_for_use_date": "2018-06-02"
+ "available_for_use_date": "2018-06-02",
+ "location": "Fletcher Location"
},
{
"asset_name": "ERPNext",
"item_code": "ERP",
"gross_purchase_amount": 100000,
"asset_owner": "Company",
- "available_for_use_date": "2018-09-02"
+ "available_for_use_date": "2018-09-02",
+ "location":"Main Location"
},
{
"asset_name": "Chair 1",
"item_code": "Chair",
"gross_purchase_amount": 10000,
"asset_owner": "Company",
- "available_for_use_date": "2018-07-02"
+ "available_for_use_date": "2018-07-02",
+ "location": "Zany Location"
},
{
"asset_name": "Chair 2",
"item_code": "Chair",
"gross_purchase_amount": 10000,
"asset_owner": "Company",
- "available_for_use_date": "2018-07-02"
+ "available_for_use_date": "2018-07-02",
+ "location": "Avg Location"
}
]
diff --git a/erpnext/demo/data/location.json b/erpnext/demo/data/location.json
new file mode 100644
index 0000000..b521aa0
--- /dev/null
+++ b/erpnext/demo/data/location.json
@@ -0,0 +1,22 @@
+[
+ {
+ "location_name": "Main Location",
+ "latitude": 40.0,
+ "longitude": 20.0
+ },
+ {
+ "location_name": "Avg Location",
+ "latitude": 63.0,
+ "longitude": 99.3
+ },
+ {
+ "location_name": "Zany Location",
+ "latitude": 47.5,
+ "longitude": 10.0
+ },
+ {
+ "location_name": "Fletcher Location",
+ "latitude": 100.90,
+ "longitude": 80
+ }
+]
\ No newline at end of file
diff --git a/erpnext/demo/setup/manufacture.py b/erpnext/demo/setup/manufacture.py
index d384636..7d6b501 100644
--- a/erpnext/demo/setup/manufacture.py
+++ b/erpnext/demo/setup/manufacture.py
@@ -9,6 +9,7 @@
from six import iteritems
def setup_data():
+ import_json("Location")
import_json("Asset Category")
setup_item()
setup_workstation()
diff --git a/erpnext/demo/setup/setup_data.py b/erpnext/demo/setup/setup_data.py
index a395c7c..05ee28a 100644
--- a/erpnext/demo/setup/setup_data.py
+++ b/erpnext/demo/setup/setup_data.py
@@ -134,7 +134,7 @@
salary_component = frappe.get_doc('Salary Component', d.name)
salary_component.append('accounts', dict(
company=erpnext.get_default_company(),
- default_account=frappe.get_value('Account', dict(account_name=('like', 'Salary%')))
+ account=frappe.get_value('Account', dict(account_name=('like', 'Salary%')))
))
salary_component.save()
diff --git a/erpnext/demo/user/purchase.py b/erpnext/demo/user/purchase.py
index 86757df..b7aca79 100644
--- a/erpnext/demo/user/purchase.py
+++ b/erpnext/demo/user/purchase.py
@@ -11,7 +11,7 @@
from erpnext.exceptions import InvalidCurrency
from erpnext.stock.doctype.material_request.material_request import make_request_for_quotation
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import \
- make_supplier_quotation as make_quotation_from_rfq
+ make_supplier_quotation_from_rfq
def work():
frappe.set_user(frappe.db.get_global('demo_purchase_user'))
@@ -44,7 +44,7 @@
rfq = frappe.get_doc('Request for Quotation', rfq.name)
for supplier in rfq.suppliers:
- supplier_quotation = make_quotation_from_rfq(rfq.name, supplier.supplier)
+ supplier_quotation = make_supplier_quotation_from_rfq(rfq.name, for_supplier=supplier.supplier)
supplier_quotation.save()
supplier_quotation.submit()
diff --git a/erpnext/demo/user/stock.py b/erpnext/demo/user/stock.py
index f95a6b8..d44da7d 100644
--- a/erpnext/demo/user/stock.py
+++ b/erpnext/demo/user/stock.py
@@ -79,7 +79,7 @@
if item.qty:
item.qty = item.qty - round(random.randint(1, item.qty))
try:
- stock_reco.insert(ignore_permissions=True)
+ stock_reco.insert(ignore_permissions=True, ignore_mandatory=True)
stock_reco.submit()
frappe.db.commit()
except OpeningEntryAccountError:
diff --git a/erpnext/domains/healthcare.py b/erpnext/domains/healthcare.py
index 8bd4c76..bbeb2c6 100644
--- a/erpnext/domains/healthcare.py
+++ b/erpnext/domains/healthcare.py
@@ -49,6 +49,22 @@
'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/education/api.py b/erpnext/education/api.py
index bf9f221..afa0be9 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -7,7 +7,7 @@
import json
from frappe import _
from frappe.model.mapper import get_mapped_doc
-from frappe.utils import flt, cstr
+from frappe.utils import flt, cstr, getdate
from frappe.email.doctype.email_group.email_group import add_subscribers
def get_course(program):
@@ -36,6 +36,7 @@
student.save()
program_enrollment = frappe.new_doc("Program Enrollment")
program_enrollment.student = student.name
+ program_enrollment.student_category = student.student_category
program_enrollment.student_name = student.title
program_enrollment.program = frappe.db.get_value("Student Applicant", source_name, "program")
frappe.publish_realtime('enroll_student_progress', {"progress": [2, 4]}, user=frappe.session.user)
@@ -67,6 +68,13 @@
:param date: Date.
"""
+ if student_group:
+ academic_year = frappe.db.get_value('Student Group', student_group, 'academic_year')
+ if academic_year:
+ year_start_date, year_end_date = frappe.db.get_value('Academic Year', academic_year, ['year_start_date', 'year_end_date'])
+ if getdate(date) < getdate(year_start_date) or getdate(date) > getdate(year_end_date):
+ frappe.throw(_('Attendance cannot be marked outside of Academic Year {0}').format(academic_year))
+
present = json.loads(students_present)
absent = json.loads(students_absent)
diff --git a/erpnext/education/desk_page/education/education.json b/erpnext/education/desk_page/education/education.json
deleted file mode 100644
index 77ee8ec..0000000
--- a/erpnext/education/desk_page/education/education.json
+++ /dev/null
@@ -1,154 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Student and Instructor",
- "links": "[\n {\n \"label\": \"Student\",\n \"name\": \"Student\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Instructor\",\n \"name\": \"Instructor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Guardian\",\n \"name\": \"Guardian\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group\",\n \"name\": \"Student Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Log\",\n \"name\": \"Student Log\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Masters",
- "links": "[\n {\n \"label\": \"Program\",\n \"name\": \"Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course\",\n \"name\": \"Course\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Topic\",\n \"name\": \"Topic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Room\",\n \"name\": \"Room\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Content Masters",
- "links": "[\n {\n \"label\": \"Article\",\n \"name\": \"Article\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Video\",\n \"name\": \"Video\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz\",\n \"name\": \"Quiz\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"label\": \"Education Settings\",\n \"name\": \"Education Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Category\",\n \"name\": \"Student Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Batch Name\",\n \"name\": \"Student Batch Name\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Grading Scale\",\n \"name\": \"Grading Scale\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Term\",\n \"name\": \"Academic Term\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Year\",\n \"name\": \"Academic Year\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Admission",
- "links": "[\n {\n \"label\": \"Student Applicant\",\n \"name\": \"Student Applicant\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Admission\",\n \"name\": \"Student Admission\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment\",\n \"name\": \"Program Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Fees",
- "links": "[\n {\n \"label\": \"Fee Structure\",\n \"name\": \"Fee Structure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Category\",\n \"name\": \"Fee Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Schedule\",\n \"name\": \"Fee Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fees\",\n \"name\": \"Fees\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Student Fee Collection Report\",\n \"name\": \"Student Fee Collection\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Program wise Fee Collection Report\",\n \"name\": \"Program wise Fee Collection\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Schedule",
- "links": "[\n {\n \"label\": \"Course Schedule\",\n \"name\": \"Course Schedule\",\n \"route\": \"#List/Course Schedule/Calendar\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Attendance",
- "links": "[\n {\n \"label\": \"Student Attendance\",\n \"name\": \"Student Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Leave Application\",\n \"name\": \"Student Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Monthly Attendance Sheet\",\n \"name\": \"Student Monthly Attendance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Absent Student Report\",\n \"name\": \"Absent Student Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Batch-Wise Attendance\",\n \"name\": \"Student Batch-Wise Attendance\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "LMS Activity",
- "links": "[\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Activity\",\n \"name\": \"Course Activity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz Activity\",\n \"name\": \"Quiz Activity\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Assessment",
- "links": "[\n {\n \"label\": \"Assessment Plan\",\n \"name\": \"Assessment Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Group\",\n \"link\": \"Tree/Assessment Group\",\n \"name\": \"Assessment Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result\",\n \"name\": \"Assessment Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Criteria\",\n \"name\": \"Assessment Criteria\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Assessment Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Assessment Result\"\n ],\n \"doctype\": \"Assessment Result\",\n \"is_query_report\": true,\n \"label\": \"Course wise Assessment Report\",\n \"name\": \"Course wise Assessment Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Assessment Result\"\n ],\n \"doctype\": \"Assessment Result\",\n \"is_query_report\": true,\n \"label\": \"Final Assessment Grades\",\n \"name\": \"Final Assessment Grades\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Assessment Plan\"\n ],\n \"doctype\": \"Assessment Plan\",\n \"is_query_report\": true,\n \"label\": \"Assessment Plan Status\",\n \"name\": \"Assessment Plan Status\",\n \"type\": \"report\"\n },\n {\n \"label\": \"Student Report Generation Tool\",\n \"name\": \"Student Report Generation Tool\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Tools",
- "links": "[\n {\n \"label\": \"Student Attendance Tool\",\n \"name\": \"Student Attendance Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result Tool\",\n \"name\": \"Assessment Result Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group Creation Tool\",\n \"name\": \"Student Group Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment Tool\",\n \"name\": \"Program Enrollment Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Other Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Program Enrollment\"\n ],\n \"doctype\": \"Program Enrollment\",\n \"is_query_report\": true,\n \"label\": \"Student and Guardian Contact Details\",\n \"name\": \"Student and Guardian Contact Details\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Domains",
- "charts": [
- {
- "chart_name": "Program Enrollments",
- "label": "Program Enrollments"
- }
- ],
- "creation": "2020-03-02 17:22:57.066401",
- "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": "Education",
- "modified": "2020-07-27 19:35:18.832694",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Education",
- "onboarding": "Education",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "restrict_to_domain": "Education",
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Active",
- "label": "Student",
- "link_to": "Student",
- "stats_filter": "{\n \"enabled\": 1\n}",
- "type": "DocType"
- },
- {
- "color": "#cef6d1",
- "format": "{} Active",
- "label": "Instructor",
- "link_to": "Instructor",
- "stats_filter": "{\n \"status\": \"Active\"\n}",
- "type": "DocType"
- },
- {
- "color": "",
- "format": "",
- "label": "Program",
- "link_to": "Program",
- "stats_filter": "",
- "type": "DocType"
- },
- {
- "label": "Course",
- "link_to": "Course",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Unpaid",
- "label": "Fees",
- "link_to": "Fees",
- "stats_filter": "{\n \"outstanding_amount\": [\"!=\", 0.0]\n}",
- "type": "DocType"
- },
- {
- "label": "Student Monthly Attendance Sheet",
- "link_to": "Student Monthly Attendance Sheet",
- "type": "Report"
- },
- {
- "label": "Course Scheduling Tool",
- "link_to": "Course Scheduling Tool",
- "type": "DocType"
- },
- {
- "label": "Student Attendance Tool",
- "link_to": "Student Attendance Tool",
- "type": "DocType"
- },
- {
- "label": "Dashboard",
- "link_to": "Education",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.js b/erpnext/education/doctype/assessment_plan/assessment_plan.js
index c4c5614..726c0fc 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan.js
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan.js
@@ -30,6 +30,23 @@
frappe.set_route('Form', 'Assessment Result Tool');
}, __('Tools'));
}
+
+ frm.set_query('course', function() {
+ return {
+ query: 'erpnext.education.doctype.program_enrollment.program_enrollment.get_program_courses',
+ filters: {
+ 'program': frm.doc.program
+ }
+ };
+ });
+
+ frm.set_query('academic_term', function() {
+ return {
+ filters: {
+ 'academic_year': frm.doc.academic_year
+ }
+ };
+ });
},
course: function(frm) {
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.json b/erpnext/education/doctype/assessment_plan/assessment_plan.json
index 95ed853..5066fdf 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan.json
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan.json
@@ -12,8 +12,8 @@
"assessment_group",
"grading_scale",
"column_break_2",
- "course",
"program",
+ "course",
"academic_year",
"academic_term",
"section_break_5",
@@ -198,7 +198,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-05-09 14:56:26.746988",
+ "modified": "2020-10-23 15:55:35.076251",
"modified_by": "Administrator",
"module": "Education",
"name": "Assessment Plan",
diff --git a/erpnext/education/doctype/assessment_result/assessment_result.js b/erpnext/education/doctype/assessment_result/assessment_result.js
index 63d1aee..617a873 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result.js
+++ b/erpnext/education/doctype/assessment_result/assessment_result.js
@@ -7,6 +7,23 @@
frm.trigger('setup_chart');
}
frm.set_df_property('details', 'read_only', 1);
+
+ frm.set_query('course', function() {
+ return {
+ query: 'erpnext.education.doctype.program_enrollment.program_enrollment.get_program_courses',
+ filters: {
+ 'program': frm.doc.program
+ }
+ };
+ });
+
+ frm.set_query('academic_term', function() {
+ return {
+ filters: {
+ 'academic_year': frm.doc.academic_year
+ }
+ };
+ });
},
onload: function(frm) {
diff --git a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.js b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.js
index 3cd4512..053f0c2 100644
--- a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.js
+++ b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.js
@@ -128,7 +128,7 @@
result_table.find(`span[data-student=${assessment_result.student}].total-score-grade`).html(assessment_result.grade);
let link_span = result_table.find(`span[data-student=${assessment_result.student}].total-result-link`);
$(link_span).css("display", "block");
- $(link_span).find("a").attr("href", "#Form/Assessment Result/"+assessment_result.name);
+ $(link_span).find("a").attr("href", "/app/assessment-result/"+assessment_result.name);
}
});
}
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.py b/erpnext/education/doctype/course_enrollment/course_enrollment.py
index b082be2..f7aa6e9 100644
--- a/erpnext/education/doctype/course_enrollment/course_enrollment.py
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment.py
@@ -6,9 +6,13 @@
import frappe
from frappe import _
from frappe.model.document import Document
+from frappe.utils import get_link_to_form
from functools import reduce
class CourseEnrollment(Document):
+ def validate(self):
+ self.validate_duplication()
+
def get_progress(self, student):
"""
Returns Progress of given student for a particular course enrollment
@@ -27,13 +31,15 @@
return []
def validate_duplication(self):
- enrollment = frappe.get_all("Course Enrollment", filters={
+ enrollment = frappe.db.exists("Course Enrollment", {
"student": self.student,
"course": self.course,
- "program_enrollment": self.program_enrollment
+ "program_enrollment": self.program_enrollment,
+ "name": ("!=", self.name)
})
if enrollment:
- frappe.throw(_("Student is already enrolled."))
+ frappe.throw(_("Student is already enrolled via Course Enrollment {0}").format(
+ get_link_to_form("Course Enrollment", enrollment)), title=_('Duplicate Entry'))
def add_quiz_activity(self, quiz_name, quiz_response, answers, score, status):
result = {k: ('Correct' if v else 'Wrong') for k,v in answers.items()}
diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
index 5ecace2..e22c7ce 100644
--- a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
+++ b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
@@ -17,8 +17,9 @@
setup_program()
student = create_student({"first_name": "_Test First", "last_name": "_Test Last", "email": "_test_student_1@example.com"})
program_enrollment = student.enroll_in_program("_Test Program")
- course_enrollment = student.enroll_in_course("_Test Course 1", program_enrollment.name)
- make_course_activity(course_enrollment.name, "Article", "_Test Article 1-1")
+ course_enrollment = frappe.db.get_value("Course Enrollment",
+ {"course": "_Test Course 1", "student": student.name, "program_enrollment": program_enrollment.name}, 'name')
+ make_course_activity(course_enrollment, "Article", "_Test Article 1-1")
def test_get_progress(self):
student = get_student("_test_student_1@example.com")
@@ -30,5 +31,14 @@
self.assertTrue(finished in progress)
frappe.db.rollback()
+ def tearDown(self):
+ for entry in frappe.db.get_all("Course Enrollment"):
+ frappe.delete_doc("Course Enrollment", entry.name)
+
+ for entry in frappe.db.get_all("Program Enrollment"):
+ doc = frappe.get_doc("Program Enrollment", entry.name)
+ doc.cancel()
+ doc.delete()
+
diff --git a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js
index 20503f9..d57f46a 100644
--- a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js
+++ b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js
@@ -19,17 +19,22 @@
}
const { course_schedules } = r.message;
if (course_schedules) {
+ const course_schedules_html = course_schedules.map(c => `
+ <tr>
+ <td><a href="/app/course-schedule/${c.name}">${c.name}</a></td>
+ <td>${c.schedule_date}</td>
+ </tr>
+ `).join('');
+
const html = `
- <table class="table table-bordered">
- <caption>${__('Following course schedules were created')}</caption>
- <thead><tr><th>${__("Course")}</th><th>${__("Date")}</th></tr></thead>
- <tbody>
- ${course_schedules.map(
- c => `<tr><td><a href="#Form/Course Schedule/${c.name}">${c.name}</a></td>
- <td>${c.schedule_date}</td></tr>`
- ).join('')}
- </tbody>
- </table>`
+ <table class="table table-bordered">
+ <caption>${__('Following course schedules were created')}</caption>
+ <thead><tr><th>${__("Course")}</th><th>${__("Date")}</th></tr></thead>
+ <tbody>
+ ${course_schedules_html}
+ </tbody>
+ </table>
+ `;
frappe.msgprint(html);
}
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.js b/erpnext/education/doctype/fee_schedule/fee_schedule.js
index 75dd446..0089957 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule.js
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule.js
@@ -1,6 +1,7 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Fee Schedule', {
setup: function(frm) {
frm.add_fetch('fee_structure', 'receivable_account', 'receivable_account');
@@ -8,6 +9,10 @@
frm.add_fetch('fee_structure', 'cost_center', 'cost_center');
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm) {
frm.set_query('receivable_account', function(doc) {
return {
@@ -43,13 +48,15 @@
frm.reload_doc();
}
if (data.progress) {
- let progress_bar = $(cur_frm.dashboard.progress_area).find('.progress-bar');
+ let progress_bar = $(cur_frm.dashboard.progress_area.body).find('.progress-bar');
if (progress_bar) {
$(progress_bar).removeClass('progress-bar-danger').addClass('progress-bar-success progress-bar-striped');
$(progress_bar).css('width', data.progress+'%');
}
}
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js
index b331c6d..310c410 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.js
+++ b/erpnext/education/doctype/fee_structure/fee_structure.js
@@ -1,6 +1,8 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Fee Structure', {
setup: function(frm) {
frm.add_fetch('company', 'default_receivable_account', 'receivable_account');
@@ -8,6 +10,10 @@
frm.add_fetch('company', 'cost_center', 'cost_center');
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm) {
frm.set_query('academic_term', function() {
return {
@@ -35,6 +41,8 @@
}
};
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/education/doctype/fees/fees.js b/erpnext/education/doctype/fees/fees.js
index aaf42b4..ac66acd 100644
--- a/erpnext/education/doctype/fees/fees.js
+++ b/erpnext/education/doctype/fees/fees.js
@@ -1,6 +1,7 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Fees", {
setup: function(frm) {
@@ -9,15 +10,19 @@
frm.add_fetch("fee_structure", "cost_center", "cost_center");
},
- onload: function(frm){
- frm.set_query("academic_term",function(){
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
+ onload: function(frm) {
+ frm.set_query("academic_term", function() {
return{
- "filters":{
+ "filters": {
"academic_year": (frm.doc.academic_year)
}
};
});
- frm.set_query("fee_structure",function(){
+ frm.set_query("fee_structure", function() {
return{
"filters":{
"academic_year": (frm.doc.academic_year)
@@ -45,6 +50,8 @@
if (!frm.doc.posting_date) {
frm.doc.posting_date = frappe.datetime.get_today();
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/education/doctype/instructor/instructor.js b/erpnext/education/doctype/instructor/instructor.js
index abb47ed..24e80fa 100644
--- a/erpnext/education/doctype/instructor/instructor.js
+++ b/erpnext/education/doctype/instructor/instructor.js
@@ -41,5 +41,24 @@
}
};
});
+
+ frm.set_query("academic_term", "instructor_log", function(_doc, cdt, cdn) {
+ let d = locals[cdt][cdn];
+ return {
+ filters: {
+ "academic_year": d.academic_year
+ }
+ };
+ });
+
+ frm.set_query("course", "instructor_log", function(_doc, cdt, cdn) {
+ let d = locals[cdt][cdn];
+ return {
+ query: "erpnext.education.doctype.program_enrollment.program_enrollment.get_program_courses",
+ filters: {
+ "program": d.program
+ }
+ };
+ });
}
});
\ No newline at end of file
diff --git a/erpnext/education/doctype/instructor_log/instructor_log.json b/erpnext/education/doctype/instructor_log/instructor_log.json
index dc9380f..5b9e1f9 100644
--- a/erpnext/education/doctype/instructor_log/instructor_log.json
+++ b/erpnext/education/doctype/instructor_log/instructor_log.json
@@ -1,336 +1,88 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-12-27 08:55:52.680284",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-12-27 08:55:52.680284",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "academic_year",
+ "academic_term",
+ "department",
+ "column_break_3",
+ "program",
+ "course",
+ "student_group",
+ "section_break_8",
+ "other_details"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 1,
- "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": 0,
- "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",
+ "in_list_view": 1,
+ "label": "Academic Year",
+ "options": "Academic Year",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 1,
- "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": 0,
- "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",
+ "in_list_view": 1,
+ "label": "Academic Term",
+ "options": "Academic Term"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "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": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department"
+ },
{
- "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
- },
+ "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": "program",
- "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": "Program",
- "length": 0,
- "no_copy": 0,
- "options": "Program",
- "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": "program",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Program",
+ "options": "Program",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "course",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Course",
+ "options": "Course"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 0,
- "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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "student_group",
+ "fieldtype": "Link",
+ "label": "Student Group",
+ "options": "Student Group"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_8",
- "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_8",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "other_details",
- "fieldtype": "Small 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": "Other details",
- "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": "other_details",
+ "fieldtype": "Small Text",
+ "label": "Other details"
}
- ],
- "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:38:30.902942",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Instructor Log",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "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,
- "track_views": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-10-23 15:15:50.759657",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Instructor Log",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "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/program/test_program.py b/erpnext/education/doctype/program/test_program.py
index 3bcca3a..d753036 100644
--- a/erpnext/education/doctype/program/test_program.py
+++ b/erpnext/education/doctype/program/test_program.py
@@ -49,6 +49,11 @@
self.assertEqual(course[1].name, "_Test Course 2")
frappe.db.rollback()
+ def tearDown(self):
+ for dt in ["Program", "Course", "Topic", "Article"]:
+ for entry in frappe.get_all(dt):
+ frappe.delete_doc(dt, entry.program)
+
def make_program(name):
program = frappe.get_doc({
"doctype": "Program",
@@ -68,7 +73,7 @@
program = frappe.get_doc("Program", program_name)
course_list = [make_course(course_name) for course_name in course_name_list]
for course in course_list:
- program.append("courses", {"course": course})
+ program.append("courses", {"course": course, "required": 1})
program.save()
return program
diff --git a/erpnext/education/doctype/program_course/program_course.json b/erpnext/education/doctype/program_course/program_course.json
index 940358e..dc6b3fc 100644
--- a/erpnext/education/doctype/program_course/program_course.json
+++ b/erpnext/education/doctype/program_course/program_course.json
@@ -17,9 +17,7 @@
"in_list_view": 1,
"label": "Course",
"options": "Course",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fetch_from": "course.course_name",
@@ -27,23 +25,19 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "Course Name",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
- "default": "0",
+ "default": "1",
"fieldname": "required",
"fieldtype": "Check",
"in_list_view": 1,
- "label": "Mandatory",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Mandatory"
}
],
"istable": 1,
"links": [],
- "modified": "2020-06-09 18:56:10.213241",
+ "modified": "2020-09-15 18:14:22.816795",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Course",
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.js b/erpnext/education/doctype/program_enrollment/program_enrollment.js
index e3b3e9f..f9c65fb 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.js
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.js
@@ -2,16 +2,24 @@
// For license information, please see license.txt
-frappe.ui.form.on("Program Enrollment", {
+frappe.ui.form.on('Program Enrollment', {
setup: function(frm) {
frm.add_fetch('fee_structure', 'total_amount', 'amount');
},
- onload: function(frm, cdt, cdn){
- frm.set_query("academic_term", "fees", function(){
- return{
- "filters":{
- "academic_year": (frm.doc.academic_year)
+ onload: function(frm) {
+ frm.set_query('academic_term', function() {
+ return {
+ 'filters':{
+ 'academic_year': frm.doc.academic_year
+ }
+ };
+ });
+
+ frm.set_query('academic_term', 'fees', function() {
+ return {
+ 'filters':{
+ 'academic_year': frm.doc.academic_year
}
};
});
@@ -24,9 +32,9 @@
};
if (frm.doc.program) {
- frm.set_query("course", "courses", function(doc, cdt, cdn) {
- return{
- query: "erpnext.education.doctype.program_enrollment.program_enrollment.get_program_courses",
+ frm.set_query('course', 'courses', function() {
+ return {
+ query: 'erpnext.education.doctype.program_enrollment.program_enrollment.get_program_courses',
filters: {
'program': frm.doc.program
}
@@ -34,9 +42,9 @@
});
}
- frm.set_query("student", function() {
+ frm.set_query('student', function() {
return{
- query: "erpnext.education.doctype.program_enrollment.program_enrollment.get_students",
+ query: 'erpnext.education.doctype.program_enrollment.program_enrollment.get_students',
filters: {
'academic_year': frm.doc.academic_year,
'academic_term': frm.doc.academic_term
@@ -49,14 +57,14 @@
frm.events.get_courses(frm);
if (frm.doc.program) {
frappe.call({
- method: "erpnext.education.api.get_fee_schedule",
+ method: 'erpnext.education.api.get_fee_schedule',
args: {
- "program": frm.doc.program,
- "student_category": frm.doc.student_category
+ 'program': frm.doc.program,
+ 'student_category': frm.doc.student_category
},
callback: function(r) {
- if(r.message) {
- frm.set_value("fees" ,r.message);
+ if (r.message) {
+ frm.set_value('fees' ,r.message);
frm.events.get_courses(frm);
}
}
@@ -65,17 +73,17 @@
},
student_category: function() {
- frappe.ui.form.trigger("Program Enrollment", "program");
+ frappe.ui.form.trigger('Program Enrollment', 'program');
},
get_courses: function(frm) {
- frm.set_value("courses",[]);
+ frm.set_value('courses',[]);
frappe.call({
- method: "get_courses",
+ method: 'get_courses',
doc:frm.doc,
callback: function(r) {
- if(r.message) {
- frm.set_value("courses", r.message);
+ if (r.message) {
+ frm.set_value('courses', r.message);
}
}
})
@@ -84,10 +92,10 @@
frappe.ui.form.on('Program Enrollment Course', {
courses_add: function(frm){
- frm.fields_dict['courses'].grid.get_field('course').get_query = function(doc){
+ frm.fields_dict['courses'].grid.get_field('course').get_query = function(doc) {
var course_list = [];
if(!doc.__islocal) course_list.push(doc.name);
- $.each(doc.courses, function(idx, val){
+ $.each(doc.courses, function(_idx, val) {
if (val.course) course_list.push(val.course);
});
return { filters: [['Course', 'name', 'not in', course_list]] };
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.json b/erpnext/education/doctype/program_enrollment/program_enrollment.json
index 1d8a434..4a00fd0 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.json
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.json
@@ -1,775 +1,218 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "EDU-ENR-.YYYY.-.#####",
- "beta": 0,
- "creation": "2015-12-02 12:58:32.916080",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "EDU-ENR-.YYYY.-.#####",
+ "creation": "2015-12-02 12:58:32.916080",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "student",
+ "student_name",
+ "student_category",
+ "student_batch_name",
+ "school_house",
+ "column_break_4",
+ "program",
+ "academic_year",
+ "academic_term",
+ "enrollment_date",
+ "boarding_student",
+ "enrolled_courses",
+ "courses",
+ "transportation",
+ "mode_of_transportation",
+ "column_break_13",
+ "vehicle_no",
+ "section_break_7",
+ "fees",
+ "amended_from",
+ "image"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "student",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Student",
- "length": 0,
- "no_copy": 0,
- "options": "Student",
- "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",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Student",
+ "options": "Student",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "student.title",
- "fieldname": "student_name",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Student 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
- },
+ "fetch_from": "student.title",
+ "fieldname": "student_name",
+ "fieldtype": "Read Only",
+ "in_global_search": 1,
+ "label": "Student Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "student_category",
- "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": "Student Category",
- "length": 0,
- "no_copy": 0,
- "options": "Student Category",
- "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": "student_category",
+ "fieldtype": "Link",
+ "label": "Student Category",
+ "options": "Student Category"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "student_batch_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Student Batch",
- "length": 0,
- "no_copy": 0,
- "options": "Student Batch Name",
- "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_on_submit": 1,
+ "fieldname": "student_batch_name",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Student Batch",
+ "options": "Student Batch Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "school_house",
- "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": "School House",
- "length": 0,
- "no_copy": 0,
- "options": "School House",
- "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_on_submit": 1,
+ "fieldname": "school_house",
+ "fieldtype": "Link",
+ "label": "School House",
+ "options": "School House"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "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_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 1,
- "in_standard_filter": 1,
- "label": "Program",
- "length": 0,
- "no_copy": 0,
- "options": "Program",
- "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": "program",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Program",
+ "options": "Program",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 1,
- "in_standard_filter": 1,
- "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": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Academic Year",
+ "options": "Academic Year",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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": 0,
- "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"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "enrollment_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": "Enrollment 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
- },
+ "default": "Today",
+ "fieldname": "enrollment_date",
+ "fieldtype": "Date",
+ "label": "Enrollment Date",
+ "reqd": 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 if the Student is residing at the Institute's Hostel.",
- "fieldname": "boarding_student",
- "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": "Boarding Student",
- "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
- },
+ "default": "0",
+ "description": "Check this if the Student is residing at the Institute's Hostel.",
+ "fieldname": "boarding_student",
+ "fieldtype": "Check",
+ "label": "Boarding Student"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "vehicle_no",
- "columns": 0,
- "fieldname": "transportation",
- "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": "Transportation",
- "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,
+ "collapsible_depends_on": "vehicle_no",
+ "fieldname": "transportation",
+ "fieldtype": "Section Break",
+ "label": "Transportation"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mode_of_transportation",
- "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": "Mode of Transportation",
- "length": 0,
- "no_copy": 0,
- "options": "\nWalking\nInstitute's Bus\nPublic Transport\nSelf-Driving Vehicle\nPick/Drop by Guardian",
- "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_on_submit": 1,
+ "fieldname": "mode_of_transportation",
+ "fieldtype": "Select",
+ "label": "Mode of Transportation",
+ "options": "\nWalking\nInstitute's Bus\nPublic Transport\nSelf-Driving Vehicle\nPick/Drop by Guardian"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_13",
- "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_13",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "vehicle_no",
- "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": "Vehicle/Bus 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "vehicle_no",
+ "fieldtype": "Data",
+ "label": "Vehicle/Bus Number"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "enrolled_courses",
- "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": "Enrolled courses",
- "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": "enrolled_courses",
+ "fieldtype": "Section Break",
+ "label": "Enrolled courses"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "courses",
- "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": "Courses",
- "length": 0,
- "no_copy": 0,
- "options": "Program Enrollment 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "courses",
+ "fieldtype": "Table",
+ "label": "Courses",
+ "options": "Program Enrollment Course"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "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,
- "label": "Fees",
- "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_7",
+ "fieldtype": "Section Break",
+ "label": "Fees"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "fees",
- "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": "Fees",
- "length": 0,
- "no_copy": 0,
- "options": "Program Fee",
- "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,
- "width": ""
- },
+ "fieldname": "fees",
+ "fieldtype": "Table",
+ "label": "Fees",
+ "options": "Program Fee"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Program Enrollment",
- "permlevel": 0,
- "print_hide": 1,
- "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": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Program Enrollment",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "image",
- "fieldtype": "Attach Image",
- "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,
- "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 Image",
+ "hidden": 1,
+ "label": "Image"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_field": "image",
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2018-11-07 21:13:06.502279",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Program Enrollment",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "image_field": "image",
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-09-15 18:12:11.988565",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Program Enrollment",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Academics User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "LMS User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Education",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "student_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "restrict_to_domain": "Education",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "student_name"
}
\ No newline at end of file
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py
index 3e27670..d18c0f9 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py
@@ -7,12 +7,15 @@
from frappe import msgprint, _
from frappe.model.document import Document
from frappe.desk.reportview import get_match_cond, get_filters_cond
-from frappe.utils import comma_and
+from frappe.utils import comma_and, get_link_to_form, getdate
import erpnext.www.lms as lms
class ProgramEnrollment(Document):
def validate(self):
self.validate_duplication()
+ self.validate_academic_year()
+ if self.academic_term:
+ self.validate_academic_term()
if not self.student_name:
self.student_name = frappe.db.get_value("Student", self.student, "title")
if not self.courses:
@@ -23,11 +26,34 @@
self.make_fee_records()
self.create_course_enrollments()
+ def validate_academic_year(self):
+ start_date, end_date = frappe.db.get_value("Academic Year", self.academic_year, ["year_start_date", "year_end_date"])
+ if self.enrollment_date:
+ if start_date and getdate(self.enrollment_date) < getdate(start_date):
+ frappe.throw(_("Enrollment Date cannot be before the Start Date of the Academic Year {0}").format(
+ get_link_to_form("Academic Year", self.academic_year)))
+
+ if end_date and getdate(self.enrollment_date) > getdate(end_date):
+ frappe.throw(_("Enrollment Date cannot be after the End Date of the Academic Term {0}").format(
+ get_link_to_form("Academic Year", self.academic_year)))
+
+ def validate_academic_term(self):
+ start_date, end_date = frappe.db.get_value("Academic Term", self.academic_term, ["term_start_date", "term_end_date"])
+ if self.enrollment_date:
+ if start_date and getdate(self.enrollment_date) < getdate(start_date):
+ frappe.throw(_("Enrollment Date cannot be before the Start Date of the Academic Term {0}").format(
+ get_link_to_form("Academic Term", self.academic_term)))
+
+ if end_date and getdate(self.enrollment_date) > getdate(end_date):
+ frappe.throw(_("Enrollment Date cannot be after the End Date of the Academic Term {0}").format(
+ get_link_to_form("Academic Term", self.academic_term)))
+
def validate_duplication(self):
enrollment = frappe.get_all("Program Enrollment", filters={
"student": self.student,
"program": self.program,
"academic_year": self.academic_year,
+ "academic_term": self.academic_term,
"docstatus": ("<", 2),
"name": ("!=", self.name)
})
@@ -61,7 +87,7 @@
fees.submit()
fee_list.append(fees.name)
if fee_list:
- fee_list = ["""<a href="#Form/Fees/%s" target="_blank">%s</a>""" % \
+ fee_list = ["""<a href="/app/Form/Fees/%s" target="_blank">%s</a>""" % \
(fee, fee) for fee in fee_list]
msgprint(_("Fee Records Created - {0}").format(comma_and(fee_list)))
@@ -70,10 +96,9 @@
def create_course_enrollments(self):
student = frappe.get_doc("Student", self.student)
- program = frappe.get_doc("Program", self.program)
- course_list = [course.course for course in program.courses]
+ course_list = [course.course for course in self.courses]
for course_name in course_list:
- student.enroll_in_course(course_name=course_name, program_enrollment=self.name)
+ student.enroll_in_course(course_name=course_name, program_enrollment=self.name, enrollment_date=self.enrollment_date)
def get_all_course_enrollments(self):
course_enrollment_names = frappe.get_list("Course Enrollment", filters={'program_enrollment': self.name})
@@ -99,21 +124,24 @@
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_program_courses(doctype, txt, searchfield, start, page_len, filters):
- if filters.get('program'):
- return frappe.db.sql("""select course, course_name from `tabProgram Course`
- where parent = %(program)s and course like %(txt)s {match_cond}
- order by
- if(locate(%(_txt)s, course), locate(%(_txt)s, course), 99999),
- idx desc,
- `tabProgram Course`.course asc
- limit {start}, {page_len}""".format(
- match_cond=get_match_cond(doctype),
- start=start,
- page_len=page_len), {
- "txt": "%{0}%".format(txt),
- "_txt": txt.replace('%', ''),
- "program": filters['program']
- })
+ if not filters.get('program'):
+ frappe.msgprint(_("Please select a Program first."))
+ return []
+
+ return frappe.db.sql("""select course, course_name from `tabProgram Course`
+ where parent = %(program)s and course like %(txt)s {match_cond}
+ order by
+ if(locate(%(_txt)s, course), locate(%(_txt)s, course), 99999),
+ idx desc,
+ `tabProgram Course`.course asc
+ limit {start}, {page_len}""".format(
+ match_cond=get_match_cond(doctype),
+ start=start,
+ page_len=page_len), {
+ "txt": "%{0}%".format(txt),
+ "_txt": txt.replace('%', ''),
+ "program": filters['program']
+ })
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
index c6cbee1..fec6422 100644
--- a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
@@ -23,4 +23,13 @@
course_enrollments = student.get_all_course_enrollments()
self.assertTrue("_Test Course 1" in course_enrollments.keys())
self.assertTrue("_Test Course 2" in course_enrollments.keys())
- frappe.db.rollback()
\ No newline at end of file
+ frappe.db.rollback()
+
+ def tearDown(self):
+ for entry in frappe.db.get_all("Course Enrollment"):
+ frappe.delete_doc("Course Enrollment", entry.name)
+
+ for entry in frappe.db.get_all("Program Enrollment"):
+ doc = frappe.get_doc("Program Enrollment", entry.name)
+ doc.cancel()
+ doc.delete()
\ No newline at end of file
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 9f8f9f4..8180102 100644
--- a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
+++ b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
@@ -30,7 +30,7 @@
.format(condition), self.as_dict(), as_dict=1)
elif self.get_students_from == "Program Enrollment":
condition2 = 'and student_batch_name=%(student_batch)s' if self.student_batch else " "
- students = frappe.db.sql('''select student, student_name, student_batch_name from `tabProgram Enrollment`
+ students = frappe.db.sql('''select student, student_name, student_batch_name, student_category from `tabProgram Enrollment`
where program=%(program)s and academic_year=%(academic_year)s {0} {1} and docstatus != 2'''
.format(condition, condition2), self.as_dict(), as_dict=1)
@@ -57,6 +57,7 @@
prog_enrollment = frappe.new_doc("Program Enrollment")
prog_enrollment.student = stud.student
prog_enrollment.student_name = stud.student_name
+ prog_enrollment.student_category = stud.student_category
prog_enrollment.program = self.new_program
prog_enrollment.academic_year = self.new_academic_year
prog_enrollment.academic_term = self.new_academic_term
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index e0d7514..81626f1 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -147,7 +147,7 @@
enrollment.save(ignore_permissions=True)
except frappe.exceptions.ValidationError:
enrollment_name = frappe.get_list("Course Enrollment", filters={"student": self.name, "course": course_name, "program_enrollment": program_enrollment})[0].name
- return frappe.get_doc("Program Enrollment", enrollment_name)
+ return frappe.get_doc("Course Enrollment", enrollment_name)
else:
return enrollment
diff --git a/erpnext/education/doctype/student/test_student.py b/erpnext/education/doctype/student/test_student.py
index 8610edb..2e52637 100644
--- a/erpnext/education/doctype/student/test_student.py
+++ b/erpnext/education/doctype/student/test_student.py
@@ -42,6 +42,16 @@
self.assertTrue("_Test Course 2" in course_enrollments.keys())
frappe.db.rollback()
+ def tearDown(self):
+ for entry in frappe.db.get_all("Course Enrollment"):
+ frappe.delete_doc("Course Enrollment", entry.name)
+
+ for entry in frappe.db.get_all("Program Enrollment"):
+ doc = frappe.get_doc("Program Enrollment", entry.name)
+ doc.cancel()
+ doc.delete()
+
+
def create_student(student_dict):
student = get_student(student_dict['email'])
if not student:
diff --git a/erpnext/education/doctype/student_admission/student_admission.json b/erpnext/education/doctype/student_admission/student_admission.json
index 1096888..75f2162 100644
--- a/erpnext/education/doctype/student_admission/student_admission.json
+++ b/erpnext/education/doctype/student_admission/student_admission.json
@@ -51,12 +51,14 @@
"fieldname": "admission_start_date",
"fieldtype": "Date",
"label": "Admission Start Date",
+ "mandatory_depends_on": "enable_admission_application",
"no_copy": 1
},
{
"fieldname": "admission_end_date",
"fieldtype": "Date",
"label": "Admission End Date",
+ "mandatory_depends_on": "enable_admission_application",
"no_copy": 1
},
{
@@ -83,6 +85,7 @@
},
{
"default": "0",
+ "depends_on": "published",
"fieldname": "enable_admission_application",
"fieldtype": "Check",
"label": "Enable Admission Application"
@@ -91,7 +94,7 @@
"has_web_view": 1,
"is_published_field": "published",
"links": [],
- "modified": "2020-06-15 20:18:38.591626",
+ "modified": "2020-09-18 00:14:54.615321",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Admission",
diff --git a/erpnext/education/doctype/student_admission/student_admission.py b/erpnext/education/doctype/student_admission/student_admission.py
index 2781c9c..0febb96 100644
--- a/erpnext/education/doctype/student_admission/student_admission.py
+++ b/erpnext/education/doctype/student_admission/student_admission.py
@@ -19,6 +19,9 @@
if not self.route: #pylint: disable=E0203
self.route = "admissions/" + "-".join(self.title.split(" "))
+ if self.enable_admission_application and not self.program_details:
+ frappe.throw(_("Please add programs to enable admission application."))
+
def get_context(self, context):
context.no_cache = 1
context.show_sidebar = True
diff --git a/erpnext/education/doctype/student_admission/templates/student_admission.html b/erpnext/education/doctype/student_admission/templates/student_admission.html
index e5a9ead..f9ddac0 100644
--- a/erpnext/education/doctype/student_admission/templates/student_admission.html
+++ b/erpnext/education/doctype/student_admission/templates/student_admission.html
@@ -21,7 +21,7 @@
{% elif frappe.utils.getdate(doc.admission_start_date) > today %}
blue"> Application will open
{% else %}
- darkgrey
+ gray
{% endif %}
</span>
</div>
@@ -43,31 +43,35 @@
<thead>
<tr class="active">
<th style="width: 90px">Program/Std.</th>
- <th style="width: 170px">Minumum Age</th>
- <th style="width: 170px">Maximum Age</th>
+ <th style="width: 180px">Description</th>
+ <th style="width: 100px">Minumum Age</th>
+ <th style="width: 100px">Maximum Age</th>
<th style="width: 100px">Application Fee</th>
+ {%- if doc.enable_admission_application and frappe.utils.getdate(doc.admission_start_date) <= today -%}
+ <th style="width: 120px"></th>
+ {% endif %}
</tr>
</thead>
<tbody>
{% for row in program_details %}
<tr>
<td>{{ row.program }}</td>
+ <td><div class="text-muted">{{ row.description if row.description else '' }}</div></td>
<td>{{ row.min_age }}</td>
<td>{{ row.max_age }}</td>
<td>{{ row.application_fee }}</td>
+ {%- if doc.enable_admission_application and frappe.utils.getdate(doc.admission_start_date) <= today -%}
+ <td>
+ <a class='btn btn-sm btn-primary' href='/student-applicant?new=1&student_admission={{doc.name}}&program={{row.program}}&academic_year={{academic_year}}'>
+ {{ _("Apply Now") }}
+ </a>
+ </td>
+ {% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
- {%- if doc.enable_admission_application -%}
- <br>
- <p>
- <a class='btn btn-primary'
- href='/student-applicant?new=1&student_admission={{doc.name}}'>
- {{ _("Apply Now") }}</a>
- </p>
- {% endif %}
{% endblock %}
diff --git a/erpnext/education/doctype/student_admission/templates/student_admission_row.html b/erpnext/education/doctype/student_admission/templates/student_admission_row.html
index e049773..99868d5 100644
--- a/erpnext/education/doctype/student_admission/templates/student_admission_row.html
+++ b/erpnext/education/doctype/student_admission/templates/student_admission_row.html
@@ -1,8 +1,8 @@
-<div class="web-list-item">
+<div class="web-list-item transaction-list-item">
{% set today = frappe.utils.getdate(frappe.utils.nowdate()) %}
- <a href = "{{ doc.route }}/">
+ <a href = "{{ doc.route }}/" class="no-underline">
<div class="row">
- <div class="col-sm-6 text-left small bold" style="margin-top: -3px;"">
+ <div class="col-sm-4 bold">
<span class="indicator
{% if frappe.utils.getdate(doc.admission_end_date) == today %}
red
@@ -11,10 +11,18 @@
{% elif frappe.utils.getdate(doc.admission_start_date) > today %}
blue
{% else %}
- darkgrey
+ gray
{% endif %}
">{{ doc.title }}</span>
</div>
+ <div class="col-sm-2 small">
+ <span class="text-muted">
+ Academic Year
+ </span>
+ <div class="text-muted bold">
+ {{ doc.academic_year }}
+ </div>
+ </div>
<div class="col-sm-3 small">
<span class="text-muted">
Starts on
@@ -27,7 +35,7 @@
<span class="text-muted">
Ends on
</span>
- <div class="bold">
+ <div class=" text-muted bold">
{{ frappe.format_date(doc.admission_end_date) }}
</div>
</div>
diff --git a/erpnext/education/doctype/student_admission_program/student_admission_program.json b/erpnext/education/doctype/student_admission_program/student_admission_program.json
index e9f041e..d14b9a4 100644
--- a/erpnext/education/doctype/student_admission_program/student_admission_program.json
+++ b/erpnext/education/doctype/student_admission_program/student_admission_program.json
@@ -8,6 +8,7 @@
"program",
"min_age",
"max_age",
+ "description",
"column_break_4",
"application_fee",
"applicant_naming_series"
@@ -18,52 +19,47 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Program",
- "options": "Program",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Program"
},
{
"fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "application_fee",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "Application Fee",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Application Fee"
},
{
"fieldname": "applicant_naming_series",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Naming Series (for Student Applicant)",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Naming Series (for Student Applicant)"
},
{
"fieldname": "min_age",
"fieldtype": "Int",
"in_list_view": 1,
- "label": "Minimum Age",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Minimum Age"
},
{
"fieldname": "max_age",
"fieldtype": "Int",
"in_list_view": 1,
- "label": "Maximum Age",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Maximum Age"
+ },
+ {
+ "fetch_from": "program.description",
+ "fetch_if_empty": 1,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
}
],
"istable": 1,
"links": [],
- "modified": "2020-06-10 23:06:30.037404",
+ "modified": "2020-10-05 13:03:42.005985",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Admission Program",
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.json b/erpnext/education/doctype/student_applicant/student_applicant.json
index bca38fb..95f9224 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.json
+++ b/erpnext/education/doctype/student_applicant/student_applicant.json
@@ -11,6 +11,7 @@
"middle_name",
"last_name",
"program",
+ "student_category",
"lms_only",
"paid",
"column_break_8",
@@ -168,6 +169,7 @@
"fieldname": "student_email_id",
"fieldtype": "Data",
"label": "Student Email Address",
+ "options": "Email",
"unique": 1
},
{
@@ -256,12 +258,18 @@
"options": "Student Applicant",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "student_category",
+ "fieldtype": "Link",
+ "label": "Student Category",
+ "options": "Student Category"
}
],
"image_field": "image",
"is_submittable": 1,
"links": [],
- "modified": "2020-09-07 19:31:30.063563",
+ "modified": "2021-03-01 23:00:25.119241",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Applicant",
diff --git a/erpnext/education/doctype/student_attendance/student_attendance.json b/erpnext/education/doctype/student_attendance/student_attendance.json
index 55384b9..e6e46d1 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance.json
+++ b/erpnext/education/doctype/student_attendance/student_attendance.json
@@ -10,6 +10,7 @@
"naming_series",
"student",
"student_name",
+ "student_mobile_number",
"course_schedule",
"student_group",
"column_break_3",
@@ -93,11 +94,19 @@
"options": "Student Attendance",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fetch_from": "student.student_mobile_number",
+ "fieldname": "student_mobile_number",
+ "fieldtype": "Read Only",
+ "label": "Student Mobile Number",
+ "options": "Phone"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-07-08 13:55:42.580181",
+ "modified": "2021-03-24 00:02:11.005895",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Attendance",
diff --git a/erpnext/education/doctype/student_attendance/student_attendance.py b/erpnext/education/doctype/student_attendance/student_attendance.py
index c1b6850..2e9e6cf 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance.py
+++ b/erpnext/education/doctype/student_attendance/student_attendance.py
@@ -6,17 +6,20 @@
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import get_link_to_form
+from frappe.utils import get_link_to_form, getdate, formatdate
+from erpnext import get_default_company
from erpnext.education.api import get_student_group_students
-
+from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
class StudentAttendance(Document):
def validate(self):
self.validate_mandatory()
+ self.validate_date()
self.set_date()
self.set_student_group()
self.validate_student()
self.validate_duplication()
+ self.validate_is_holiday()
def set_date(self):
if self.course_schedule:
@@ -27,6 +30,18 @@
frappe.throw(_('{0} or {1} is mandatory').format(frappe.bold('Student Group'),
frappe.bold('Course Schedule')), title=_('Mandatory Fields'))
+ def validate_date(self):
+ if not self.leave_application and getdate(self.date) > getdate():
+ frappe.throw(_('Attendance cannot be marked for future dates.'))
+
+ if self.student_group:
+ academic_year = frappe.db.get_value('Student Group', self.student_group, 'academic_year')
+ if academic_year:
+ year_start_date, year_end_date = frappe.db.get_value('Academic Year', academic_year, ['year_start_date', 'year_end_date'])
+ if year_start_date and year_end_date:
+ if getdate(self.date) < getdate(year_start_date) or getdate(self.date) > getdate(year_end_date):
+ frappe.throw(_('Attendance cannot be marked outside of Academic Year {0}').format(academic_year))
+
def set_student_group(self):
if self.course_schedule:
self.student_group = frappe.db.get_value('Course Schedule', self.course_schedule, 'student_group')
@@ -63,6 +78,21 @@
})
if attendance_record:
- record = get_link_to_form('Attendance Record', attendance_record)
+ record = get_link_to_form('Student Attendance', attendance_record)
frappe.throw(_('Student Attendance record {0} already exists against the Student {1}')
.format(record, frappe.bold(self.student)), title=_('Duplicate Entry'))
+
+ def validate_is_holiday(self):
+ holiday_list = get_holiday_list()
+ if is_holiday(holiday_list, self.date):
+ frappe.throw(_('Attendance cannot be marked for {0} as it is a holiday.').format(
+ frappe.bold(formatdate(self.date))))
+
+def get_holiday_list(company=None):
+ if not company:
+ company = get_default_company() or frappe.get_all('Company')[0].name
+
+ holiday_list = frappe.get_cached_value('Company', company, 'default_holiday_list')
+ if not holiday_list:
+ frappe.throw(_('Please set a default Holiday List for Company {0}').format(frappe.bold(get_default_company())))
+ return holiday_list
diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
index 0384505..b59d848 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
@@ -52,6 +52,8 @@
},
date: function(frm) {
+ if (frm.doc.date > frappe.datetime.get_today())
+ frappe.throw(__("Cannot mark attendance for future dates."));
frm.trigger("student_group");
},
@@ -133,8 +135,8 @@
return !stud.disabled && !stud.checked;
});
- frappe.confirm(__("Do you want to update attendance?<br>Present: {0}\
- <br>Absent: {1}", [students_present.length, students_absent.length]),
+ frappe.confirm(__("Do you want to update attendance? <br> Present: {0} <br> Absent: {1}",
+ [students_present.length, students_absent.length]),
function() { //ifyes
if(!frappe.request.ajax_count) {
frappe.call({
diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.json b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.json
index 26b28b3..ee8f484 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.json
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.json
@@ -1,333 +1,118 @@
{
- "allow_copy": 1,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-11-16 17:12:46.437539",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_copy": 1,
+ "creation": "2016-11-16 17:12:46.437539",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "based_on",
+ "group_based_on",
+ "column_break_2",
+ "student_group",
+ "academic_year",
+ "academic_term",
+ "course_schedule",
+ "date",
+ "attendance",
+ "students_html"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "based_on",
- "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": "Based On",
- "length": 0,
- "no_copy": 0,
- "options": "Student Group\nCourse 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "based_on",
+ "fieldtype": "Select",
+ "label": "Based On",
+ "options": "Student Group\nCourse Schedule"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Batch",
- "depends_on": "eval:doc.based_on == \"Student Group\"",
- "fieldname": "group_based_on",
- "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": "Group Based On",
- "length": 0,
- "no_copy": 0,
- "options": "Batch\nCourse\nActivity",
- "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
- },
+ "default": "Batch",
+ "depends_on": "eval:doc.based_on == \"Student Group\"",
+ "fieldname": "group_based_on",
+ "fieldtype": "Select",
+ "label": "Group Based On",
+ "options": "Batch\nCourse\nActivity"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.based_on ==\"Student Group\"",
- "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,
- "unique": 0
- },
+ "depends_on": "eval:doc.based_on ==\"Student Group\"",
+ "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,
- "depends_on": "eval:doc.based_on ==\"Course Schedule\"",
- "fieldname": "course_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": "Course Schedule",
- "length": 0,
- "no_copy": 0,
- "options": "Course 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,
- "unique": 0
- },
+ "depends_on": "eval:doc.based_on ==\"Course Schedule\"",
+ "fieldname": "course_schedule",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Course Schedule",
+ "options": "Course Schedule",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.based_on ==\"Student Group\"",
- "fieldname": "date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.based_on ==\"Student Group\"",
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: (doc.course_schedule \n|| (doc.student_group && doc.date))",
- "fieldname": "attendance",
- "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": "Attendance",
- "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
- },
+ "depends_on": "eval: (doc.course_schedule \n|| (doc.student_group && doc.date))",
+ "fieldname": "attendance",
+ "fieldtype": "Section Break",
+ "label": "Attendance"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "students_html",
- "fieldtype": "HTML",
- "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": "Students HTML",
- "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": "students_html",
+ "fieldtype": "HTML",
+ "label": "Students HTML"
+ },
+ {
+ "fetch_from": "student_group.academic_year",
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "label": "Academic Year",
+ "options": "Academic Year",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "student_group.academic_term",
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "label": "Academic Term",
+ "options": "Academic Term",
+ "read_only": 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,
- "modified": "2017-11-10 18:55:36.168044",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Student Attendance Tool",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "hide_toolbar": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2020-10-23 17:52:28.078971",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Attendance Tool",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 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": "Instructor",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
+ "create": 1,
+ "read": 1,
+ "role": "Instructor",
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 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": 0,
- "track_seen": 0
+ ],
+ "restrict_to_domain": "Education",
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
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 be26440..028db91 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
@@ -20,10 +20,10 @@
student_list = frappe.get_list("Student Group Student", fields=["student", "student_name", "group_roll_number"] , \
filters={"parent": student_group, "active": 1}, order_by= "group_roll_number")
- if not student_list:
- student_list = frappe.get_list("Student Group Student", fields=["student", "student_name", "group_roll_number"] ,
+ if not student_list:
+ student_list = frappe.get_list("Student Group Student", fields=["student", "student_name", "group_roll_number"] ,
filters={"parent": student_group, "active": 1}, order_by= "group_roll_number")
-
+
if course_schedule:
student_attendance_list= frappe.db.sql('''select student, status from `tabStudent Attendance` where \
course_schedule= %s''', (course_schedule), as_dict=1)
@@ -32,7 +32,7 @@
student_group= %s and date= %s and \
(course_schedule is Null or course_schedule='')''',
(student_group, date), as_dict=1)
-
+
for attendance in student_attendance_list:
for student in student_list:
if student.student == attendance.student:
diff --git a/erpnext/education/doctype/student_leave_application/student_leave_application.json b/erpnext/education/doctype/student_leave_application/student_leave_application.json
index ad53976..31b3da2 100644
--- a/erpnext/education/doctype/student_leave_application/student_leave_application.json
+++ b/erpnext/education/doctype/student_leave_application/student_leave_application.json
@@ -11,6 +11,7 @@
"column_break_3",
"from_date",
"to_date",
+ "total_leave_days",
"section_break_5",
"attendance_based_on",
"student_group",
@@ -110,11 +111,17 @@
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_leave_days",
+ "fieldtype": "Float",
+ "label": "Total Leave Days",
+ "read_only": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-07-08 13:22:38.329002",
+ "modified": "2020-09-21 18:10:24.440669",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Leave Application",
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 c8841c9..ef67012 100644
--- a/erpnext/education/doctype/student_leave_application/student_leave_application.py
+++ b/erpnext/education/doctype/student_leave_application/student_leave_application.py
@@ -6,11 +6,14 @@
import frappe
from frappe import _
from datetime import timedelta
-from frappe.utils import get_link_to_form, getdate
+from frappe.utils import get_link_to_form, getdate, date_diff, flt
+from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from frappe.model.document import Document
class StudentLeaveApplication(Document):
def validate(self):
+ self.validate_holiday_list()
self.validate_duplicate()
self.validate_from_to_dates('from_date', 'to_date')
@@ -39,10 +42,19 @@
frappe.throw(_('Leave application {0} already exists against the student {1}')
.format(link, frappe.bold(self.student)), title=_('Duplicate Entry'))
+ def validate_holiday_list(self):
+ holiday_list = get_holiday_list()
+ self.total_leave_days = get_number_of_leave_days(self.from_date, self.to_date, holiday_list)
+
def update_attendance(self):
+ holiday_list = get_holiday_list()
+
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
date = dt.strftime('%Y-%m-%d')
+ if is_holiday(holiday_list, date):
+ continue
+
attendance = frappe.db.exists('Student Attendance', {
'student': self.student,
'date': date,
@@ -89,3 +101,19 @@
def daterange(start_date, end_date):
for n in range(int ((end_date - start_date).days)+1):
yield start_date + timedelta(n)
+
+def get_number_of_leave_days(from_date, to_date, holiday_list):
+ number_of_days = date_diff(to_date, from_date) + 1
+
+ holidays = frappe.db.sql("""
+ SELECT
+ COUNT(DISTINCT holiday_date)
+ FROM `tabHoliday` h1,`tabHoliday List` h2
+ WHERE
+ h1.parent = h2.name and
+ h1.holiday_date between %s and %s and
+ h2.name = %s""", (from_date, to_date, holiday_list))[0][0]
+
+ number_of_days = flt(number_of_days) - flt(holidays)
+
+ return number_of_days
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 e9b568a..fcdd428 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
@@ -5,13 +5,15 @@
import frappe
import unittest
-from frappe.utils import getdate, add_days
+from frappe.utils import getdate, add_days, add_months
+from erpnext import get_default_company
from erpnext.education.doctype.student_group.test_student_group import get_random_group
from erpnext.education.doctype.student.test_student import create_student
class TestStudentLeaveApplication(unittest.TestCase):
def setUp(self):
frappe.db.sql("""delete from `tabStudent Leave Application`""")
+ create_holiday_list()
def test_attendance_record_creation(self):
leave_application = create_leave_application()
@@ -35,20 +37,45 @@
attendance_status = frappe.db.get_value('Student Attendance', {'leave_application': leave_application.name}, 'docstatus')
self.assertTrue(attendance_status, 2)
+ def test_holiday(self):
+ today = getdate()
+ leave_application = create_leave_application(from_date=today, to_date= add_days(today, 1), submit=0)
-def create_leave_application(from_date=None, to_date=None, mark_as_present=0):
+ # holiday list validation
+ company = get_default_company() or frappe.get_all('Company')[0].name
+ frappe.db.set_value('Company', company, 'default_holiday_list', '')
+ self.assertRaises(frappe.ValidationError, leave_application.save)
+
+ frappe.db.set_value('Company', company, 'default_holiday_list', 'Test Holiday List for Student')
+ leave_application.save()
+
+ leave_application.reload()
+ self.assertEqual(leave_application.total_leave_days, 1)
+
+ # check no attendance record created for a holiday
+ leave_application.submit()
+ self.assertIsNone(frappe.db.exists('Student Attendance', {'leave_application': leave_application.name, 'date': add_days(today, 1)}))
+
+ def tearDown(self):
+ company = get_default_company() or frappe.get_all('Company')[0].name
+ frappe.db.set_value('Company', company, 'default_holiday_list', '_Test Holiday List')
+
+
+def create_leave_application(from_date=None, to_date=None, mark_as_present=0, submit=1):
student = get_student()
- leave_application = frappe.get_doc({
- 'doctype': 'Student Leave Application',
- 'student': student.name,
- 'attendance_based_on': 'Student Group',
- 'student_group': get_random_group().name,
- 'from_date': from_date if from_date else getdate(),
- 'to_date': from_date if from_date else getdate(),
- 'mark_as_present': mark_as_present
- }).insert()
- leave_application.submit()
+ leave_application = frappe.new_doc('Student Leave Application')
+ leave_application.student = student.name
+ leave_application.attendance_based_on = 'Student Group'
+ leave_application.student_group = get_random_group().name
+ leave_application.from_date = from_date if from_date else getdate()
+ leave_application.to_date = from_date if from_date else getdate()
+ leave_application.mark_as_present = mark_as_present
+
+ if submit:
+ leave_application.insert()
+ leave_application.submit()
+
return leave_application
def create_student_attendance(date=None, status=None):
@@ -67,4 +94,22 @@
email='test_student@gmail.com',
first_name='Test',
last_name='Student'
- ))
\ No newline at end of file
+ ))
+
+def create_holiday_list():
+ holiday_list = 'Test Holiday List for Student'
+ today = getdate()
+ if not frappe.db.exists('Holiday List', holiday_list):
+ frappe.get_doc(dict(
+ doctype = 'Holiday List',
+ holiday_list_name = holiday_list,
+ from_date = add_months(today, -6),
+ to_date = add_months(today, 6),
+ holidays = [
+ dict(holiday_date=add_days(today, 1), description = 'Test')
+ ]
+ )).insert()
+
+ company = get_default_company() or frappe.get_all('Company')[0].name
+ frappe.db.set_value('Company', company, 'default_holiday_list', holiday_list)
+ return holiday_list
\ No newline at end of file
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 4e57cc6..c3487cc 100644
--- a/erpnext/education/report/absent_student_report/absent_student_report.py
+++ b/erpnext/education/report/absent_student_report/absent_student_report.py
@@ -3,8 +3,10 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cstr, cint, getdate
+from frappe.utils import formatdate
from frappe import msgprint, _
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
+from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
def execute(filters=None):
if not filters: filters = {}
@@ -15,6 +17,11 @@
columns = get_columns(filters)
date = filters.get("date")
+ holiday_list = get_holiday_list()
+ if is_holiday(holiday_list, filters.get("date")):
+ msgprint(_("No attendance has been marked for {0} as it is a Holiday").format(frappe.bold(formatdate(filters.get("date")))))
+
+
absent_students = get_absent_students(date)
leave_applicants = get_leave_applications(date)
if absent_students:
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 c65d233..7793dcf 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
@@ -3,8 +3,10 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cstr, cint, getdate
+from frappe.utils import formatdate
from frappe import msgprint, _
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
+from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
def execute(filters=None):
if not filters: filters = {}
@@ -12,6 +14,10 @@
if not filters.get("date"):
msgprint(_("Please select date"), raise_exception=1)
+ holiday_list = get_holiday_list()
+ if is_holiday(holiday_list, filters.get("date")):
+ msgprint(_("No attendance has been marked for {0} as it is a Holiday").format(frappe.bold(formatdate(filters.get("date")))))
+
columns = get_columns(filters)
active_student_group = get_active_student_group()
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 d820bfb..04dc8c0 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
@@ -7,6 +7,8 @@
from frappe import msgprint, _
from calendar import monthrange
from erpnext.education.api import get_student_group_students
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
+from erpnext.support.doctype.issue.issue import get_holidays
def execute(filters=None):
if not filters: filters = {}
@@ -19,26 +21,32 @@
students_list = get_students_list(students)
att_map = get_attendance_list(from_date, to_date, filters.get("student_group"), students_list)
data = []
+
for stud in students:
row = [stud.student, stud.student_name]
student_status = frappe.db.get_value("Student", stud.student, "enabled")
date = from_date
total_p = total_a = 0.0
+
for day in range(total_days_in_month):
status="None"
+
if att_map.get(stud.student):
status = att_map.get(stud.student).get(date, "None")
elif not student_status:
status = "Inactive"
else:
status = "None"
- status_map = {"Present": "P", "Absent": "A", "None": "", "Inactive":"-"}
+
+ status_map = {"Present": "P", "Absent": "A", "None": "", "Inactive":"-", "Holiday":"H"}
row.append(status_map[status])
+
if status == "Present":
total_p += 1
elif status == "Absent":
total_a += 1
date = add_days(date, 1)
+
row += [total_p, total_a]
data.append(row)
return columns, data
@@ -63,14 +71,19 @@
and date between %s and %s
order by student, date''',
(student_group, from_date, to_date), as_dict=1)
+
att_map = {}
students_with_leave_application = get_students_with_leave_application(from_date, to_date, students_list)
for d in attendance_list:
att_map.setdefault(d.student, frappe._dict()).setdefault(d.date, "")
+
if students_with_leave_application.get(d.date) and d.student in students_with_leave_application.get(d.date):
att_map[d.student][d.date] = "Present"
else:
att_map[d.student][d.date] = d.status
+
+ att_map = mark_holidays(att_map, from_date, to_date, students_list)
+
return att_map
def get_students_with_leave_application(from_date, to_date, students_list):
@@ -108,3 +121,14 @@
if not year_list:
year_list = [getdate().year]
return "\n".join(str(year) for year in year_list)
+
+def mark_holidays(att_map, from_date, to_date, students_list):
+ holiday_list = get_holiday_list()
+ holidays = get_holidays(holiday_list)
+
+ for dt in daterange(getdate(from_date), getdate(to_date)):
+ if dt in holidays:
+ for student in students_list:
+ att_map.setdefault(student, frappe._dict()).setdefault(dt, "Holiday")
+
+ return att_map
diff --git a/erpnext/education/web_form/student_applicant/student_applicant.json b/erpnext/education/web_form/student_applicant/student_applicant.json
index 1810f07..7b4eaa1 100644
--- a/erpnext/education/web_form/student_applicant/student_applicant.json
+++ b/erpnext/education/web_form/student_applicant/student_applicant.json
@@ -8,6 +8,7 @@
"allow_print": 0,
"amount": 0.0,
"amount_based_on_field": 0,
+ "apply_document_permissions": 0,
"creation": "2016-09-22 13:10:10.792735",
"doc_type": "Student Applicant",
"docstatus": 0,
@@ -16,7 +17,7 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
- "modified": "2020-06-11 22:53:45.875310",
+ "modified": "2020-10-07 23:13:07.814941",
"modified_by": "Administrator",
"module": "Education",
"name": "student-applicant",
@@ -69,19 +70,7 @@
"show_in_filter": 0
},
{
- "allow_read_on_all_link_options": 0,
- "fieldname": "image",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Image",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0,
- "show_in_filter": 0
- },
- {
- "allow_read_on_all_link_options": 0,
+ "allow_read_on_all_link_options": 1,
"fieldname": "program",
"fieldtype": "Link",
"hidden": 0,
@@ -94,7 +83,7 @@
"show_in_filter": 0
},
{
- "allow_read_on_all_link_options": 0,
+ "allow_read_on_all_link_options": 1,
"fieldname": "academic_year",
"fieldtype": "Link",
"hidden": 0,
@@ -107,6 +96,19 @@
"show_in_filter": 0
},
{
+ "allow_read_on_all_link_options": 1,
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Academic Term",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Academic Term",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
"allow_read_on_all_link_options": 0,
"fieldname": "date_of_birth",
"fieldtype": "Date",
@@ -119,6 +121,19 @@
"show_in_filter": 0
},
{
+ "allow_read_on_all_link_options": 1,
+ "fieldname": "gender",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Gender",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Gender",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
"allow_read_on_all_link_options": 0,
"fieldname": "blood_group",
"fieldtype": "Select",
@@ -140,7 +155,7 @@
"max_length": 0,
"max_value": 0,
"read_only": 0,
- "reqd": 0,
+ "reqd": 1,
"show_in_filter": 0
},
{
@@ -157,7 +172,7 @@
},
{
"allow_read_on_all_link_options": 0,
- "default": "INDIAN",
+ "default": "",
"fieldname": "nationality",
"fieldtype": "Data",
"hidden": 0,
@@ -207,19 +222,6 @@
},
{
"allow_read_on_all_link_options": 0,
- "fieldname": "guardians",
- "fieldtype": "Table",
- "hidden": 0,
- "label": "Guardians",
- "max_length": 0,
- "max_value": 0,
- "options": "Student Guardian",
- "read_only": 0,
- "reqd": 0,
- "show_in_filter": 0
- },
- {
- "allow_read_on_all_link_options": 0,
"fieldname": "siblings",
"fieldtype": "Table",
"hidden": 0,
diff --git a/erpnext/education/workspace/education/education.json b/erpnext/education/workspace/education/education.json
new file mode 100644
index 0000000..bf74961
--- /dev/null
+++ b/erpnext/education/workspace/education/education.json
@@ -0,0 +1,701 @@
+{
+ "category": "Domains",
+ "charts": [
+ {
+ "chart_name": "Program Enrollments",
+ "label": "Program Enrollments"
+ }
+ ],
+ "creation": "2020-03-02 17:22:57.066401",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "education",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Education",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student and Instructor",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student",
+ "link_to": "Student",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Instructor",
+ "link_to": "Instructor",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Guardian",
+ "link_to": "Guardian",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Group",
+ "link_to": "Student Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Log",
+ "link_to": "Student Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Masters",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Program",
+ "link_to": "Program",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course",
+ "link_to": "Course",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Topic",
+ "link_to": "Topic",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Room",
+ "link_to": "Room",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Content Masters",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Article",
+ "link_to": "Article",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Video",
+ "link_to": "Video",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quiz",
+ "link_to": "Quiz",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Education Settings",
+ "link_to": "Education Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Category",
+ "link_to": "Student Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Batch Name",
+ "link_to": "Student Batch Name",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Grading Scale",
+ "link_to": "Grading Scale",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Academic Term",
+ "link_to": "Academic Term",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Academic Year",
+ "link_to": "Academic Year",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Admission",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Applicant",
+ "link_to": "Student Applicant",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Admission",
+ "link_to": "Student Admission",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Program Enrollment",
+ "link_to": "Program Enrollment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Enrollment",
+ "link_to": "Course Enrollment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fees",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fee Structure",
+ "link_to": "Fee Structure",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fee Category",
+ "link_to": "Fee Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fee Schedule",
+ "link_to": "Fee Schedule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fees",
+ "link_to": "Fees",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Fees",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student Fee Collection Report",
+ "link_to": "Student Fee Collection",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Fees",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Program wise Fee Collection Report",
+ "link_to": "Program wise Fee Collection",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Schedule",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Schedule",
+ "link_to": "Course Schedule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Scheduling Tool",
+ "link_to": "Course Scheduling Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Attendance",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Attendance",
+ "link_to": "Student Attendance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Leave Application",
+ "link_to": "Student Leave Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Student Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student Monthly Attendance Sheet",
+ "link_to": "Student Monthly Attendance Sheet",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Student Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Absent Student Report",
+ "link_to": "Absent Student Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Student Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student Batch-Wise Attendance",
+ "link_to": "Student Batch-Wise Attendance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "LMS Activity",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Enrollment",
+ "link_to": "Course Enrollment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Activity",
+ "link_to": "Course Activity",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quiz Activity",
+ "link_to": "Quiz Activity",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Plan",
+ "link_to": "Assessment Plan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Group",
+ "link_to": "Assessment Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Result",
+ "link_to": "Assessment Result",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Criteria",
+ "link_to": "Assessment Criteria",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Assessment Result",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Course wise Assessment Report",
+ "link_to": "Course wise Assessment Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Assessment Result",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Final Assessment Grades",
+ "link_to": "Final Assessment Grades",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Assessment Plan",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Assessment Plan Status",
+ "link_to": "Assessment Plan Status",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Report Generation Tool",
+ "link_to": "Student Report Generation Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tools",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Attendance Tool",
+ "link_to": "Student Attendance Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Result Tool",
+ "link_to": "Assessment Result Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Group Creation Tool",
+ "link_to": "Student Group Creation Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Program Enrollment Tool",
+ "link_to": "Program Enrollment Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Scheduling Tool",
+ "link_to": "Course Scheduling Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Other Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Program Enrollment",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student and Guardian Contact Details",
+ "link_to": "Student and Guardian Contact Details",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:37.448989",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Education",
+ "onboarding": "Education",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "restrict_to_domain": "Education",
+ "shortcuts": [
+ {
+ "color": "Grey",
+ "format": "{} Active",
+ "label": "Student",
+ "link_to": "Student",
+ "stats_filter": "{\n \"enabled\": 1\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "format": "{} Active",
+ "label": "Instructor",
+ "link_to": "Instructor",
+ "stats_filter": "{\n \"status\": \"Active\"\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "",
+ "format": "",
+ "label": "Program",
+ "link_to": "Program",
+ "stats_filter": "",
+ "type": "DocType"
+ },
+ {
+ "label": "Course",
+ "link_to": "Course",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "format": "{} Unpaid",
+ "label": "Fees",
+ "link_to": "Fees",
+ "stats_filter": "{\n \"outstanding_amount\": [\"!=\", 0.0]\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Student Monthly Attendance Sheet",
+ "link_to": "Student Monthly Attendance Sheet",
+ "type": "Report"
+ },
+ {
+ "label": "Course Scheduling Tool",
+ "link_to": "Course Scheduling Tool",
+ "type": "DocType"
+ },
+ {
+ "label": "Student Attendance Tool",
+ "link_to": "Student Attendance Tool",
+ "type": "DocType"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Education",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index d59f909..f0a05ed 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -2,12 +2,13 @@
import frappe
from frappe import _
import json
-from frappe.utils import cstr, cint, nowdate, flt
+from frappe.utils import cstr, cint, nowdate, getdate, flt, get_request_session, get_datetime
from erpnext.erpnext_integrations.utils import validate_webhooks_request
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import get_shopify_url, get_header
@frappe.whitelist(allow_guest=True)
@validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret')
@@ -18,7 +19,7 @@
dump_request_data(order, event)
-def sync_sales_order(order, request_id=None):
+def sync_sales_order(order, request_id=None, old_order_sync=False):
frappe.set_user('Administrator')
shopify_settings = frappe.get_doc("Shopify Settings")
frappe.flags.request_id = request_id
@@ -27,7 +28,7 @@
try:
validate_customer(order, shopify_settings)
validate_item(order, shopify_settings)
- create_order(order, shopify_settings)
+ create_order(order, shopify_settings, old_order_sync=old_order_sync)
except Exception as e:
make_shopify_log(status="Error", exception=e)
@@ -77,13 +78,13 @@
if item.get("product_id") and not frappe.db.get_value("Item", {"shopify_product_id": item.get("product_id")}, "name"):
sync_item_from_shopify(shopify_settings, item)
-def create_order(order, shopify_settings, company=None):
+def create_order(order, shopify_settings, old_order_sync=False, company=None):
so = create_sales_order(order, shopify_settings, company)
if so:
if order.get("financial_status") == "paid":
- create_sales_invoice(order, shopify_settings, so)
+ create_sales_invoice(order, shopify_settings, so, old_order_sync=old_order_sync)
- if order.get("fulfillments"):
+ if order.get("fulfillments") and not old_order_sync:
create_delivery_note(order, shopify_settings, so)
def create_sales_order(shopify_order, shopify_settings, company=None):
@@ -92,7 +93,7 @@
so = frappe.db.get_value("Sales Order", {"shopify_order_id": shopify_order.get("id")}, "name")
if not so:
- items = get_order_items(shopify_order.get("line_items"), shopify_settings)
+ items = get_order_items(shopify_order.get("line_items"), shopify_settings, getdate(shopify_order.get('created_at')))
if not items:
message = 'Following items exists in the shopify order but relevant records were not found in the shopify Product master'
@@ -106,8 +107,10 @@
"doctype": "Sales Order",
"naming_series": shopify_settings.sales_order_series or "SO-Shopify-",
"shopify_order_id": shopify_order.get("id"),
+ "shopify_order_number": shopify_order.get("name"),
"customer": customer or shopify_settings.default_customer,
- "delivery_date": nowdate(),
+ "transaction_date": getdate(shopify_order.get("created_at")) or nowdate(),
+ "delivery_date": getdate(shopify_order.get("created_at")) or nowdate(),
"company": shopify_settings.company,
"selling_price_list": shopify_settings.price_list,
"ignore_pricing_rule": 1,
@@ -132,32 +135,42 @@
frappe.db.commit()
return so
-def create_sales_invoice(shopify_order, shopify_settings, so):
+def create_sales_invoice(shopify_order, shopify_settings, so, old_order_sync=False):
if not frappe.db.get_value("Sales Invoice", {"shopify_order_id": shopify_order.get("id")}, "name")\
and so.docstatus==1 and not so.per_billed and cint(shopify_settings.sync_sales_invoice):
+ if old_order_sync:
+ posting_date = getdate(shopify_order.get('created_at'))
+ else:
+ posting_date = nowdate()
+
si = make_sales_invoice(so.name, ignore_permissions=True)
si.shopify_order_id = shopify_order.get("id")
+ si.shopify_order_number = shopify_order.get("name")
+ si.set_posting_time = 1
+ si.posting_date = posting_date
+ si.due_date = posting_date
si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-"
si.flags.ignore_mandatory = True
set_cost_center(si.items, shopify_settings.cost_center)
si.insert(ignore_mandatory=True)
si.submit()
- make_payament_entry_against_sales_invoice(si, shopify_settings)
+ make_payament_entry_against_sales_invoice(si, shopify_settings, posting_date)
frappe.db.commit()
def set_cost_center(items, cost_center):
for item in items:
item.cost_center = cost_center
-def make_payament_entry_against_sales_invoice(doc, shopify_settings):
+def make_payament_entry_against_sales_invoice(doc, shopify_settings, posting_date=None):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
- payemnt_entry = get_payment_entry(doc.doctype, doc.name, bank_account=shopify_settings.cash_bank_account)
- payemnt_entry.flags.ignore_mandatory = True
- payemnt_entry.reference_no = doc.name
- payemnt_entry.reference_date = nowdate()
- payemnt_entry.insert(ignore_permissions=True)
- payemnt_entry.submit()
+ payment_entry = get_payment_entry(doc.doctype, doc.name, bank_account=shopify_settings.cash_bank_account)
+ payment_entry.flags.ignore_mandatory = True
+ payment_entry.reference_no = doc.name
+ payment_entry.posting_date = posting_date or nowdate()
+ payment_entry.reference_date = posting_date or nowdate()
+ payment_entry.insert(ignore_permissions=True)
+ payment_entry.submit()
def create_delivery_note(shopify_order, shopify_settings, so):
if not cint(shopify_settings.sync_delivery_note):
@@ -169,6 +182,9 @@
dn = make_delivery_note(so.name)
dn.shopify_order_id = fulfillment.get("order_id")
+ dn.shopify_order_number = shopify_order.get("name")
+ dn.set_posting_time = 1
+ dn.posting_date = getdate(fulfillment.get("created_at"))
dn.shopify_fulfillment_id = fulfillment.get("id")
dn.naming_series = shopify_settings.delivery_note_series or "DN-Shopify-"
dn.items = get_fulfillment_items(dn.items, fulfillment.get("line_items"), shopify_settings)
@@ -187,7 +203,7 @@
discounted_amount += flt(discount.get("amount"))
return discounted_amount
-def get_order_items(order_items, shopify_settings):
+def get_order_items(order_items, shopify_settings, delivery_date):
items = []
all_product_exists = True
product_not_exists = []
@@ -205,7 +221,7 @@
"item_code": item_code,
"item_name": shopify_item.get("name"),
"rate": shopify_item.get("price"),
- "delivery_date": nowdate(),
+ "delivery_date": delivery_date,
"qty": shopify_item.get("quantity"),
"stock_uom": shopify_item.get("uom") or _("Nos"),
"warehouse": shopify_settings.warehouse
@@ -244,6 +260,15 @@
"""Shipping lines represents the shipping details,
each such shipping detail consists of a list of tax_lines"""
for shipping_charge in shipping_lines:
+ if shipping_charge.get("price"):
+ taxes.append({
+ "charge_type": _("Actual"),
+ "account_head": get_tax_account_head(shipping_charge),
+ "description": shipping_charge["title"],
+ "tax_amount": shipping_charge["price"],
+ "cost_center": shopify_settings.cost_center
+ })
+
for tax in shipping_charge.get("tax_lines"):
taxes.append({
"charge_type": _("Actual"),
@@ -265,3 +290,64 @@
frappe.throw(_("Tax Account not specified for Shopify Tax {0}").format(tax.get("title")))
return tax_account
+
+@frappe.whitelist(allow_guest=True)
+def sync_old_orders():
+ frappe.set_user('Administrator')
+ shopify_settings = frappe.get_doc('Shopify Settings')
+
+ if not shopify_settings.sync_missing_orders:
+ return
+
+ url = get_url(shopify_settings)
+ session = get_request_session()
+
+ try:
+ res = session.get(url, headers=get_header(shopify_settings))
+ res.raise_for_status()
+ orders = res.json()["orders"]
+
+ for order in orders:
+ if is_sync_complete(shopify_settings, order):
+ stop_sync(shopify_settings)
+ return
+
+ sync_sales_order(order=order, old_order_sync=True)
+ last_order_id = order.get('id')
+
+ if last_order_id:
+ shopify_settings.load_from_db()
+ shopify_settings.last_order_id = last_order_id
+ shopify_settings.save()
+ frappe.db.commit()
+
+ except Exception as e:
+ raise e
+
+def stop_sync(shopify_settings):
+ shopify_settings.sync_missing_orders = 0
+ shopify_settings.last_order_id = ''
+ shopify_settings.save()
+ frappe.db.commit()
+
+def get_url(shopify_settings):
+ last_order_id = shopify_settings.last_order_id
+
+ if not last_order_id:
+ if shopify_settings.sync_based_on == 'Date':
+ url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&created_at_min={0}&since_id=0".format(
+ get_datetime(shopify_settings.from_date)), shopify_settings)
+ else:
+ url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
+ shopify_settings.from_order_id), shopify_settings)
+ else:
+ url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
+
+ return url
+
+def is_sync_complete(shopify_settings, order):
+ if shopify_settings.sync_based_on == 'Date':
+ return getdate(shopify_settings.to_date) < getdate(order.get('created_at'))
+ else:
+ return cstr(order.get('id')) == cstr(shopify_settings.to_order_id)
+
diff --git a/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json b/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json
deleted file mode 100644
index 8dcc77d..0000000
--- a/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Marketplace",
- "links": "[\n {\n \"description\": \"Woocommerce marketplace settings\",\n \"label\": \"Woocommerce Settings\",\n \"name\": \"Woocommerce Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Amazon MWS settings\",\n \"label\": \"Amazon MWS Settings\",\n \"name\": \"Amazon MWS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Shopify settings\",\n \"label\": \"Shopify Settings\",\n \"name\": \"Shopify Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Payments",
- "links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"description\": \"Plaid settings\",\n \"label\": \"Plaid Settings\",\n \"name\": \"Plaid Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Exotel settings\",\n \"label\": \"Exotel Settings\",\n \"name\": \"Exotel Settings\",\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [],
- "creation": "2020-08-20 19:30:48.138801",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends": "Integrations",
- "extends_another_page": 1,
- "hide_custom": 1,
- "idx": 0,
- "is_standard": 1,
- "label": "ERPNext Integrations",
- "modified": "2020-08-23 16:30:51.494655",
- "modified_by": "Administrator",
- "module": "ERPNext Integrations",
- "name": "ERPNext Integrations",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": []
-}
\ No newline at end of file
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 cc75a0a..148c1a6 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
@@ -117,7 +117,7 @@
return response
except Exception as e:
delay = math.pow(4, x) * 125
- frappe.log_error(message=e, title=str(mws_method))
+ frappe.log_error(message=e, title=f'Method "{mws_method.__name__}" failed')
time.sleep(delay)
continue
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/erpnext_integrations/doctype/mpesa_settings/__init__.py
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html b/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html
new file mode 100644
index 0000000..2c4d4bb
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/account_balance.html
@@ -0,0 +1,28 @@
+
+{% if not jQuery.isEmptyObject(data) %}
+<h5 style="margin-top: 20px;"> {{ __("Balance Details") }} </h5>
+<table class="table table-bordered small">
+ <thead>
+ <tr>
+ <th style="width: 20%">{{ __("Account Type") }}</th>
+ <th style="width: 20%" class="text-right">{{ __("Current Balance") }}</th>
+ <th style="width: 20%" class="text-right">{{ __("Available Balance") }}</th>
+ <th style="width: 20%" class="text-right">{{ __("Reserved Balance") }}</th>
+ <th style="width: 20%" class="text-right">{{ __("Uncleared Balance") }}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for(const [key, value] of Object.entries(data)) { %}
+ <tr>
+ <td> {%= key %} </td>
+ <td class="text-right"> {%= value["current_balance"] %} </td>
+ <td class="text-right"> {%= value["available_balance"] %} </td>
+ <td class="text-right"> {%= value["reserved_balance"] %} </td>
+ <td class="text-right"> {%= value["uncleared_balance"] %} </td>
+ </tr>
+ {% } %}
+ </tbody>
+</table>
+{% else %}
+<p style="margin-top: 30px;"> Account Balance Information Not Available. </p>
+{% endif %}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
new file mode 100644
index 0000000..554c6b0
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
@@ -0,0 +1,118 @@
+import base64
+import requests
+from requests.auth import HTTPBasicAuth
+import datetime
+
+class MpesaConnector():
+ def __init__(self, env="sandbox", app_key=None, app_secret=None, sandbox_url="https://sandbox.safaricom.co.ke",
+ live_url="https://api.safaricom.co.ke"):
+ """Setup configuration for Mpesa connector and generate new access token."""
+ self.env = env
+ self.app_key = app_key
+ self.app_secret = app_secret
+ if env == "sandbox":
+ self.base_url = sandbox_url
+ else:
+ self.base_url = live_url
+ self.authenticate()
+
+ def authenticate(self):
+ """
+ This method is used to fetch the access token required by Mpesa.
+
+ Returns:
+ access_token (str): This token is to be used with the Bearer header for further API calls to Mpesa.
+ """
+ authenticate_uri = "/oauth/v1/generate?grant_type=client_credentials"
+ authenticate_url = "{0}{1}".format(self.base_url, authenticate_uri)
+ r = requests.get(
+ authenticate_url,
+ auth=HTTPBasicAuth(self.app_key, self.app_secret)
+ )
+ self.authentication_token = r.json()['access_token']
+ return r.json()['access_token']
+
+ def get_balance(self, initiator=None, security_credential=None, party_a=None, identifier_type=None,
+ remarks=None, queue_timeout_url=None,result_url=None):
+ """
+ This method uses Mpesa's Account Balance API to to enquire the balance on a M-Pesa BuyGoods (Till Number).
+
+ Args:
+ initiator (str): Username used to authenticate the transaction.
+ security_credential (str): Generate from developer portal.
+ command_id (str): AccountBalance.
+ party_a (int): Till number being queried.
+ identifier_type (int): Type of organization receiving the transaction. (MSISDN/Till Number/Organization short code)
+ remarks (str): Comments that are sent along with the transaction(maximum 100 characters).
+ queue_timeout_url (str): The url that handles information of timed out transactions.
+ result_url (str): The url that receives results from M-Pesa api call.
+
+ Returns:
+ OriginatorConverstionID (str): The unique request ID for tracking a transaction.
+ ConversationID (str): The unique request ID returned by mpesa for each request made
+ ResponseDescription (str): Response Description message
+ """
+
+ payload = {
+ "Initiator": initiator,
+ "SecurityCredential": security_credential,
+ "CommandID": "AccountBalance",
+ "PartyA": party_a,
+ "IdentifierType": identifier_type,
+ "Remarks": remarks,
+ "QueueTimeOutURL": queue_timeout_url,
+ "ResultURL": result_url
+ }
+ headers = {'Authorization': 'Bearer {0}'.format(self.authentication_token), 'Content-Type': "application/json"}
+ saf_url = "{0}{1}".format(self.base_url, "/mpesa/accountbalance/v1/query")
+ r = requests.post(saf_url, headers=headers, json=payload)
+ return r.json()
+
+ def stk_push(self, business_shortcode=None, passcode=None, amount=None, callback_url=None, reference_code=None,
+ phone_number=None, description=None):
+ """
+ This method uses Mpesa's Express API to initiate online payment on behalf of a customer.
+
+ Args:
+ business_shortcode (int): The short code of the organization.
+ passcode (str): Get from developer portal
+ amount (int): The amount being transacted
+ callback_url (str): A CallBack URL is a valid secure URL that is used to receive notifications from M-Pesa API.
+ reference_code(str): Account Reference: This is an Alpha-Numeric parameter that is defined by your system as an Identifier of the transaction for CustomerPayBillOnline transaction type.
+ phone_number(int): The Mobile Number to receive the STK Pin Prompt.
+ description(str): This is any additional information/comment that can be sent along with the request from your system. MAX 13 characters
+
+ Success Response:
+ CustomerMessage(str): Messages that customers can understand.
+ CheckoutRequestID(str): This is a global unique identifier of the processed checkout transaction request.
+ ResponseDescription(str): Describes Success or failure
+ MerchantRequestID(str): This is a global unique Identifier for any submitted payment request.
+ ResponseCode(int): 0 means success all others are error codes. e.g.404.001.03
+
+ Error Reponse:
+ requestId(str): This is a unique requestID for the payment request
+ errorCode(str): This is a predefined code that indicates the reason for request failure.
+ errorMessage(str): This is a predefined code that indicates the reason for request failure.
+ """
+
+ time = str(datetime.datetime.now()).split(".")[0].replace("-", "").replace(" ", "").replace(":", "")
+ password = "{0}{1}{2}".format(str(business_shortcode), str(passcode), time)
+ encoded = base64.b64encode(bytes(password, encoding='utf8'))
+ payload = {
+ "BusinessShortCode": business_shortcode,
+ "Password": encoded.decode("utf-8"),
+ "Timestamp": time,
+ "Amount": amount,
+ "PartyA": int(phone_number),
+ "PartyB": reference_code,
+ "PhoneNumber": int(phone_number),
+ "CallBackURL": callback_url,
+ "AccountReference": reference_code,
+ "TransactionDesc": description,
+ "TransactionType": "CustomerPayBillOnline" if self.env == "sandbox" else "CustomerBuyGoodsOnline"
+ }
+ headers = {'Authorization': 'Bearer {0}'.format(self.authentication_token), 'Content-Type': "application/json"}
+
+ saf_url = "{0}{1}".format(self.base_url, "/mpesa/stkpush/v1/processrequest")
+ r = requests.post(saf_url, headers=headers, json=payload)
+ return r.json()
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
new file mode 100644
index 0000000..0499e88
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
@@ -0,0 +1,53 @@
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+def create_custom_pos_fields():
+ """Create custom fields corresponding to POS Settings and POS Invoice."""
+ pos_field = {
+ "POS Invoice": [
+ {
+ "fieldname": "request_for_payment",
+ "label": "Request for Payment",
+ "fieldtype": "Button",
+ "hidden": 1,
+ "insert_after": "contact_email"
+ },
+ {
+ "fieldname": "mpesa_receipt_number",
+ "label": "Mpesa Receipt Number",
+ "fieldtype": "Data",
+ "read_only": 1,
+ "insert_after": "company"
+ }
+ ]
+ }
+ if not frappe.get_meta("POS Invoice").has_field("request_for_payment"):
+ create_custom_fields(pos_field)
+
+ record_dict = [{
+ "doctype": "POS Field",
+ "fieldname": "contact_mobile",
+ "label": "Mobile No",
+ "fieldtype": "Data",
+ "options": "Phone",
+ "parenttype": "POS Settings",
+ "parent": "POS Settings",
+ "parentfield": "invoice_fields"
+ },
+ {
+ "doctype": "POS Field",
+ "fieldname": "request_for_payment",
+ "label": "Request for Payment",
+ "fieldtype": "Button",
+ "parenttype": "POS Settings",
+ "parent": "POS Settings",
+ "parentfield": "invoice_fields"
+ }
+ ]
+ create_pos_settings(record_dict)
+
+def create_pos_settings(record_dict):
+ for record in record_dict:
+ if frappe.db.exists("POS Field", {"fieldname": record.get("fieldname")}):
+ continue
+ frappe.get_doc(record).insert()
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js
new file mode 100644
index 0000000..7c8ae5c
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js
@@ -0,0 +1,37 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Mpesa Settings', {
+ onload_post_render: function(frm) {
+ frm.events.setup_account_balance_html(frm);
+ },
+
+ refresh: function(frm) {
+ frappe.realtime.on("refresh_mpesa_dashboard", function(){
+ frm.reload_doc();
+ frm.events.setup_account_balance_html(frm);
+ });
+ },
+
+ get_account_balance: function(frm) {
+ if (!frm.doc.initiator_name && !frm.doc.security_credential) {
+ frappe.throw(__("Please set the initiator name and the security credential"));
+ }
+ frappe.call({
+ method: "get_account_balance_info",
+ doc: frm.doc
+ });
+ },
+
+ setup_account_balance_html: function(frm) {
+ if (!frm.doc.account_balance) return;
+ $("div").remove(".form-dashboard-section.custom");
+ frm.dashboard.add_section(
+ frappe.render_template('account_balance', {
+ data: JSON.parse(frm.doc.account_balance)
+ })
+ );
+ frm.dashboard.show();
+ }
+
+});
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json
new file mode 100644
index 0000000..8f3b427
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json
@@ -0,0 +1,152 @@
+{
+ "actions": [],
+ "autoname": "field:payment_gateway_name",
+ "creation": "2020-09-10 13:21:27.398088",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "payment_gateway_name",
+ "consumer_key",
+ "consumer_secret",
+ "initiator_name",
+ "till_number",
+ "transaction_limit",
+ "sandbox",
+ "column_break_4",
+ "business_shortcode",
+ "online_passkey",
+ "security_credential",
+ "get_account_balance",
+ "account_balance"
+ ],
+ "fields": [
+ {
+ "fieldname": "payment_gateway_name",
+ "fieldtype": "Data",
+ "label": "Payment Gateway Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "consumer_key",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Consumer Key",
+ "reqd": 1
+ },
+ {
+ "fieldname": "consumer_secret",
+ "fieldtype": "Password",
+ "in_list_view": 1,
+ "label": "Consumer Secret",
+ "reqd": 1
+ },
+ {
+ "fieldname": "till_number",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Till Number",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "sandbox",
+ "fieldtype": "Check",
+ "label": "Sandbox"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "online_passkey",
+ "fieldtype": "Password",
+ "label": " Online PassKey",
+ "reqd": 1
+ },
+ {
+ "fieldname": "initiator_name",
+ "fieldtype": "Data",
+ "label": "Initiator Name"
+ },
+ {
+ "fieldname": "security_credential",
+ "fieldtype": "Small Text",
+ "label": "Security Credential"
+ },
+ {
+ "fieldname": "account_balance",
+ "fieldtype": "Long Text",
+ "hidden": 1,
+ "label": "Account Balance",
+ "read_only": 1
+ },
+ {
+ "fieldname": "get_account_balance",
+ "fieldtype": "Button",
+ "label": "Get Account Balance"
+ },
+ {
+ "depends_on": "eval:(doc.sandbox==0)",
+ "fieldname": "business_shortcode",
+ "fieldtype": "Data",
+ "label": "Business Shortcode",
+ "mandatory_depends_on": "eval:(doc.sandbox==0)"
+ },
+ {
+ "default": "150000",
+ "fieldname": "transaction_limit",
+ "fieldtype": "Float",
+ "label": "Transaction Limit",
+ "non_negative": 1
+ }
+ ],
+ "links": [],
+ "modified": "2021-03-02 17:35:14.084342",
+ "modified_by": "Administrator",
+ "module": "ERPNext Integrations",
+ "name": "Mpesa Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
new file mode 100644
index 0000000..b571802
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
@@ -0,0 +1,278 @@
+# -*- 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 loads, dumps
+
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.utils import call_hook_method, fmt_money
+from frappe.integrations.utils import create_request_log, create_payment_gateway
+from frappe.utils import get_request_site_address
+from erpnext.erpnext_integrations.utils import create_mode_of_payment
+from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_connector import MpesaConnector
+from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import create_custom_pos_fields
+
+class MpesaSettings(Document):
+ supported_currencies = ["KES"]
+
+ def validate_transaction_currency(self, currency):
+ if currency not in self.supported_currencies:
+ frappe.throw(_("Please select another payment method. Mpesa does not support transactions in currency '{0}'").format(currency))
+
+ def on_update(self):
+ create_custom_pos_fields()
+ create_payment_gateway('Mpesa-' + self.payment_gateway_name, settings='Mpesa Settings', controller=self.payment_gateway_name)
+ call_hook_method('payment_gateway_enabled', gateway='Mpesa-' + self.payment_gateway_name, payment_channel="Phone")
+
+ # required to fetch the bank account details from the payment gateway account
+ frappe.db.commit()
+ create_mode_of_payment('Mpesa-' + self.payment_gateway_name, payment_type="Phone")
+
+ def request_for_payment(self, **kwargs):
+ args = frappe._dict(kwargs)
+ request_amounts = self.split_request_amount_according_to_transaction_limit(args)
+
+ for i, amount in enumerate(request_amounts):
+ args.request_amount = amount
+ if frappe.flags.in_test:
+ from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_payment_request_response_payload
+ response = frappe._dict(get_payment_request_response_payload(amount))
+ else:
+ response = frappe._dict(generate_stk_push(**args))
+
+ self.handle_api_response("CheckoutRequestID", args, response)
+
+ def split_request_amount_according_to_transaction_limit(self, args):
+ request_amount = args.request_amount
+ if request_amount > self.transaction_limit:
+ # make multiple requests
+ request_amounts = []
+ requests_to_be_made = frappe.utils.ceil(request_amount / self.transaction_limit) # 480/150 = ceil(3.2) = 4
+ for i in range(requests_to_be_made):
+ amount = self.transaction_limit
+ if i == requests_to_be_made - 1:
+ amount = request_amount - (self.transaction_limit * i) # for 4th request, 480 - (150 * 3) = 30
+ request_amounts.append(amount)
+ else:
+ request_amounts = [request_amount]
+
+ return request_amounts
+
+ def get_account_balance_info(self):
+ payload = dict(
+ reference_doctype="Mpesa Settings",
+ reference_docname=self.name,
+ doc_details=vars(self)
+ )
+
+ if frappe.flags.in_test:
+ from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_test_account_balance_response
+ response = frappe._dict(get_test_account_balance_response())
+ else:
+ response = frappe._dict(get_account_balance(payload))
+
+ self.handle_api_response("ConversationID", payload, response)
+
+ def handle_api_response(self, global_id, request_dict, response):
+ """Response received from API calls returns a global identifier for each transaction, this code is returned during the callback."""
+ # check error response
+ if getattr(response, "requestId"):
+ req_name = getattr(response, "requestId")
+ error = response
+ else:
+ # global checkout id used as request name
+ req_name = getattr(response, global_id)
+ error = None
+
+ if not frappe.db.exists('Integration Request', req_name):
+ create_request_log(request_dict, "Host", "Mpesa", req_name, error)
+
+ if error:
+ frappe.throw(_(getattr(response, "errorMessage")), title=_("Transaction Error"))
+
+def generate_stk_push(**kwargs):
+ """Generate stk push by making a API call to the stk push API."""
+ args = frappe._dict(kwargs)
+ try:
+ callback_url = get_request_site_address(True) + "/api/method/erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings.verify_transaction"
+
+ mpesa_settings = frappe.get_doc("Mpesa Settings", args.payment_gateway[6:])
+ env = "production" if not mpesa_settings.sandbox else "sandbox"
+ # for sandbox, business shortcode is same as till number
+ business_shortcode = mpesa_settings.business_shortcode if env == "production" else mpesa_settings.till_number
+
+ connector = MpesaConnector(env=env,
+ app_key=mpesa_settings.consumer_key,
+ app_secret=mpesa_settings.get_password("consumer_secret"))
+
+ mobile_number = sanitize_mobile_number(args.sender)
+
+ response = connector.stk_push(
+ business_shortcode=business_shortcode, amount=args.request_amount,
+ passcode=mpesa_settings.get_password("online_passkey"),
+ callback_url=callback_url, reference_code=mpesa_settings.till_number,
+ phone_number=mobile_number, description="POS Payment"
+ )
+
+ return response
+
+ except Exception:
+ frappe.log_error(title=_("Mpesa Express Transaction Error"))
+ frappe.throw(_("Issue detected with Mpesa configuration, check the error logs for more details"), title=_("Mpesa Express Error"))
+
+def sanitize_mobile_number(number):
+ """Add country code and strip leading zeroes from the phone number."""
+ return "254" + str(number).lstrip("0")
+
+@frappe.whitelist(allow_guest=True)
+def verify_transaction(**kwargs):
+ """Verify the transaction result received via callback from stk."""
+ transaction_response = frappe._dict(kwargs["Body"]["stkCallback"])
+
+ checkout_id = getattr(transaction_response, "CheckoutRequestID", "")
+ 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
+ success = False # for reporting successfull callback to point of sale ui
+
+ if transaction_response['ResultCode'] == 0:
+ if integration_request.reference_doctype and integration_request.reference_docname:
+ try:
+ item_response = transaction_response["CallbackMetadata"]["Item"]
+ amount = fetch_param_value(item_response, "Amount", "Name")
+ mpesa_receipt = fetch_param_value(item_response, "MpesaReceiptNumber", "Name")
+ pr = frappe.get_doc(integration_request.reference_doctype, integration_request.reference_docname)
+
+ mpesa_receipts, completed_payments = get_completed_integration_requests_info(
+ integration_request.reference_doctype,
+ integration_request.reference_docname,
+ checkout_id
+ )
+
+ total_paid = amount + sum(completed_payments)
+ mpesa_receipts = ', '.join(mpesa_receipts + [mpesa_receipt])
+
+ if total_paid >= pr.grand_total:
+ pr.run_method("on_payment_authorized", 'Completed')
+ success = True
+
+ frappe.db.set_value("POS Invoice", pr.reference_name, "mpesa_receipt_number", mpesa_receipts)
+ integration_request.handle_success(transaction_response)
+ except Exception:
+ integration_request.handle_failure(transaction_response)
+ frappe.log_error(frappe.get_traceback())
+
+ else:
+ integration_request.handle_failure(transaction_response)
+
+ frappe.publish_realtime(
+ event='process_phone_payment',
+ doctype="POS Invoice",
+ docname=transaction_data.payment_reference,
+ user=integration_request.owner,
+ message={
+ 'amount': total_paid,
+ 'success': success,
+ 'failure_message': transaction_response["ResultDesc"] if transaction_response['ResultCode'] != 0 else ''
+ },
+ )
+
+def get_completed_integration_requests_info(reference_doctype, reference_docname, checkout_id):
+ output_of_other_completed_requests = frappe.get_all("Integration Request", filters={
+ 'name': ['!=', checkout_id],
+ 'reference_doctype': reference_doctype,
+ 'reference_docname': reference_docname,
+ 'status': 'Completed'
+ }, pluck="output")
+
+ mpesa_receipts, completed_payments = [], []
+
+ for out in output_of_other_completed_requests:
+ out = frappe._dict(loads(out))
+ item_response = out["CallbackMetadata"]["Item"]
+ completed_amount = fetch_param_value(item_response, "Amount", "Name")
+ completed_mpesa_receipt = fetch_param_value(item_response, "MpesaReceiptNumber", "Name")
+ completed_payments.append(completed_amount)
+ mpesa_receipts.append(completed_mpesa_receipt)
+
+ return mpesa_receipts, completed_payments
+
+def get_account_balance(request_payload):
+ """Call account balance API to send the request to the Mpesa Servers."""
+ try:
+ mpesa_settings = frappe.get_doc("Mpesa Settings", request_payload.get("reference_docname"))
+ env = "production" if not mpesa_settings.sandbox else "sandbox"
+ connector = MpesaConnector(env=env,
+ app_key=mpesa_settings.consumer_key,
+ app_secret=mpesa_settings.get_password("consumer_secret"))
+
+ callback_url = get_request_site_address(True) + "/api/method/erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings.process_balance_info"
+
+ response = connector.get_balance(mpesa_settings.initiator_name, mpesa_settings.security_credential, mpesa_settings.till_number, 4, mpesa_settings.name, callback_url, callback_url)
+ return response
+ except Exception:
+ frappe.log_error(title=_("Account Balance Processing Error"))
+ frappe.throw(_("Please check your configuration and try again"), title=_("Error"))
+
+@frappe.whitelist(allow_guest=True)
+def process_balance_info(**kwargs):
+ """Process and store account balance information received via callback from the account balance API call."""
+ account_balance_response = frappe._dict(kwargs["Result"])
+
+ conversation_id = getattr(account_balance_response, "ConversationID", "")
+ request = frappe.get_doc("Integration Request", conversation_id)
+
+ if request.status == "Completed":
+ return
+
+ transaction_data = frappe._dict(loads(request.data))
+
+ if account_balance_response["ResultCode"] == 0:
+ try:
+ result_params = account_balance_response["ResultParameters"]["ResultParameter"]
+
+ balance_info = fetch_param_value(result_params, "AccountBalance", "Key")
+ balance_info = format_string_to_json(balance_info)
+
+ ref_doc = frappe.get_doc(transaction_data.reference_doctype, transaction_data.reference_docname)
+ ref_doc.db_set("account_balance", balance_info)
+
+ request.handle_success(account_balance_response)
+ frappe.publish_realtime("refresh_mpesa_dashboard", doctype="Mpesa Settings",
+ docname=transaction_data.reference_docname, user=transaction_data.owner)
+ except Exception:
+ request.handle_failure(account_balance_response)
+ frappe.log_error(title=_("Mpesa Account Balance Processing Error"), message=account_balance_response)
+ else:
+ request.handle_failure(account_balance_response)
+
+def format_string_to_json(balance_info):
+ """
+ Format string to json.
+
+ e.g: '''Working Account|KES|481000.00|481000.00|0.00|0.00'''
+ => {'Working Account': {'current_balance': '481000.00',
+ 'available_balance': '481000.00',
+ 'reserved_balance': '0.00',
+ 'uncleared_balance': '0.00'}}
+ """
+ balance_dict = frappe._dict()
+ for account_info in balance_info.split("&"):
+ account_info = account_info.split('|')
+ balance_dict[account_info[0]] = dict(
+ current_balance=fmt_money(account_info[2], currency="KES"),
+ available_balance=fmt_money(account_info[3], currency="KES"),
+ reserved_balance=fmt_money(account_info[4], currency="KES"),
+ uncleared_balance=fmt_money(account_info[5], currency="KES")
+ )
+ return dumps(balance_dict)
+
+def fetch_param_value(response, key, key_field):
+ """Fetch the specified key from list of dictionary. Key is identified via the key field."""
+ for param in response:
+ if param[key_field] == key:
+ return param["Value"]
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
new file mode 100644
index 0000000..2948796
--- /dev/null
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -0,0 +1,355 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+from json import dumps
+import frappe
+import unittest
+from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings import process_balance_info, verify_transaction
+from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
+
+class TestMpesaSettings(unittest.TestCase):
+ def tearDown(self):
+ frappe.db.sql('delete from `tabMpesa Settings`')
+ frappe.db.sql('delete from `tabIntegration Request` where integration_request_service = "Mpesa"')
+
+ def test_creation_of_payment_gateway(self):
+ create_mpesa_settings(payment_gateway_name="_Test")
+
+ mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test")
+ self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"}))
+ self.assertTrue(mode_of_payment.name)
+ self.assertEquals(mode_of_payment.type, "Phone")
+
+ def test_processing_of_account_balance(self):
+ mpesa_doc = create_mpesa_settings(payment_gateway_name="_Account Balance")
+ mpesa_doc.get_account_balance_info()
+
+ callback_response = get_account_balance_callback_payload()
+ process_balance_info(**callback_response)
+ integration_request = frappe.get_doc("Integration Request", "AG_20200927_00007cdb1f9fb6494315")
+
+ # test integration request creation and successful update of the status on receiving callback response
+ self.assertTrue(integration_request)
+ self.assertEquals(integration_request.status, "Completed")
+
+ # test formatting of account balance received as string to json with appropriate currency symbol
+ mpesa_doc.reload()
+ self.assertEquals(mpesa_doc.account_balance, dumps({
+ "Working Account": {
+ "current_balance": "Sh 481,000.00",
+ "available_balance": "Sh 481,000.00",
+ "reserved_balance": "Sh 0.00",
+ "uncleared_balance": "Sh 0.00"
+ }
+ }))
+
+ integration_request.delete()
+
+ def test_processing_of_callback_payload(self):
+ create_mpesa_settings(payment_gateway_name="Payment")
+ mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
+ frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
+ frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES")
+
+ pos_invoice = create_pos_invoice(do_not_submit=1)
+ pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 500})
+ pos_invoice.contact_mobile = "093456543894"
+ pos_invoice.currency = "KES"
+ pos_invoice.save()
+
+ pr = pos_invoice.create_payment_request()
+ # test payment request creation
+ self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+
+ # submitting payment request creates integration requests with random id
+ integration_req_ids = frappe.get_all("Integration Request", filters={
+ 'reference_doctype': pr.doctype,
+ 'reference_docname': pr.name,
+ }, pluck="name")
+
+ callback_response = get_payment_callback_payload(Amount=500, CheckoutRequestID=integration_req_ids[0])
+ verify_transaction(**callback_response)
+ # test creation of integration request
+ integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
+
+ # test integration request creation and successful update of the status on receiving callback response
+ self.assertTrue(integration_request)
+ self.assertEquals(integration_request.status, "Completed")
+
+ pos_invoice.reload()
+ integration_request.reload()
+ self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
+ self.assertEquals(integration_request.status, "Completed")
+
+ frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
+ integration_request.delete()
+ pr.reload()
+ pr.cancel()
+ pr.delete()
+ pos_invoice.delete()
+
+ def test_processing_of_multiple_callback_payload(self):
+ create_mpesa_settings(payment_gateway_name="Payment")
+ mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
+ frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
+ frappe.db.set_value("Mpesa Settings", "Payment", "transaction_limit", "500")
+ frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES")
+
+ pos_invoice = create_pos_invoice(do_not_submit=1)
+ pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 1000})
+ pos_invoice.contact_mobile = "093456543894"
+ pos_invoice.currency = "KES"
+ pos_invoice.save()
+
+ pr = pos_invoice.create_payment_request()
+ # test payment request creation
+ self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+
+ # submitting payment request creates integration requests with random id
+ integration_req_ids = frappe.get_all("Integration Request", filters={
+ 'reference_doctype': pr.doctype,
+ 'reference_docname': pr.name,
+ }, pluck="name")
+
+ # create random receipt nos and send it as response to callback handler
+ mpesa_receipt_numbers = [frappe.utils.random_string(5) for d in integration_req_ids]
+
+ integration_requests = []
+ for i in range(len(integration_req_ids)):
+ callback_response = get_payment_callback_payload(
+ Amount=500,
+ CheckoutRequestID=integration_req_ids[i],
+ MpesaReceiptNumber=mpesa_receipt_numbers[i]
+ )
+ # handle response manually
+ verify_transaction(**callback_response)
+ # test completion of integration request
+ integration_request = frappe.get_doc("Integration Request", integration_req_ids[i])
+ self.assertEquals(integration_request.status, "Completed")
+ integration_requests.append(integration_request)
+
+ # check receipt number once all the integration requests are completed
+ pos_invoice.reload()
+ self.assertEquals(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
+
+ frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
+ [d.delete() for d in integration_requests]
+ pr.reload()
+ pr.cancel()
+ pr.delete()
+ pos_invoice.delete()
+
+ def test_processing_of_only_one_succes_callback_payload(self):
+ create_mpesa_settings(payment_gateway_name="Payment")
+ mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
+ frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
+ frappe.db.set_value("Mpesa Settings", "Payment", "transaction_limit", "500")
+ frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES")
+
+ pos_invoice = create_pos_invoice(do_not_submit=1)
+ pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 1000})
+ pos_invoice.contact_mobile = "093456543894"
+ pos_invoice.currency = "KES"
+ pos_invoice.save()
+
+ pr = pos_invoice.create_payment_request()
+ # test payment request creation
+ self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+
+ # submitting payment request creates integration requests with random id
+ integration_req_ids = frappe.get_all("Integration Request", filters={
+ 'reference_doctype': pr.doctype,
+ 'reference_docname': pr.name,
+ }, pluck="name")
+
+ # create random receipt nos and send it as response to callback handler
+ mpesa_receipt_numbers = [frappe.utils.random_string(5) for d in integration_req_ids]
+
+ callback_response = get_payment_callback_payload(
+ Amount=500,
+ CheckoutRequestID=integration_req_ids[0],
+ MpesaReceiptNumber=mpesa_receipt_numbers[0]
+ )
+ # handle response manually
+ verify_transaction(**callback_response)
+ # test completion of integration request
+ integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
+ self.assertEquals(integration_request.status, "Completed")
+
+ # now one request is completed
+ # second integration request fails
+ # now retrying payment request should make only one integration request again
+ pr = pos_invoice.create_payment_request()
+ new_integration_req_ids = frappe.get_all("Integration Request", filters={
+ 'reference_doctype': pr.doctype,
+ 'reference_docname': pr.name,
+ 'name': ['not in', integration_req_ids]
+ }, pluck="name")
+
+ self.assertEquals(len(new_integration_req_ids), 1)
+
+ frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
+ frappe.db.sql("delete from `tabIntegration Request` where integration_request_service = 'Mpesa'")
+ pr.reload()
+ pr.cancel()
+ pr.delete()
+ pos_invoice.delete()
+
+def create_mpesa_settings(payment_gateway_name="Express"):
+ if frappe.db.exists("Mpesa Settings", payment_gateway_name):
+ return frappe.get_doc("Mpesa Settings", payment_gateway_name)
+
+ doc = frappe.get_doc(dict( #nosec
+ doctype="Mpesa Settings",
+ payment_gateway_name=payment_gateway_name,
+ consumer_key="5sMu9LVI1oS3oBGPJfh3JyvLHwZOdTKn",
+ consumer_secret="VI1oS3oBGPJfh3JyvLHw",
+ online_passkey="LVI1oS3oBGPJfh3JyvLHwZOd",
+ till_number="174379"
+ ))
+
+ doc.insert(ignore_permissions=True)
+ return doc
+
+def get_test_account_balance_response():
+ """Response received after calling the account balance API."""
+ return {
+ "ResultType":0,
+ "ResultCode":0,
+ "ResultDesc":"The service request has been accepted successfully.",
+ "OriginatorConversationID":"10816-694520-2",
+ "ConversationID":"AG_20200927_00007cdb1f9fb6494315",
+ "TransactionID":"LGR0000000",
+ "ResultParameters":{
+ "ResultParameter":[
+ {
+ "Key":"ReceiptNo",
+ "Value":"LGR919G2AV"
+ },
+ {
+ "Key":"Conversation ID",
+ "Value":"AG_20170727_00004492b1b6d0078fbe"
+ },
+ {
+ "Key":"FinalisedTime",
+ "Value":20170727101415
+ },
+ {
+ "Key":"Amount",
+ "Value":10
+ },
+ {
+ "Key":"TransactionStatus",
+ "Value":"Completed"
+ },
+ {
+ "Key":"ReasonType",
+ "Value":"Salary Payment via API"
+ },
+ {
+ "Key":"TransactionReason"
+ },
+ {
+ "Key":"DebitPartyCharges",
+ "Value":"Fee For B2C Payment|KES|33.00"
+ },
+ {
+ "Key":"DebitAccountType",
+ "Value":"Utility Account"
+ },
+ {
+ "Key":"InitiatedTime",
+ "Value":20170727101415
+ },
+ {
+ "Key":"Originator Conversation ID",
+ "Value":"19455-773836-1"
+ },
+ {
+ "Key":"CreditPartyName",
+ "Value":"254708374149 - John Doe"
+ },
+ {
+ "Key":"DebitPartyName",
+ "Value":"600134 - Safaricom157"
+ }
+ ]
+ },
+ "ReferenceData":{
+ "ReferenceItem":{
+ "Key":"Occasion",
+ "Value":"aaaa"
+ }
+ }
+ }
+
+def get_payment_request_response_payload(Amount=500):
+ """Response received after successfully calling the stk push process request API."""
+
+ CheckoutRequestID = frappe.utils.random_string(10)
+
+ return {
+ "MerchantRequestID": "8071-27184008-1",
+ "CheckoutRequestID": CheckoutRequestID,
+ "ResultCode": 0,
+ "ResultDesc": "The service request is processed successfully.",
+ "CallbackMetadata": {
+ "Item": [
+ { "Name": "Amount", "Value": Amount },
+ { "Name": "MpesaReceiptNumber", "Value": "LGR7OWQX0R" },
+ { "Name": "TransactionDate", "Value": 20201006113336 },
+ { "Name": "PhoneNumber", "Value": 254723575670 }
+ ]
+ }
+ }
+
+def get_payment_callback_payload(Amount=500, CheckoutRequestID="ws_CO_061020201133231972", MpesaReceiptNumber="LGR7OWQX0R"):
+ """Response received from the server as callback after calling the stkpush process request API."""
+ return {
+ "Body":{
+ "stkCallback":{
+ "MerchantRequestID":"19465-780693-1",
+ "CheckoutRequestID":CheckoutRequestID,
+ "ResultCode":0,
+ "ResultDesc":"The service request is processed successfully.",
+ "CallbackMetadata":{
+ "Item":[
+ { "Name":"Amount", "Value":Amount },
+ { "Name":"MpesaReceiptNumber", "Value":MpesaReceiptNumber },
+ { "Name":"Balance" },
+ { "Name":"TransactionDate", "Value":20170727154800 },
+ { "Name":"PhoneNumber", "Value":254721566839 }
+ ]
+ }
+ }
+ }
+ }
+
+def get_account_balance_callback_payload():
+ """Response received from the server as callback after calling the account balance API."""
+ return {
+ "Result":{
+ "ResultType": 0,
+ "ResultCode": 0,
+ "ResultDesc": "The service request is processed successfully.",
+ "OriginatorConversationID": "16470-170099139-1",
+ "ConversationID": "AG_20200927_00007cdb1f9fb6494315",
+ "TransactionID": "OIR0000000",
+ "ResultParameters": {
+ "ResultParameter": [
+ {
+ "Key": "AccountBalance",
+ "Value": "Working Account|KES|481000.00|481000.00|0.00|0.00"
+ },
+ { "Key": "BOCompletedTime", "Value": 20200927234123 }
+ ]
+ },
+ "ReferenceData": {
+ "ReferenceItem": {
+ "Key": "QueueTimeoutURL",
+ "Value": "https://internalsandbox.safaricom.co.ke/mpesa/abresults/v1/submit"
+ }
+ }
+ }
+ }
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index a033a2a..5f990cd 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -20,7 +20,7 @@
client_id=self.settings.plaid_client_id,
secret=self.settings.get_password("plaid_secret"),
environment=self.settings.plaid_env,
- api_version="2019-05-29"
+ api_version="2020-09-14"
)
def get_access_token(self, public_token):
@@ -30,20 +30,32 @@
access_token = response["access_token"]
return access_token
- def get_link_token(self):
- token_request = {
+ def get_token_request(self, update_mode=False):
+ country_codes = ["US", "CA", "FR", "IE", "NL", "ES", "GB"] if self.settings.enable_european_access else ["US", "CA"]
+ args = {
"client_name": self.client_name,
- "client_id": self.settings.plaid_client_id,
- "secret": self.settings.plaid_secret,
- "products": self.products,
# only allow Plaid-supported languages and countries (LAST: Sep-19-2020)
"language": frappe.local.lang if frappe.local.lang in ["en", "fr", "es", "nl"] else "en",
- "country_codes": ["US", "CA", "FR", "IE", "NL", "ES", "GB"],
+ "country_codes": country_codes,
"user": {
"client_user_id": frappe.generate_hash(frappe.session.user, length=32)
}
}
+ if update_mode:
+ args["access_token"] = self.access_token
+ else:
+ args.update({
+ "client_id": self.settings.plaid_client_id,
+ "secret": self.settings.plaid_secret,
+ "products": self.products,
+ })
+
+ return args
+
+ def get_link_token(self, update_mode=False):
+ token_request = self.get_token_request(update_mode)
+
try:
response = self.client.LinkToken.create(token_request)
except InvalidRequestError:
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
index 22a4004..bbc2ca8 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
@@ -12,9 +12,25 @@
refresh: function (frm) {
if (frm.doc.enabled) {
- frm.add_custom_button('Link a new bank account', () => {
+ frm.add_custom_button(__('Link a new bank account'), () => {
new erpnext.integrations.plaidLink(frm);
});
+
+ frm.add_custom_button(__("Sync Now"), () => {
+ frappe.call({
+ method: "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.enqueue_synchronization",
+ freeze: true,
+ callback: () => {
+ let bank_transaction_link = '<a href="#List/Bank Transaction">Bank Transaction</a>';
+
+ frappe.msgprint({
+ title: __("Sync Started"),
+ message: __("The sync has started in the background, please check the {0} list for new records.", [bank_transaction_link]),
+ alert: 1
+ });
+ }
+ });
+ }).addClass("btn-primary");
}
}
});
@@ -30,10 +46,18 @@
this.product = ["auth", "transactions"];
this.plaid_env = this.frm.doc.plaid_env;
this.client_name = frappe.boot.sitename;
- this.token = await this.frm.call("get_link_token").then(resp => resp.message);
+ this.token = await this.get_link_token();
this.init_plaid();
}
+ async get_link_token() {
+ const token = await this.frm.call("get_link_token").then(resp => resp.message);
+ if (!token) {
+ frappe.throw(__('Cannot retrieve link token. Check Error Log for more information'));
+ }
+ return token;
+ }
+
init_plaid() {
const me = this;
me.loadScript(me.plaidUrl)
@@ -78,8 +102,8 @@
}
onScriptError(error) {
- frappe.msgprint("There was an issue connecting to Plaid's authentication server");
- frappe.msgprint(error);
+ frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information"));
+ console.log(error);
}
plaid_success(token, response) {
@@ -107,4 +131,4 @@
});
}, __("Select a company"), __("Continue"));
}
-};
+};
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
index 2706217..e7176ea 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2018-10-25 10:02:48.656165",
"doctype": "DocType",
"editable_grid": 1,
@@ -11,7 +12,8 @@
"plaid_client_id",
"plaid_secret",
"column_break_7",
- "plaid_env"
+ "plaid_env",
+ "enable_european_access"
],
"fields": [
{
@@ -58,10 +60,17 @@
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_european_access",
+ "fieldtype": "Check",
+ "label": "Enable European Access"
}
],
"issingle": 1,
- "modified": "2020-09-12 02:31:44.542385",
+ "links": [],
+ "modified": "2021-03-02 17:35:27.544259",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Plaid Settings",
@@ -79,5 +88,6 @@
}
],
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index e535e81..21f6fee 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -166,7 +166,6 @@
related_bank = frappe.db.get_values("Bank Account", bank_account, ["bank", "integration_id"], as_dict=True)
access_token = frappe.db.get_value("Bank", related_bank[0].bank, "plaid_access_token")
account_id = related_bank[0].integration_id
-
else:
access_token = frappe.db.get_value("Bank", bank, "plaid_access_token")
account_id = None
@@ -205,8 +204,8 @@
"date": getdate(transaction["date"]),
"status": status,
"bank_account": bank_account,
- "debit": debit,
- "credit": credit,
+ "deposit": debit,
+ "withdrawal": credit,
"currency": transaction["iso_currency_code"],
"transaction_id": transaction["transaction_id"],
"reference_number": transaction["payment_meta"]["reference_number"],
@@ -228,13 +227,23 @@
def automatic_synchronization():
settings = frappe.get_doc("Plaid Settings", "Plaid Settings")
-
if settings.enabled == 1 and settings.automatic_sync == 1:
- plaid_accounts = frappe.get_all("Bank Account", filters={"integration_id": ["!=", ""]}, fields=["name", "bank"])
+ enqueue_synchronization()
- for plaid_account in plaid_accounts:
- frappe.enqueue(
- "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions",
- bank=plaid_account.bank,
- bank_account=plaid_account.name
- )
+@frappe.whitelist()
+def enqueue_synchronization():
+ plaid_accounts = frappe.get_all("Bank Account",
+ filters={"integration_id": ["!=", ""]},
+ fields=["name", "bank"])
+
+ for plaid_account in plaid_accounts:
+ frappe.enqueue(
+ "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions",
+ bank=plaid_account.bank,
+ bank_account=plaid_account.name
+ )
+
+@frappe.whitelist()
+def get_link_token_for_update(access_token):
+ plaid = PlaidConnector(access_token)
+ return plaid.get_link_token(update_mode=True)
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json
index 2e10751..308e7d1 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json
@@ -1,7 +1,9 @@
{
+ "actions": [],
"creation": "2015-05-18 05:21:07.270859",
"doctype": "DocType",
"document_type": "System",
+ "engine": "InnoDB",
"field_order": [
"status_html",
"enable_shopify",
@@ -40,7 +42,16 @@
"sales_invoice_series",
"section_break_22",
"html_16",
- "taxes"
+ "taxes",
+ "syncing_details_section",
+ "sync_missing_orders",
+ "sync_based_on",
+ "column_break_41",
+ "from_date",
+ "to_date",
+ "from_order_id",
+ "to_order_id",
+ "last_order_id"
],
"fields": [
{
@@ -255,10 +266,71 @@
"fieldtype": "Table",
"label": "Shopify Tax Account",
"options": "Shopify Tax Account"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "syncing_details_section",
+ "fieldtype": "Section Break",
+ "label": "Syncing Missing Orders"
+ },
+ {
+ "depends_on": "eval:doc.sync_missing_orders",
+ "fieldname": "last_order_id",
+ "fieldtype": "Data",
+ "label": "Last Order Id",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_41",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "description": "On checking this Order from the ",
+ "fieldname": "sync_missing_orders",
+ "fieldtype": "Check",
+ "label": "Sync Missing Old Shopify Orders"
+ },
+ {
+ "depends_on": "eval:doc.sync_missing_orders",
+ "fieldname": "sync_based_on",
+ "fieldtype": "Select",
+ "label": "Sync Based On",
+ "mandatory_depends_on": "eval:doc.sync_missing_orders",
+ "options": "\nDate\nShopify Order Id"
+ },
+ {
+ "depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "label": "From Date",
+ "mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
+ },
+ {
+ "depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "label": "To Date",
+ "mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
+ },
+ {
+ "depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
+ "fieldname": "from_order_id",
+ "fieldtype": "Data",
+ "label": "From Order Id",
+ "mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
+ },
+ {
+ "depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
+ "fieldname": "to_order_id",
+ "fieldtype": "Data",
+ "label": "To Order Id",
+ "mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
}
],
"issingle": 1,
- "modified": "2020-09-18 17:26:09.703215",
+ "links": [],
+ "modified": "2021-03-02 17:35:41.953317",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Shopify Settings",
@@ -276,5 +348,6 @@
}
],
"sort_field": "modified",
- "sort_order": "DESC"
-}
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 25ffd28..cbdf906 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -87,7 +87,7 @@
def get_header(settings):
header = {'Content-Type': 'application/json'}
- return header;
+ return header
@frappe.whitelist()
def get_series():
@@ -121,17 +121,23 @@
],
"Sales Order": [
dict(fieldname='shopify_order_id', label='Shopify Order Id',
- fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
+ fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
+ dict(fieldname='shopify_order_number', label='Shopify Order Number',
+ fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
],
"Delivery Note":[
dict(fieldname='shopify_order_id', label='Shopify Order Id',
fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
+ dict(fieldname='shopify_order_number', label='Shopify Order Number',
+ fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1),
dict(fieldname='shopify_fulfillment_id', label='Shopify Fulfillment Id',
fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
],
"Sales Invoice": [
dict(fieldname='shopify_order_id', label='Shopify Order Id',
- fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
+ fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
+ dict(fieldname='shopify_order_number', label='Shopify Order Number',
+ fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
]
}
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
index 64ef3dc..5f471ab 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
@@ -5,7 +5,7 @@
import frappe
import unittest, os, json
-from frappe.utils import cstr
+from frappe.utils import cstr, cint
from erpnext.erpnext_integrations.connectors.shopify_connection import create_order
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import make_item
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
@@ -13,21 +13,31 @@
class ShopifySettings(unittest.TestCase):
- def setUp(self):
+ @classmethod
+ def setUpClass(cls):
frappe.set_user("Administrator")
+ cls.allow_negative_stock = cint(frappe.db.get_value('Stock Settings', None, 'allow_negative_stock'))
+ if not cls.allow_negative_stock:
+ frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 1)
+
# use the fixture data
- import_doc(path=frappe.get_app_path("erpnext", "erpnext_integrations/doctype/shopify_settings/test_data/custom_field.json"),
- ignore_links=True, overwrite=True)
+ import_doc(frappe.get_app_path("erpnext", "erpnext_integrations/doctype/shopify_settings/test_data/custom_field.json"))
frappe.reload_doctype("Customer")
frappe.reload_doctype("Sales Order")
frappe.reload_doctype("Delivery Note")
frappe.reload_doctype("Sales Invoice")
- self.setup_shopify()
+ cls.setup_shopify()
- def setup_shopify(self):
+ @classmethod
+ def tearDownClass(cls):
+ if not cls.allow_negative_stock:
+ frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0)
+
+ @classmethod
+ def setup_shopify(cls):
shopify_settings = frappe.get_doc("Shopify Settings")
shopify_settings.taxes = []
@@ -57,41 +67,40 @@
"delivery_note_series": "DN-"
}).save(ignore_permissions=True)
- self.shopify_settings = shopify_settings
-
+ cls.shopify_settings = shopify_settings
+
def test_order(self):
- ### Create Customer ###
+ # Create Customer
with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_customer.json")) as shopify_customer:
shopify_customer = json.load(shopify_customer)
create_customer(shopify_customer.get("customer"), self.shopify_settings)
- ### Create Item ###
+ # Create Item
with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_item.json")) as shopify_item:
shopify_item = json.load(shopify_item)
make_item("_Test Warehouse - _TC", shopify_item.get("product"))
-
- ### Create Order ###
+ # Create Order
with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_order.json")) as shopify_order:
shopify_order = json.load(shopify_order)
- create_order(shopify_order.get("order"), self.shopify_settings, "_Test Company")
+ create_order(shopify_order.get("order"), self.shopify_settings, False, company="_Test Company")
sales_order = frappe.get_doc("Sales Order", {"shopify_order_id": cstr(shopify_order.get("order").get("id"))})
self.assertEqual(cstr(shopify_order.get("order").get("id")), sales_order.shopify_order_id)
- #check for customer
+ # Check for customer
shopify_order_customer_id = cstr(shopify_order.get("order").get("customer").get("id"))
sales_order_customer_id = frappe.get_value("Customer", sales_order.customer, "shopify_customer_id")
self.assertEqual(shopify_order_customer_id, sales_order_customer_id)
- #check sales invoice
+ # Check sales invoice
sales_invoice = frappe.get_doc("Sales Invoice", {"shopify_order_id": sales_order.shopify_order_id})
self.assertEqual(sales_invoice.rounded_total, sales_order.rounded_total)
- #check delivery note
+ # Check delivery note
delivery_note_count = frappe.db.sql("""select count(*) from `tabDelivery Note`
where shopify_order_id = %s""", sales_order.shopify_order_id)[0][0]
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
index fd16d1e..5482b9c 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
@@ -23,10 +23,10 @@
frappe.msgprint({
message: __("An error has occurred during {0}. Check {1} for more details",
[
- repl("<a href='#Form/Tally Migration/%(tally_document)s' class='variant-click'>%(tally_document)s</a>", {
+ repl("<a href='/app/tally-migration/%(tally_document)s' class='variant-click'>%(tally_document)s</a>", {
tally_document: frm.docname
}),
- "<a href='#List/Error Log' class='variant-click'>Error Log</a>"
+ "<a href='/app/error-log' class='variant-click'>Error Log</a>"
]
),
title: __("Tally Migration Error"),
diff --git a/erpnext/erpnext_integrations/taxjar_integration.py b/erpnext/erpnext_integrations/taxjar_integration.py
index 24fc3d4..f960998 100644
--- a/erpnext/erpnext_integrations/taxjar_integration.py
+++ b/erpnext/erpnext_integrations/taxjar_integration.py
@@ -1,5 +1,7 @@
import traceback
+import taxjar
+
import frappe
from erpnext import get_default_company
from frappe import _
@@ -29,7 +31,6 @@
def create_transaction(doc, method):
- import taxjar
"""Create an order transaction in TaxJar"""
if not TAXJAR_CREATE_TRANSACTIONS:
diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py
index 84f7f5a..362f6cf 100644
--- a/erpnext/erpnext_integrations/utils.py
+++ b/erpnext/erpnext_integrations/utils.py
@@ -3,6 +3,7 @@
from frappe import _
import base64, hashlib, hmac
from six.moves.urllib.parse import urlparse
+from erpnext import get_default_company
def validate_webhooks_request(doctype, hmac_key, secret_key='secret'):
def innerfn(fn):
@@ -41,3 +42,30 @@
server_url = '{uri.scheme}://{uri.netloc}/api/method/{endpoint}'.format(uri=urlparse(url), endpoint=endpoint)
return server_url
+
+def create_mode_of_payment(gateway, payment_type="General"):
+ payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
+ "payment_gateway": gateway
+ }, ['payment_account'])
+
+ if not frappe.db.exists("Mode of Payment", gateway) and payment_gateway_account:
+ mode_of_payment = frappe.get_doc({
+ "doctype": "Mode of Payment",
+ "mode_of_payment": gateway,
+ "enabled": 1,
+ "type": payment_type,
+ "accounts": [{
+ "doctype": "Mode of Payment Account",
+ "company": get_default_company(),
+ "default_account": payment_gateway_account
+ }]
+ })
+ mode_of_payment.insert(ignore_permissions=True)
+
+def get_tracking_url(carrier, tracking_number):
+ # Return the formatted Tracking URL.
+ tracking_url = ''
+ url_reference = frappe.get_value('Parcel Service', carrier, 'url_reference')
+ if url_reference:
+ tracking_url = frappe.render_template(url_reference, {'tracking_number': tracking_number})
+ return tracking_url
diff --git a/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
new file mode 100644
index 0000000..4a5e54e
--- /dev/null
+++ b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
@@ -0,0 +1,116 @@
+{
+ "category": "Modules",
+ "charts": [],
+ "creation": "2020-08-20 19:30:48.138801",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends": "Integrations",
+ "extends_another_page": 1,
+ "hide_custom": 1,
+ "idx": 0,
+ "is_standard": 1,
+ "label": "ERPNext Integrations",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Marketplace",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Woocommerce Settings",
+ "link_to": "Woocommerce Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Amazon MWS Settings",
+ "link_to": "Amazon MWS Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shopify Settings",
+ "link_to": "Shopify Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payments",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "GoCardless Settings",
+ "link_to": "GoCardless Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "M-Pesa Settings",
+ "link_to": "Mpesa Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Plaid Settings",
+ "link_to": "Plaid Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Exotel Settings",
+ "link_to": "Exotel Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:35.846528",
+ "modified_by": "Administrator",
+ "module": "ERPNext Integrations",
+ "name": "ERPNext Integrations",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": []
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..d258d57
--- /dev/null
+++ b/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json
@@ -0,0 +1,82 @@
+{
+ "category": "Modules",
+ "charts": [],
+ "creation": "2020-07-31 10:38:54.021237",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends": "Settings",
+ "extends_another_page": 1,
+ "hide_custom": 0,
+ "idx": 0,
+ "is_standard": 1,
+ "label": "ERPNext Integrations Settings",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Integrations Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Woocommerce Settings",
+ "link_to": "Woocommerce Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shopify Settings",
+ "link_to": "Shopify Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Amazon MWS Settings",
+ "link_to": "Amazon MWS Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Plaid Settings",
+ "link_to": "Plaid Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Exotel Settings",
+ "link_to": "Exotel Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:34.732552",
+ "modified_by": "Administrator",
+ "module": "ERPNext Integrations",
+ "name": "ERPNext Integrations Settings",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": []
+}
\ No newline at end of file
diff --git a/erpnext/exceptions.py b/erpnext/exceptions.py
index d92af5d..04291cd 100644
--- a/erpnext/exceptions.py
+++ b/erpnext/exceptions.py
@@ -6,3 +6,5 @@
class InvalidAccountCurrency(frappe.ValidationError): pass
class InvalidCurrency(frappe.ValidationError): pass
class PartyDisabled(frappe.ValidationError):pass
+class InvalidAccountDimensionError(frappe.ValidationError): pass
+class MandatoryAccountDimensionError(frappe.ValidationError): pass
diff --git a/erpnext/healthcare/desk_page/healthcare/healthcare.json b/erpnext/healthcare/desk_page/healthcare/healthcare.json
index 6546b08..af601f3 100644
--- a/erpnext/healthcare/desk_page/healthcare/healthcare.json
+++ b/erpnext/healthcare/desk_page/healthcare/healthcare.json
@@ -32,18 +32,23 @@
},
{
"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\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]"
+ "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]"
+ "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",
@@ -64,7 +69,7 @@
"idx": 0,
"is_standard": 1,
"label": "Healthcare",
- "modified": "2020-06-25 23:50:56.951698",
+ "modified": "2020-11-26 22:09:09.164584",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Healthcare",
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.js b/erpnext/healthcare/doctype/appointment_type/appointment_type.js
index 15916a5..861675a 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.js
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.js
@@ -2,4 +2,82 @@
// 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);
+ }
+ }
+ });
+ }
+ }
+});
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.json b/erpnext/healthcare/doctype/appointment_type/appointment_type.json
index 58753bb..3872318 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.json
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.json
@@ -12,7 +12,10 @@
"appointment_type",
"ip",
"default_duration",
- "color"
+ "color",
+ "billing_section",
+ "price_list",
+ "items"
],
"fields": [
{
@@ -52,10 +55,27 @@
"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": "2020-02-03 21:06:05.833050",
+ "modified": "2021-01-22 09:41:05.010524",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Appointment Type",
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.py b/erpnext/healthcare/doctype/appointment_type/appointment_type.py
index 1dacffa..67a24f3 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.py
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.py
@@ -4,6 +4,53 @@
from __future__ import unicode_literals
from frappe.model.document import Document
+import frappe
class AppointmentType(Document):
- pass
+ 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/accounts/doctype/bank_statement_settings_item/__init__.py b/erpnext/healthcare/doctype/appointment_type_service_item/__init__.py
similarity index 100%
rename from erpnext/accounts/doctype/bank_statement_settings_item/__init__.py
rename to erpnext/healthcare/doctype/appointment_type_service_item/__init__.py
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
new file mode 100644
index 0000000..5ff68cd
--- /dev/null
+++ b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json
@@ -0,0 +1,67 @@
+{
+ "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 Item"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-01-22 09:35:26.503443",
+ "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/appointment_type_service_item/appointment_type_service_item.py b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
new file mode 100644
index 0000000..b2e0e82
--- /dev/null
+++ b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
@@ -0,0 +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):
+ pass
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
index eb7d4bd..b55d5d6 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
@@ -85,8 +85,7 @@
callback: function(r) {
if (r.message) {
frappe.show_alert({
- message: __('Stock Entry {0} created',
- ['<a class="bold" href="#Form/Stock Entry/'+ r.message + '">' + r.message + '</a>']),
+ message: __('Stock Entry {0} created', ['<a class="bold" href="/app/stock-entry/'+ r.message + '">' + r.message + '</a>']),
indicator: 'green'
});
}
@@ -105,8 +104,7 @@
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()]);
+ 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() {
@@ -366,7 +364,7 @@
let age = new Date();
age.setTime(ageMS);
let years = age.getFullYear() - 1970;
- return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
+ return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`;
};
// List Stock items
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index e55a143..325c209 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -100,7 +100,6 @@
allow_start = self.set_actual_qty()
if allow_start:
self.db_set('status', 'In Progress')
- insert_clinical_procedure_to_medical_record(self)
return 'success'
return 'insufficient stock'
@@ -122,6 +121,7 @@
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:
@@ -247,21 +247,3 @@
}, target_doc, set_missing_values)
return doc
-
-
-def insert_clinical_procedure_to_medical_record(doc):
- subject = frappe.bold(_("Clinical Procedure conducted: ")) + cstr(doc.procedure_template) + "<br>"
- if doc.practitioner:
- subject += frappe.bold(_('Healthcare Practitioner: ')) + doc.practitioner
- if subject and doc.notes:
- subject += '<br/>' + doc.notes
-
- 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.start_date
- medical_record.reference_doctype = 'Clinical Procedure'
- medical_record.reference_name = doc.name
- medical_record.reference_owner = doc.owner
- medical_record.save(ignore_permissions=True)
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index 4ee5f6b..fb72073 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+ # -*- coding: utf-8 -*-
# Copyright (c) 2017, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
@@ -60,6 +60,7 @@
procedure.practitioner = practitioner
procedure.consume_stock = procedure_template.allow_stock_consumption
procedure.items = procedure_template.items
- procedure.warehouse = frappe.db.get_single_value('Stock Settings', 'default_warehouse')
+ procedure.company = "_Test Company"
+ procedure.warehouse = "_Test Warehouse - _TC"
procedure.submit()
return procedure
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json
index 5e4d59c..d91e6bf 100644
--- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json
+++ b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json
@@ -43,7 +43,8 @@
"ignore_user_permissions": 1,
"in_list_view": 1,
"label": "Dosage",
- "options": "Prescription Dosage"
+ "options": "Prescription Dosage",
+ "reqd": 1
},
{
"fieldname": "period",
@@ -51,14 +52,16 @@
"ignore_user_permissions": 1,
"in_list_view": 1,
"label": "Period",
- "options": "Prescription Duration"
+ "options": "Prescription Duration",
+ "reqd": 1
},
{
"fieldname": "dosage_form",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Dosage Form",
- "options": "Dosage Form"
+ "options": "Dosage Form",
+ "reqd": 1
},
{
"fieldname": "column_break_7",
@@ -72,7 +75,7 @@
"label": "Comment"
},
{
- "depends_on": "use_interval",
+ "depends_on": "usage_interval",
"fieldname": "interval",
"fieldtype": "Int",
"in_list_view": 1,
@@ -80,6 +83,7 @@
},
{
"default": "1",
+ "depends_on": "usage_interval",
"fieldname": "update_schedule",
"fieldtype": "Check",
"hidden": 1,
@@ -99,12 +103,13 @@
"default": "0",
"fieldname": "usage_interval",
"fieldtype": "Check",
+ "hidden": 1,
"label": "Dosage by Time Interval"
}
],
"istable": 1,
"links": [],
- "modified": "2020-02-26 17:02:42.741338",
+ "modified": "2020-09-30 23:32:09.495288",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Drug Prescription",
diff --git a/erpnext/healthcare/doctype/exercise/exercise.json b/erpnext/healthcare/doctype/exercise/exercise.json
index 2486a5d..683cc6d 100644
--- a/erpnext/healthcare/doctype/exercise/exercise.json
+++ b/erpnext/healthcare/doctype/exercise/exercise.json
@@ -37,7 +37,8 @@
"depends_on": "eval:doc.parenttype==\"Therapy\";",
"fieldname": "counts_completed",
"fieldtype": "Int",
- "label": "Counts Completed"
+ "label": "Counts Completed",
+ "no_copy": 1
},
{
"fieldname": "assistance_level",
@@ -48,7 +49,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-04-10 13:41:06.662351",
+ "modified": "2020-11-04 18:20:25.583491",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Exercise",
diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.js b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
index 68db047..b49b00e 100644
--- a/erpnext/healthcare/doctype/exercise_type/exercise_type.js
+++ b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
@@ -71,7 +71,7 @@
$('.btn-del').on('click', function() {
let id = $(this).attr('data-id');
- $('#card-'+id).addClass("zoomOutDelete");
+ $('#card-'+id).addClass("zoom-out");
setTimeout(() => {
// not using grid_rows[id].remove because
diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
index cdf692e..7e7fd82 100644
--- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
+++ b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
@@ -7,6 +7,7 @@
import unittest
from frappe.utils import nowdate, add_days
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_appointment, create_healthcare_service_items
+from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
test_dependencies = ["Company"]
@@ -15,6 +16,7 @@
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()
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
index cb747f9..8162f03 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
@@ -159,6 +159,7 @@
"fieldname": "op_consulting_charge",
"fieldtype": "Currency",
"label": "Out Patient Consulting Charge",
+ "mandatory_depends_on": "op_consulting_charge_item",
"options": "Currency"
},
{
@@ -174,7 +175,8 @@
{
"fieldname": "inpatient_visit_charge",
"fieldtype": "Currency",
- "label": "Inpatient Visit Charge"
+ "label": "Inpatient Visit Charge",
+ "mandatory_depends_on": "inpatient_visit_charge_item"
},
{
"depends_on": "eval: !doc.__islocal",
@@ -280,7 +282,7 @@
],
"image_field": "image",
"links": [],
- "modified": "2020-04-06 13:44:24.759623",
+ "modified": "2021-01-22 10:14:43.187675",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Healthcare Practitioner",
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
index a03b579..b75f271 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit_tree.js
+++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit_tree.js
@@ -12,20 +12,20 @@
get_tree_nodes: 'erpnext.healthcare.utils.get_children',
ignore_fields:["parent_healthcare_service_unit"],
onrender: function(node) {
- if (node.data.occupied_out_of_vacant!==undefined){
- $('<span class="balance-area pull-right text-muted small">'
+ if (node.data.occupied_out_of_vacant!==undefined) {
+ $('<span class="balance-area pull-right">'
+ " " + node.data.occupied_out_of_vacant
+ '</span>').insertBefore(node.$ul);
}
if (node.data && node.data.inpatient_occupancy!==undefined) {
- if (node.data.inpatient_occupancy == 1){
- if (node.data.occupancy_status == "Occupied"){
- $('<span class="balance-area pull-right small">'
+ if (node.data.inpatient_occupancy == 1) {
+ if (node.data.occupancy_status == "Occupied") {
+ $('<span class="balance-area pull-right">'
+ " " + node.data.occupancy_status
+ '</span>').insertBefore(node.$ul);
}
- if (node.data.occupancy_status == "Vacant"){
- $('<span class="balance-area pull-right text-muted small">'
+ if (node.data.occupancy_status == "Vacant") {
+ $('<span class="balance-area pull-right">'
+ " " + node.data.occupancy_status
+ '</span>').insertBefore(node.$ul);
}
diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
index 0104386..ddf1bce 100644
--- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
+++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
@@ -17,6 +17,9 @@
"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",
@@ -302,11 +305,28 @@
"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": "2020-07-08 15:17:21.543218",
+ "modified": "2021-01-13 09:04:35.877700",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Healthcare Settings",
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/__init__.py b/erpnext/healthcare/doctype/inpatient_medication_entry/__init__.py
similarity index 100%
rename from erpnext/accounts/doctype/bank_statement_transaction_entry/__init__.py
rename to erpnext/healthcare/doctype/inpatient_medication_entry/__init__.py
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
new file mode 100644
index 0000000..a7b06b1
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
@@ -0,0 +1,74 @@
+// 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
new file mode 100644
index 0000000..b1a6ee4
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.json
@@ -0,0 +1,204 @@
+{
+ "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
new file mode 100644
index 0000000..e731908
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
@@ -0,0 +1,320 @@
+# -*- 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, getdate, nowtime
+from erpnext.stock.utils import get_latest_stock_qty
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
+
+class InpatientMedicationEntry(Document):
+ def validate(self):
+ self.validate_medication_orders()
+
+ 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 += """
+ <td>{0}</td>
+ <td>{1}</td>
+ </tr>""".format(item_link, frappe.bold(shortage_qty))
+
+ message += """
+ <table class='table'>
+ <thead>
+ <th>{0}</th>
+ <th>{1}</th>
+ </thead>
+ {2}
+ </table>
+ """.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
new file mode 100644
index 0000000..a4bec45
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py
@@ -0,0 +1,16 @@
+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
new file mode 100644
index 0000000..7cb5a48
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.utils import add_days, getdate, now_datetime
+from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
+from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import create_ipmo, create_ipme
+from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import get_drug_shortage_map, make_difference_stock_entry
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
+
+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()
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/inpatient_medication_entry_detail/__init__.py
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
new file mode 100644
index 0000000..e3d7212
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.json
@@ -0,0 +1,163 @@
+{
+ "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
new file mode 100644
index 0000000..644898d
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class InpatientMedicationEntryDetail(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/inpatient_medication_order/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/inpatient_medication_order/__init__.py
diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.js b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.js
new file mode 100644
index 0000000..690e2e7
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.js
@@ -0,0 +1,107 @@
+// 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
new file mode 100644
index 0000000..e31d2e3
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.json
@@ -0,0 +1,196 @@
+{
+ "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
new file mode 100644
index 0000000..33cbbec
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py
@@ -0,0 +1,74 @@
+# -*- 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)
+
+ 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
new file mode 100644
index 0000000..1c31876
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order_list.js
@@ -0,0 +1,16 @@
+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
new file mode 100644
index 0000000..a21caca
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.utils import add_days, getdate, now_datetime
+from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
+
+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 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_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/accounts/doctype/bank_statement_transaction_entry/__init__.py b/erpnext/healthcare/doctype/inpatient_medication_order_entry/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_transaction_entry/__init__.py
copy to erpnext/healthcare/doctype/inpatient_medication_order_entry/__init__.py
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
new file mode 100644
index 0000000..72999a9
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.json
@@ -0,0 +1,94 @@
+{
+ "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
new file mode 100644
index 0000000..ebfe366
--- /dev/null
+++ b/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class InpatientMedicationOrderEntry(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json
index 5ced845..aaf0e85 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json
@@ -53,7 +53,7 @@
"discharge_ordered_date",
"discharge_practitioner",
"discharge_encounter",
- "discharge_date",
+ "discharge_datetime",
"cb_discharge",
"discharge_instructions",
"followup_date",
@@ -404,14 +404,15 @@
"permlevel": 1
},
{
- "fieldname": "discharge_date",
- "fieldtype": "Date",
+ "fieldname": "discharge_datetime",
+ "fieldtype": "Datetime",
"label": "Discharge Date",
"read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-05-21 02:26:22.144575",
+ "modified": "2021-03-18 14:44:11.689956",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Inpatient Record",
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
index bc76970..2934316 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe, json
from frappe import _
-from frappe.utils import today, now_datetime, getdate, get_datetime
+from frappe.utils import today, now_datetime, getdate, get_datetime, get_link_to_form
from frappe.model.document import Document
from frappe.desk.reportview import get_match_cond
@@ -50,7 +50,7 @@
if ip_record:
msg = _(("Already {0} Patient {1} with Inpatient Record ").format(ip_record[0].status, self.patient) \
- + """ <b><a href="#Form/Inpatient Record/{0}">{0}</a></b>""".format(ip_record[0].name))
+ + """ <b><a href="/app/Form/Inpatient Record/{0}">{0}</a></b>""".format(ip_record[0].name))
frappe.throw(msg)
def admit(self, service_unit, check_in, expected_discharge=None):
@@ -113,6 +113,7 @@
inpatient_record.status = 'Admission Scheduled'
inpatient_record.save(ignore_permissions = True)
+
@frappe.whitelist()
def schedule_discharge(args):
discharge_order = json.loads(args)
@@ -126,16 +127,19 @@
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:
@@ -144,54 +148,88 @@
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_invoiced_inpatient(inpatient_record)
- inpatient_record.discharge_date = today()
+ validate_inpatient_invoicing(inpatient_record)
+ inpatient_record.discharge_datetime = now_datetime()
inpatient_record.status = "Discharged"
inpatient_record.save(ignore_permissions = True)
-def validate_invoiced_inpatient(inpatient_record):
- pending_invoices = []
+
+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 += """
+ <td>{0}</td>
+ <td>{1}</td>
+ </tr>""".format(doctype, docnames)
+
+ message += """
+ <table class='table'>
+ <thead>
+ <th>{0}</th>
+ <th>{1}</th>
+ </thead>
+ {2}
+ </table>
+ """.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 inpatient_occupancy.invoiced != 1:
+ 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.append("Inpatient Occupancy (" + 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_inpatient_docs_not_invoiced(doc, inpatient_record)
+ 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)
- if pending_invoices:
- frappe.throw(_("Can not mark Inpatient Record Discharged, there are Unbilled Invoices {0}").format(", "
- .join(pending_invoices)), title=_('Unbilled 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_name.name
+ doc_ids += ", " + doc_link
else:
- doc_ids = doc_name.name
+ doc_ids = doc_link
if doc_ids:
- pending_invoices.append(doc + " (" + doc_ids + ")")
+ pending_invoices[doc] = doc_ids
return pending_invoices
-def get_inpatient_docs_not_invoiced(doc, inpatient_record):
+
+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'
@@ -203,6 +241,7 @@
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
@@ -212,6 +251,7 @@
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:
@@ -221,6 +261,7 @@
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):
diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
index 2bef5fb..a8c7720 100644
--- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
@@ -8,6 +8,8 @@
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):
@@ -40,6 +42,60 @@
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()
@@ -63,6 +119,13 @@
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')
@@ -76,13 +139,20 @@
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():
- service_unit = get_random("Healthcare Service Unit", filters={"inpatient_occupancy": 1})
+
+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 = "Test Service Unit Ip Occupancy"
+ 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"
@@ -104,6 +174,7 @@
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})
@@ -115,6 +186,7 @@
return service_unit_type.name
return service_unit_type
+
def create_patient():
patient = frappe.db.exists('Patient', '_Test IPD Patient')
if not patient:
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.js b/erpnext/healthcare/doctype/lab_test/lab_test.js
index f1634c1..bb7976c 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.js
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.js
@@ -258,5 +258,5 @@
var age = new Date();
age.setTime(ageMS);
var years = age.getFullYear() - 1970;
- return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
+ 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
index edf1d91..ac61fea 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.json
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.json
@@ -359,6 +359,7 @@
{
"fieldname": "normal_test_items",
"fieldtype": "Table",
+ "label": "Normal Test Result",
"options": "Normal Test Result",
"print_hide": 1
},
@@ -380,6 +381,7 @@
{
"fieldname": "sensitivity_test_items",
"fieldtype": "Table",
+ "label": "Sensitivity Test Result",
"options": "Sensitivity Test Result",
"print_hide": 1,
"report_hide": 1
@@ -529,6 +531,7 @@
{
"fieldname": "descriptive_test_items",
"fieldtype": "Table",
+ "label": "Descriptive Test Result",
"options": "Descriptive Test Result",
"print_hide": 1,
"report_hide": 1
@@ -549,13 +552,14 @@
{
"fieldname": "organism_test_items",
"fieldtype": "Table",
+ "label": "Organism Test Result",
"options": "Organism Test Result",
"print_hide": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-07-30 18:18:38.516215",
+ "modified": "2020-11-30 11:04:17.195848",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Lab Test",
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py
index 2db7743..4b57cd0 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.py
@@ -17,11 +17,9 @@
self.validate_result_values()
self.db_set('submitted_date', getdate())
self.db_set('status', 'Completed')
- insert_lab_test_to_medical_record(self)
def on_cancel(self):
self.db_set('status', 'Cancelled')
- delete_lab_test_from_medical_record(self)
self.reload()
def on_update(self):
@@ -330,60 +328,6 @@
return frappe.get_doc('Employee', emp_id)
return None
-def insert_lab_test_to_medical_record(doc):
- table_row = False
- subject = cstr(doc.lab_test_name)
- if doc.practitioner:
- subject += frappe.bold(_('Healthcare Practitioner: '))+ doc.practitioner + '<br>'
- if doc.normal_test_items:
- item = doc.normal_test_items[0]
- comment = ''
- if item.lab_test_comment:
- comment = str(item.lab_test_comment)
- table_row = frappe.bold(_('Lab Test Conducted: ')) + item.lab_test_name
-
- if item.lab_test_event:
- table_row += frappe.bold(_('Lab Test Event: ')) + item.lab_test_event
-
- if item.result_value:
- table_row += ' ' + frappe.bold(_('Lab Test Result: ')) + item.result_value
-
- if item.normal_range:
- table_row += ' ' + _('Normal Range: ') + item.normal_range
- table_row += ' ' + comment
-
- elif doc.descriptive_test_items:
- item = doc.descriptive_test_items[0]
-
- if item.lab_test_particulars and item.result_value:
- table_row = item.lab_test_particulars + ' ' + item.result_value
-
- elif doc.sensitivity_test_items:
- item = doc.sensitivity_test_items[0]
-
- if item.antibiotic and item.antibiotic_sensitivity:
- table_row = item.antibiotic + ' ' + item.antibiotic_sensitivity
-
- if table_row:
- subject += '<br>' + table_row
- if doc.lab_test_comment:
- subject += '<br>' + cstr(doc.lab_test_comment)
-
- 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.result_date
- medical_record.reference_doctype = 'Lab Test'
- medical_record.reference_name = doc.name
- medical_record.reference_owner = doc.owner
- medical_record.save(ignore_permissions = True)
-
-def delete_lab_test_from_medical_record(self):
- medical_record_id = frappe.db.sql('select name from `tabPatient Medical Record` where reference_name=%s', (self.name))
-
- if medical_record_id and medical_record_id[0][0]:
- frappe.delete_doc('Patient Medical Record', medical_record_id[0][0])
@frappe.whitelist()
def get_lab_test_prescribed(patient):
diff --git a/erpnext/healthcare/doctype/patient/patient.js b/erpnext/healthcare/doctype/patient/patient.js
index 490f247..bce42e5 100644
--- a/erpnext/healthcare/doctype/patient/patient.js
+++ b/erpnext/healthcare/doctype/patient/patient.js
@@ -46,11 +46,11 @@
}
},
onload: function (frm) {
- if(!frm.doc.dob){
+ if (!frm.doc.dob) {
$(frm.fields_dict['age_html'].wrapper).html('');
}
- if(frm.doc.dob){
- $(frm.fields_dict['age_html'].wrapper).html('AGE : ' + get_age(frm.doc.dob));
+ if (frm.doc.dob) {
+ $(frm.fields_dict['age_html'].wrapper).html(`${__('AGE')} : ${get_age(frm.doc.dob)}`);
}
}
});
@@ -65,7 +65,7 @@
}
else {
let age_str = get_age(frm.doc.dob);
- $(frm.fields_dict['age_html'].wrapper).html('AGE : ' + age_str);
+ $(frm.fields_dict['age_html'].wrapper).html(`${__('AGE')} : ${age_str}`);
}
}
else {
diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py
index 63dd8d4..8603f97 100644
--- a/erpnext/healthcare/doctype/patient/patient.py
+++ b/erpnext/healthcare/doctype/patient/patient.py
@@ -108,7 +108,7 @@
if self.dob:
dob = getdate(self.dob)
age = dateutil.relativedelta.relativedelta(getdate(), dob)
- age_str = str(age.years) + ' year(s) ' + str(age.months) + ' month(s) ' + str(age.days) + ' day(s)'
+ age_str = str(age.years) + ' ' + _("Years(s)") + ' ' + str(age.months) + ' ' + _("Month(s)") + ' ' + str(age.days) + ' ' + _("Day(s)")
return age_str
def invoice_patient_registration(self):
diff --git a/erpnext/healthcare/doctype/patient/patient_dashboard.py b/erpnext/healthcare/doctype/patient/patient_dashboard.py
index e3def72..39603f7 100644
--- a/erpnext/healthcare/doctype/patient/patient_dashboard.py
+++ b/erpnext/healthcare/doctype/patient/patient_dashboard.py
@@ -18,6 +18,10 @@
{
'label': _('Billing'),
'items': ['Sales Invoice']
+ },
+ {
+ 'label': _('Orders'),
+ 'items': ['Inpatient Medication Order']
}
]
}
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
index 2d6b645..2976ef1 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
@@ -22,23 +22,37 @@
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: {
- 'department': frm.doc.department
+ company: frm.doc.company,
+ inpatient_record: frm.doc.inpatient_record
}
};
});
- frm.set_query('service_unit', function(){
+
+ frm.set_query('therapy_plan', function() {
return {
filters: {
- 'is_group': false,
- 'allow_appointments': true,
- 'company': frm.doc.company
+ '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) {
@@ -128,6 +142,20 @@
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', '');
@@ -136,6 +164,55 @@
}
},
+ 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) => {
@@ -160,14 +237,18 @@
// 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 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);
}
}
});
@@ -510,61 +591,10 @@
);
};
-frappe.ui.form.on('Patient Appointment', '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, 'department', data.message.department);
- frappe.model.set_value(frm.doctype, frm.docname, 'paid_amount', data.message.op_consulting_charge);
- frappe.model.set_value(frm.doctype, frm.docname, 'billing_item', data.message.op_consulting_charge_item);
- }
- });
- }
-});
-
-frappe.ui.form.on('Patient Appointment', 'patient', function(frm) {
- if (frm.doc.patient) {
- 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);
- }
- });
- }
-});
-
-frappe.ui.form.on('Patient Appointment', 'appointment_type', function(frm) {
- if (frm.doc.appointment_type) {
- frappe.call({
- method: 'frappe.client.get',
- args: {
- doctype: 'Appointment Type',
- name: frm.doc.appointment_type
- },
- callback: function(data) {
- frappe.model.set_value(frm.doctype,frm.docname, 'duration',data.message.default_duration);
- }
- });
- }
-});
-
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 + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
+ 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
index ac35acc..83c92af 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
@@ -19,19 +19,19 @@
"inpatient_record",
"column_break_1",
"company",
- "service_unit",
- "procedure_template",
- "get_procedure_from_encounter",
- "procedure_prescription",
- "therapy_type",
- "get_prescribed_therapies",
- "therapy_plan",
"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",
@@ -79,6 +79,7 @@
"set_only_once": 1
},
{
+ "fetch_from": "appointment_type.default_duration",
"fieldname": "duration",
"fieldtype": "Int",
"in_filter": 1,
@@ -144,7 +145,6 @@
"in_standard_filter": 1,
"label": "Healthcare Practitioner",
"options": "Healthcare Practitioner",
- "read_only": 1,
"reqd": 1,
"search_index": 1,
"set_only_once": 1
@@ -158,7 +158,6 @@
"in_standard_filter": 1,
"label": "Department",
"options": "Medical Department",
- "read_only": 1,
"search_index": 1,
"set_only_once": 1
},
@@ -227,12 +226,14 @@
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"label": "Mode of Payment",
- "options": "Mode of Payment"
+ "options": "Mode of Payment",
+ "read_only_depends_on": "invoiced"
},
{
"fieldname": "paid_amount",
"fieldtype": "Currency",
- "label": "Paid Amount"
+ "label": "Paid Amount",
+ "read_only_depends_on": "invoiced"
},
{
"fieldname": "column_break_2",
@@ -284,7 +285,7 @@
"report_hide": 1
},
{
- "depends_on": "eval:doc.patient;",
+ "depends_on": "eval:doc.patient && doc.therapy_plan;",
"fieldname": "therapy_type",
"fieldtype": "Link",
"label": "Therapy",
@@ -292,18 +293,18 @@
"set_only_once": 1
},
{
- "depends_on": "eval:doc.patient && doc.__islocal;",
+ "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 && doc.therapy_type",
+ "depends_on": "eval: doc.patient;",
"fieldname": "therapy_plan",
"fieldtype": "Link",
"label": "Therapy Plan",
- "mandatory_depends_on": "eval: doc.patient && doc.therapy_type",
- "options": "Therapy Plan"
+ "options": "Therapy Plan",
+ "set_only_once": 1
},
{
"fieldname": "ref_sales_invoice",
@@ -348,7 +349,7 @@
}
],
"links": [],
- "modified": "2020-05-21 03:04:21.400893",
+ "modified": "2021-02-08 13:13:15.116833",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Appointment",
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
index e685b20..1f76cd6 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -18,6 +18,7 @@
class PatientAppointment(Document):
def validate(self):
self.validate_overlaps()
+ self.validate_service_unit()
self.set_appointment_datetime()
self.validate_customer_created()
self.set_status()
@@ -25,6 +26,7 @@
def after_insert(self):
self.update_prescription_details()
+ self.set_payment_details()
invoice_appointment(self)
self.update_fee_validity()
send_confirmation_msg(self)
@@ -63,19 +65,39 @@
if overlaps:
overlapping_details = _('Appointment overlaps with ')
- overlapping_details += "<b><a href='#Form/Patient Appointment/{0}'>{0}</a></b><br>".format(overlaps[0][0])
+ overlapping_details += "<b><a href='/app/Form/Patient Appointment/{0}'>{0}</a></b><br>".format(overlaps[0][0])
overlapping_details += _('{0} has appointment scheduled with {1} at {2} having {3} minute(s) duration.').format(
overlaps[0][1], overlaps[0][2], overlaps[0][3], overlaps[0][4])
frappe.throw(overlapping_details, title=_('Appointments Overlapping'))
+ 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)) + '<br>'
+ 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 += " <b><a href='#Form/Patient/{0}'>{0}</a></b>".format(self.patient)
+ msg += " <b><a href='/app/Form/Patient/{0}'>{0}</a></b>".format(self.patient)
frappe.throw(msg, title=_('Customer Not Found'))
def update_prescription_details(self):
@@ -91,6 +113,17 @@
if fee_validity:
frappe.msgprint(_('{0} has fee validity till {1}').format(self.patient, fee_validity.valid_till))
+ 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):
@@ -123,31 +156,37 @@
fee_validity = None
if automate_invoicing and not appointment_invoiced and not fee_validity:
- 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)
+ create_sales_invoice(appointment_doc)
- 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
+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)
- 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)
- frappe.db.set_value('Patient Appointment', appointment_doc.name, 'ref_sales_invoice', sales_invoice.name)
+ 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):
@@ -162,13 +201,14 @@
def get_appointment_item(appointment_doc, item):
- service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment_doc)
- item.item_code = service_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 = practitioner_charge
- item.amount = practitioner_charge
+ item.rate = charge
+ item.amount = charge
item.qty = 1
item.reference_dt = 'Patient Appointment'
item.reference_dn = appointment_doc.name
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index eeed157..2bb8a53 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -5,14 +5,16 @@
import unittest
import frappe
from erpnext.healthcare.doctype.patient_appointment.patient_appointment import update_status, make_encounter
-from frappe.utils import nowdate, add_days
+from frappe.utils import nowdate, add_days, now_datetime
from frappe.utils.make_random import get_random
+from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
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()
def test_status(self):
patient, medical_department, practitioner = create_healthcare_docs()
@@ -21,14 +23,17 @@
self.assertEquals(appointment.status, 'Open')
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2))
self.assertEquals(appointment.status, 'Scheduled')
- create_encounter(appointment)
+ encounter = create_encounter(appointment)
self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
+ encounter.cancel()
+ self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
def test_start_encounter(self):
patient, medical_department, 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)
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 1)
+ appointment.reload()
+ self.assertEqual(appointment.invoiced, 1)
encounter = make_encounter(appointment.name)
self.assertTrue(encounter)
self.assertEqual(encounter.company, appointment.company)
@@ -37,7 +42,7 @@
# invoiced flag mapped from appointment
self.assertEqual(encounter.invoiced, frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'))
- def test_invoicing(self):
+ def test_auto_invoicing(self):
patient, medical_department, 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)
@@ -53,6 +58,50 @@
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, medical_department, 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)
+ appointment_type = create_appointment_type()
+
+ appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
+ invoice=1, appointment_type=appointment_type.name, department='_Test 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, medical_department, 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, medical_department, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
@@ -74,6 +123,59 @@
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, medical_department, 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, medical_department, 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 create_healthcare_docs():
patient = create_patient()
@@ -121,23 +223,28 @@
encounter.submit()
return encounter
-def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0):
+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 = '_Test Medical Department'
+ 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'
- appointment.paid_amount = 500
+ if appointment_type:
+ appointment.appointment_type = appointment_type
if procedure_template:
appointment.procedure_template = create_clinical_procedure_template().get('name')
- appointment.save(ignore_permissions=True)
+ if save:
+ appointment.save(ignore_permissions=True)
return appointment
def create_healthcare_service_items():
@@ -148,6 +255,7 @@
item.item_name = 'Consulting Charges'
item.item_group = 'Services'
item.is_stock_item = 0
+ item.stock_uom = 'Nos'
item.save()
return item.name
@@ -162,4 +270,29 @@
template.description = 'Knee Surgery and Rehab'
template.rate = 50000
template.save()
- return template
\ No newline at end of file
+ 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': '_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()
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
index 6353d19..aaeaa69 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
@@ -58,6 +58,14 @@
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() {
@@ -350,5 +358,5 @@
let age = new Date();
age.setTime(ageMS);
let years = age.getFullYear() - 1970;
- return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
+ 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
index 15675f4..b646ff9 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
@@ -210,7 +210,7 @@
{
"fieldname": "drug_prescription",
"fieldtype": "Table",
- "label": "Items",
+ "label": "Drug Prescription",
"options": "Drug Prescription"
},
{
@@ -328,7 +328,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-05-16 21:00:08.644531",
+ "modified": "2020-11-30 10:39:00.783119",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Encounter",
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
index 262fc46..cc21417 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
@@ -6,8 +6,9 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cstr
+from frappe.utils import cstr, getdate, add_days
from frappe import _
+from frappe.model.mapper import get_mapped_doc
class PatientEncounter(Document):
def validate(self):
@@ -16,26 +17,69 @@
def on_update(self):
if self.appointment:
frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed')
- update_encounter_medical_record(self)
-
- def after_insert(self):
- insert_encounter_to_medical_record(self)
def on_submit(self):
- update_encounter_medical_record(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')
- delete_medical_record(self)
- def on_submit(self):
- create_therapy_plan(self)
+ 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()
+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')
@@ -51,51 +95,8 @@
encounter.db_set('therapy_plan', doc.name)
frappe.msgprint(_('Therapy Plan {0} created successfully.').format(frappe.bold(doc.name)), alert=True)
-def insert_encounter_to_medical_record(doc):
- subject = set_subject_field(doc)
- 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.encounter_date
- medical_record.reference_doctype = 'Patient Encounter'
- medical_record.reference_name = doc.name
- medical_record.reference_owner = doc.owner
- medical_record.save(ignore_permissions=True)
-def update_encounter_medical_record(encounter):
- medical_record_id = frappe.db.exists('Patient Medical Record', {'reference_name': encounter.name})
-
- if medical_record_id and medical_record_id[0][0]:
- subject = set_subject_field(encounter)
- frappe.db.set_value('Patient Medical Record', medical_record_id[0][0], 'subject', subject)
- else:
- insert_encounter_to_medical_record(encounter)
-
-def delete_medical_record(encounter):
- frappe.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name)
-
-def set_subject_field(encounter):
- subject = frappe.bold(_('Healthcare Practitioner: ')) + encounter.practitioner + '<br>'
- if encounter.symptoms:
- subject += frappe.bold(_('Symptoms: ')) + '<br>'
- for entry in encounter.symptoms:
- subject += cstr(entry.complaint) + '<br>'
- else:
- subject += frappe.bold(_('No Symptoms')) + '<br>'
-
- if encounter.diagnosis:
- subject += frappe.bold(_('Diagnosis: ')) + '<br>'
- for entry in encounter.diagnosis:
- subject += cstr(entry.diagnosis) + '<br>'
- else:
- subject += frappe.bold(_('No Diagnosis')) + '<br>'
-
- if encounter.drug_prescription:
- subject += '<br>' + _('Drug(s) Prescribed.')
- if encounter.lab_test_prescription:
- subject += '<br>' + _('Test(s) Prescribed.')
- if encounter.procedure_prescription:
- subject += '<br>' + _('Procedure(s) Prescribed.')
-
- return subject
+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)
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
index b08b172..39e54f5 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
@@ -5,12 +5,18 @@
return {
'fieldname': 'encounter',
'non_standard_fieldnames': {
- 'Patient Medical Record': 'reference_name'
+ '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/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/patient_history_custom_document_type/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/patient_history_custom_document_type/__init__.py
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
new file mode 100644
index 0000000..3025c7b
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json
@@ -0,0 +1,55 @@
+{
+ "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
new file mode 100644
index 0000000..f0a1f92
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class PatientHistoryCustomDocumentType(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/patient_history_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/patient_history_settings/__init__.py
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js
new file mode 100644
index 0000000..453da6a
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js
@@ -0,0 +1,133 @@
+// 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(`
+ <div class="columns-search">
+ <input type="text" placeholder="${__('Search')}" data-element="search" class="form-control input-xs">
+ </div>`
+ );
+
+ 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
new file mode 100644
index 0000000..143e2c9
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json
@@ -0,0 +1,55 @@
+{
+ "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
new file mode 100644
index 0000000..2e8c994
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
@@ -0,0 +1,188 @@
+# -*- 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
+from frappe import _
+from frappe.utils import cstr, cint
+from frappe.model.document import Document
+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)))
+
+ 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
+
+ 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')) + ': ') + '<br>' + cstr(formatted_value) + '<br>'
+
+ 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) + '<br>'
+
+ 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 += '<tr>'
+ for cdf in child_meta.fields:
+ if cdf.in_list_view:
+ if create_head:
+ table_head += '<td>' + cdf.label + '</td>'
+ if item.get(cdf.fieldname):
+ table_row += '<td>' + str(item.get(cdf.fieldname)) + '</td>'
+ else:
+ table_row += '<td></td>'
+ create_head = False
+ table_row += '</tr>'
+
+ html += "<table class='table table-condensed table-bordered'>" + table_head + table_row + "</table>"
+
+ 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
\ No newline at end of file
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
new file mode 100644
index 0000000..c93b788
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+import json
+from frappe.utils import getdate
+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 = "<b>Date: </b>{0}<br><b>Rating: </b>3<br><b>Feedback: </b>Test Patient History Settings<br>".format(
+ frappe.utils.format_date(getdate()))
+ self.assertEqual(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
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/patient_history_standard_document_type/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/patient_history_standard_document_type/__init__.py
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
new file mode 100644
index 0000000..b43099c
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json
@@ -0,0 +1,57 @@
+{
+ "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
new file mode 100644
index 0000000..2d94911
--- /dev/null
+++ b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class PatientHistoryStandardDocumentType(Document):
+ pass
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
index aa85a23..c1d9872 100644
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
+++ b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
@@ -6,16 +6,19 @@
import frappe
from frappe.utils import nowdate
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_encounter, create_healthcare_docs, create_appointment
+from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
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, medical_department, practitioner = create_healthcare_docs()
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)
diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.js b/erpnext/healthcare/doctype/sample_collection/sample_collection.js
index 0390391..ddf8285 100644
--- a/erpnext/healthcare/doctype/sample_collection/sample_collection.js
+++ b/erpnext/healthcare/doctype/sample_collection/sample_collection.js
@@ -36,5 +36,5 @@
var age = new Date();
age.setTime(ageMS);
var years = age.getFullYear() - 1970;
- return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
+ return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`;
};
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index 526bb95..7fb159d 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -5,10 +5,10 @@
import frappe
import unittest
-from frappe.utils import getdate
+from frappe.utils import getdate, flt, nowdate
from erpnext.healthcare.doctype.therapy_type.test_therapy_type import create_therapy_type
-from erpnext.healthcare.doctype.therapy_plan.therapy_plan import make_therapy_session
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_patient
+from erpnext.healthcare.doctype.therapy_plan.therapy_plan import make_therapy_session, make_sales_invoice
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_patient, create_appointment
class TestTherapyPlan(unittest.TestCase):
def test_creation_on_encounter_submission(self):
@@ -20,25 +20,54 @@
plan = create_therapy_plan()
self.assertEquals(plan.status, 'Not Started')
- session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab')
+ session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
- session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab')
+ session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
+ patient, medical_department, 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.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
+ session.cancel()
+ self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
-def create_therapy_plan():
+ 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.assertEquals(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()
- plan.append('therapy_plan_details', {
- 'therapy_type': therapy_type.name,
- 'no_of_sessions': 2
- })
+
+ 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
@@ -55,3 +84,22 @@
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
index dea0cfe..d1f72d6 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
@@ -13,49 +13,89 @@
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.__islocal && 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]}
- }
- }
- }];
+ if (frm.doc.therapy_plan_template) {
+ frappe.meta.get_docfield('Therapy Plan Detail', 'therapy_type', frm.doc.name).read_only = 1;
+ frappe.meta.get_docfield('Therapy Plan Detail', 'no_of_sessions', frm.doc.name).read_only = 1;
+ }
+ },
- 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
- },
- 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'));
+ 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 = '';
- let added_min = false;
// completed sessions
let title = __('{0} sessions completed', [frm.doc.total_sessions_completed]);
@@ -71,7 +111,6 @@
});
if (bars[0].width == '0%') {
bars[0].width = '0.5%';
- added_min = 0.5;
}
message = title;
frm.dashboard.add_progress(__('Status'), bars, message);
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
index 9edfeb2..c03e9de 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
@@ -9,11 +9,13 @@
"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",
@@ -46,6 +48,7 @@
"fieldtype": "Table",
"label": "Therapy Plan Details",
"options": "Therapy Plan Detail",
+ "read_only_depends_on": "therapy_plan_template",
"reqd": 1
},
{
@@ -105,11 +108,28 @@
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Company",
- "options": "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-05-25 14:38:53.649315",
+ "modified": "2020-11-04 18:13:13.564999",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Plan",
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
index e0f015f..ac01c60 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
-from frappe.utils import today
+from frappe.utils import flt, today
class TherapyPlan(Document):
def validate(self):
@@ -33,19 +33,68 @@
self.db_set('total_sessions', total_sessions)
self.db_set('total_sessions_completed', total_sessions_completed)
+ 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):
+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()
\ No newline at end of file
+ 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
index df64782..6526acd 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
@@ -4,10 +4,18 @@
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_detail/therapy_plan_detail.json b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
index 9eb20e2..77f08af 100644
--- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
+++ b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
@@ -30,12 +30,13 @@
"fieldname": "sessions_completed",
"fieldtype": "Int",
"label": "Sessions Completed",
+ "no_copy": 1,
"read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-03-30 22:02:01.740109",
+ "modified": "2020-11-04 18:15:52.173450",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Plan Detail",
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/therapy_plan_template/__init__.py
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
index 2ad7984..33ee29d 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+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
new file mode 100644
index 0000000..86de192
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js
@@ -0,0 +1,57 @@
+// 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
new file mode 100644
index 0000000..48fc896
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json
@@ -0,0 +1,132 @@
+{
+ "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
new file mode 100644
index 0000000..748c12c
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
@@ -0,0 +1,73 @@
+# -*- 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)
\ No newline at end of file
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
new file mode 100644
index 0000000..c748fbf
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
@@ -0,0 +1,13 @@
+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/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py
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
new file mode 100644
index 0000000..5553a11
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json
@@ -0,0 +1,54 @@
+{
+ "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
new file mode 100644
index 0000000..7b979fe
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class TherapyPlanTemplateDetail(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
index e66e667..fd20003 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
@@ -19,9 +19,22 @@
}
};
});
+
+ 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]),
@@ -36,15 +49,43 @@
})
}, 'Create');
- 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');
+ 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({
@@ -92,23 +133,12 @@
'start_date': data.message.appointment_date,
'start_time': data.message.appointment_time,
'service_unit': data.message.service_unit,
- 'company': data.message.company
+ 'company': data.message.company,
+ 'duration': data.message.duration
};
frm.set_value(values);
}
});
- } else {
- let values = {
- 'patient': '',
- 'therapy_type': '',
- 'therapy_plan': '',
- 'practitioner': '',
- 'department': '',
- 'start_date': '',
- 'start_time': '',
- 'service_unit': '',
- };
- frm.set_value(values);
}
},
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
index dc0cafc..0bb2b0e 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
@@ -47,7 +47,8 @@
"fieldname": "appointment",
"fieldtype": "Link",
"label": "Appointment",
- "options": "Patient Appointment"
+ "options": "Patient Appointment",
+ "set_only_once": 1
},
{
"fieldname": "patient",
@@ -90,7 +91,8 @@
"fetch_from": "therapy_template.default_duration",
"fieldname": "duration",
"fieldtype": "Int",
- "label": "Duration"
+ "label": "Duration",
+ "reqd": 1
},
{
"fieldname": "location",
@@ -192,6 +194,7 @@
"fieldname": "total_counts_completed",
"fieldtype": "Int",
"label": "Total Counts Completed",
+ "no_copy": 1,
"read_only": 1
},
{
@@ -220,7 +223,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-30 10:56:10.354268",
+ "modified": "2020-11-04 18:14:25.999939",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Session",
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.py b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
index 9650183..51f267f 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.py
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
@@ -4,21 +4,52 @@
from __future__ import unicode_literals
import frappe
+import datetime
from frappe.model.document import Document
+from frappe.utils import get_time, flt
from frappe.model.mapper import get_mapped_doc
from frappe import _
-from frappe.utils import cstr, getdate
+from frappe.utils import cstr, getdate, get_link_to_form
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_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()
- insert_session_medical_record(self)
+
+ 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):
@@ -110,23 +141,3 @@
item.reference_dt = 'Therapy Session'
item.reference_dn = therapy.name
return item
-
-
-def insert_session_medical_record(doc):
- subject = frappe.bold(_('Therapy: ')) + cstr(doc.therapy_type) + '<br>'
- if doc.therapy_plan:
- subject += frappe.bold(_('Therapy Plan: ')) + cstr(doc.therapy_plan) + '<br>'
- if doc.practitioner:
- subject += frappe.bold(_('Healthcare Practitioner: ')) + doc.practitioner
- subject += frappe.bold(_('Total Counts Targeted: ')) + cstr(doc.total_counts_targeted) + '<br>'
- subject += frappe.bold(_('Total Counts Completed: ')) + cstr(doc.total_counts_completed) + '<br>'
-
- 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.start_date
- medical_record.reference_doctype = 'Therapy Session'
- medical_record.reference_name = doc.name
- medical_record.reference_owner = doc.owner
- medical_record.save(ignore_permissions=True)
\ 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
index ea3d84e..6c825b8 100644
--- a/erpnext/healthcare/doctype/therapy_type/therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/therapy_type.py
@@ -41,7 +41,7 @@
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_name = self.rate
+ item_price.price_list_rate = self.rate
item_price.ignore_mandatory = True
item_price.save()
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
index 69d81ff..35c823d 100644
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py
+++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
@@ -12,47 +12,7 @@
def validate(self):
self.set_title()
- def on_submit(self):
- insert_vital_signs_to_medical_record(self)
-
- def on_cancel(self):
- delete_vital_signs_from_medical_record(self)
-
def set_title(self):
self.title = _('{0} on {1}').format(self.patient_name or self.patient,
frappe.utils.format_date(self.signs_date))[:100]
-def insert_vital_signs_to_medical_record(doc):
- subject = set_subject_field(doc)
- 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.signs_date
- medical_record.reference_doctype = 'Vital Signs'
- medical_record.reference_name = doc.name
- medical_record.reference_owner = doc.owner
- medical_record.flags.ignore_mandatory = True
- medical_record.save(ignore_permissions=True)
-
-def delete_vital_signs_from_medical_record(doc):
- medical_record = frappe.db.get_value('Patient Medical Record', {'reference_name': doc.name})
- if medical_record:
- frappe.delete_doc('Patient Medical Record', medical_record)
-
-def set_subject_field(doc):
- subject = ''
- if doc.temperature:
- subject += frappe.bold(_('Temperature: ')) + cstr(doc.temperature) + '<br>'
- if doc.pulse:
- subject += frappe.bold(_('Pulse: ')) + cstr(doc.pulse) + '<br>'
- if doc.respiratory_rate:
- subject += frappe.bold(_('Respiratory Rate: ')) + cstr(doc.respiratory_rate) + '<br>'
- if doc.bp:
- subject += frappe.bold(_('BP: ')) + cstr(doc.bp) + '<br>'
- if doc.bmi:
- subject += frappe.bold(_('BMI: ')) + cstr(doc.bmi) + '<br>'
- if doc.nutrition_note:
- subject += frappe.bold(_('Note: ')) + cstr(doc.nutrition_note) + '<br>'
-
- return subject
diff --git a/erpnext/healthcare/page/patient_history/patient_history.css b/erpnext/healthcare/page/patient_history/patient_history.css
index 865d6ab..1bb5891 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.css
+++ b/erpnext/healthcare/page/patient_history/patient_history.css
@@ -109,6 +109,11 @@
padding-right: 0px;
}
+.patient-history-filter {
+ margin-left: 35px;
+ width: 25%;
+}
+
#page-medical_record .plot-wrapper {
padding: 20px 15px;
border-bottom: 1px solid #d1d8dd;
diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html
index 7a9446d..be486c6 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.html
+++ b/erpnext/healthcare/page/patient_history/patient_history.html
@@ -1,6 +1,5 @@
<div class="col-sm-12">
<div class="col-sm-3">
- <p class="text-center">{%= __("Select Patient") %}</p>
<p class="patient" style="margin: auto; max-width: 300px; margin-bottom: 20px;"></p>
<div class="patient_details" style="z-index=0"></div>
</div>
@@ -11,6 +10,13 @@
<div id="chart" class="col-sm-12 patient_vital_charts">
</div>
</div>
+ <div class="header-separator col-sm-12 d-flex border-bottom py-3" style="display:none"></div>
+ <div class="row">
+ <div class="col-sm-12 d-flex">
+ <div class="patient-history-filter doctype-filter"></div>
+ <div class="patient-history-filter date-filter"></div>
+ </div>
+ </div>
<div class="col-sm-12 patient_documents_list">
</div>
<div class="col-sm-12 text-center py-3">
diff --git a/erpnext/healthcare/page/patient_history/patient_history.js b/erpnext/healthcare/page/patient_history/patient_history.js
index fe5b7bc..54343aa 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.js
+++ b/erpnext/healthcare/page/patient_history/patient_history.js
@@ -1,141 +1,225 @@
-frappe.provide("frappe.patient_history");
+frappe.provide('frappe.patient_history');
frappe.pages['patient_history'].on_page_load = function(wrapper) {
- var me = this;
- var page = frappe.ui.make_app_page({
+ let me = this;
+ let page = frappe.ui.make_app_page({
parent: wrapper,
title: 'Patient History',
single_column: true
});
- frappe.breadcrumbs.add("Healthcare");
+ frappe.breadcrumbs.add('Healthcare');
let pid = '';
- page.main.html(frappe.render_template("patient_history", {}));
- var patient = frappe.ui.form.make_control({
- parent: page.main.find(".patient"),
+ page.main.html(frappe.render_template('patient_history', {}));
+ page.main.find('.header-separator').hide();
+
+ let patient = frappe.ui.form.make_control({
+ parent: page.main.find('.patient'),
df: {
- fieldtype: "Link",
- options: "Patient",
- fieldname: "patient",
- change: function(){
- if(pid != patient.get_value() && patient.get_value()){
+ fieldtype: 'Link',
+ options: 'Patient',
+ fieldname: 'patient',
+ placeholder: __('Select Patient'),
+ only_select: true,
+ change: function() {
+ let patient_id = patient.get_value();
+ if (pid != patient_id && patient_id) {
me.start = 0;
- me.page.main.find(".patient_documents_list").html("");
- get_documents(patient.get_value(), me);
- show_patient_info(patient.get_value(), me);
- show_patient_vital_charts(patient.get_value(), me, "bp", "mmHg", "Blood Pressure");
+ me.page.main.find('.patient_documents_list').html('');
+ setup_filters(patient_id, me);
+ get_documents(patient_id, me);
+ show_patient_info(patient_id, me);
+ show_patient_vital_charts(patient_id, me, 'bp', 'mmHg', 'Blood Pressure');
}
- pid = patient.get_value();
+ pid = patient_id;
}
},
- only_input: true,
});
patient.refresh();
- if (frappe.route_options){
+ if (frappe.route_options) {
patient.set_value(frappe.route_options.patient);
}
- this.page.main.on("click", ".btn-show-chart", function() {
- var btn_show_id = $(this).attr("data-show-chart-id"), pts = $(this).attr("data-pts");
- var title = $(this).attr("data-title");
+ this.page.main.on('click', '.btn-show-chart', function() {
+ let btn_show_id = $(this).attr('data-show-chart-id'), pts = $(this).attr('data-pts');
+ let title = $(this).attr('data-title');
show_patient_vital_charts(patient.get_value(), me, btn_show_id, pts, title);
});
- this.page.main.on("click", ".btn-more", function() {
- var 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"];
+ 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'];
frappe.call({
- method: "erpnext.healthcare.utils.render_doc_as_html",
+ 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+"\
- <div align='center'><a class='btn octicon octicon-chevron-up btn-default btn-xs\
- btn-less' data-doctype='"+doctype+"' data-docname='"+docname+"'></a></div>");
- me.page.main.find("."+docname).parent().find('.document-html').show();
- me.page.main.find("."+docname).parent().find('.document-html').attr('data-fetched', "1");
+ if (r.message) {
+ me.page.main.find('.' + docname).hide();
+
+ me.page.main.find('.' + docname).parent().find('.document-html').html(
+ `${r.message.html}
+ <div align='center'>
+ <a class='btn octicon octicon-chevron-up btn-default btn-xs btn-less'
+ data-doctype='${doctype}'
+ data-docname='${docname}'>
+ </a>
+ </div>
+ `);
+
+ me.page.main.find('.' + docname).parent().find('.document-html').show();
+ me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1');
}
- },
- freeze: true
+ }
});
}
}
});
- this.page.main.on("click", ".btn-less", function() {
- var 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();
+ 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.start = 0;
- me.page.main.on("click", ".btn-get-records", function(){
+ me.page.main.on('click', '.btn-get-records', function() {
get_documents(patient.get_value(), me);
});
};
-var get_documents = function(patient, me){
+let setup_filters = function(patient, me) {
+ $('.doctype-filter').empty();
+ 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'),
+ input_class: 'input-xs',
+ change: () => {
+ me.start = 0;
+ me.page.main.find('.patient_documents_list').html('');
+ get_documents(patient, me, 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('');
+ get_documents(patient, me, doctype_filter.get_value(), selected_date_range);
+ }
+ }
+ },
+ parent: $('.date-filter')
+ });
+ date_range_field.refresh();
+ });
+};
+
+let get_documents = function(patient, me, document_types="", selected_date_range="") {
+ let filters = {
+ name: patient,
+ start: me.start,
+ page_length: 20
+ };
+ if (document_types)
+ filters['document_types'] = document_types;
+ if (selected_date_range)
+ filters['date_range'] = selected_date_range;
+
frappe.call({
- "method": "erpnext.healthcare.page.patient_history.patient_history.get_feed",
- args: {
- name: patient,
- start: me.start,
- page_length: 20
- },
- callback: function (r) {
- var data = r.message;
- if(data.length){
+ 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed',
+ args: filters,
+ callback: function(r) {
+ let data = r.message;
+ if (data.length) {
add_to_records(me, data);
- }else{
- me.page.main.find(".patient_documents_list").append("<div class='text-muted' align='center'><br><br>No more records..<br><br></div>");
- me.page.main.find(".btn-get-records").hide();
+ } else {
+ me.page.main.find('.patient_documents_list').append(`
+ <div class='text-muted' align='center'>
+ <br><br>${__('No more records..')}<br><br>
+ </div>`);
+ me.page.main.find('.btn-get-records').hide();
}
}
});
};
-var add_to_records = function(me, data){
- var details = "<ul class='nav nav-pills nav-stacked'>";
- var i;
- for(i=0; i<data.length; i++){
- if(data[i].reference_doctype){
+let add_to_records = function(me, data) {
+ let details = "<ul class='nav nav-pills nav-stacked'>";
+ let i;
+ for (i=0; i<data.length; i++) {
+ if (data[i].reference_doctype) {
let label = '';
- if(data[i].subject){
- label += "<br/>"+data[i].subject;
+ if (data[i].subject) {
+ label += "<br/>" + data[i].subject;
}
data[i] = add_date_separator(data[i]);
- if(frappe.user_info(data[i].owner).image){
+
+ if (frappe.user_info(data[i].owner).image) {
data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
- }
- else{
+ } else {
data[i].imgsrc = false;
}
- var time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
- time_line_heading += data[i].reference_doctype + " - "+ data[i].reference_name;
- details += `<li data-toggle='pill' class='patient_doc_menu'
- data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
- <div class='col-sm-12 d-flex border-bottom py-3'>`;
- if (data[i].imgsrc){
- details += `<span class='mr-3'>
- <img class='avtar' src='${data[i].imgsrc}' width='32' height='32'>
- </img>
- </span>`;
- }else{
- details += `<span class='mr-3 avatar avatar-small' style='width:32px; height:32px;'><div align='center' class='standard-image'
- style='background-color: #fafbfc;'>${data[i].practitioner ? data[i].practitioner.charAt(0) : "U"}</div></span>`;
+
+ let time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
+ time_line_heading += data[i].reference_doctype + " - " +
+ `<a onclick="frappe.set_route('Form', '${data[i].reference_doctype}', '${data[i].reference_name}');">
+ ${data[i].reference_name}
+ </a>`;
+
+ details += `
+ <li data-toggle='pill' class='patient_doc_menu'
+ data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
+ <div class='col-sm-12 d-flex border-bottom py-3'>`;
+
+ if (data[i].imgsrc) {
+ details += `
+ <span class='mr-3'>
+ <img class='avtar' src='${data[i].imgsrc}' width='32' height='32'></img>
+ </span>`;
+ } else {
+ details += `<span class='mr-3 avatar avatar-small' style='width:32px; height:32px;'>
+ <div align='center' class='standard-image' style='background-color: #fafbfc;'>
+ ${data[i].practitioner ? data[i].practitioner.charAt(0) : 'U'}
+ </div>
+ </span>`;
}
+
details += `<div class='d-flex flex-column width-full'>
<div>
- `+time_line_heading+` on
+ `+time_line_heading+`
<span>
${data[i].date_sep}
</span>
@@ -156,133 +240,150 @@
</li>`;
}
}
- details += "</ul>";
- me.page.main.find(".patient_documents_list").append(details);
+
+ details += '</ul>';
+ me.page.main.find('.patient_documents_list').append(details);
me.start += data.length;
- if(data.length===20){
+
+ if (data.length === 20) {
me.page.main.find(".btn-get-records").show();
- }else{
+ } else {
me.page.main.find(".btn-get-records").hide();
- me.page.main.find(".patient_documents_list").append("<div class='text-muted' align='center'><br><br>No more records..<br><br></div>");
+ me.page.main.find(".patient_documents_list").append(`
+ <div class='text-muted' align='center'>
+ <br><br>${__('No more records..')}<br><br>
+ </div>`);
}
};
-var add_date_separator = function(data) {
- var date = frappe.datetime.str_to_obj(data.creation);
+let add_date_separator = function(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));
- var diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date));
- if(diff < 1) {
- var pdate = 'Today';
- } else if(diff < 2) {
- pdate = 'Yesterday';
+ if (diff < 1) {
+ pdate = __('Today');
+ } else if (diff < 2) {
+ pdate = __('Yesterday');
} else {
- pdate = frappe.datetime.global_date_format(date);
+ pdate = __('on ') + frappe.datetime.global_date_format(date);
}
data.date_sep = pdate;
return data;
};
-var show_patient_info = function(patient, me){
+let show_patient_info = function(patient, me) {
frappe.call({
- "method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail",
+ 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
args: {
patient: patient
},
- callback: function (r) {
- var data = r.message;
- var details = "";
- if(data.image){
- details += "<div><img class='thumbnail' width=75% src='"+data.image+"'></div>";
+ callback: function(r) {
+ let data = r.message;
+ let details = '';
+ if (data.image) {
+ details += `<div><img class='thumbnail' width=75% src='${data.image}'></div>`;
}
- details += "<b>" + data.patient_name +"</b><br>" + data.sex;
- if(data.email) details += "<br>" + data.email;
- if(data.mobile) details += "<br>" + data.mobile;
- if(data.occupation) details += "<br><br><b>Occupation :</b> " + data.occupation;
- if(data.blood_group) details += "<br><b>Blood group : </b> " + data.blood_group;
- if(data.allergies) details += "<br><br><b>Allergies : </b> "+ data.allergies.replace("\n", "<br>");
- if(data.medication) details += "<br><b>Medication : </b> "+ data.medication.replace("\n", "<br>");
- if(data.alcohol_current_use) details += "<br><br><b>Alcohol use : </b> "+ data.alcohol_current_use;
- if(data.alcohol_past_use) details += "<br><b>Alcohol past use : </b> "+ data.alcohol_past_use;
- if(data.tobacco_current_use) details += "<br><b>Tobacco use : </b> "+ data.tobacco_current_use;
- if(data.tobacco_past_use) details += "<br><b>Tobacco past use : </b> "+ data.tobacco_past_use;
- if(data.medical_history) details += "<br><br><b>Medical history : </b> "+ data.medical_history.replace("\n", "<br>");
- if(data.surgical_history) details += "<br><b>Surgical history : </b> "+ data.surgical_history.replace("\n", "<br>");
- if(data.surrounding_factors) details += "<br><br><b>Occupational hazards : </b> "+ data.surrounding_factors.replace("\n", "<br>");
- if(data.other_risk_factors) details += "<br><b>Other risk factors : </b> " + data.other_risk_factors.replace("\n", "<br>");
- if(data.patient_details) details += "<br><br><b>More info : </b> " + data.patient_details.replace("\n", "<br>");
- if(details){
- details = "<div style='padding-left:10px; font-size:13px;' align='center'>" + details + "</div>";
+ details += `<b> ${data.patient_name} </b><br> ${data.sex}`;
+ if (data.email) details += `<br> ${data.email}`;
+ if (data.mobile) details += `<br> ${data.mobile}`;
+ if (data.occupation) details += `<br><br><b> ${__('Occupation')} : </b> ${data.occupation}`;
+ if (data.blood_group) details += `<br><b> ${__('Blood Group')} : </b> ${data.blood_group}`;
+ if (data.allergies) details += `<br><br><b> ${__('Allerigies')} : </b> ${data.allergies.replace("\n", ", ")}`;
+ if (data.medication) details += `<br><b> ${__('Medication')} : </b> ${data.medication.replace("\n", ", ")}`;
+ if (data.alcohol_current_use) details += `<br><br><b> ${__('Alcohol use')} : </b> ${data.alcohol_current_use}`;
+ if (data.alcohol_past_use) details += `<br><b> ${__('Alcohol past use')} : </b> ${data.alcohol_past_use}`;
+ if (data.tobacco_current_use) details += `<br><b> ${__('Tobacco use')} : </b> ${data.tobacco_current_use}`;
+ if (data.tobacco_past_use) details += `<br><b> ${__('Tobacco past use')} : </b> ${data.tobacco_past_use}`;
+ if (data.medical_history) details += `<br><br><b> ${__('Medical history')} : </b> ${data.medical_history.replace("\n", ", ")}`;
+ if (data.surgical_history) details += `<br><b> ${__('Surgical history')} : </b> ${data.surgical_history.replace("\n", ", ")}`;
+ if (data.surrounding_factors) details += `<br><br><b> ${__('Occupational hazards')} : </b> ${data.surrounding_factors.replace("\n", ", ")}`;
+ if (data.other_risk_factors) details += `<br><b> ${__('Other risk factors')} : </b> ${data.other_risk_factors.replace("\n", ", ")}`;
+ if (data.patient_details) details += `<br><br><b> ${__('More info')} : </b> ${data.patient_details.replace("\n", ", ")}`;
+
+ if (details) {
+ details = `<div style='padding-left:10px; font-size:13px;' align='left'>` + details + `</div>`;
}
- me.page.main.find(".patient_details").html(details);
+ me.page.main.find('.patient_details').html(details);
}
});
};
-var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
+let show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
frappe.call({
- method: "erpnext.healthcare.utils.get_patient_vitals",
+ method: 'erpnext.healthcare.utils.get_patient_vitals',
args:{
patient: patient
},
callback: function(r) {
- if (r.message){
- var show_chart_btns_html = "<div style='padding-top:5px;'><a class='btn btn-default btn-xs btn-show-chart' \
- data-show-chart-id='bp' data-pts='mmHg' data-title='Blood Pressure'>Blood Pressure</a>\
- <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='pulse_rate' \
- data-pts='per Minutes' data-title='Respiratory/Pulse Rate'>Respiratory/Pulse Rate</a>\
- <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' \
- data-pts='°C or °F' data-title='Temperature'>Temperature</a>\
- <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' \
- data-pts='' data-title='BMI'>BMI</a></div>";
- me.page.main.find(".show_chart_btns").html(show_chart_btns_html);
- var data = r.message;
+ if (r.message) {
+ let show_chart_btns_html = `
+ <div style='padding-top:10px;'>
+ <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bp' data-pts='mmHg' data-title='Blood Pressure'>
+ ${__('Blood Pressure')}
+ </a>
+ <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='pulse_rate' data-pts='per Minutes' data-title='Respiratory/Pulse Rate'>
+ ${__('Respiratory/Pulse Rate')}
+ </a>
+ <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' data-pts='°C or °F' data-title='Temperature'>
+ ${__('Temperature')}
+ </a>
+ <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' data-pts='' data-title='BMI'>
+ ${__('BMI')}
+ </a>
+ </div>`;
+
+ 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(var i=0; i<data.length; i++){
- labels.push(data[i].signs_date+"||"+data[i].signs_time);
- if(btn_show_id=="bp"){
+
+ for (let i=0; i<data.length; i++) {
+ labels.push(data[i].signs_date+'||'+data[i].signs_time);
+
+ if (btn_show_id === 'bp') {
bp_systolic.push(data[i].bp_systolic);
bp_diastolic.push(data[i].bp_diastolic);
}
- if(btn_show_id=="temperature"){
+ if (btn_show_id === 'temperature') {
temperature.push(data[i].temperature);
}
- if(btn_show_id=="pulse_rate"){
+ if (btn_show_id === 'pulse_rate') {
pulse.push(data[i].pulse);
respiratory_rate.push(data[i].respiratory_rate);
}
- if(btn_show_id=="bmi"){
+ if (btn_show_id === 'bmi') {
bmi.push(data[i].bmi);
height.push(data[i].height);
weight.push(data[i].weight);
}
}
- if(btn_show_id=="temperature"){
- datasets.push({name: "Temperature", values: temperature, chartType:'line'});
+ if (btn_show_id === 'temperature') {
+ datasets.push({name: 'Temperature', values: temperature, chartType: 'line'});
}
- if(btn_show_id=="bmi"){
- datasets.push({name: "BMI", values: bmi, chartType:'line'});
- datasets.push({name: "Height", values: height, chartType:'line'});
- datasets.push({name: "Weight", values: weight, chartType:'line'});
+ if (btn_show_id === 'bmi') {
+ datasets.push({name: 'BMI', values: bmi, chartType: 'line'});
+ datasets.push({name: 'Height', values: height, chartType: 'line'});
+ datasets.push({name: 'Weight', values: weight, chartType: 'line'});
}
- if(btn_show_id=="bp"){
- datasets.push({name: "BP Systolic", values: bp_systolic, chartType:'line'});
- datasets.push({name: "BP Diastolic", values: bp_diastolic, chartType:'line'});
+ if (btn_show_id === 'bp') {
+ datasets.push({name: 'BP Systolic', values: bp_systolic, chartType: 'line'});
+ datasets.push({name: 'BP Diastolic', values: bp_diastolic, chartType: 'line'});
}
- if(btn_show_id=="pulse_rate"){
- datasets.push({name: "Heart Rate / Pulse", values: pulse, chartType:'line'});
- datasets.push({name: "Respiratory Rate", values: respiratory_rate, chartType:'line'});
+ if (btn_show_id === 'pulse_rate') {
+ datasets.push({name: 'Heart Rate / Pulse', values: pulse, chartType: 'line'});
+ datasets.push({name: 'Respiratory Rate', values: respiratory_rate, chartType: 'line'});
}
- new frappe.Chart( ".patient_vital_charts", {
+ new frappe.Chart('.patient_vital_charts', {
data: {
labels: labels,
datasets: datasets
},
title: title,
- type: 'axis-mixed', // 'axis-mixed', 'bar', 'line', 'pie', 'percentage'
+ type: 'axis-mixed',
height: 200,
colors: ['purple', '#ffa3ef', 'light-blue'],
@@ -291,9 +392,11 @@
formatTooltipY: d => d + ' ' + pts,
}
});
- }else{
- me.page.main.find(".patient_vital_charts").html("");
- me.page.main.find(".show_chart_btns").html("");
+ 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.py b/erpnext/healthcare/page/patient_history/patient_history.py
index 772aa4e..4cdfd64 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.py
+++ b/erpnext/healthcare/page/patient_history/patient_history.py
@@ -4,36 +4,70 @@
from __future__ import unicode_literals
import frappe
+import json
from frappe.utils import cint
from erpnext.healthcare.utils import render_docs_as_html
@frappe.whitelist()
-def get_feed(name, start=0, page_length=20):
+def get_feed(name, document_types=None, date_range=None, start=0, page_length=20):
"""get feed"""
- result = frappe.db.sql("""select name, owner, creation,
- reference_doctype, reference_name, subject
- from `tabPatient Medical Record`
- where patient=%(patient)s
- order by creation desc
- limit %(start)s, %(page_length)s""",
- {
- "patient": name,
- "start": cint(start),
- "page_length": cint(page_length)
- }, as_dict=True)
+ 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.sql("""select name, owner, modified, creation,
- reference_doctype, reference_name, subject
- from `tabPatient Medical Record`
- where reference_name=%(docname)s and reference_doctype=%(doctype)s
- order by creation desc""",
- {
- "docname": docname,
- "doctype": doctype
- }, as_dict=True)
+ 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/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/healthcare/report/inpatient_medication_orders/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/healthcare/report/inpatient_medication_orders/__init__.py
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js
new file mode 100644
index 0000000..a10f837
--- /dev/null
+++ b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js
@@ -0,0 +1,57 @@
+// 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
new file mode 100644
index 0000000..9217fa1
--- /dev/null
+++ b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json
@@ -0,0 +1,36 @@
+{
+ "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
new file mode 100644
index 0000000..b907730
--- /dev/null
+++ b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
@@ -0,0 +1,198 @@
+# 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
\ No newline at end of file
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
new file mode 100644
index 0000000..4b461f1
--- /dev/null
+++ b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
@@ -0,0 +1,128 @@
+# 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
+import frappe
+import datetime
+from frappe.utils import getdate, now_datetime
+from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
+from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import create_ipmo, create_ipme
+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/setup.py b/erpnext/healthcare/setup.py
index 0684080..bf4df7e 100644
--- a/erpnext/healthcare/setup.py
+++ b/erpnext/healthcare/setup.py
@@ -16,6 +16,7 @@
create_healthcare_item_groups()
create_sensitivity()
add_healthcare_service_unit_tree_root()
+ setup_patient_history_settings()
def create_medical_departments():
departments = [
@@ -213,3 +214,82 @@
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"}
+ ])
+ }
\ No newline at end of file
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index dbd3b83..d3d22c8 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -5,8 +5,11 @@
from __future__ import unicode_literals
import math
import frappe
+import json
from frappe import _
+from frappe.utils.formatters import format_value
from frappe.utils import time_diff_in_hours, rounded
+from six import string_types
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity
from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
@@ -23,18 +26,19 @@
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 += " <b><a href='#Form/Patient/{0}'>{0}</a></b>".format(patient.name)
+ msg += " <b><a href='/app/Form/Patient/{0}'>{0}</a></b>".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(
@@ -62,7 +66,9 @@
income_account = None
service_item = None
if appointment.practitioner:
- service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment)
+ 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',
@@ -76,11 +82,13 @@
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.name, 'company': company, 'invoiced': False, 'docstatus': 1}
+ filters={'patient': patient, 'company': company, 'invoiced': False, 'docstatus': 1}
)
if encounters:
for encounter in encounters:
@@ -89,7 +97,13 @@
income_account = None
service_item = None
if encounter.practitioner:
- service_item, practitioner_charge = get_service_item_and_practitioner_charge(encounter)
+ 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({
@@ -165,10 +179,10 @@
if procedure.invoice_separately_as_consumables and procedure.consume_stock \
and procedure.status == 'Completed' and not procedure.consumption_invoiced:
- service_item = get_healthcare_service_item('clinical_procedure_consumable_item')
+ service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item')
if not service_item:
msg = _('Please Configure Clinical Procedure Consumable Item in ')
- msg += '''<b><a href='#Form/Healthcare Settings'>Healthcare Settings</a></b>'''
+ msg += '''<b><a href='/app/Form/Healthcare Settings'>Healthcare Settings</a></b>'''
frappe.throw(msg, title=_('Missing Configuration'))
clinical_procedures_to_invoice.append({
@@ -246,12 +260,44 @@
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}
+ 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:
@@ -264,24 +310,50 @@
return therapy_sessions_to_invoice
-
+@frappe.whitelist()
def get_service_item_and_practitioner_charge(doc):
+ if isinstance(doc, string_types):
+ 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 is_inpatient:
- service_item = get_practitioner_service_item(doc.practitioner, 'inpatient_visit_charge_item')
+
+ 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('inpatient_visit_charge_item')
- else:
- service_item = get_practitioner_service_item(doc.practitioner, 'op_consulting_charge_item')
- if not service_item:
- service_item = get_healthcare_service_item('op_consulting_charge_item')
+ service_item = get_healthcare_service_item(is_inpatient)
+
if not service_item:
throw_config_service_item(is_inpatient)
- practitioner_charge = get_practitioner_charge(doc.practitioner, 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
@@ -291,7 +363,7 @@
service_item_label = _('Inpatient Visit Charge Item')
msg = _(('Please Configure {0} in ').format(service_item_label) \
- + '''<b><a href='#Form/Healthcare Settings'>Healthcare Settings</a></b>''')
+ + '''<b><a href='/app/Form/Healthcare Settings'>Healthcare Settings</a></b>''')
frappe.throw(msg, title=_('Missing Configuration'))
@@ -301,16 +373,31 @@
charge_name = _('Inpatient Visit Charge')
msg = _(('Please Configure {0} for Healthcare Practitioner').format(charge_name) \
- + ''' <b><a href='#Form/Healthcare Practitioner/{0}'>{0}</a></b>'''.format(practitioner))
+ + ''' <b><a href='/app/Form/Healthcare Practitioner/{0}'>{0}</a></b>'''.format(practitioner))
frappe.throw(msg, title=_('Missing Configuration'))
-def get_practitioner_service_item(practitioner, service_item_field):
- return frappe.db.get_value('Healthcare Practitioner', practitioner, service_item_field)
+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(service_item_field):
- return frappe.db.get_single_value('Healthcare Settings', service_item_field)
+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):
@@ -341,7 +428,8 @@
invoiced = True
if item.reference_dt == 'Clinical Procedure':
- if get_healthcare_service_item('clinical_procedure_consumable_item') == item.item_code:
+ 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)
@@ -363,13 +451,14 @@
def validate_invoiced_on_submit(item):
- if item.reference_dt == 'Clinical Procedure' and get_healthcare_service_item('clinical_procedure_consumable_item') == item.item_code:
+ 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))
+ 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):
@@ -609,11 +698,15 @@
html += "<table class='table table-condensed table-bordered'>" \
+ table_head + table_row + "</table>"
continue
+
#on other field types 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:
- html += '<br>{0} : {1}'.format(df.label or df.fieldname, \
- doc.get(df.fieldname))
+ if doc.get(df.fieldname):
+ formatted_value = format_value(doc.get(df.fieldname), meta.get_field(df.fieldname), doc)
+ html += '<br>{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 + '</div></div>'
elif sec_on and not col_on and has_data:
@@ -621,6 +714,6 @@
><div class='col-md-12 col-sm-12'>" \
+ section_html + html +'</div></div>'
if doc_html:
- doc_html = "<div class='small'><div class='col-md-12 text-right'><a class='btn btn-default btn-xs' href='#Form/%s/%s'></a></div>" %(doctype, docname) + doc_html + '</div>'
+ doc_html = "<div class='small'><div class='col-md-12 text-right'><a class='btn btn-default btn-xs' href='/app/Form/%s/%s'></a></div>" %(doctype, docname) + doc_html + '</div>'
return {'html': doc_html}
diff --git a/erpnext/healthcare/workspace/healthcare/healthcare.json b/erpnext/healthcare/workspace/healthcare/healthcare.json
new file mode 100644
index 0000000..b93dda2
--- /dev/null
+++ b/erpnext/healthcare/workspace/healthcare/healthcare.json
@@ -0,0 +1,536 @@
+{
+ "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": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "healthcare",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Healthcare",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Masters",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient",
+ "link_to": "Patient",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Healthcare Practitioner",
+ "link_to": "Healthcare Practitioner",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Practitioner Schedule",
+ "link_to": "Practitioner Schedule",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Medical Department",
+ "link_to": "Medical Department",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "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"
+ },
+ {
+ "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": "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"
+ },
+ {
+ "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": "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"
+ },
+ {
+ "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": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Healthcare Settings",
+ "link_to": "Healthcare Settings",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Laboratory Setup",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lab Test Template",
+ "link_to": "Lab Test Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lab Test Sample",
+ "link_to": "Lab Test Sample",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lab Test UOM",
+ "link_to": "Lab Test UOM",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sensitivity",
+ "link_to": "Sensitivity",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Laboratory",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lab Test",
+ "link_to": "Lab Test",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sample Collection",
+ "link_to": "Sample Collection",
+ "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": "Rehabilitation and Physiotherapy",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Exercise Type",
+ "link_to": "Exercise Type",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Therapy Type",
+ "link_to": "Therapy Type",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Therapy Plan",
+ "link_to": "Therapy Plan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Therapy Session",
+ "link_to": "Therapy Session",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient Assessment Template",
+ "link_to": "Patient Assessment Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient Assessment",
+ "link_to": "Patient Assessment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Records and History",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient History",
+ "link_to": "patient_history",
+ "link_type": "Page",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient Progress",
+ "link_to": "patient-progress",
+ "link_type": "Page",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient Medical Record",
+ "link_to": "Patient Medical Record",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "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": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Patient Appointment Analytics",
+ "link_to": "Patient Appointment Analytics",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Lab Test Report",
+ "link_to": "Lab Test Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:34.841396",
+ "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": "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"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index abb34b8..c2798a3 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -10,22 +10,27 @@
app_email = "info@erpnext.com"
app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
-app_logo_url = '/assets/erpnext/images/erp-icon.svg'
+app_logo_url = "/assets/erpnext/images/erpnext-logo.svg"
develop_version = '13.x.x-develop'
-app_include_js = "assets/js/erpnext.min.js"
-app_include_css = "assets/css/erpnext.css"
-web_include_js = "assets/js/erpnext-web.min.js"
-web_include_css = "assets/css/erpnext-web.css"
+app_include_js = "/assets/js/erpnext.min.js"
+app_include_css = "/assets/css/erpnext.css"
+web_include_js = "/assets/js/erpnext-web.min.js"
+web_include_css = "/assets/css/erpnext-web.css"
doctype_js = {
+ "Address": "public/js/address.js",
"Communication": "public/js/communication.js",
"Event": "public/js/event.js",
"Newsletter": "public/js/newsletter.js"
}
+override_doctype_class = {
+ 'Address': 'erpnext.accounts.custom.address.ERPNextAddress'
+}
+
welcome_email = "erpnext.setup.utils.welcome_email"
# setup wizard
@@ -41,6 +46,7 @@
get_help_messages = "erpnext.utilities.activation.get_help_messages"
leaderboards = "erpnext.startup.leaderboard.get_leaderboards"
filters_config = "erpnext.startup.filters.get_filters_config"
+additional_print_settings = "erpnext.controllers.print_settings.get_print_settings"
on_session_creation = [
"erpnext.portal.utils.create_customer_or_supplier",
@@ -72,8 +78,8 @@
"Job Opening", "Student Admission"]
website_context = {
- "favicon": "/assets/erpnext/images/favicon.png",
- "splash_image": "/assets/erpnext/images/erp-icon.svg"
+ "favicon": "/assets/erpnext/images/erpnext-favicon.svg",
+ "splash_image": "/assets/erpnext/images/erpnext-logo.svg"
}
website_route_rules = [
@@ -189,6 +195,10 @@
{"name": "call-disconnect", "src": "/assets/erpnext/sounds/call-disconnect.mp3", "volume": 0.2},
]
+has_upload_permission = {
+ "Employee": "erpnext.hr.doctype.employee.employee.has_upload_permission"
+}
+
has_website_permission = {
"Sales Order": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Quotation": "erpnext.controllers.website_list_for_contact.has_website_permission",
@@ -216,6 +226,11 @@
}
doc_events = {
+ "*": {
+ "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",
"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty"
@@ -232,6 +247,9 @@
"Website Settings": {
"validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products"
},
+ "Tax Category": {
+ "validate": "erpnext.regional.india.utils.validate_tax_category"
+ },
"Sales Invoice": {
"on_submit": [
"erpnext.regional.create_transaction_log",
@@ -245,7 +263,11 @@
"on_trash": "erpnext.regional.check_deletion_permission"
},
"Purchase Invoice": {
- "validate": "erpnext.regional.india.utils.update_grand_total_for_rcm"
+ "validate": [
+ "erpnext.regional.india.utils.update_grand_total_for_rcm",
+ "erpnext.regional.united_arab_emirates.utils.update_grand_total_for_rcm",
+ "erpnext.regional.united_arab_emirates.utils.validate_returns"
+ ]
},
"Payment Entry": {
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status", "erpnext.accounts.doctype.dunning.dunning.resolve_dunning"],
@@ -254,17 +276,20 @@
'Address': {
'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code', 'erpnext.regional.india.utils.update_gst_category']
},
+ 'Supplier': {
+ 'validate': 'erpnext.regional.india.utils.validate_pan_for_india'
+ },
('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
'validate': ['erpnext.regional.india.utils.set_place_of_supply']
},
+ ('Sales Invoice', 'Purchase Invoice'): {
+ 'validate': ['erpnext.regional.india.utils.validate_document_name']
+ },
"Contact": {
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
- "after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information",
+ "after_insert": "erpnext.telephony.doctype.call_log.call_log.link_existing_conversations",
"validate": "erpnext.crm.utils.update_lead_phone_numbers"
},
- "Lead": {
- "after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information"
- },
"Email Unsubscribe": {
"after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient"
},
@@ -277,7 +302,8 @@
# to maintain data integrity we exempted payment entry. it will un-link when sales invoice get cancelled.
# if payment entry not in auto cancel exempted doctypes it will cancel payment entry.
auto_cancel_exempted_doctypes= [
- "Payment Entry"
+ "Payment Entry",
+ "Inpatient Medication Entry"
]
scheduler_events = {
@@ -301,6 +327,8 @@
"erpnext.projects.doctype.project.project.collect_project_status",
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
+ "erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
+ "erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries"
],
"daily": [
"erpnext.stock.reorder_item.reorder_item",
@@ -327,21 +355,24 @@
"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.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email",
+ "erpnext.non_profit.doctype.membership.membership.set_expired_status"
],
"daily_long": [
"erpnext.setup.doctype.email_digest.email_digest.send",
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
+ "erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.automatically_allocate_leaves_based_on_leave_policy",
"erpnext.hr.utils.generate_leave_encashment",
- "erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.create_process_loan_security_shortfall",
- "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
+ "erpnext.hr.utils.allocate_earned_leaves",
+ "erpnext.hr.utils.grant_leaves_automatically",
+ "erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
+ "erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
"erpnext.crm.doctype.lead.lead.daily_open_lead"
],
"monthly_long": [
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
- "erpnext.hr.utils.allocate_earned_leaves",
- "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_demand_loans"
+ "erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_demand_loans"
]
}
@@ -370,6 +401,15 @@
communication_doctypes = ["Customer", "Supplier"]
+accounting_dimension_doctypes = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
+ "Expense Claim", "Expense Claim Detail", "Expense Taxes and Charges", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note",
+ "Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
+ "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"
+]
+
regional_overrides = {
'France': {
'erpnext.tests.test_regional.test_method': 'erpnext.regional.france.utils.test_method'
@@ -379,12 +419,15 @@
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_header': 'erpnext.regional.india.utils.get_itemised_tax_breakup_header',
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data',
'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details',
+ 'erpnext.controllers.taxes_and_totals.get_regional_round_off_accounts': 'erpnext.regional.india.utils.get_regional_round_off_accounts',
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
- 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries'
+ 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
+ 'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields'
},
'United Arab Emirates': {
- 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data'
+ 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
+ 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.united_arab_emirates.utils.make_regional_gl_entries',
},
'Saudi Arabia': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data'
@@ -421,42 +464,43 @@
{"doctype": "Sales Order", "index": 8},
{"doctype": "Quotation", "index": 9},
{"doctype": "Work Order", "index": 10},
- {"doctype": "Purchase Receipt", "index": 11},
- {"doctype": "Purchase Invoice", "index": 12},
- {"doctype": "Delivery Note", "index": 13},
- {"doctype": "Stock Entry", "index": 14},
- {"doctype": "Material Request", "index": 15},
- {"doctype": "Delivery Trip", "index": 16},
- {"doctype": "Pick List", "index": 17},
- {"doctype": "Salary Slip", "index": 18},
- {"doctype": "Leave Application", "index": 19},
- {"doctype": "Expense Claim", "index": 20},
- {"doctype": "Payment Entry", "index": 21},
- {"doctype": "Lead", "index": 22},
- {"doctype": "Opportunity", "index": 23},
- {"doctype": "Item Price", "index": 24},
- {"doctype": "Purchase Taxes and Charges Template", "index": 25},
- {"doctype": "Sales Taxes and Charges", "index": 26},
- {"doctype": "Asset", "index": 27},
- {"doctype": "Project", "index": 28},
- {"doctype": "Task", "index": 29},
- {"doctype": "Timesheet", "index": 30},
- {"doctype": "Issue", "index": 31},
- {"doctype": "Serial No", "index": 32},
- {"doctype": "Batch", "index": 33},
- {"doctype": "Branch", "index": 34},
- {"doctype": "Department", "index": 35},
- {"doctype": "Employee Grade", "index": 36},
- {"doctype": "Designation", "index": 37},
- {"doctype": "Job Opening", "index": 38},
- {"doctype": "Job Applicant", "index": 39},
- {"doctype": "Job Offer", "index": 40},
- {"doctype": "Salary Structure Assignment", "index": 41},
- {"doctype": "Appraisal", "index": 42},
- {"doctype": "Loan", "index": 43},
- {"doctype": "Maintenance Schedule", "index": 44},
- {"doctype": "Maintenance Visit", "index": 45},
- {"doctype": "Warranty Claim", "index": 46},
+ {"doctype": "Purchase Order", "index": 11},
+ {"doctype": "Purchase Receipt", "index": 12},
+ {"doctype": "Purchase Invoice", "index": 13},
+ {"doctype": "Delivery Note", "index": 14},
+ {"doctype": "Stock Entry", "index": 15},
+ {"doctype": "Material Request", "index": 16},
+ {"doctype": "Delivery Trip", "index": 17},
+ {"doctype": "Pick List", "index": 18},
+ {"doctype": "Salary Slip", "index": 19},
+ {"doctype": "Leave Application", "index": 20},
+ {"doctype": "Expense Claim", "index": 21},
+ {"doctype": "Payment Entry", "index": 22},
+ {"doctype": "Lead", "index": 23},
+ {"doctype": "Opportunity", "index": 24},
+ {"doctype": "Item Price", "index": 25},
+ {"doctype": "Purchase Taxes and Charges Template", "index": 26},
+ {"doctype": "Sales Taxes and Charges", "index": 27},
+ {"doctype": "Asset", "index": 28},
+ {"doctype": "Project", "index": 29},
+ {"doctype": "Task", "index": 30},
+ {"doctype": "Timesheet", "index": 31},
+ {"doctype": "Issue", "index": 32},
+ {"doctype": "Serial No", "index": 33},
+ {"doctype": "Batch", "index": 34},
+ {"doctype": "Branch", "index": 35},
+ {"doctype": "Department", "index": 36},
+ {"doctype": "Employee Grade", "index": 37},
+ {"doctype": "Designation", "index": 38},
+ {"doctype": "Job Opening", "index": 39},
+ {"doctype": "Job Applicant", "index": 40},
+ {"doctype": "Job Offer", "index": 41},
+ {"doctype": "Salary Structure Assignment", "index": 42},
+ {"doctype": "Appraisal", "index": 43},
+ {"doctype": "Loan", "index": 44},
+ {"doctype": "Maintenance Schedule", "index": 45},
+ {"doctype": "Maintenance Visit", "index": 46},
+ {"doctype": "Warranty Claim", "index": 47},
],
"Healthcare": [
{'doctype': 'Patient', 'index': 1},
@@ -558,4 +602,8 @@
{'doctype': 'Hotel Room Package', 'index': 3},
{'doctype': 'Hotel Room Type', 'index': 4}
]
-}
\ No newline at end of file
+}
+
+additional_timeline_content = {
+ '*': ['erpnext.telephony.doctype.call_log.call_log.get_linked_call_logs']
+}
diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json
deleted file mode 100644
index 895cf72..0000000
--- a/erpnext/hr/desk_page/hr/hr.json
+++ /dev/null
@@ -1,130 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Employee",
- "links": "[\n {\n \"label\": \"Employee\",\n \"name\": \"Employee\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employment Type\",\n \"name\": \"Employment Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Branch\",\n \"name\": \"Branch\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Department\",\n \"name\": \"Department\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Designation\",\n \"name\": \"Designation\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Grade\",\n \"name\": \"Employee Grade\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Group\",\n \"name\": \"Employee Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Health Insurance\",\n \"name\": \"Employee Health Insurance\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Employee Lifecycle",
- "links": "[\n {\n \"dependencies\": [\n \"Job Applicant\"\n ],\n \"label\": \"Employee Onboarding\",\n \"name\": \"Employee Onboarding\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Skill Map\",\n \"name\": \"Employee Skill Map\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Promotion\",\n \"name\": \"Employee Promotion\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Transfer\",\n \"name\": \"Employee Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Separation\",\n \"name\": \"Employee Separation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Onboarding Template\",\n \"name\": \"Employee Onboarding Template\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Separation Template\",\n \"name\": \"Employee Separation Template\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Shift Management",
- "links": "[\n {\n \"label\": \"Shift Type\",\n \"name\": \"Shift Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shift Request\",\n \"name\": \"Shift Request\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shift Assignment\",\n \"name\": \"Shift Assignment\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Leaves",
- "links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Application\",\n \"name\": \"Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Allocation\",\n \"name\": \"Leave Allocation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Type\"\n ],\n \"label\": \"Leave Policy\",\n \"name\": \"Leave Policy\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Period\",\n \"name\": \"Leave Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Type\",\n \"name\": \"Leave Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Holiday List\",\n \"name\": \"Holiday List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Compensatory Leave Request\",\n \"name\": \"Compensatory Leave Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Encashment\",\n \"name\": \"Leave Encashment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Block List\",\n \"name\": \"Leave Block List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Application\"\n ],\n \"doctype\": \"Leave Application\",\n \"is_query_report\": true,\n \"label\": \"Employee Leave Balance\",\n \"name\": \"Employee Leave Balance\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Attendance",
- "links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Attendance Tool\",\n \"name\": \"Employee Attendance Tool\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Attendance\",\n \"name\": \"Attendance\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Attendance Request\",\n \"name\": \"Attendance Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Upload Attendance\",\n \"name\": \"Upload Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Checkin\",\n \"name\": \"Employee Checkin\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Attendance\"\n ],\n \"doctype\": \"Attendance\",\n \"is_query_report\": true,\n \"label\": \"Monthly Attendance Sheet\",\n \"name\": \"Monthly Attendance Sheet\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Expense Claims",
- "links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Expense Claim\",\n \"name\": \"Expense Claim\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Advance\",\n \"name\": \"Employee Advance\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"label\": \"HR Settings\",\n \"name\": \"HR Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Daily Work Summary Group\",\n \"name\": \"Daily Work Summary Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Team Updates\",\n \"name\": \"team-updates\",\n \"type\": \"page\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Fleet Management",
- "links": "[\n {\n \"label\": \"Vehicle\",\n \"name\": \"Vehicle\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Vehicle Log\",\n \"name\": \"Vehicle Log\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Vehicle\"\n ],\n \"doctype\": \"Vehicle\",\n \"is_query_report\": true,\n \"label\": \"Vehicle Expenses\",\n \"name\": \"Vehicle Expenses\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Recruitment",
- "links": "[\n {\n \"label\": \"Job Opening\",\n \"name\": \"Job Opening\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Applicant\",\n \"name\": \"Job Applicant\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Offer\",\n \"name\": \"Job Offer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Staffing Plan\",\n \"name\": \"Staffing Plan\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Training",
- "links": "[\n {\n \"label\": \"Training Program\",\n \"name\": \"Training Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Event\",\n \"name\": \"Training Event\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Result\",\n \"name\": \"Training Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Feedback\",\n \"name\": \"Training Feedback\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Employee Birthday\",\n \"name\": \"Employee Birthday\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Employees working on a holiday\",\n \"name\": \"Employees working on a holiday\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Department Analytics\",\n \"name\": \"Department Analytics\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Performance",
- "links": "[\n {\n \"label\": \"Appraisal\",\n \"name\": \"Appraisal\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Appraisal Template\",\n \"name\": \"Appraisal Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Energy Point Rule\",\n \"name\": \"Energy Point Rule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Energy Point Log\",\n \"name\": \"Energy Point Log\",\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Attendance Count",
- "label": "Attendance Count"
- }
- ],
- "creation": "2020-03-02 15:48:58.322521",
- "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": "HR",
- "modified": "2020-08-11 17:04:38.655417",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "HR",
- "onboarding": "Human Resource",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Active",
- "label": "Employee",
- "link_to": "Employee",
- "stats_filter": "{\"status\":\"Active\"}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Open",
- "label": "Leave Application",
- "link_to": "Leave Application",
- "stats_filter": "{\"status\":\"Open\"}",
- "type": "DocType"
- },
- {
- "label": "Attendance",
- "link_to": "Attendance",
- "stats_filter": "",
- "type": "DocType"
- },
- {
- "label": "Job Applicant",
- "link_to": "Job Applicant",
- "type": "DocType"
- },
- {
- "label": "Monthly Attendance Sheet",
- "link_to": "Monthly Attendance Sheet",
- "type": "Report"
- },
- {
- "format": "{} Open",
- "label": "Dashboard",
- "link_to": "Human Resource",
- "stats_filter": "{\n \"status\": \"Open\"\n}",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/appraisal/appraisal.js b/erpnext/hr/doctype/appraisal/appraisal.js
index 02f1557..1a30cea 100644
--- a/erpnext/hr/doctype/appraisal/appraisal.js
+++ b/erpnext/hr/doctype/appraisal/appraisal.js
@@ -10,13 +10,13 @@
};
},
- onload: function(frm) {
+ onload: function(frm) {
if(!frm.doc.status) {
frm.set_value('status', 'Draft');
}
},
- kra_template: function(frm) {
+ kra_template: function(frm) {
frm.doc.goals = [];
erpnext.utils.map_current_doc({
method: "erpnext.hr.doctype.appraisal.appraisal.fetch_appraisal_template",
@@ -24,31 +24,56 @@
frm: frm
});
},
-
- calculate_total: function(frm) {
- let goals = frm.doc.goals || [];
- let total =0;
- for(let i = 0; i<goals.length; i++){
+
+ calculate_total: function(frm) {
+ let goals = frm.doc.goals || [];
+ let total = 0;
+
+ if (goals == []) {
+ frm.set_value('total_score', 0);
+ return;
+ }
+ for (let i = 0; i<goals.length; i++) {
total = flt(total)+flt(goals[i].score_earned)
}
- frm.set_value('total_score', total);
+ if (!isNaN(total)) {
+ frm.set_value('total_score', total);
+ frm.refresh_field('calculate_total');
+ }
+ },
+
+ set_score_earned: function(frm) {
+ let goals = frm.doc.goals || [];
+ for (let i = 0; i<goals.length; i++) {
+ var d = locals[goals[i].doctype][goals[i].name];
+ if (d.score && d.per_weightage) {
+ d.score_earned = flt(d.per_weightage*d.score, precision("score_earned", d))/100;
+ }
+ else {
+ d.score_earned = 0;
+ }
+ refresh_field('score_earned', d.name, 'goals');
+ }
+ frm.trigger('calculate_total');
}
});
frappe.ui.form.on('Appraisal Goal', {
score: function(frm, cdt, cdn) {
var d = locals[cdt][cdn];
- if (d.score) {
- if (flt(d.score) > 5) {
- frappe.msgprint(__("Score must be less than or equal to 5"));
- d.score = 0;
- refresh_field('score', d.name, 'goals');
- }
- d.score_earned = flt(d.per_weightage*d.score, precision("score_earned", d))/100;
- } else {
- d.score_earned = 0;
+ if (flt(d.score) > 5) {
+ frappe.msgprint(__("Score must be less than or equal to 5"));
+ d.score = 0;
+ refresh_field('score', d.name, 'goals');
}
- refresh_field('score_earned', d.name, 'goals');
- frm.trigger('calculate_total');
+ else {
+ frm.trigger('set_score_earned');
+ }
+ },
+ per_weightage: function(frm) {
+ frm.trigger('set_score_earned');
+ },
+ goals_remove: function(frm) {
+ frm.trigger('set_score_earned');
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/appraisal/appraisal.json b/erpnext/hr/doctype/appraisal/appraisal.json
index 91201d4..9ca7bcc 100644
--- a/erpnext/hr/doctype/appraisal/appraisal.json
+++ b/erpnext/hr/doctype/appraisal/appraisal.json
@@ -1,775 +1,254 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-01-10 16:34:12",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2013-01-10 16:34:12",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "employee_details",
+ "naming_series",
+ "kra_template",
+ "employee",
+ "employee_name",
+ "column_break0",
+ "status",
+ "start_date",
+ "end_date",
+ "department",
+ "section_break0",
+ "goals",
+ "total_score",
+ "section_break1",
+ "remarks",
+ "other_details",
+ "company",
+ "column_break_17",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee_details",
- "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": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "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": "employee_details",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "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": "Series",
- "length": 0,
- "no_copy": 1,
- "options": "HR-APR-.YY.-.MM.",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "HR-APR-.YY.-.MM.",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "kra_template",
- "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": 1,
- "label": "Appraisal Template",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "kra_template",
- "oldfieldtype": "Link",
- "options": "Appraisal Template",
- "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": 0
- },
+ "fieldname": "kra_template",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Appraisal Template",
+ "oldfieldname": "kra_template",
+ "oldfieldtype": "Link",
+ "options": "Appraisal Template",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "description": "",
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "For Employee",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "employee",
- "oldfieldtype": "Link",
- "options": "Employee",
- "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": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "kra_template",
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "For Employee",
+ "oldfieldname": "employee",
+ "oldfieldtype": "Link",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "For Employee Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "employee_name",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "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
- },
+ "depends_on": "kra_template",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "For Employee Name",
+ "oldfieldname": "employee_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "column_break0",
- "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,
- "oldfieldtype": "Column Break",
- "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,
+ "depends_on": "kra_template",
+ "fieldname": "column_break0",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "depends_on": "kra_template",
- "fieldname": "status",
- "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": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nCompleted\nCancelled",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Draft",
+ "depends_on": "kra_template",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "\nDraft\nSubmitted\nCompleted\nCancelled",
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "start_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Start Date",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "start_date",
- "oldfieldtype": "Date",
- "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": 0
- },
+ "depends_on": "kra_template",
+ "fieldname": "start_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Start Date",
+ "oldfieldname": "start_date",
+ "oldfieldtype": "Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "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": "End Date",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "end_date",
- "oldfieldtype": "Date",
- "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": 0
- },
+ "depends_on": "kra_template",
+ "fieldname": "end_date",
+ "fieldtype": "Date",
+ "label": "End Date",
+ "oldfieldname": "end_date",
+ "oldfieldtype": "Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "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": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "section_break0",
- "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": "Goals",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "Simple",
- "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
- },
+ "depends_on": "kra_template",
+ "fieldname": "section_break0",
+ "fieldtype": "Section Break",
+ "label": "Goals",
+ "oldfieldtype": "Section Break",
+ "options": "Simple"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "goals",
- "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": "Goals",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "appraisal_details",
- "oldfieldtype": "Table",
- "options": "Appraisal Goal",
- "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": "goals",
+ "fieldtype": "Table",
+ "label": "Goals",
+ "oldfieldname": "appraisal_details",
+ "oldfieldtype": "Table",
+ "options": "Appraisal Goal"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "calculate_total_score",
- "fieldtype": "Button",
- "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": "Calculate Total Score",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Button",
- "options": "calculate_total",
- "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": "total_score",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Total Score (Out of 5)",
+ "no_copy": 1,
+ "oldfieldname": "total_score",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_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": "Total Score (Out of 5)",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "total_score",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "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
- },
+ "depends_on": "kra_template",
+ "fieldname": "section_break1",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "section_break1",
- "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,
- "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
- },
+ "description": "Any other remarks, noteworthy effort that should go in the records.",
+ "fieldname": "remarks",
+ "fieldtype": "Text",
+ "label": "Remarks"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Any other remarks, noteworthy effort that should go in the records.",
- "fieldname": "remarks",
- "fieldtype": "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": "Remarks",
- "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
- },
+ "depends_on": "kra_template",
+ "fieldname": "other_details",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "kra_template",
- "fieldname": "other_details",
- "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": "",
- "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": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "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": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_17",
+ "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_17",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 1,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Appraisal",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Appraisal",
+ "print_hide": 1,
+ "read_only": 1,
+ "report_hide": 1,
"width": "150px"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-thumbs-up",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2020-09-18 17:26:09.703215",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Appraisal",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-thumbs-up",
+ "idx": 1,
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-10-03 21:48:33.297065",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Appraisal",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "status, employee, employee_name",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "employee",
- "title_field": "employee_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "search_fields": "status, employee, employee_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "employee",
+ "title_field": "employee_name"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/appraisal/appraisal.py b/erpnext/hr/doctype/appraisal/appraisal.py
index e69dfa8..f760187 100644
--- a/erpnext/hr/doctype/appraisal/appraisal.py
+++ b/erpnext/hr/doctype/appraisal/appraisal.py
@@ -50,7 +50,7 @@
total_w += flt(d.per_weightage)
if int(total_w) != 100:
- frappe.throw(_("Total weightage assigned should be 100%. It is {0}").format(str(total_w) + "%"))
+ frappe.throw(_("Total weightage assigned should be 100%.<br>It is {0}").format(str(total_w) + "%"))
if frappe.db.get_value("Employee", self.employee, "user_id") != \
frappe.session.user and total == 0:
diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py
index 373b940..18a4fe5 100644
--- a/erpnext/hr/doctype/attendance/attendance.py
+++ b/erpnext/hr/doctype/attendance/attendance.py
@@ -131,6 +131,10 @@
data = json.loads(data)
data = frappe._dict(data)
company = frappe.get_value('Employee', data.employee, 'company')
+ if not data.unmarked_days:
+ frappe.throw(_("Please select a date."))
+ return
+
for date in data.unmarked_days:
doc_dict = {
'doctype': 'Attendance',
diff --git a/erpnext/hr/doctype/attendance/attendance_list.js b/erpnext/hr/doctype/attendance/attendance_list.js
index 6df3dbd..0c7eafe 100644
--- a/erpnext/hr/doctype/attendance/attendance_list.js
+++ b/erpnext/hr/doctype/attendance/attendance_list.js
@@ -12,7 +12,7 @@
onload: function(list_view) {
let me = this;
const months = moment.months()
- list_view.page.add_inner_button( __("Mark Attendance"), function(){
+ list_view.page.add_inner_button( __("Mark Attendance"), function() {
let dialog = new frappe.ui.Dialog({
title: __("Mark Attendance"),
fields: [
@@ -22,11 +22,12 @@
fieldtype: 'Link',
options: 'Employee',
reqd: 1,
- onchange: function(){
+ 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;
}
},
{
@@ -35,13 +36,18 @@
fieldname: "month",
options: months,
reqd: 1,
- onchange: function(){
+ 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 =>{
- dialog.set_df_property("unmarked_days", "hidden", 0);
- dialog.set_df_property("unmarked_days", "options", 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;
+ }
});
}
}
@@ -64,21 +70,25 @@
hidden: 1
},
],
- primary_action(data){
- frappe.confirm(__('Mark attendance as <b>' + data.status + '</b> for <b>' + data.month +'</b>' + ' on selected dates?'), () => {
- frappe.call({
- method: "erpnext.hr.doctype.attendance.attendance.mark_bulk_attendance",
- args: {
- data : data
- },
- callback: function(r) {
- if(r.message === 1) {
- frappe.show_alert({message:__("Attendance Marked"), indicator:'blue'});
- cur_dialog.hide();
+ 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]));
+ } else {
+ 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) {
+ if (r.message === 1) {
+ frappe.show_alert({message: __("Attendance Marked"), indicator: 'blue'});
+ cur_dialog.hide();
+ }
}
- }
+ });
});
- });
+ }
dialog.hide();
list_view.refresh();
},
diff --git a/erpnext/hr/doctype/attendance_request/test_attendance_request.py b/erpnext/hr/doctype/attendance_request/test_attendance_request.py
index 92b1eae..3c42bd9 100644
--- a/erpnext/hr/doctype/attendance_request/test_attendance_request.py
+++ b/erpnext/hr/doctype/attendance_request/test_attendance_request.py
@@ -8,6 +8,8 @@
from frappe.utils import nowdate
from datetime import date
+test_dependencies = ["Employee"]
+
class TestAttendanceRequest(unittest.TestCase):
def setUp(self):
for doctype in ["Attendance Request", "Attendance"]:
@@ -56,4 +58,4 @@
self.assertEqual(attendance.docstatus, 2)
def get_employee():
- return frappe.get_doc("Employee", "_T-Employee-00001")
\ No newline at end of file
+ return frappe.get_doc("Employee", "_T-Employee-00001")
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 1615ab3..74ce301 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
@@ -10,6 +10,8 @@
from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
+test_dependencies = ["Employee"]
+
class TestCompensatoryLeaveRequest(unittest.TestCase):
def setUp(self):
frappe.db.sql(''' delete from `tabCompensatory Leave Request`''')
@@ -129,4 +131,4 @@
],
"holiday_list_name": "_Test Compensatory Leave"
})
- holiday_list.save()
\ No newline at end of file
+ holiday_list.save()
diff --git a/erpnext/hr/doctype/department_approver/department_approver.py b/erpnext/hr/doctype/department_approver/department_approver.py
index 9b2de0e..d337959 100644
--- a/erpnext/hr/doctype/department_approver/department_approver.py
+++ b/erpnext/hr/doctype/department_approver/department_approver.py
@@ -20,7 +20,7 @@
approvers = []
department_details = {}
department_list = []
- employee = frappe.get_value("Employee", filters.get("employee"), ["department", "leave_approver", "expense_approver", "shift_request_approver"], as_dict=True)
+ employee = frappe.get_value("Employee", filters.get("employee"), ["employee_name","department", "leave_approver", "expense_approver", "shift_request_approver"], as_dict=True)
employee_department = filters.get("department") or employee.department
if employee_department:
@@ -59,11 +59,9 @@
and approver.approver=user.name""",(d, "%" + txt + "%", parentfield), as_list=True)
if len(approvers) == 0:
- frappe.throw(_("Please set {0} for the Employee or for Department: {1}").
- format(
- field_name, frappe.bold(employee_department),
- frappe.bold(employee.name)
- ),
- title=_(field_name + " Missing"))
+ error_msg = _("Please set {0} for the Employee: {1}").format(field_name, frappe.bold(employee.employee_name))
+ if department_list:
+ error_msg += _(" or for Department: {0}").format(frappe.bold(employee_department))
+ frappe.throw(error_msg, title=_(field_name + " Missing"))
return set(tuple(approver) for approver in approvers)
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index 8c02e4f..5123d6a 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -57,7 +57,6 @@
"column_break_45",
"shift_request_approver",
"attendance_and_leave_details",
- "leave_policy",
"attendance_device_id",
"column_break_44",
"holiday_list",
@@ -109,7 +108,6 @@
"encashment_date",
"exit_interview_details",
"held_on",
- "reason_for_resignation",
"new_workplace",
"feedback",
"lft",
@@ -413,14 +411,6 @@
"options": "Branch"
},
{
- "fetch_from": "grade.default_leave_policy",
- "fetch_if_empty": 1,
- "fieldname": "leave_policy",
- "fieldtype": "Link",
- "label": "Leave Policy",
- "options": "Leave Policy"
- },
- {
"description": "Applicable Holiday List",
"fieldname": "holiday_list",
"fieldtype": "Link",
@@ -673,16 +663,16 @@
"oldfieldtype": "Date"
},
{
- "depends_on": "eval:doc.status == \"Left\"",
"fieldname": "relieving_date",
"fieldtype": "Date",
"label": "Relieving Date",
+ "mandatory_depends_on": "eval:doc.status == \"Left\"",
"oldfieldname": "relieving_date",
"oldfieldtype": "Date"
},
{
"fieldname": "reason_for_leaving",
- "fieldtype": "Data",
+ "fieldtype": "Small Text",
"label": "Reason for Leaving",
"oldfieldname": "reason_for_leaving",
"oldfieldtype": "Data"
@@ -696,6 +686,7 @@
"options": "\nYes\nNo"
},
{
+ "depends_on": "eval:doc.leave_encashed ==\"Yes\"",
"fieldname": "encashment_date",
"fieldtype": "Date",
"label": "Encashment Date",
@@ -705,7 +696,6 @@
{
"fieldname": "exit_interview_details",
"fieldtype": "Column Break",
- "label": "Exit Interview Details",
"oldfieldname": "col_brk6",
"oldfieldtype": "Column Break",
"width": "50%"
@@ -713,19 +703,11 @@
{
"fieldname": "held_on",
"fieldtype": "Date",
- "label": "Held On",
+ "label": "Exit Interview Held On",
"oldfieldname": "held_on",
"oldfieldtype": "Date"
},
{
- "fieldname": "reason_for_resignation",
- "fieldtype": "Select",
- "label": "Reason for Resignation",
- "oldfieldname": "reason_for_resignation",
- "oldfieldtype": "Select",
- "options": "\nBetter Prospects\nHealth Concerns"
- },
- {
"fieldname": "new_workplace",
"fieldtype": "Data",
"label": "New Workplace",
@@ -809,37 +791,29 @@
"fieldname": "expense_approver",
"fieldtype": "Link",
"label": "Expense Approver",
- "options": "User",
- "show_days": 1,
- "show_seconds": 1
+ "options": "User"
},
{
"fieldname": "approvers_section",
"fieldtype": "Section Break",
- "label": "Approvers",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Approvers"
},
{
"fieldname": "column_break_45",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "shift_request_approver",
"fieldtype": "Link",
"label": "Shift Request Approver",
- "options": "User",
- "show_days": 1,
- "show_seconds": 1
+ "options": "User"
}
],
"icon": "fa fa-user",
"idx": 24,
"image_field": "image",
"links": [],
- "modified": "2020-07-28 01:36:04.109189",
+ "modified": "2021-01-02 16:54:33.477439",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
@@ -881,7 +855,6 @@
"write": 1
}
],
- "quick_entry": 1,
"search_fields": "employee_name",
"show_name_in_global_search": 1,
"sort_field": "modified",
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 7338cbb..629bc57 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -8,7 +8,7 @@
from frappe.model.naming import set_name_by_naming_series
from frappe import throw, _, scrub
from frappe.permissions import add_user_permission, remove_user_permission, \
- set_user_permission_if_allowed, has_permission
+ set_user_permission_if_allowed, has_permission, get_doc_permissions
from frappe.model.document import Document
from erpnext.utilities.transaction_base import delete_events
from frappe.utils.nestedset import NestedSet
@@ -57,13 +57,16 @@
remove_user_permission(
"Employee", self.name, existing_user_id)
+ def after_rename(self, old, new, merge):
+ self.db_set("employee", new)
+
def set_employee_name(self):
self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))
def validate_user_details(self):
data = frappe.db.get_value('User',
self.user_id, ['enabled', 'user_image'], as_dict=1)
- if data.get("user_image"):
+ if data.get("user_image") and self.image == '':
self.image = data.get("user_image")
self.validate_for_enabled_user_id(data.get("enabled", 0))
self.validate_duplicate_user_id()
@@ -132,7 +135,7 @@
try:
frappe.get_doc({
"doctype": "File",
- "file_name": self.image,
+ "file_url": self.image,
"attached_to_doctype": "User",
"attached_to_name": self.user_id
}).insert()
@@ -178,8 +181,11 @@
)
if reports_to:
link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name, label=employee.employee_name) for employee in reports_to]
- throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ")
- + ', '.join(link_to_employees), EmployeeLeftValidationError)
+ message = _("The following employees are currently still reporting to {0}:").format(frappe.bold(self.employee_name))
+ message += "<br><br><ul><li>" + "</li><li>".join(link_to_employees)
+ message += "</li></ul><br>"
+ message += _("Please make sure the employees above report to another Active employee.")
+ throw(message, EmployeeLeftValidationError, _("Cannot Relieve Employee"))
if not self.relieving_date:
throw(_("Please enter relieving date."))
@@ -212,7 +218,7 @@
def validate_preferred_email(self):
if self.prefered_contact_email and not self.get(scrub(self.prefered_contact_email)):
- frappe.msgprint(_("Please enter " + self.prefered_contact_email))
+ frappe.msgprint(_("Please enter {0}").format(self.prefered_contact_email))
def validate_onboarding_process(self):
employee_onboarding = frappe.get_all("Employee Onboarding",
@@ -272,63 +278,89 @@
if int(frappe.db.get_single_value("HR Settings", "stop_birthday_reminders") or 0):
return
- birthdays = get_employees_who_are_born_today()
+ employees_born_today = get_employees_who_are_born_today()
- if birthdays:
- employee_list = frappe.get_all('Employee',
- fields=['name','employee_name'],
- filters={'status': 'Active',
- 'company': birthdays[0]['company']
- }
- )
- employee_emails = get_employee_emails(employee_list)
- birthday_names = [name["employee_name"] for name in birthdays]
- birthday_emails = [email["user_id"] or email["personal_email"] or email["company_email"] for email in birthdays]
+ for company, birthday_persons in employees_born_today.items():
+ employee_emails = get_all_employee_emails(company)
+ birthday_person_emails = [get_employee_email(doc) for doc in birthday_persons]
+ recipients = list(set(employee_emails) - set(birthday_person_emails))
- birthdays.append({'company_email': '','employee_name': '','personal_email': '','user_id': ''})
+ reminder_text, message = get_birthday_reminder_text_and_message(birthday_persons)
+ send_birthday_reminder(recipients, reminder_text, birthday_persons, message)
- for e in birthdays:
- if e['company_email'] or e['personal_email'] or e['user_id']:
- if len(birthday_names) == 1:
- continue
- recipients = e['company_email'] or e['personal_email'] or e['user_id']
+ if len(birthday_persons) > 1:
+ # special email for people sharing birthdays
+ for person in birthday_persons:
+ person_email = person["user_id"] or person["personal_email"] or person["company_email"]
+ others = [d for d in birthday_persons if d != person]
+ reminder_text, message = get_birthday_reminder_text_and_message(others)
+ send_birthday_reminder(person_email, reminder_text, others, message)
+def get_employee_email(employee_doc):
+ return employee_doc["user_id"] or employee_doc["personal_email"] or employee_doc["company_email"]
- else:
- recipients = list(set(employee_emails) - set(birthday_emails))
-
- frappe.sendmail(recipients=recipients,
- subject=_("Birthday Reminder"),
- message=get_birthday_reminder_message(e, birthday_names),
- header=['Birthday Reminder', 'green'],
- )
-
-def get_birthday_reminder_message(employee, employee_names):
- """Get employee birthday reminder message"""
- pattern = "</Li><Br><Li>"
- message = pattern.join(filter(lambda u: u not in (employee['employee_name']), employee_names))
- message = message.title()
-
- if pattern not in message:
- message = "Today is {0}'s birthday \U0001F603".format(message)
-
+def get_birthday_reminder_text_and_message(birthday_persons):
+ if len(birthday_persons) == 1:
+ birthday_person_text = birthday_persons[0]['name']
else:
- message = "Today your colleagues are celebrating their birthdays \U0001F382<br><ul><strong><li> " + message +"</li></strong></ul>"
+ # converts ["Jim", "Rim", "Dim"] to Jim, Rim & Dim
+ person_names = [d['name'] for d in birthday_persons]
+ last_person = person_names[-1]
+ birthday_person_text = ", ".join(person_names[:-1])
+ birthday_person_text = _("{} & {}").format(birthday_person_text, last_person)
- return message
+ reminder_text = _("Today is {0}'s birthday 🎉").format(birthday_person_text)
+ message = _("A friendly reminder of an important date for our team.")
+ message += "<br>"
+ message += _("Everyone, let’s congratulate {0} on their birthday.").format(birthday_person_text)
+ return reminder_text, message
-def get_employees_who_are_born_today():
- """Get Employee properties whose birthday is today."""
- return frappe.db.get_values("Employee",
- fieldname=["name", "personal_email", "company", "company_email", "user_id", "employee_name"],
- filters={
- "date_of_birth": ("like", "%{}".format(format_datetime(getdate(), "-MM-dd"))),
- "status": "Active",
- },
- as_dict=True
+def send_birthday_reminder(recipients, reminder_text, birthday_persons, message):
+ frappe.sendmail(
+ recipients=recipients,
+ subject=_("Birthday Reminder"),
+ template="birthday_reminder",
+ args=dict(
+ reminder_text=reminder_text,
+ birthday_persons=birthday_persons,
+ message=message,
+ ),
+ header=_("Birthday Reminder 🎂")
)
+def get_employees_who_are_born_today():
+ """Get all employee born today & group them based on their company"""
+ from collections import defaultdict
+ employees_born_today = frappe.db.multisql({
+ "mariadb": """
+ SELECT `personal_email`, `company`, `company_email`, `user_id`, `employee_name` AS 'name', `image`
+ FROM `tabEmployee`
+ WHERE
+ DAY(date_of_birth) = DAY(%(today)s)
+ AND
+ MONTH(date_of_birth) = MONTH(%(today)s)
+ AND
+ `status` = 'Active'
+ """,
+ "postgres": """
+ SELECT "personal_email", "company", "company_email", "user_id", "employee_name" AS 'name', "image"
+ FROM "tabEmployee"
+ WHERE
+ DATE_PART('day', "date_of_birth") = date_part('day', %(today)s)
+ AND
+ DATE_PART('month', "date_of_birth") = date_part('month', %(today)s)
+ AND
+ "status" = 'Active'
+ """,
+ }, dict(today=today()), as_dict=1)
+
+ grouped_employees = defaultdict(lambda: [])
+
+ for employee_doc in employees_born_today:
+ grouped_employees[employee_doc.get('company')].append(employee_doc)
+
+ return grouped_employees
def get_holiday_list_for_employee(employee, raise_exception=True):
if employee:
@@ -398,6 +430,26 @@
user.insert()
return user.name
+def get_all_employee_emails(company):
+ '''Returns list of employee emails either based on user_id or company_email'''
+ employee_list = frappe.get_all('Employee',
+ fields=['name','employee_name'],
+ filters={
+ 'status': 'Active',
+ 'company': company
+ }
+ )
+ employee_emails = []
+ for employee in employee_list:
+ if not employee:
+ continue
+ user, company_email, personal_email = frappe.db.get_value('Employee',
+ employee, ['user_id', 'company_email', 'personal_email'])
+ email = user or company_email or personal_email
+ if email:
+ employee_emails.append(email)
+ return employee_emails
+
def get_employee_emails(employee_list):
'''Returns list of employee emails either based on user_id or company_email'''
employee_emails = []
@@ -414,9 +466,9 @@
@frappe.whitelist()
def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
- filters = []
+ filters = [['status', '!=', 'Left']]
if company and company != 'All Companies':
- filters = [['company', '=', company]]
+ filters.append(['company', '=', company])
fields = ['name as value', 'employee_name as title']
@@ -449,3 +501,10 @@
'allow': 'Employee',
'for_value': employee_name
})
+
+def has_upload_permission(doc, ptype='read', user=None):
+ if not user:
+ user = frappe.session.user
+ if get_doc_permissions(doc, user=user, ptype=ptype).get(ptype):
+ return True
+ return doc.user_id == user
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee/employee_list.js b/erpnext/hr/doctype/employee/employee_list.js
index 7a66d12..4483703 100644
--- a/erpnext/hr/doctype/employee/employee_list.js
+++ b/erpnext/hr/doctype/employee/employee_list.js
@@ -3,7 +3,7 @@
filters: [["status","=", "Active"]],
get_indicator: function(doc) {
var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];
- indicator[1] = {"Active": "green", "Temporary Leave": "red", "Left": "darkgrey"}[doc.status];
+ indicator[1] = {"Active": "green", "Temporary Leave": "red", "Left": "gray"}[doc.status];
return indicator;
}
};
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index f4b214a..7d652a7 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -16,11 +16,13 @@
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
employee.date_of_birth = "1992" + frappe.utils.nowdate()[4:]
employee.company_email = "test@example.com"
+ employee.company = "_Test Company"
employee.save()
from erpnext.hr.doctype.employee.employee import get_employees_who_are_born_today, send_birthday_reminders
- self.assertTrue(employee.name in [e.name for e in get_employees_who_are_born_today()])
+ employees_born_today = get_employees_who_are_born_today()
+ self.assertTrue(employees_born_today.get("_Test Company"))
frappe.db.sql("delete from `tabEmail Queue`")
@@ -46,6 +48,7 @@
self.assertRaises(EmployeeLeftValidationError, employee1_doc.save)
def make_employee(user, company=None, **kwargs):
+ ""
if not frappe.db.get_value("User", user):
frappe.get_doc({
"doctype": "User",
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js
index cba8ee9..5037ceb 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.js
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.js
@@ -15,11 +15,21 @@
});
frm.set_query("advance_account", function() {
+ if (!frm.doc.employee) {
+ frappe.msgprint(__("Please select employee first"));
+ }
+ let company_currency = erpnext.get_currency(frm.doc.company);
+ let currencies = [company_currency];
+ if (frm.doc.currency && (frm.doc.currency != company_currency)) {
+ currencies.push(frm.doc.currency);
+ }
+
return {
filters: {
"root_type": "Asset",
"is_group": 0,
- "company": frm.doc.company
+ "company": frm.doc.company,
+ "account_currency": ["in", currencies],
}
};
});
@@ -63,7 +73,7 @@
}, __('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.events.make_deduction_via_additional_salary(frm)
+ frm.events.make_deduction_via_additional_salary(frm);
}, __('Create'));
}
}
@@ -127,7 +137,9 @@
'employee_advance_name': frm.doc.name,
'return_amount': flt(frm.doc.paid_amount - frm.doc.claimed_amount),
'advance_account': frm.doc.advance_account,
- 'mode_of_payment': frm.doc.mode_of_payment
+ 'mode_of_payment': frm.doc.mode_of_payment,
+ 'currency': frm.doc.currency,
+ 'exchange_rate': frm.doc.exchange_rate
},
callback: function(r) {
const doclist = frappe.model.sync(r.message);
@@ -138,16 +150,74 @@
employee: function (frm) {
if (frm.doc.employee) {
- return frappe.call({
- method: "erpnext.hr.doctype.employee_advance.employee_advance.get_pending_amount",
- args: {
- "employee": frm.doc.employee,
- "posting_date": frm.doc.posting_date
- },
- callback: function(r) {
- frm.set_value("pending_amount",r.message);
- }
- });
+ frappe.run_serially([
+ () => frm.trigger('get_employee_currency'),
+ () => frm.trigger('get_pending_amount')
+ ]);
}
+ },
+
+ get_pending_amount: function(frm) {
+ frappe.call({
+ method: "erpnext.hr.doctype.employee_advance.employee_advance.get_pending_amount",
+ args: {
+ "employee": frm.doc.employee,
+ "posting_date": frm.doc.posting_date
+ },
+ callback: function(r) {
+ frm.set_value("pending_amount", r.message);
+ }
+ });
+ },
+
+ get_employee_currency: function(frm) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.refresh_fields();
+ }
+ }
+ });
+ },
+
+ currency: function(frm) {
+ if (frm.doc.currency) {
+ var from_currency = frm.doc.currency;
+ var company_currency;
+ if (!frm.doc.company) {
+ company_currency = erpnext.get_currency(frappe.defaults.get_default("Company"));
+ } else {
+ company_currency = erpnext.get_currency(frm.doc.company);
+ }
+ if (from_currency != company_currency) {
+ frm.events.set_exchange_rate(frm, from_currency, company_currency);
+ } else {
+ frm.set_value("exchange_rate", 1.0);
+ frm.set_df_property('exchange_rate', 'hidden', 1);
+ frm.set_df_property("exchange_rate", "description", "" );
+ }
+ frm.refresh_fields();
+ }
+ },
+
+ set_exchange_rate: function(frm, from_currency, company_currency) {
+ frappe.call({
+ method: "erpnext.setup.utils.get_exchange_rate",
+ args: {
+ from_currency: from_currency,
+ to_currency: company_currency,
+ },
+ callback: function(r) {
+ frm.set_value("exchange_rate", flt(r.message));
+ frm.set_df_property('exchange_rate', 'hidden', 0);
+ frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
+ + " = [?] " + company_currency);
+ }
+ });
}
});
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json
index 0d90913..cf6b540 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.json
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.json
@@ -13,6 +13,8 @@
"department",
"column_break_4",
"posting_date",
+ "currency",
+ "exchange_rate",
"repay_unclaimed_amount_from_salary",
"section_break_8",
"purpose",
@@ -91,7 +93,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Advance Amount",
- "options": "Company:company:default_currency",
+ "options": "currency",
"reqd": 1
},
{
@@ -99,7 +101,7 @@
"fieldtype": "Currency",
"label": "Paid Amount",
"no_copy": 1,
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -107,7 +109,7 @@
"fieldtype": "Currency",
"label": "Claimed Amount",
"no_copy": 1,
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -161,7 +163,7 @@
"fieldname": "return_amount",
"fieldtype": "Currency",
"label": "Returned Amount",
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -175,13 +177,31 @@
"fieldname": "pending_amount",
"fieldtype": "Currency",
"label": "Pending Amount",
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.employee)",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "reqd": 1
+ },
+ {
+ "depends_on": "currency",
+ "fieldname": "exchange_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-12 12:42:39.833818",
+ "modified": "2020-11-25 12:01:55.980721",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Advance",
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index 3c435b8..cb72f6b 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -19,7 +19,6 @@
def validate(self):
self.set_status()
- self.validate_employee_advance_account()
def on_cancel(self):
self.ignore_linked_doctypes = ('GL Entry')
@@ -38,16 +37,9 @@
elif self.docstatus == 2:
self.status = "Cancelled"
- def validate_employee_advance_account(self):
- company_currency = erpnext.get_company_currency(self.company)
- if (self.advance_account and
- company_currency != frappe.db.get_value('Account', self.advance_account, 'account_currency')):
- frappe.throw(_("Advance account currency should be same as company currency {0}")
- .format(company_currency))
-
def set_total_advance_paid(self):
paid_amount = frappe.db.sql("""
- select ifnull(sum(debit_in_account_currency), 0) as paid_amount
+ select ifnull(sum(debit), 0) as paid_amount
from `tabGL Entry`
where against_voucher_type = 'Employee Advance'
and against_voucher = %s
@@ -56,7 +48,7 @@
""", (self.name, self.employee), as_dict=1)[0].paid_amount
return_amount = frappe.db.sql("""
- select name, ifnull(sum(credit_in_account_currency), 0) as return_amount
+ select ifnull(sum(credit), 0) as return_amount
from `tabGL Entry`
where against_voucher_type = 'Employee Advance'
and voucher_type != 'Expense Claim'
@@ -65,6 +57,11 @@
and party = %s
""", (self.name, self.employee), as_dict=1)[0].return_amount
+ if paid_amount != 0:
+ paid_amount = flt(paid_amount) / flt(self.exchange_rate)
+ if return_amount != 0:
+ return_amount = flt(return_amount) / flt(self.exchange_rate)
+
if flt(paid_amount) > self.advance_amount:
frappe.throw(_("Row {0}# Paid Amount cannot be greater than requested advance amount"),
EmployeeAdvanceOverPayment)
@@ -107,16 +104,27 @@
doc = frappe.get_doc(dt, dn)
payment_account = get_default_bank_cash_account(doc.company, account_type="Cash",
mode_of_payment=doc.mode_of_payment)
+ if not payment_account:
+ frappe.throw(_("Please set a Default Cash Account in Company defaults"))
+
+ advance_account_currency = frappe.db.get_value('Account', doc.advance_account, 'account_currency')
+
+ advance_amount, advance_exchange_rate = get_advance_amount_advance_exchange_rate(advance_account_currency,doc )
+
+ paying_amount, paying_exchange_rate = get_paying_amount_paying_exchange_rate(payment_account, doc)
je = frappe.new_doc("Journal Entry")
je.posting_date = nowdate()
je.voucher_type = 'Bank Entry'
je.company = doc.company
je.remark = 'Payment against Employee Advance: ' + dn + '\n' + doc.purpose
+ je.multi_currency = 1 if advance_account_currency != payment_account.account_currency else 0
je.append("accounts", {
"account": doc.advance_account,
- "debit_in_account_currency": flt(doc.advance_amount),
+ "account_currency": advance_account_currency,
+ "exchange_rate": flt(advance_exchange_rate),
+ "debit_in_account_currency": flt(advance_amount),
"reference_type": "Employee Advance",
"reference_name": doc.name,
"party_type": "Employee",
@@ -128,19 +136,41 @@
je.append("accounts", {
"account": payment_account.account,
"cost_center": erpnext.get_default_cost_center(doc.company),
- "credit_in_account_currency": flt(doc.advance_amount),
+ "credit_in_account_currency": flt(paying_amount),
"account_currency": payment_account.account_currency,
- "account_type": payment_account.account_type
+ "account_type": payment_account.account_type,
+ "exchange_rate": flt(paying_exchange_rate)
})
return je.as_dict()
+def get_advance_amount_advance_exchange_rate(advance_account_currency, doc):
+ if advance_account_currency != doc.currency:
+ advance_amount = flt(doc.advance_amount) * flt(doc.exchange_rate)
+ advance_exchange_rate = 1
+ else:
+ advance_amount = doc.advance_amount
+ advance_exchange_rate = doc.exchange_rate
+
+ return advance_amount, advance_exchange_rate
+
+def get_paying_amount_paying_exchange_rate(payment_account, doc):
+ if payment_account.account_currency != doc.currency:
+ paying_amount = flt(doc.advance_amount) * flt(doc.exchange_rate)
+ paying_exchange_rate = 1
+ else:
+ paying_amount = doc.advance_amount
+ paying_exchange_rate = doc.exchange_rate
+
+ return paying_amount, paying_exchange_rate
+
@frappe.whitelist()
def create_return_through_additional_salary(doc):
import json
doc = frappe._dict(json.loads(doc))
additional_salary = frappe.new_doc('Additional Salary')
additional_salary.employee = doc.employee
+ additional_salary.currency = doc.currency
additional_salary.amount = doc.paid_amount - doc.claimed_amount
additional_salary.company = doc.company
additional_salary.ref_doctype = doc.doctype
@@ -149,26 +179,28 @@
return additional_salary
@frappe.whitelist()
-def make_return_entry(employee, company, employee_advance_name, return_amount, advance_account, mode_of_payment=None):
- return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
-
- mode_of_payment_type = ''
- if mode_of_payment:
- mode_of_payment_type = frappe.get_cached_value('Mode of Payment', mode_of_payment, 'type')
- if mode_of_payment_type not in ["Cash", "Bank"]:
- # if mode of payment is General then it unset the type
- mode_of_payment_type = None
-
+def make_return_entry(employee, company, employee_advance_name, return_amount, advance_account, currency, exchange_rate, mode_of_payment=None):
+ bank_cash_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
+ if not bank_cash_account:
+ frappe.throw(_("Please set a Default Cash Account in Company defaults"))
+
+ advance_account_currency = frappe.db.get_value('Account', advance_account, 'account_currency')
+
je = frappe.new_doc('Journal Entry')
je.posting_date = nowdate()
- # if mode of payment is Bank then voucher type is Bank Entry
- je.voucher_type = '{} Entry'.format(mode_of_payment_type) if mode_of_payment_type else 'Cash Entry'
+ je.voucher_type = get_voucher_type(mode_of_payment)
je.company = company
je.remark = 'Return against Employee Advance: ' + employee_advance_name
+ je.multi_currency = 1 if advance_account_currency != bank_cash_account.account_currency else 0
+
+ advance_account_amount = flt(return_amount) if advance_account_currency==currency \
+ else flt(return_amount) * flt(exchange_rate)
je.append('accounts', {
'account': advance_account,
- 'credit_in_account_currency': return_amount,
+ 'credit_in_account_currency': advance_account_amount,
+ 'account_currency': advance_account_currency,
+ 'exchange_rate': flt(exchange_rate) if advance_account_currency == currency else 1,
'reference_type': 'Employee Advance',
'reference_name': employee_advance_name,
'party_type': 'Employee',
@@ -176,13 +208,25 @@
'is_advance': 'Yes'
})
+ bank_amount = flt(return_amount) if bank_cash_account.account_currency==currency \
+ else flt(return_amount) * flt(exchange_rate)
+
je.append("accounts", {
- "account": return_account.account,
- "debit_in_account_currency": return_amount,
- "account_currency": return_account.account_currency,
- "account_type": return_account.account_type
+ "account": bank_cash_account.account,
+ "debit_in_account_currency": bank_amount,
+ "account_currency": bank_cash_account.account_currency,
+ "account_type": bank_cash_account.account_type,
+ "exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1
})
return je.as_dict()
+def get_voucher_type(mode_of_payment=None):
+ voucher_type = "Cash Entry"
+ if mode_of_payment:
+ mode_of_payment_type = frappe.get_cached_value('Mode of Payment', mode_of_payment, 'type')
+ if mode_of_payment_type == "Bank":
+ voucher_type = "Bank Entry"
+
+ return voucher_type
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
index 2097e71..c88b2b8 100644
--- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
@@ -3,15 +3,17 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe, erpnext
import unittest
from frappe.utils import nowdate
from erpnext.hr.doctype.employee_advance.employee_advance import make_bank_entry
from erpnext.hr.doctype.employee_advance.employee_advance import EmployeeAdvanceOverPayment
+from erpnext.hr.doctype.employee.test_employee import make_employee
class TestEmployeeAdvance(unittest.TestCase):
def test_paid_amount_and_status(self):
- advance = make_employee_advance()
+ employee_name = make_employee("_T@employe.advance")
+ advance = make_employee_advance(employee_name)
journal_entry = make_payment_entry(advance)
journal_entry.submit()
@@ -33,11 +35,13 @@
return journal_entry
-def make_employee_advance():
+def make_employee_advance(employee_name):
doc = frappe.new_doc("Employee Advance")
- doc.employee = "_T-Employee-00001"
+ doc.employee = employee_name
doc.company = "_Test company"
doc.purpose = "For site visit"
+ doc.currency = erpnext.get_company_currency("_Test company")
+ doc.exchange_rate = 1
doc.advance_amount = 1000
doc.posting_date = nowdate()
doc.advance_account = "_Test Employee Advance - _TC"
diff --git a/erpnext/hr/doctype/employee_grade/employee_grade.json b/erpnext/hr/doctype/employee_grade/employee_grade.json
index e63ffae..88b061a 100644
--- a/erpnext/hr/doctype/employee_grade/employee_grade.json
+++ b/erpnext/hr/doctype/employee_grade/employee_grade.json
@@ -1,167 +1,69 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "Prompt",
- "beta": 0,
- "creation": "2018-04-13 16:14:24.174138",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "creation": "2018-04-13 16:14:24.174138",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "default_salary_structure"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_leave_policy",
- "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": "Default Leave Policy",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Policy",
- "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": "default_salary_structure",
"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": "Default Salary Structure",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Structure",
- "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
+ "options": "Salary Structure"
}
],
- "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-18 17:17:45.617624",
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-08-26 13:12:07.815330",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Grade",
- "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": "HR 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": "HR User",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
- "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
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
index 4e9ee3b..336e13c 100644
--- a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
+++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
@@ -38,7 +38,8 @@
onboarding.insert()
onboarding.submit()
- self.assertEqual(onboarding.project, 'Employee Onboarding : Test Researcher - test@researcher.com')
+ project_name = frappe.db.get_value("Project", onboarding.project, "project_name")
+ self.assertEqual(project_name, 'Employee Onboarding : Test Researcher - test@researcher.com')
# don't allow making employee if onboarding is not complete
self.assertRaises(IncompleteTaskError, make_employee, onboarding.name)
diff --git a/erpnext/hr/doctype/employee_transfer/employee_transfer.py b/erpnext/hr/doctype/employee_transfer/employee_transfer.py
index c730e02..3539970 100644
--- a/erpnext/hr/doctype/employee_transfer/employee_transfer.py
+++ b/erpnext/hr/doctype/employee_transfer/employee_transfer.py
@@ -50,8 +50,9 @@
employee = frappe.get_doc("Employee", self.employee)
if self.create_new_employee_id:
if self.new_employee_id:
- frappe.throw(_("Please delete the Employee <a href='#Form/Employee/{0}'>{0}</a>\
- to cancel this document").format(self.new_employee_id))
+ frappe.throw(_("Please delete the Employee {0} to cancel this document").format(
+ "<a href='/app/Form/Employee/{0}'>{0}</a>".format(self.new_employee_id)
+ ))
#mark the employee as active
employee.status = "Active"
employee.relieving_date = ''
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 221300b..629341f 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -2,11 +2,21 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.hr");
+frappe.provide("erpnext.accounts.dimensions");
-erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
- expense_type: function(doc, cdt, cdn) {
+frappe.ui.form.on('Expense Claim', {
+ onload: function(frm) {
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+});
+
+frappe.ui.form.on('Expense Claim Detail', {
+ expense_type: function(frm, cdt, cdn) {
var d = locals[cdt][cdn];
- if(!doc.company) {
+ if (!frm.doc.company) {
d.expense_type = "";
frappe.msgprint(__("Please set the Company"));
this.frm.refresh_fields();
@@ -20,7 +30,7 @@
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
args: {
"expense_claim_type": d.expense_type,
- "company": doc.company
+ "company": frm.doc.company
},
callback: function(r) {
if (r.message) {
@@ -32,8 +42,6 @@
}
});
-$.extend(cur_frm.cscript, new erpnext.hr.ExpenseClaimController({frm: cur_frm}));
-
cur_frm.add_fetch('employee', 'company', 'company');
cur_frm.add_fetch('employee','employee_name','employee_name');
cur_frm.add_fetch('expense_type','description','description');
@@ -167,15 +175,6 @@
};
});
- frm.set_query("cost_center", "expenses", function() {
- return {
- filters: {
- "company": frm.doc.company,
- "is_group": 0
- }
- };
- });
-
frm.set_query("payable_account", function() {
return {
filters: {
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 6e97f05..f9e3a44 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -7,6 +7,7 @@
from frappe.utils import random_string, nowdate
from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
from erpnext.accounts.doctype.account.test_account import create_account
+from erpnext.hr.doctype.employee.test_employee import make_employee
test_records = frappe.get_test_records('Expense Claim')
test_dependencies = ['Employee']
@@ -19,35 +20,36 @@
frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """)
frappe.db.sql("update `tabExpense Claim` set project = '', task = ''")
- frappe.get_doc({
+ project = frappe.get_doc({
"project_name": "_Test Project 1",
"doctype": "Project"
- }).save()
+ })
+ project.save()
task = frappe.get_doc(dict(
doctype = 'Task',
subject = '_Test Project Task 1',
status = 'Open',
- project = '_Test Project 1'
+ project = project.name
)).insert()
task_name = task.name
payable_account = get_payable_account(company_name)
- make_expense_claim(payable_account, 300, 200, company_name, "Travel Expenses - _TC4", "_Test Project 1", task_name)
+ make_expense_claim(payable_account, 300, 200, company_name, "Travel Expenses - _TC4", project.name, task_name)
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
- self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_expense_claim"), 200)
- expense_claim2 = make_expense_claim(payable_account, 600, 500, company_name, "Travel Expenses - _TC4","_Test Project 1", task_name)
+ expense_claim2 = make_expense_claim(payable_account, 600, 500, company_name, "Travel Expenses - _TC4", project.name, task_name)
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 700)
- self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 700)
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_expense_claim"), 700)
expense_claim2.cancel()
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
- self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
+ self.assertEqual(frappe.db.get_value("Project", project.name, "total_expense_claim"), 200)
def test_expense_claim_status(self):
payable_account = get_payable_account(company_name)
@@ -126,6 +128,9 @@
def make_expense_claim(payable_account, amount, sanctioned_amount, company, account, project=None, task_name=None, do_not_submit=False, taxes=None):
employee = frappe.db.get_value("Employee", {"status": "Active"})
+ if not employee:
+ employee = make_employee("test_employee@expense_claim.com", company=company)
+
currency, cost_center = frappe.db.get_value('Company', company, ['default_currency', 'cost_center'])
expense_claim = {
"doctype": "Expense Claim",
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 885e3ee..020457d 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
@@ -71,9 +71,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
- "oldfieldname": "tax_amount",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency"
+ "options": "currency"
},
{
"columns": 2,
@@ -81,9 +79,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Total",
- "oldfieldname": "total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -106,7 +102,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-05-11 19:01:26.611758",
+ "modified": "2020-09-23 20:27:36.027728",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Taxes and Charges",
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py
index 76dc942..6df7bc8 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list.py
@@ -1,3 +1,4 @@
+
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
@@ -32,7 +33,7 @@
def validate_days(self):
- if self.from_date > self.to_date:
+ if getdate(self.from_date) > getdate(self.to_date):
throw(_("To Date cannot be before From Date"))
for day in self.get("holidays"):
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index c42e1d7..09666c5 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -13,6 +13,7 @@
"stop_birthday_reminders",
"expense_approver_mandatory_in_expense_claim",
"leave_settings",
+ "send_leave_notification",
"leave_approval_notification_template",
"leave_status_notification_template",
"role_allowed_to_create_backdated_leave_application",
@@ -21,6 +22,7 @@
"show_leaves_of_all_department_members_in_calendar",
"auto_leave_encashment",
"restrict_backdated_leave_application",
+ "automatically_allocate_leaves_based_on_leave_policy",
"hiring_settings",
"check_vacancies"
],
@@ -28,144 +30,126 @@
{
"fieldname": "employee_settings",
"fieldtype": "Section Break",
- "label": "Employee Settings",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Employee Settings"
},
{
"description": "Enter retirement age in years",
"fieldname": "retirement_age",
"fieldtype": "Data",
- "label": "Retirement Age",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Retirement Age"
},
{
"default": "Naming Series",
- "description": "Employee record is created using selected field. ",
+ "description": "Employee records are created using the selected field",
"fieldname": "emp_created_by",
"fieldtype": "Select",
"label": "Employee Records to be created by",
- "options": "Naming Series\nEmployee Number\nFull Name",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Naming Series\nEmployee Number\nFull Name"
},
{
"fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"default": "0",
- "description": "Don't send Employee Birthday Reminders",
+ "description": "Don't send employee birthday reminders",
"fieldname": "stop_birthday_reminders",
"fieldtype": "Check",
- "label": "Stop Birthday Reminders",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Stop Birthday Reminders"
},
{
"default": "1",
"fieldname": "expense_approver_mandatory_in_expense_claim",
"fieldtype": "Check",
- "label": "Expense Approver Mandatory In Expense Claim",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Expense Approver Mandatory In Expense Claim"
},
{
"collapsible": 1,
"fieldname": "leave_settings",
"fieldtype": "Section Break",
- "label": "Leave Settings",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Leave Settings"
},
{
+ "depends_on": "eval: doc.send_leave_notification == 1",
"fieldname": "leave_approval_notification_template",
"fieldtype": "Link",
"label": "Leave Approval Notification Template",
- "options": "Email Template",
- "show_days": 1,
- "show_seconds": 1
+ "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",
- "options": "Email Template",
- "show_days": 1,
- "show_seconds": 1
+ "mandatory_depends_on": "eval: doc.send_leave_notification == 1",
+ "options": "Email Template"
},
{
"fieldname": "column_break_18",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"default": "1",
"fieldname": "leave_approver_mandatory_in_leave_application",
"fieldtype": "Check",
- "label": "Leave Approver Mandatory In Leave Application",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Leave Approver Mandatory In Leave Application"
},
{
"default": "0",
"fieldname": "show_leaves_of_all_department_members_in_calendar",
"fieldtype": "Check",
- "label": "Show Leaves Of All Department Members In Calendar",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Show Leaves Of All Department Members In Calendar"
},
{
"collapsible": 1,
"fieldname": "hiring_settings",
"fieldtype": "Section Break",
- "label": "Hiring Settings",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Hiring Settings"
},
{
"default": "0",
"fieldname": "check_vacancies",
"fieldtype": "Check",
- "label": "Check Vacancies On Job Offer Creation",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Check Vacancies On Job Offer Creation"
},
{
"default": "0",
"fieldname": "auto_leave_encashment",
"fieldtype": "Check",
- "label": "Auto Leave Encashment",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Auto Leave Encashment"
},
{
"default": "0",
"fieldname": "restrict_backdated_leave_application",
"fieldtype": "Check",
- "label": "Restrict Backdated Leave Application",
- "show_days": 1,
- "show_seconds": 1
+ "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",
- "options": "Role",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Role"
+ },
+ {
+ "default": "0",
+ "fieldname": "automatically_allocate_leaves_based_on_leave_policy",
+ "fieldtype": "Check",
+ "label": "Automatically Allocate Leaves Based On Leave Policy"
+ },
+ {
+ "default": "1",
+ "fieldname": "send_leave_notification",
+ "fieldtype": "Check",
+ "label": "Send Leave Notification"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"links": [],
- "modified": "2020-06-04 15:15:09.865476",
+ "modified": "2021-03-14 02:04:22.907159",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
@@ -182,5 +166,6 @@
}
],
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json
index c13548a..1360fd1 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.json
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.json
@@ -11,15 +11,24 @@
"field_order": [
"applicant_name",
"email_id",
+ "phone_number",
+ "country",
"status",
"column_break_3",
"job_title",
"source",
"source_name",
+ "applicant_rating",
"section_break_6",
"notes",
"cover_letter",
- "resume_attachment"
+ "resume_attachment",
+ "resume_link",
+ "section_break_16",
+ "currency",
+ "column_break_18",
+ "lower_range",
+ "upper_range"
],
"fields": [
{
@@ -91,12 +100,65 @@
"fieldtype": "Data",
"label": "Notes",
"read_only": 1
+ },
+ {
+ "fieldname": "phone_number",
+ "fieldtype": "Data",
+ "label": "Phone Number",
+ "options": "Phone"
+ },
+ {
+ "fieldname": "country",
+ "fieldtype": "Link",
+ "label": "Country",
+ "options": "Country"
+ },
+ {
+ "fieldname": "resume_link",
+ "fieldtype": "Data",
+ "label": "Resume Link"
+ },
+ {
+ "fieldname": "applicant_rating",
+ "fieldtype": "Rating",
+ "in_list_view": 1,
+ "label": "Applicant Rating"
+ },
+ {
+ "fieldname": "section_break_16",
+ "fieldtype": "Section Break",
+ "label": "Salary Expectation"
+ },
+ {
+ "fieldname": "lower_range",
+ "fieldtype": "Currency",
+ "label": "Lower Range",
+ "options": "currency",
+ "precision": "0"
+ },
+ {
+ "fieldname": "upper_range",
+ "fieldtype": "Currency",
+ "label": "Upper Range",
+ "options": "currency",
+ "precision": "0"
+ },
+ {
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency"
}
],
"icon": "fa fa-user",
"idx": 1,
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-01-13 16:19:39.113330",
+ "modified": "2020-09-18 12:39:02.557563",
"modified_by": "Administrator",
"module": "HR",
"name": "Job Applicant",
diff --git a/erpnext/hr/doctype/job_applicant/test_job_applicant.py b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
index 6d275c8..8728342 100644
--- a/erpnext/hr/doctype/job_applicant/test_job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
@@ -13,11 +13,21 @@
def create_job_applicant(**args):
args = frappe._dict(args)
- job_applicant = frappe.get_doc({
- "doctype": "Job Applicant",
+
+ filters = {
"applicant_name": args.applicant_name or "_Test Applicant",
"email_id": args.email_id or "test_applicant@example.com",
+ }
+
+ if frappe.db.exists("Job Applicant", filters):
+ return frappe.get_doc("Job Applicant", filters)
+
+ job_applicant = frappe.get_doc({
+ "doctype": "Job Applicant",
"status": args.status or "Open"
})
+
+ job_applicant.update(filters)
job_applicant.save()
- return job_applicant
\ No newline at end of file
+
+ return job_applicant
diff --git a/erpnext/hr/doctype/job_offer/job_offer.py b/erpnext/hr/doctype/job_offer/job_offer.py
index c397a3f..7e650f7 100644
--- a/erpnext/hr/doctype/job_offer/job_offer.py
+++ b/erpnext/hr/doctype/job_offer/job_offer.py
@@ -16,7 +16,7 @@
def validate(self):
self.validate_vacancies()
- job_offer = frappe.db.exists("Job Offer",{"job_applicant": self.job_applicant})
+ job_offer = frappe.db.exists("Job Offer",{"job_applicant": self.job_applicant, "docstatus": ["!=", 2]})
if job_offer and job_offer != self.name:
frappe.throw(_("Job Offer: {0} is already for Job Applicant: {1}").format(frappe.bold(job_offer), frappe.bold(self.job_applicant)))
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py
index 8886596..690a692 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.py
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.py
@@ -13,14 +13,15 @@
class TestJobOffer(unittest.TestCase):
def test_job_offer_creation_against_vacancies(self):
- create_staffing_plan(staffing_details=[{
- "designation": "Designer",
+ frappe.db.set_value("HR Settings", None, "check_vacancies", 1)
+ job_applicant = create_job_applicant(email_id="test_job_offer@example.com")
+ job_offer = create_job_offer(job_applicant=job_applicant.name, designation="UX Designer")
+
+ create_staffing_plan(name='Test No Vacancies', staffing_details=[{
+ "designation": "UX Designer",
"vacancies": 0,
"estimated_cost_per_position": 5000
}])
- frappe.db.set_value("HR Settings", None, "check_vacancies", 1)
- job_applicant = create_job_applicant(email_id="test_job_offer@example.com")
- job_offer = create_job_offer(job_applicant=job_applicant.name, designation="Researcher")
self.assertRaises(frappe.ValidationError, job_offer.submit)
# test creation of job offer when vacancies are not present
diff --git a/erpnext/hr/doctype/job_opening/job_opening.json b/erpnext/hr/doctype/job_opening/job_opening.json
index 4437e02..b8f6df6 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.json
+++ b/erpnext/hr/doctype/job_opening/job_opening.json
@@ -1,456 +1,188 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:route",
- "beta": 0,
- "creation": "2013-01-15 16:13:36",
- "custom": 0,
- "description": "Description of a Job Opening",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "field:route",
+ "creation": "2013-01-15 16:13:36",
+ "description": "Description of a Job Opening",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "job_title",
+ "company",
+ "status",
+ "column_break_5",
+ "designation",
+ "department",
+ "staffing_plan",
+ "planned_vacancies",
+ "section_break_6",
+ "publish",
+ "route",
+ "column_break_12",
+ "job_application_route",
+ "section_break_14",
+ "description",
+ "section_break_16",
+ "currency",
+ "lower_range",
+ "upper_range",
+ "column_break_20",
+ "publish_salary_range"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "job_title",
- "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": "Job Title",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "job_title",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Job Title",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "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": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "Open\nClosed",
- "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": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "options": "Open\nClosed"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "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_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "designation",
- "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": "Designation",
- "length": 0,
- "no_copy": 0,
- "options": "Designation",
- "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": "designation",
+ "fieldtype": "Link",
+ "label": "Designation",
+ "options": "Designation",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "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": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "staffing_plan",
- "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": "Staffing Plan",
- "length": 0,
- "no_copy": 0,
- "options": "Staffing Plan",
- "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": "staffing_plan",
+ "fieldtype": "Link",
+ "label": "Staffing Plan",
+ "options": "Staffing Plan",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "staffing_plan",
- "fieldname": "planned_vacancies",
- "fieldtype": "Int",
- "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": "Planned number of Positions",
- "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
- },
+ "depends_on": "staffing_plan",
+ "fieldname": "planned_vacancies",
+ "fieldtype": "Int",
+ "label": "Planned number of Positions",
+ "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": "publish",
- "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": "Publish on website",
- "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": "publish",
+ "fieldtype": "Check",
+ "label": "Publish on website"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "publish",
- "fieldname": "route",
- "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": "Route",
- "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,
+ "depends_on": "publish",
+ "fieldname": "route",
+ "fieldtype": "Data",
+ "label": "Route",
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Job profile, qualifications required etc.",
- "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": 1,
- "in_standard_filter": 0,
- "label": "Description",
- "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
+ "description": "Job profile, qualifications required etc.",
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_list_view": 1,
+ "label": "Description"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_14",
+ "fieldtype": "Section Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_16",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency"
+ },
+ {
+ "fieldname": "lower_range",
+ "fieldtype": "Currency",
+ "label": "Lower Range",
+ "options": "currency",
+ "precision": "0"
+ },
+ {
+ "fieldname": "upper_range",
+ "fieldtype": "Currency",
+ "label": "Upper Range",
+ "options": "currency",
+ "precision": "0"
+ },
+ {
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "publish",
+ "description": "Route to the custom Job Application Webform",
+ "fieldname": "job_application_route",
+ "fieldtype": "Data",
+ "label": "Job Application Route"
+ },
+ {
+ "default": "0",
+ "fieldname": "publish_salary_range",
+ "fieldtype": "Check",
+ "label": "Publish Salary Range"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-bookmark",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-05-20 15:38:44.705823",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Job Opening",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-bookmark",
+ "idx": 1,
+ "links": [],
+ "modified": "2020-09-18 11:23:29.488923",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Job Opening",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Guest",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "read": 1,
+ "role": "Guest"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py
index 00883d7..1e89767 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.py
+++ b/erpnext/hr/doctype/job_opening/job_opening.py
@@ -43,9 +43,8 @@
current_count = designation_counts['employee_count'] + designation_counts['job_openings']
if self.planned_vacancies <= current_count:
- frappe.throw(_("Job Openings for designation {0} already open \
- or hiring completed as per Staffing Plan {1}"
- .format(self.designation, self.staffing_plan)))
+ frappe.throw(_("Job Openings for designation {0} already open or hiring completed as per Staffing Plan {1}").format(
+ self.designation, self.staffing_plan))
def get_context(self, context):
context.parents = [{'route': 'jobs', 'title': _('All Jobs') }]
@@ -56,7 +55,8 @@
context.get_list = get_job_openings
def get_job_openings(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by=None):
- fields = ['name', 'status', 'job_title', 'description']
+ fields = ['name', 'status', 'job_title', 'description', 'publish_salary_range',
+ 'lower_range', 'upper_range', 'currency', 'job_application_route']
filters = filters or {}
filters.update({
diff --git a/erpnext/hr/doctype/job_opening/templates/job_opening_row.html b/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
index 5da8cc8..c015101 100644
--- a/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
+++ b/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
@@ -1,9 +1,18 @@
<div class="my-5">
<h3>{{ doc.job_title }}</h3>
<p>{{ doc.description }}</p>
+ {%- if doc.publish_salary_range -%}
+ <p><b>{{_("Salary range per month")}}: </b>{{ frappe.format_value(frappe.utils.flt(doc.lower_range), currency=doc.currency) }} - {{ frappe.format_value(frappe.utils.flt(doc.upper_range), currency=doc.currency) }}</p>
+ {% endif %}
<div>
- <a class="btn btn-primary"
- href="/job_application?new=1&job_title={{ doc.name }}">
+ {%- if doc.job_application_route -%}
+ <a class='btn btn-primary'
+ href='/{{doc.job_application_route}}?new=1&job_title={{ doc.name }}'>
{{ _("Apply Now") }}</a>
+ {% else %}
+ <a class='btn btn-primary'
+ href='/job_application?new=1&job_title={{ doc.name }}'>
+ {{ _("Apply Now") }}</a>
+ {% endif %}
</div>
</div>
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 007497e..3a300c0 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-02-20 19:10:38",
@@ -10,6 +11,7 @@
"employee",
"employee_name",
"department",
+ "company",
"column_break1",
"leave_type",
"from_date",
@@ -24,6 +26,7 @@
"compensatory_request",
"leave_period",
"leave_policy",
+ "leave_policy_assignment",
"carry_forwarded_leaves_count",
"expired",
"amended_from",
@@ -160,9 +163,10 @@
"read_only": 1
},
{
- "fetch_from": "employee.leave_policy",
+ "fetch_from": "leave_policy_assignment.leave_policy",
"fieldname": "leave_policy",
"fieldtype": "Link",
+ "hidden": 1,
"in_standard_filter": 1,
"label": "Leave Policy",
"options": "Leave Policy",
@@ -209,12 +213,30 @@
"fieldtype": "Float",
"label": "Carry Forwarded Leaves",
"read_only": 1
+ },
+ {
+ "fieldname": "leave_policy_assignment",
+ "fieldtype": "Link",
+ "label": "Leave Policy Assignment",
+ "options": "Leave Policy Assignment",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1,
+ "reqd": 1
}
],
"icon": "fa fa-ok",
"idx": 1,
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
- "modified": "2019-08-08 15:08:42.440909",
+ "links": [],
+ "modified": "2021-01-04 18:46:13.184104",
"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 03fe3fa..69d605d 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -18,7 +18,6 @@
class LeaveAllocation(Document):
def validate(self):
self.validate_period()
- self.validate_new_leaves_allocated_value()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
self.set_total_leaves_allocated()
@@ -51,9 +50,19 @@
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
+ if self.leave_policy_assignment:
+ self.update_leave_policy_assignments_when_no_allocations_left()
if self.carry_forward:
self.set_carry_forwarded_leaves_in_previous_allocation(on_cancel=True)
+ def update_leave_policy_assignments_when_no_allocations_left(self):
+ allocations = frappe.db.get_list("Leave Allocation", filters = {
+ "docstatus": 1,
+ "leave_policy_assignment": self.leave_policy_assignment
+ })
+ if len(allocations) == 0:
+ frappe.db.set_value("Leave Policy Assignment", self.leave_policy_assignment ,"leaves_allocated", 0)
+
def validate_period(self):
if date_diff(self.to_date, self.from_date) <= 0:
frappe.throw(_("To date cannot be before from date"))
@@ -62,11 +71,6 @@
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
- def validate_new_leaves_allocated_value(self):
- """validate that leave allocation is in multiples of 0.5"""
- if flt(self.new_leaves_allocated) % 0.5:
- frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
-
def validate_allocation_overlap(self):
leave_allocation = frappe.db.sql("""
SELECT
@@ -82,7 +86,7 @@
frappe.msgprint(_("{0} already allocated for Employee {1} for period {2} to {3}")
.format(self.leave_type, self.employee, formatdate(self.from_date), formatdate(self.to_date)))
- frappe.throw(_('Reference') + ': <a href="#Form/Leave Allocation/{0}">{0}</a>'
+ frappe.throw(_('Reference') + ': <a href="/app/Form/Leave Allocation/{0}">{0}</a>'
.format(leave_allocation[0][0]), OverlapError)
def validate_back_dated_allocation(self):
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
index 93f7b83..3ab176f 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
@@ -5,7 +5,7 @@
frappe.listview_settings['Leave Allocation'] = {
get_indicator: function(doc) {
if(doc.status==="Expired") {
- return [__("Expired"), "darkgrey", "expired, =, 1"];
+ return [__("Expired"), "gray", "expired, =, 1"];
}
},
};
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 26f077a..0b71036 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -6,6 +6,10 @@
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation, expire_allocation
class TestLeaveAllocation(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ frappe.db.sql("delete from `tabLeave Period`")
+
def test_overlapping_allocation(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -177,4 +181,4 @@
})
return leave_allocation
-test_dependencies = ["Employee", "Leave Type"]
\ No newline at end of file
+test_dependencies = ["Employee", "Leave Type"]
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index d62e418..9ccb915 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -75,7 +75,8 @@
frm.dashboard.add_section(
frappe.render_template('leave_application_dashboard', {
data: leave_details
- })
+ }),
+ __("Allocated Leaves")
);
frm.dashboard.show();
let allowed_leave_types = Object.keys(leave_details);
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 3f25f58..350cead 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -40,7 +40,8 @@
def on_update(self):
if self.status == "Open" and self.docstatus < 1:
# notify leave approver about creation
- self.notify_leave_approver()
+ if frappe.db.get_single_value("HR Settings", "send_leave_notification"):
+ self.notify_leave_approver()
def on_submit(self):
if self.status == "Open":
@@ -50,7 +51,8 @@
self.update_attendance()
# notify leave applier about approval
- self.notify_employee()
+ if frappe.db.get_single_value("HR Settings", "send_leave_notification"):
+ self.notify_employee()
self.create_leave_ledger_entry()
self.reload()
@@ -60,7 +62,8 @@
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
# notify leave applier about cancellation
- self.notify_employee()
+ if frappe.db.get_single_value("HR Settings", "send_leave_notification"):
+ self.notify_employee()
self.cancel_attendance()
def validate_applicable_after(self):
@@ -130,8 +133,7 @@
if self.status == "Approved":
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
date = dt.strftime("%Y-%m-%d")
- status = "Half Day" if getdate(date) == getdate(self.half_day_date) else "On Leave"
-
+ status = "Half Day" if self.half_day_date and getdate(date) == getdate(self.half_day_date) else "On Leave"
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
attendance_date = date, docstatus = ('!=', 2)))
@@ -246,7 +248,7 @@
def throw_overlap_error(self, d):
msg = _("Employee {0} has already applied for {1} between {2} and {3} : ").format(self.employee,
d['leave_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \
- + """ <b><a href="#Form/Leave Application/{0}">{0}</a></b>""".format(d["name"])
+ + """ <b><a href="/app/Form/Leave Application/{0}">{0}</a></b>""".format(d["name"])
frappe.throw(msg, OverlapError)
def get_total_leaves_on_half_day(self):
@@ -293,7 +295,8 @@
def set_half_day_date(self):
if self.from_date == self.to_date and self.half_day == 1:
self.half_day_date = self.from_date
- elif self.half_day == 0:
+
+ if self.half_day == 0:
self.half_day_date = None
def notify_employee(self):
@@ -376,24 +379,32 @@
if expiry_date:
self.create_ledger_entry_for_intermediate_allocation_expiry(expiry_date, submit, lwp)
else:
+ raise_exception = True
+ if frappe.flags.in_patch:
+ raise_exception=False
+
args = dict(
leaves=self.total_leave_days * -1,
from_date=self.from_date,
to_date=self.to_date,
is_lwp=lwp,
- holiday_list=get_holiday_list_for_employee(self.employee)
+ holiday_list=get_holiday_list_for_employee(self.employee, raise_exception=raise_exception) or ''
)
create_leave_ledger_entry(self, args, submit)
def create_ledger_entry_for_intermediate_allocation_expiry(self, expiry_date, submit, lwp):
''' splits leave application into two ledger entries to consider expiry of allocation '''
+
+ raise_exception = True
+ if frappe.flags.in_patch:
+ raise_exception=False
+
args = dict(
from_date=self.from_date,
to_date=expiry_date,
leaves=(date_diff(expiry_date, self.from_date) + 1) * -1,
is_lwp=lwp,
- holiday_list=get_holiday_list_for_employee(self.employee),
-
+ holiday_list=get_holiday_list_for_employee(self.employee, raise_exception=raise_exception) or ''
)
create_leave_ledger_entry(self, args, submit)
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.html b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
index d30e3b9..9f667a6 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
@@ -1,15 +1,14 @@
{% if not jQuery.isEmptyObject(data) %}
-<h5 style="margin-top: 20px;"> {{ __("Allocated Leaves") }} </h5>
<table class="table table-bordered small">
<thead>
<tr>
<th style="width: 16%">{{ __("Leave Type") }}</th>
- <th style="width: 16%" class="text-right">{{ __("Total Allocated Leaves") }}</th>
- <th style="width: 16%" class="text-right">{{ __("Expired Leaves") }}</th>
- <th style="width: 16%" class="text-right">{{ __("Used Leaves") }}</th>
- <th style="width: 16%" class="text-right">{{ __("Pending Leaves") }}</th>
- <th style="width: 16%" class="text-right">{{ __("Available Leaves") }}</th>
+ <th style="width: 16%" class="text-right">{{ __("Total Allocated Leave") }}</th>
+ <th style="width: 16%" class="text-right">{{ __("Expired Leave") }}</th>
+ <th style="width: 16%" class="text-right">{{ __("Used Leave") }}</th>
+ <th style="width: 16%" class="text-right">{{ __("Pending Leave") }}</th>
+ <th style="width: 16%" class="text-right">{{ __("Available Leave") }}</th>
</tr>
</thead>
<tbody>
@@ -26,5 +25,5 @@
</tbody>
</table>
{% else %}
-<p style="margin-top: 30px;"> No Leaves have been allocated. </p>
-{% endif %}
\ No newline at end of file
+<p style="margin-top: 30px;"> No Leave has been allocated. </p>
+{% endif %}
diff --git a/erpnext/hr/doctype/leave_application/leave_application_list.js b/erpnext/hr/doctype/leave_application/leave_application_list.js
index cbb4b73..a3c03b1 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_list.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_list.js
@@ -1,5 +1,6 @@
frappe.listview_settings['Leave Application'] = {
add_fields: ["leave_type", "employee", "employee_name", "total_leave_days", "from_date", "to_date"],
+ has_indicator_for_draft: 1,
get_indicator: function (doc) {
if (doc.status === "Approved") {
return [__("Approved"), "green", "status,=,Approved"];
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 6e909c3..b335c48 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -10,8 +10,9 @@
from frappe.utils import add_days, nowdate, now_datetime, getdate, add_months
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
+from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
-test_dependencies = ["Leave Allocation", "Leave Block List"]
+test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
_test_records = [
{
@@ -410,25 +411,39 @@
self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, nowdate(), add_days(nowdate(), 8)), 21)
def test_earned_leaves_creation(self):
+
+ frappe.db.sql('''delete from `tabLeave Period`''')
+ frappe.db.sql('''delete from `tabLeave Policy Assignment`''')
+ frappe.db.sql('''delete from `tabLeave Allocation`''')
+ frappe.db.sql('''delete from `tabLeave Ledger Entry`''')
+
leave_period = get_leave_period()
employee = get_employee()
leave_type = 'Test Earned Leave Type'
- if not frappe.db.exists('Leave Type', leave_type):
- frappe.get_doc(dict(
- leave_type_name = leave_type,
- doctype = 'Leave Type',
- is_earned_leave = 1,
- earned_leave_frequency = 'Monthly',
- rounding = 0.5,
- max_leaves_allowed = 6
- )).insert()
+ frappe.delete_doc_if_exists("Leave Type", 'Test Earned Leave Type', force=1)
+ frappe.get_doc(dict(
+ leave_type_name = leave_type,
+ doctype = 'Leave Type',
+ is_earned_leave = 1,
+ earned_leave_frequency = 'Monthly',
+ rounding = 0.5,
+ max_leaves_allowed = 6
+ )).insert()
+
leave_policy = frappe.get_doc({
"doctype": "Leave Policy",
"leave_policy_details": [{"leave_type": leave_type, "annual_allocation": 6}]
}).insert()
- frappe.db.set_value("Employee", employee.name, "leave_policy", leave_policy.name)
- allocate_leaves(employee, leave_period, leave_type, 0, eligible_leaves = 12)
+ data = {
+ "assignment_based_on": "Leave Period",
+ "leave_policy": leave_policy.name,
+ "leave_period": leave_period.name
+ }
+
+ leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))
+
+ frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0]).grant_leave_alloc_for_employee()
from erpnext.hr.utils import allocate_earned_leaves
i = 0
@@ -624,4 +639,4 @@
"docstatus": 1
}).insert()
- allocate_leave.submit()
\ No newline at end of file
+ allocate_leave.submit()
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.js b/erpnext/hr/doctype/leave_encashment/leave_encashment.js
index 71a3422..81936a4 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.js
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.js
@@ -22,7 +22,12 @@
}
},
employee: function(frm) {
- frm.trigger("get_leave_details_for_encashment");
+ if (frm.doc.employee) {
+ frappe.run_serially([
+ () => frm.trigger('get_employee_currency'),
+ () => frm.trigger('get_leave_details_for_encashment')
+ ]);
+ }
},
leave_type: function(frm) {
frm.trigger("get_leave_details_for_encashment");
@@ -40,5 +45,20 @@
}
});
}
- }
+ },
+
+ get_employee_currency: function(frm) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.refresh_fields();
+ }
+ }
+ });
+ },
});
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.json b/erpnext/hr/doctype/leave_encashment/leave_encashment.json
index 2cf6ccf..83eeae3 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.json
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.json
@@ -12,6 +12,7 @@
"employee",
"employee_name",
"department",
+ "company",
"column_break_4",
"leave_type",
"leave_allocation",
@@ -19,9 +20,11 @@
"encashable_days",
"amended_from",
"payroll",
- "encashment_amount",
"encashment_date",
- "additional_salary"
+ "additional_salary",
+ "column_break_14",
+ "currency",
+ "encashment_amount"
],
"fields": [
{
@@ -109,6 +112,7 @@
"in_list_view": 1,
"label": "Encashment Amount",
"no_copy": 1,
+ "options": "currency",
"read_only": 1
},
{
@@ -124,11 +128,34 @@
"no_copy": 1,
"options": "Additional Salary",
"read_only": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.employee)",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_14",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2019-12-16 11:51:57.732223",
+ "modified": "2020-11-25 11:56:06.777241",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Encashment",
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 8913c64..4c1a465 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -16,10 +16,16 @@
def validate(self):
set_employee_name(self)
self.get_leave_details_for_encashment()
+ self.validate_salary_structure()
if not self.encashment_date:
self.encashment_date = getdate(nowdate())
+ def validate_salary_structure(self):
+ if not frappe.db.exists('Salary Structure Assignment', {'employee': self.employee}):
+ frappe.throw(_("There is no Salary Structure assigned to {0}. First assign a Salary Stucture.").format(self.employee))
+
+
def before_submit(self):
if self.encashment_amount <= 0:
frappe.throw(_("You can only submit Leave Encashment for a valid encashment amount"))
@@ -30,9 +36,10 @@
additional_salary = frappe.new_doc("Additional Salary")
additional_salary.company = frappe.get_value("Employee", self.employee, "company")
additional_salary.employee = self.employee
+ additional_salary.currency = self.currency
earning_component = frappe.get_value("Leave Type", self.leave_type, "earning_component")
if not earning_component:
- frappe.throw(_("Please set Earning Component for Leave type: {0}.".format(self.leave_type)))
+ frappe.throw(_("Please set Earning Component for Leave type: {0}.").format(self.leave_type))
additional_salary.salary_component = earning_component
additional_salary.payroll_date = self.encashment_date
additional_salary.amount = self.encashment_amount
@@ -98,7 +105,11 @@
create_leave_ledger_entry(self, args, submit)
# create reverse entry for expired leaves
- to_date = self.get_leave_allocation().get('to_date')
+ leave_allocation = self.get_leave_allocation()
+ if not leave_allocation:
+ return
+
+ to_date = leave_allocation.get('to_date')
if to_date < getdate(nowdate()):
args = frappe._dict(
leaves=self.encashable_days,
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index 99f6463..aafc964 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -9,6 +9,7 @@
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
+from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy\
test_dependencies = ["Leave Type"]
@@ -16,6 +17,7 @@
class TestLeaveEncashment(unittest.TestCase):
def setUp(self):
frappe.db.sql('''delete from `tabLeave Period`''')
+ frappe.db.sql('''delete from `tabLeave Policy Assignment`''')
frappe.db.sql('''delete from `tabLeave Allocation`''')
frappe.db.sql('''delete from `tabLeave Ledger Entry`''')
frappe.db.sql('''delete from `tabAdditional Salary`''')
@@ -29,14 +31,26 @@
# create employee, salary structure and assignment
self.employee = make_employee("test_employee_encashment@example.com")
- frappe.db.set_value("Employee", self.employee, "leave_policy", leave_policy.name)
+ self.leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
+
+ data = {
+ "assignment_based_on": "Leave Period",
+ "leave_policy": leave_policy.name,
+ "leave_period": self.leave_period.name
+ }
+
+ leave_policy_assignments = create_assignment_for_multiple_employees([self.employee], frappe._dict(data))
salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", self.employee,
other_details={"leave_encashment_amount_per_day": 50})
- # create the leave period and assign the leaves
- self.leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
- self.leave_period.grant_leave_allocation(employee=self.employee)
+ #grant Leaves
+ frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0]).grant_leave_alloc_for_employee()
+
+
+ def tearDown(self):
+ for dt in ["Leave Period", "Leave Allocation", "Leave Ledger Entry", "Additional Salary", "Leave Encashment", "Salary Structure", "Leave Policy"]:
+ frappe.db.sql("delete from `tab%s`" % dt)
def test_leave_balance_value_and_amount(self):
frappe.db.sql('''delete from `tabLeave Encashment`''')
@@ -45,7 +59,8 @@
employee=self.employee,
leave_type="_Test Leave Type Encashment",
leave_period=self.leave_period.name,
- payroll_date=today()
+ payroll_date=today(),
+ currency="INR"
)).insert()
self.assertEqual(leave_encashment.leave_balance, 10)
@@ -65,7 +80,8 @@
employee=self.employee,
leave_type="_Test Leave Type Encashment",
leave_period=self.leave_period.name,
- payroll_date=today()
+ payroll_date=today(),
+ currency="INR"
)).insert()
leave_encashment.submit()
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 4abba5f..d74760a 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-05-09 15:47:39.760406",
"doctype": "DocType",
"engine": "InnoDB",
@@ -8,6 +9,7 @@
"leave_type",
"transaction_type",
"transaction_name",
+ "company",
"leaves",
"column_break_7",
"from_date",
@@ -106,12 +108,22 @@
"fieldtype": "Link",
"label": "Holiday List",
"options": "Holiday List"
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1,
+ "reqd": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
- "modified": "2020-09-04 12:16:36.569066",
+ "links": [],
+ "modified": "2021-01-04 18:47:45.146652",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_period/leave_period.js b/erpnext/hr/doctype/leave_period/leave_period.js
index bad2b87..0e88bc1 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.js
+++ b/erpnext/hr/doctype/leave_period/leave_period.js
@@ -2,14 +2,6 @@
// For license information, please see license.txt
frappe.ui.form.on('Leave Period', {
- refresh: (frm)=>{
- frm.set_df_property("grant_leaves", "hidden", frm.doc.__islocal ? 1:0);
- if(!frm.is_new()) {
- frm.add_custom_button(__('Grant Leaves'), function () {
- frm.trigger("grant_leaves");
- });
- }
- },
from_date: (frm)=>{
if (frm.doc.from_date && !frm.doc.to_date) {
var a_year_from_start = frappe.datetime.add_months(frm.doc.from_date, 12);
@@ -22,73 +14,7 @@
"filters": {
"company": frm.doc.company,
}
- }
- })
- },
- grant_leaves: function(frm) {
- var d = new frappe.ui.Dialog({
- title: __('Grant Leaves'),
- fields: [
- {
- "label": "Filter Employees By (Optional)",
- "fieldname": "sec_break",
- "fieldtype": "Section Break",
- },
- {
- "label": "Employee Grade",
- "fieldname": "grade",
- "fieldtype": "Link",
- "options": "Employee Grade"
- },
- {
- "label": "Department",
- "fieldname": "department",
- "fieldtype": "Link",
- "options": "Department"
- },
- {
- "fieldname": "col_break",
- "fieldtype": "Column Break",
- },
- {
- "label": "Designation",
- "fieldname": "designation",
- "fieldtype": "Link",
- "options": "Designation"
- },
- {
- "label": "Employee",
- "fieldname": "employee",
- "fieldtype": "Link",
- "options": "Employee"
- },
- {
- "fieldname": "sec_break",
- "fieldtype": "Section Break",
- },
- {
- "label": "Add unused leaves from previous allocations",
- "fieldname": "carry_forward",
- "fieldtype": "Check"
- }
- ],
- primary_action: function() {
- var data = d.get_values();
-
- frappe.call({
- doc: frm.doc,
- method: "grant_leave_allocation",
- args: data,
- callback: function(r) {
- if(!r.exc) {
- d.hide();
- frm.reload_doc();
- }
- }
- });
- },
- primary_action_label: __('Grant')
+ };
});
- d.show();
- }
+ },
});
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 0973ac7..28a33f6 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -7,24 +7,10 @@
from frappe import _
from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil
from frappe.model.document import Document
-from erpnext.hr.utils import validate_overlap, get_employee_leave_policy
+from erpnext.hr.utils import validate_overlap
from frappe.utils.background_jobs import enqueue
-from six import iteritems
class LeavePeriod(Document):
- def get_employees(self, args):
- conditions, values = [], []
- for field, value in iteritems(args):
- if value:
- conditions.append("{0}=%s".format(field))
- values.append(value)
-
- condition_str = " and " + " and ".join(conditions) if len(conditions) else ""
-
- employees = frappe._dict(frappe.db.sql("select name, date_of_joining from tabEmployee where status='Active' {condition}" #nosec
- .format(condition=condition_str), tuple(values)))
-
- return employees
def validate(self):
self.validate_dates()
@@ -33,96 +19,3 @@
def validate_dates(self):
if getdate(self.from_date) >= getdate(self.to_date):
frappe.throw(_("To date can not be equal or less than from date"))
-
-
- def grant_leave_allocation(self, grade=None, department=None, designation=None,
- employee=None, carry_forward=0):
- employee_records = self.get_employees({
- "grade": grade,
- "department": department,
- "designation": designation,
- "name": employee
- })
-
- if employee_records:
- if len(employee_records) > 20:
- frappe.enqueue(grant_leave_alloc_for_employees, timeout=600,
- employee_records=employee_records, leave_period=self, carry_forward=carry_forward)
- else:
- grant_leave_alloc_for_employees(employee_records, self, carry_forward)
- else:
- frappe.msgprint(_("No Employee Found"))
-
-def grant_leave_alloc_for_employees(employee_records, leave_period, carry_forward=0):
- leave_allocations = []
- existing_allocations_for = get_existing_allocations(list(employee_records.keys()), leave_period.name)
- leave_type_details = get_leave_type_details()
- count = 0
- for employee in employee_records.keys():
- if employee in existing_allocations_for:
- continue
- count +=1
- leave_policy = get_employee_leave_policy(employee)
- if leave_policy:
- for leave_policy_detail in leave_policy.leave_policy_details:
- if not leave_type_details.get(leave_policy_detail.leave_type).is_lwp:
- leave_allocation = create_leave_allocation(employee, leave_policy_detail.leave_type,
- leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward, employee_records.get(employee))
- leave_allocations.append(leave_allocation)
- frappe.db.commit()
- frappe.publish_progress(count*100/len(set(employee_records.keys()) - set(existing_allocations_for)), title = _("Allocating leaves..."))
-
- if leave_allocations:
- frappe.msgprint(_("Leaves has been granted sucessfully"))
-
-def get_existing_allocations(employees, leave_period):
- leave_allocations = frappe.db.sql_list("""
- SELECT DISTINCT
- employee
- FROM `tabLeave Allocation`
- WHERE
- leave_period=%s
- AND employee in (%s)
- AND carry_forward=0
- AND docstatus=1
- """ % ('%s', ', '.join(['%s']*len(employees))), [leave_period] + employees)
- if leave_allocations:
- frappe.msgprint(_("Skipping Leave Allocation for the following employees, as Leave Allocation records already exists against them. {0}")
- .format("\n".join(leave_allocations)))
- return leave_allocations
-
-def get_leave_type_details():
- leave_type_details = frappe._dict()
- leave_types = frappe.get_all("Leave Type",
- fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carry_forwarded_leaves_after_days"])
- for d in leave_types:
- leave_type_details.setdefault(d.name, d)
- return leave_type_details
-
-def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward, date_of_joining):
- ''' Creates leave allocation for the given employee in the provided leave period '''
- if carry_forward and not leave_type_details.get(leave_type).is_carry_forward:
- carry_forward = 0
-
- # Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
- if getdate(date_of_joining) > getdate(leave_period.from_date):
- remaining_period = ((date_diff(leave_period.to_date, date_of_joining) + 1) / (date_diff(leave_period.to_date, leave_period.from_date) + 1))
- new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
-
- # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
- if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1:
- new_leaves_allocated = 0
-
- allocation = frappe.get_doc(dict(
- doctype="Leave Allocation",
- employee=employee,
- leave_type=leave_type,
- from_date=leave_period.from_date,
- to_date=leave_period.to_date,
- new_leaves_allocated=new_leaves_allocated,
- leave_period=leave_period.name,
- carry_forward=carry_forward
- ))
- allocation.save(ignore_permissions = True)
- allocation.submit()
- return allocation.name
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.py b/erpnext/hr/doctype/leave_period/test_leave_period.py
index 1762cf9..b5857bc 100644
--- a/erpnext/hr/doctype/leave_period/test_leave_period.py
+++ b/erpnext/hr/doctype/leave_period/test_leave_period.py
@@ -5,43 +5,11 @@
import frappe, erpnext
import unittest
-from frappe.utils import today, add_months
-from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
test_dependencies = ["Employee", "Leave Type", "Leave Policy"]
class TestLeavePeriod(unittest.TestCase):
- def setUp(self):
- frappe.db.sql("delete from `tabLeave Period`")
-
- def test_leave_grant(self):
- leave_type = "_Test Leave Type"
-
- # create the leave policy
- leave_policy = frappe.get_doc({
- "doctype": "Leave Policy",
- "leave_policy_details": [{
- "leave_type": leave_type,
- "annual_allocation": 20
- }]
- }).insert()
- leave_policy.submit()
-
- # create employee and assign the leave period
- employee = "test_leave_period@employee.com"
- employee_doc_name = make_employee(employee)
- frappe.db.set_value("Employee", employee_doc_name, "leave_policy", leave_policy.name)
-
- # clear the already allocated leave
- frappe.db.sql('''delete from `tabLeave Allocation` where employee=%s''', "test_leave_period@employee.com")
-
- # create the leave period
- leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
-
- # test leave_allocation
- leave_period.grant_leave_allocation(employee=employee_doc_name)
- self.assertEqual(get_leave_balance_on(employee_doc_name, leave_type, today()), 20)
+ pass
def create_leave_period(from_date, to_date, company=None):
leave_period = frappe.db.get_value('Leave Period',
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
index ff5dc2f..e0ec4be 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
@@ -4,22 +4,10 @@
def get_data():
return {
'fieldname': 'leave_policy',
- 'non_standard_fieldnames': {
- 'Employee Grade': 'default_leave_policy'
- },
'transactions': [
{
- 'label': _('Employees'),
- 'items': ['Employee', 'Employee Grade']
- },
- {
'label': _('Leaves'),
'items': ['Leave Allocation']
},
]
- }
-
-
-
-
-
\ No newline at end of file
+ }
\ No newline at end of file
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/hr/doctype/leave_policy_assignment/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/hr/doctype/leave_policy_assignment/__init__.py
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js
new file mode 100644
index 0000000..7c32a0d
--- /dev/null
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js
@@ -0,0 +1,72 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Leave Policy Assignment', {
+ onload: function(frm) {
+ frm.ignore_doctypes_on_cancel_all = ["Leave Ledger Entry"];
+ },
+
+ refresh: function(frm) {
+ if (frm.doc.docstatus === 1 && frm.doc.leaves_allocated === 0) {
+ frm.add_custom_button(__("Grant Leave"), function() {
+
+ frappe.call({
+ doc: frm.doc,
+ method: "grant_leave_alloc_for_employee",
+ callback: function(r) {
+ let leave_allocations = r.message;
+ let msg = frm.events.get_success_message(leave_allocations);
+ frappe.msgprint(msg);
+ cur_frm.refresh();
+ }
+ });
+ });
+ }
+ },
+
+ get_success_message: function(leave_allocations) {
+ let msg = __("Leaves has been granted successfully");
+ msg += "<br><table class='table table-bordered'>";
+ msg += "<tr><th>"+__('Leave Type')+"</th><th>"+__("Leave Allocation")+"</th><th>"+__("Leaves Granted")+"</th><tr>";
+ for (let key in leave_allocations) {
+ msg += "<tr><th>"+key+"</th><td>"+leave_allocations[key]["name"]+"</td><td>"+leave_allocations[key]["leaves"]+"</td></tr>";
+ }
+ msg += "</table>";
+ return msg;
+ },
+
+ assignment_based_on: function(frm) {
+ if (frm.doc.assignment_based_on) {
+ frm.events.set_effective_date(frm);
+ } else {
+ frm.set_value("effective_from", '');
+ frm.set_value("effective_to", '');
+ }
+ },
+
+ leave_period: function(frm) {
+ if (frm.doc.leave_period) {
+ frm.events.set_effective_date(frm);
+ }
+ },
+
+ set_effective_date: function(frm) {
+ if (frm.doc.assignment_based_on == "Leave Period" && frm.doc.leave_period) {
+ frappe.model.with_doc("Leave Period", frm.doc.leave_period, function () {
+ let from_date = frappe.model.get_value("Leave Period", frm.doc.leave_period, "from_date");
+ let to_date = frappe.model.get_value("Leave Period", frm.doc.leave_period, "to_date");
+ frm.set_value("effective_from", from_date);
+ frm.set_value("effective_to", to_date);
+
+ });
+ } else if (frm.doc.assignment_based_on == "Joining Date" && frm.doc.employee) {
+ frappe.model.with_doc("Employee", frm.doc.employee, function () {
+ let from_date = frappe.model.get_value("Employee", frm.doc.employee, "date_of_joining");
+ frm.set_value("effective_from", from_date);
+ frm.set_value("effective_to", frappe.datetime.add_months(frm.doc.effective_from, 12));
+ });
+ }
+ frm.refresh();
+ }
+
+});
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
new file mode 100644
index 0000000..3373350
--- /dev/null
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
@@ -0,0 +1,168 @@
+{
+ "actions": [],
+ "autoname": "HR-LPOL-ASSGN-.#####",
+ "creation": "2020-08-19 13:02:43.343666",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "company",
+ "leave_policy",
+ "carry_forward",
+ "column_break_5",
+ "assignment_based_on",
+ "leave_period",
+ "effective_from",
+ "effective_to",
+ "leaves_allocated",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "leave_policy",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Leave Policy",
+ "options": "Leave Policy",
+ "reqd": 1
+ },
+ {
+ "fieldname": "assignment_based_on",
+ "fieldtype": "Select",
+ "label": "Assignment based on",
+ "options": "\nLeave Period\nJoining Date"
+ },
+ {
+ "depends_on": "eval:doc.assignment_based_on == \"Leave Period\"",
+ "fieldname": "leave_period",
+ "fieldtype": "Link",
+ "label": "Leave Period",
+ "mandatory_depends_on": "eval:doc.assignment_based_on == \"Leave Period\"",
+ "options": "Leave Period"
+ },
+ {
+ "fieldname": "effective_from",
+ "fieldtype": "Date",
+ "label": "Effective From",
+ "read_only_depends_on": "eval:doc.assignment_based_on",
+ "reqd": 1
+ },
+ {
+ "fieldname": "effective_to",
+ "fieldtype": "Date",
+ "label": "Effective To",
+ "read_only_depends_on": "eval:doc.assignment_based_on == \"Leave Period\"",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Leave Policy Assignment",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "carry_forward",
+ "fieldtype": "Check",
+ "label": "Add unused leaves from previous allocations"
+ },
+ {
+ "default": "0",
+ "fieldname": "leaves_allocated",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Leaves Allocated",
+ "no_copy": 1,
+ "print_hide": 1
+ }
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-03-01 17:54:01.014509",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Policy Assignment",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "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": "HR User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "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
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
new file mode 100644
index 0000000..4064c56
--- /dev/null
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
@@ -0,0 +1,199 @@
+# -*- 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 import _, bold
+from frappe.utils import getdate, date_diff, comma_and, formatdate, get_datetime, flt
+from math import ceil
+import json
+from six import string_types
+
+class LeavePolicyAssignment(Document):
+
+ def validate(self):
+ self.validate_policy_assignment_overlap()
+ self.set_dates()
+
+ def set_dates(self):
+ if self.assignment_based_on == "Leave Period":
+ self.effective_from, self.effective_to = frappe.db.get_value("Leave Period", self.leave_period, ["from_date", "to_date"])
+ elif self.assignment_based_on == "Joining Date":
+ self.effective_from = frappe.db.get_value("Employee", self.employee, "date_of_joining")
+
+ def validate_policy_assignment_overlap(self):
+ leave_policy_assignments = frappe.get_all("Leave Policy Assignment", filters = {
+ "employee": self.employee,
+ "name": ("!=", self.name),
+ "docstatus": 1,
+ "effective_to": (">=", self.effective_from),
+ "effective_from": ("<=", self.effective_to)
+ })
+
+ if len(leave_policy_assignments):
+ frappe.throw(_("Leave Policy: {0} already assigned for Employee {1} for period {2} to {3}")
+ .format(bold(self.leave_policy), bold(self.employee), bold(formatdate(self.effective_from)), bold(formatdate(self.effective_to))))
+
+ def grant_leave_alloc_for_employee(self):
+ if self.leaves_allocated:
+ frappe.throw(_("Leave already have been assigned for this Leave Policy Assignment"))
+ else:
+ leave_allocations = {}
+ leave_type_details = get_leave_type_details()
+
+ leave_policy = frappe.get_doc("Leave Policy", self.leave_policy)
+ date_of_joining = frappe.db.get_value("Employee", self.employee, "date_of_joining")
+
+ for leave_policy_detail in leave_policy.leave_policy_details:
+ if not leave_type_details.get(leave_policy_detail.leave_type).is_lwp:
+ leave_allocation, new_leaves_allocated = self.create_leave_allocation(
+ leave_policy_detail.leave_type, leave_policy_detail.annual_allocation,
+ leave_type_details, date_of_joining
+ )
+
+ leave_allocations[leave_policy_detail.leave_type] = {"name": leave_allocation, "leaves": new_leaves_allocated}
+
+ self.db_set("leaves_allocated", 1)
+ return leave_allocations
+
+ def create_leave_allocation(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ # Creates leave allocation for the given employee in the provided leave period
+ carry_forward = self.carry_forward
+ if self.carry_forward and not leave_type_details.get(leave_type).is_carry_forward:
+ carry_forward = 0
+
+ new_leaves_allocated = self.get_new_leaves(leave_type, new_leaves_allocated,
+ leave_type_details, date_of_joining)
+
+ allocation = frappe.get_doc(dict(
+ doctype="Leave Allocation",
+ employee=self.employee,
+ leave_type=leave_type,
+ from_date=self.effective_from,
+ to_date=self.effective_to,
+ new_leaves_allocated=new_leaves_allocated,
+ leave_period=self.leave_period or None,
+ leave_policy_assignment = self.name,
+ leave_policy = self.leave_policy,
+ carry_forward=carry_forward
+ ))
+ allocation.save(ignore_permissions = True)
+ allocation.submit()
+ return allocation.name, new_leaves_allocated
+
+ def get_new_leaves(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ from frappe.model.meta import get_field_precision
+ precision = get_field_precision(frappe.get_meta("Leave Allocation").get_field("new_leaves_allocated"))
+
+ # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
+ if leave_type_details.get(leave_type).is_compensatory == 1:
+ new_leaves_allocated = 0
+
+ elif leave_type_details.get(leave_type).is_earned_leave == 1:
+ if self.assignment_based_on == "Leave Period":
+ new_leaves_allocated = self.get_leaves_for_passed_months(leave_type, new_leaves_allocated, leave_type_details, date_of_joining)
+ else:
+ new_leaves_allocated = 0
+ # Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
+ elif getdate(date_of_joining) > getdate(self.effective_from):
+ remaining_period = ((date_diff(self.effective_to, date_of_joining) + 1) / (date_diff(self.effective_to, self.effective_from) + 1))
+ new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
+
+ return flt(new_leaves_allocated, precision)
+
+ def get_leaves_for_passed_months(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ from erpnext.hr.utils import get_monthly_earned_leave
+
+ current_month = get_datetime().month
+ current_year = get_datetime().year
+
+ from_date = frappe.db.get_value("Leave Period", self.leave_period, "from_date")
+ if getdate(date_of_joining) > getdate(from_date):
+ from_date = date_of_joining
+
+ from_date_month = get_datetime(from_date).month
+ from_date_year = get_datetime(from_date).year
+
+ months_passed = 0
+ if current_year == from_date_year and current_month > from_date_month:
+ months_passed = current_month - from_date_month
+ elif current_year > from_date_year:
+ months_passed = (12 - from_date_month) + current_month
+
+ if months_passed > 0:
+ monthly_earned_leave = get_monthly_earned_leave(new_leaves_allocated,
+ leave_type_details.get(leave_type).earned_leave_frequency, leave_type_details.get(leave_type).rounding)
+ new_leaves_allocated = monthly_earned_leave * months_passed
+
+ return new_leaves_allocated
+
+
+@frappe.whitelist()
+def grant_leave_for_multiple_employees(leave_policy_assignments):
+ leave_policy_assignments = json.loads(leave_policy_assignments)
+ not_granted = []
+ for assignment in leave_policy_assignments:
+ try:
+ frappe.get_doc("Leave Policy Assignment", assignment).grant_leave_alloc_for_employee()
+ except Exception:
+ not_granted.append(assignment)
+
+ if len(not_granted):
+ msg = _("Leave not Granted for Assignments:")+ bold(comma_and(not_granted)) + _(". Please Check documents")
+ else:
+ msg = _("Leave granted Successfully")
+ frappe.msgprint(msg)
+
+@frappe.whitelist()
+def create_assignment_for_multiple_employees(employees, data):
+
+ if isinstance(employees, string_types):
+ employees= json.loads(employees)
+
+ if isinstance(data, string_types):
+ data = frappe._dict(json.loads(data))
+
+ docs_name = []
+ for employee in employees:
+ assignment = frappe.new_doc("Leave Policy Assignment")
+ assignment.employee = employee
+ assignment.assignment_based_on = data.assignment_based_on or None
+ assignment.leave_policy = data.leave_policy
+ assignment.effective_from = getdate(data.effective_from) or None
+ assignment.effective_to = getdate(data.effective_to) or None
+ assignment.leave_period = data.leave_period or None
+ assignment.carry_forward = data.carry_forward
+
+ assignment.save()
+ assignment.submit()
+ docs_name.append(assignment.name)
+ return docs_name
+
+
+def automatically_allocate_leaves_based_on_leave_policy():
+ today = getdate()
+ automatically_allocate_leaves_based_on_leave_policy = frappe.db.get_single_value(
+ 'HR Settings', 'automatically_allocate_leaves_based_on_leave_policy'
+ )
+
+ pending_assignments = frappe.get_list(
+ "Leave Policy Assignment",
+ filters = {"docstatus": 1, "leaves_allocated": 0, "effective_from": today}
+ )
+
+ if len(pending_assignments) and automatically_allocate_leaves_based_on_leave_policy:
+ for assignment in pending_assignments:
+ frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee()
+
+
+def get_leave_type_details():
+ leave_type_details = frappe._dict()
+ leave_types = frappe.get_all("Leave Type",
+ fields=["name", "is_lwp", "is_earned_leave", "is_compensatory",
+ "is_carry_forward", "expire_carry_forwarded_leaves_after_days", "earned_leave_frequency", "rounding"])
+ for d in leave_types:
+ leave_type_details.setdefault(d.name, d)
+ return leave_type_details
+
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
new file mode 100644
index 0000000..468f243
--- /dev/null
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
@@ -0,0 +1,138 @@
+frappe.listview_settings['Leave Policy Assignment'] = {
+ onload: function (list_view) {
+ let me = this;
+ list_view.page.add_inner_button(__("Bulk Leave Policy Assignment"), function () {
+ me.dialog = new frappe.ui.form.MultiSelectDialog({
+ doctype: "Employee",
+ target: cur_list,
+ setters: {
+ company: '',
+ department: '',
+ },
+ data_fields: [{
+ fieldname: 'leave_policy',
+ fieldtype: 'Link',
+ options: 'Leave Policy',
+ label: __('Leave Policy'),
+ reqd: 1
+ },
+ {
+ fieldname: 'assignment_based_on',
+ fieldtype: 'Select',
+ options: ["", "Leave Period"],
+ label: __('Assignment Based On'),
+ onchange: () => {
+ if (cur_dialog.fields_dict.assignment_based_on.value === "Leave Period") {
+ cur_dialog.set_df_property("effective_from", "read_only", 1);
+ cur_dialog.set_df_property("leave_period", "reqd", 1);
+ cur_dialog.set_df_property("effective_to", "read_only", 1);
+ } else {
+ cur_dialog.set_df_property("effective_from", "read_only", 0);
+ cur_dialog.set_df_property("leave_period", "reqd", 0);
+ cur_dialog.set_df_property("effective_to", "read_only", 0);
+ cur_dialog.set_value("effective_from", "");
+ cur_dialog.set_value("effective_to", "");
+ }
+ }
+ },
+ {
+ fieldname: "leave_period",
+ fieldtype: 'Link',
+ options: "Leave Period",
+ label: __('Leave Period'),
+ depends_on: doc => {
+ return doc.assignment_based_on == 'Leave Period';
+ },
+ onchange: () => {
+ if (cur_dialog.fields_dict.leave_period.value) {
+ me.set_effective_date();
+ }
+ }
+ },
+ {
+ fieldtype: "Column Break"
+ },
+ {
+ fieldname: 'effective_from',
+ fieldtype: 'Date',
+ label: __('Effective From'),
+ reqd: 1
+ },
+ {
+ fieldname: 'effective_to',
+ fieldtype: 'Date',
+ label: __('Effective To'),
+ reqd: 1
+ },
+ {
+ fieldname: 'carry_forward',
+ fieldtype: 'Check',
+ label: __('Add unused leaves from previous allocations')
+ }
+ ],
+ get_query() {
+ return {
+ filters: {
+ status: ['=', 'Active']
+ }
+ };
+ },
+ add_filters_group: 1,
+ primary_action_label: "Assign",
+ action(employees, data) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.create_assignment_for_multiple_employees',
+ async: false,
+ args: {
+ employees: employees,
+ data: data
+ }
+ });
+ cur_dialog.hide();
+ }
+ });
+ });
+
+ list_view.page.add_inner_button(__("Grant Leaves"), function () {
+ me.dialog = new frappe.ui.form.MultiSelectDialog({
+ doctype: "Leave Policy Assignment",
+ target: cur_list,
+ setters: {
+ company: '',
+ employee: '',
+ },
+ get_query() {
+ return {
+ filters: {
+ docstatus: ['=', 1],
+ leaves_allocated: ['=', 0]
+ }
+ };
+ },
+ add_filters_group: 1,
+ primary_action_label: "Grant Leaves",
+ action(leave_policy_assignments) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.grant_leave_for_multiple_employees',
+ async: false,
+ args: {
+ leave_policy_assignments: leave_policy_assignments
+ }
+ });
+ me.dialog.hide();
+ }
+ });
+ });
+ },
+
+ set_effective_date: function () {
+ if (cur_dialog.fields_dict.assignment_based_on.value === "Leave Period" && cur_dialog.fields_dict.leave_period.value) {
+ frappe.model.with_doc("Leave Period", cur_dialog.fields_dict.leave_period.value, function () {
+ let from_date = frappe.model.get_value("Leave Period", cur_dialog.fields_dict.leave_period.value, "from_date");
+ let to_date = frappe.model.get_value("Leave Period", cur_dialog.fields_dict.leave_period.value, "to_date");
+ cur_dialog.set_value("effective_from", from_date);
+ cur_dialog.set_value("effective_to", to_date);
+ });
+ }
+ }
+};
\ No newline at end of file
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
new file mode 100644
index 0000000..838e794
--- /dev/null
+++ b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.hr.doctype.leave_application.test_leave_application import get_leave_period, get_employee
+from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
+from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy
+
+test_dependencies = ["Employee"]
+
+class TestLeavePolicyAssignment(unittest.TestCase):
+
+ def setUp(self):
+ for doctype in ["Leave Application", "Leave Allocation", "Leave Policy Assignment", "Leave Ledger Entry"]:
+ frappe.db.sql("delete from `tab{0}`".format(doctype)) #nosec
+
+ def test_grant_leaves(self):
+ leave_period = get_leave_period()
+ employee = get_employee()
+
+ # create the leave policy with leave type "_Test Leave Type", allocation = 10
+ leave_policy = create_leave_policy()
+ leave_policy.submit()
+
+
+ data = {
+ "assignment_based_on": "Leave Period",
+ "leave_policy": leave_policy.name,
+ "leave_period": leave_period.name
+ }
+
+ leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))
+
+ leave_policy_assignment_doc = frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0])
+ leave_policy_assignment_doc.grant_leave_alloc_for_employee()
+ leave_policy_assignment_doc.reload()
+
+ self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 1)
+
+ leave_allocation = frappe.get_list("Leave Allocation", filters={
+ "employee": employee.name,
+ "leave_policy":leave_policy.name,
+ "leave_policy_assignment": leave_policy_assignments[0],
+ "docstatus": 1})[0]
+
+ leave_alloc_doc = frappe.get_doc("Leave Allocation", leave_allocation)
+
+ self.assertEqual(leave_alloc_doc.new_leaves_allocated, 10)
+ self.assertEqual(leave_alloc_doc.leave_type, "_Test Leave Type")
+ self.assertEqual(leave_alloc_doc.from_date, leave_period.from_date)
+ self.assertEqual(leave_alloc_doc.to_date, leave_period.to_date)
+ self.assertEqual(leave_alloc_doc.leave_policy, leave_policy.name)
+ self.assertEqual(leave_alloc_doc.leave_policy_assignment, leave_policy_assignments[0])
+
+ def test_allow_to_grant_all_leave_after_cancellation_of_every_leave_allocation(self):
+ leave_period = get_leave_period()
+ employee = get_employee()
+
+ # create the leave policy with leave type "_Test Leave Type", allocation = 10
+ leave_policy = create_leave_policy()
+ leave_policy.submit()
+
+
+ data = {
+ "assignment_based_on": "Leave Period",
+ "leave_policy": leave_policy.name,
+ "leave_period": leave_period.name
+ }
+
+ leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))
+
+ leave_policy_assignment_doc = frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0])
+ leave_policy_assignment_doc.grant_leave_alloc_for_employee()
+ leave_policy_assignment_doc.reload()
+
+
+ # every leave is allocated no more leave can be granted now
+ self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 1)
+
+ leave_allocation = frappe.get_list("Leave Allocation", filters={
+ "employee": employee.name,
+ "leave_policy":leave_policy.name,
+ "leave_policy_assignment": leave_policy_assignments[0],
+ "docstatus": 1})[0]
+
+ leave_alloc_doc = frappe.get_doc("Leave Allocation", leave_allocation)
+
+ # User all allowed to grant leave when there is no allocation against assignment
+ leave_alloc_doc.cancel()
+ leave_alloc_doc.delete()
+
+ leave_policy_assignment_doc.reload()
+
+
+ # User are now allowed to grant leave
+ self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 0)
+
+ def tearDown(self):
+ for doctype in ["Leave Application", "Leave Allocation", "Leave Policy Assignment", "Leave Ledger Entry"]:
+ frappe.db.sql("delete from `tab{0}`".format(doctype)) #nosec
+
+
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 0af832f..fc577ef 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -15,6 +15,8 @@
"column_break_3",
"is_carry_forward",
"is_lwp",
+ "is_ppl",
+ "fraction_of_daily_salary_per_leave",
"is_optional_leave",
"allow_negative",
"include_holiday",
@@ -31,6 +33,7 @@
"is_earned_leave",
"earned_leave_frequency",
"column_break_22",
+ "based_on_date_of_joining",
"rounding"
],
"fields": [
@@ -77,6 +80,7 @@
},
{
"default": "0",
+ "depends_on": "eval:doc.is_ppl == 0",
"fieldname": "is_lwp",
"fieldtype": "Check",
"label": "Is Leave Without Pay"
@@ -168,7 +172,7 @@
"fieldname": "rounding",
"fieldtype": "Select",
"label": "Rounding",
- "options": "0.5\n1.0"
+ "options": "\n0.25\n0.5\n1.0"
},
{
"depends_on": "is_carry_forward",
@@ -183,12 +187,34 @@
{
"fieldname": "column_break_22",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.is_earned_leave",
+ "description": "If checked, leave will be granted on the day of joining every month.",
+ "fieldname": "based_on_date_of_joining",
+ "fieldtype": "Check",
+ "label": "Based On Date Of Joining"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.is_lwp == 0",
+ "fieldname": "is_ppl",
+ "fieldtype": "Check",
+ "label": "Is Partially Paid Leave"
+ },
+ {
+ "depends_on": "eval:doc.is_ppl == 1",
+ "fieldname": "fraction_of_daily_salary_per_leave",
+ "fieldtype": "Float",
+ "label": "Fraction of Daily Salary per Leave",
+ "mandatory_depends_on": "eval:doc.is_ppl == 1"
}
],
"icon": "fa fa-flag",
"idx": 1,
"links": [],
- "modified": "2019-12-12 12:48:37.780254",
+ "modified": "2021-03-02 11:22:33.776320",
"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 c0d1296..21f180b 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -21,3 +21,9 @@
leave_allocation = [l['name'] for l in leave_allocation]
if leave_allocation:
frappe.throw(_('Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay').format(", ".join(leave_allocation))) #nosec
+
+ if self.is_lwp and self.is_ppl:
+ frappe.throw(_("Leave Type can be either without pay or partial pay"))
+
+ if self.is_ppl and (self.fraction_of_daily_salary_per_leave < 0 or self.fraction_of_daily_salary_per_leave > 1):
+ frappe.throw(_("The fraction of Daily Salary per Leave should be between 0 and 1"))
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index 0c4f435..7fef297 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -18,9 +18,14 @@
"allow_encashment": args.allow_encashment or 0,
"is_earned_leave": args.is_earned_leave or 0,
"is_lwp": args.is_lwp or 0,
+ "is_ppl":args.is_ppl or 0,
"is_carry_forward": args.is_carry_forward or 0,
"expire_carry_forwarded_leaves_after_days": args.expire_carry_forwarded_leaves_after_days or 0,
"encashment_threshold_days": args.encashment_threshold_days or 5,
"earning_component": "Leave Encashment"
})
+
+ if leave_type.is_ppl:
+ leave_type.fraction_of_daily_salary_per_leave = args.fraction_of_daily_salary_per_leave or 0.5
+
return leave_type
\ No newline at end of file
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
index 2c385e8..ab65260 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
@@ -88,7 +88,7 @@
def add_assignments(events, start, end, conditions=None):
query = """select name, start_date, end_date, employee_name,
- employee, docstatus
+ employee, docstatus, shift_type
from `tabShift Assignment` where
start_date >= %(start_date)s
or end_date <= %(end_date)s
@@ -97,18 +97,40 @@
if conditions:
query += conditions
- for d in frappe.db.sql(query, {"start_date":start, "end_date":end}, as_dict=True):
- e = {
- "name": d.name,
- "doctype": "Shift Assignment",
- "start_date": d.start_date,
- "end_date": d.end_date if d.end_date else nowdate(),
- "title": cstr(d.employee_name) + ": "+ \
- cstr(d.shift_type),
- "docstatus": d.docstatus
- }
- if e not in events:
- events.append(e)
+ records = frappe.db.sql(query, {"start_date":start, "end_date":end}, as_dict=True)
+ shift_timing_map = get_shift_type_timing([d.shift_type for d in records])
+
+ for d in records:
+ daily_event_start = d.start_date
+ daily_event_end = d.end_date if d.end_date else getdate()
+ delta = timedelta(days=1)
+ while daily_event_start <= daily_event_end:
+ start_timing = frappe.utils.get_datetime(daily_event_start)+ shift_timing_map[d.shift_type]['start_time']
+ end_timing = frappe.utils.get_datetime(daily_event_start)+ shift_timing_map[d.shift_type]['end_time']
+ daily_event_start += delta
+ e = {
+ "name": d.name,
+ "doctype": "Shift Assignment",
+ "start_date": start_timing,
+ "end_date": end_timing,
+ "title": cstr(d.employee_name) + ": "+ \
+ cstr(d.shift_type),
+ "docstatus": d.docstatus,
+ "allDay": 0
+ }
+ if e not in events:
+ events.append(e)
+
+ return events
+
+def get_shift_type_timing(shift_types):
+ shift_timing_map = {}
+ data = frappe.get_all("Shift Type", filters = {"name": ("IN", shift_types)}, fields = ['name', 'start_time', 'end_time'])
+
+ for d in data:
+ shift_timing_map[d.name] = d
+
+ return shift_timing_map
def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=False, next_shift_direction=None):
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
index 17a986d..bb692e1 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
@@ -6,14 +6,8 @@
"start": "start_date",
"end": "end_date",
"id": "name",
- "docstatus": 1
- },
- options: {
- header: {
- left: 'prev,next today',
- center: 'title',
- right: 'month'
- }
+ "docstatus": 1,
+ "allDay": "allDay",
},
get_events_method: "erpnext.hr.doctype.shift_assignment.shift_assignment.get_events"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py
index 1c2801b..473193d 100644
--- a/erpnext/hr/doctype/shift_request/shift_request.py
+++ b/erpnext/hr/doctype/shift_request/shift_request.py
@@ -87,5 +87,5 @@
def throw_overlap_error(self, d):
msg = _("Employee {0} has already applied for {1} between {2} and {3} : ").format(self.employee,
d['shift_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \
- + """ <b><a href="#Form/Shift Request/{0}">{0}</a></b>""".format(d["name"])
+ + """ <b><a href="/app/Form/Shift Request/{0}">{0}</a></b>""".format(d["name"])
frappe.throw(msg, OverlapError)
\ No newline at end of file
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py
index 3dcfcbf..230bb2b 100644
--- a/erpnext/hr/doctype/shift_request/test_shift_request.py
+++ b/erpnext/hr/doctype/shift_request/test_shift_request.py
@@ -7,6 +7,8 @@
import unittest
from frappe.utils import nowdate, add_days
+test_dependencies = ["Shift Type"]
+
class TestShiftRequest(unittest.TestCase):
def setUp(self):
for doctype in ["Shift Request", "Shift Assignment"]:
@@ -46,4 +48,4 @@
department_doc = frappe.get_doc("Department", department)
department_doc.append('shift_request_approver',{'approver': "test1@example.com"})
department_doc.save()
- department_doc.reload()
\ No newline at end of file
+ department_doc.reload()
diff --git a/erpnext/hr/doctype/shift_type/test_records.json b/erpnext/hr/doctype/shift_type/test_records.json
new file mode 100644
index 0000000..9040b91
--- /dev/null
+++ b/erpnext/hr/doctype/shift_type/test_records.json
@@ -0,0 +1,8 @@
+[
+ {
+ "doctype": "Shift Type",
+ "name": "Day Shift",
+ "start_time": "9:00:00",
+ "end_time": "18:00:00"
+ }
+]
diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.py b/erpnext/hr/doctype/shift_type/test_shift_type.py
index 535072a..bc4f0ea 100644
--- a/erpnext/hr/doctype/shift_type/test_shift_type.py
+++ b/erpnext/hr/doctype/shift_type/test_shift_type.py
@@ -7,14 +7,4 @@
import unittest
class TestShiftType(unittest.TestCase):
- def test_make_shift_type(self):
- if frappe.db.exists("Shift Type", "Day Shift"):
- return
- shift_type = frappe.get_doc({
- "doctype": "Shift Type",
- "name": "Day Shift",
- "start_time": "9:00:00",
- "end_time": "18:00:00"
- })
- shift_type.insert()
-
\ No newline at end of file
+ pass
diff --git a/erpnext/hr/doctype/skill/skill.json b/erpnext/hr/doctype/skill/skill.json
index 5182973..4c8a8c9 100644
--- a/erpnext/hr/doctype/skill/skill.json
+++ b/erpnext/hr/doctype/skill/skill.json
@@ -3,7 +3,7 @@
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
- "allow_rename": 0,
+ "allow_rename": 1,
"autoname": "field:skill_name",
"beta": 0,
"creation": "2019-04-16 09:54:39.486915",
@@ -16,7 +16,7 @@
"fields": [
{
"allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
+ "allow_in_quick_entry": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -46,6 +46,12 @@
"set_only_once": 0,
"translatable": 0,
"unique": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "label": "Description"
}
],
"has_web_view": 0,
@@ -56,7 +62,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-04-16 09:55:00.536328",
+ "modified": "2021-02-26 10:55:00.536328",
"modified_by": "Administrator",
"module": "HR",
"name": "Skill",
@@ -110,4 +116,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
index 5b84d00..533149a 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
@@ -39,6 +39,7 @@
detail.current_count = designation_counts['employee_count']
detail.current_openings = designation_counts['job_openings']
+ detail.total_estimated_cost = 0
if detail.number_of_positions > 0:
if detail.vacancies > 0 and detail.estimated_cost_per_position:
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.js b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
index 9df2948..29aa854 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.js
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
@@ -24,10 +24,10 @@
}
window.location.href = repl(frappe.request.url +
'?cmd=%(cmd)s&from_date=%(from_date)s&to_date=%(to_date)s', {
- cmd: "erpnext.hr.doctype.upload_attendance.upload_attendance.get_template",
- from_date: this.frm.doc.att_fr_date,
- to_date: this.frm.doc.att_to_date,
- });
+ cmd: "erpnext.hr.doctype.upload_attendance.upload_attendance.get_template",
+ from_date: this.frm.doc.att_fr_date,
+ to_date: this.frm.doc.att_to_date,
+ });
},
show_upload() {
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index edf05e8..674c8e3 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -28,7 +28,12 @@
w = UnicodeWriter()
w = add_header(w)
- w = add_data(w, args)
+ try:
+ w = add_data(w, args)
+ except Exception as e:
+ frappe.clear_messages()
+ frappe.respond_as_web_page("Holiday List Missing", html=e)
+ return
# write out response as a type csv
frappe.response['result'] = cstr(w.getvalue())
diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
index e9dc776..cf0048c 100644
--- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
@@ -6,18 +6,28 @@
import frappe
import unittest
from frappe.utils import nowdate,flt, cstr,random_string
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim
class TestVehicleLog(unittest.TestCase):
+ def setUp(self):
+ employee_id = frappe.db.sql("""select name from `tabEmployee` where name='testdriver@example.com'""")
+ self.employee_id = employee_id[0][0] if employee_id else None
+
+ if not self.employee_id:
+ self.employee_id = make_employee("testdriver@example.com", company="_Test Company")
+
+ self.license_plate = get_vehicle(self.employee_id)
+
+ def tearDown(self):
+ frappe.delete_doc("Vehicle", self.license_plate, force=1)
+ frappe.delete_doc("Employee", self.employee_id, force=1)
+
def test_make_vehicle_log_and_syncing_of_odometer_value(self):
- employee_id = frappe.db.sql("""select name from `tabEmployee` where status='Active' order by modified desc limit 1""")
- employee_id = employee_id[0][0] if employee_id else None
-
- license_plate = get_vehicle(employee_id)
-
vehicle_log = frappe.get_doc({
"doctype": "Vehicle Log",
- "license_plate": cstr(license_plate),
- "employee":employee_id,
+ "license_plate": cstr(self.license_plate),
+ "employee": self.employee_id,
"date":frappe.utils.nowdate(),
"odometer":5010,
"fuel_qty":frappe.utils.flt(50),
@@ -27,7 +37,7 @@
vehicle_log.submit()
#checking value of vehicle odometer value on submit.
- vehicle = frappe.get_doc("Vehicle", license_plate)
+ vehicle = frappe.get_doc("Vehicle", self.license_plate)
self.assertEqual(vehicle.last_odometer, vehicle_log.odometer)
#checking value vehicle odometer on vehicle log cancellation.
@@ -40,6 +50,28 @@
self.assertEqual(vehicle.last_odometer, current_odometer - distance_travelled)
+ vehicle_log.delete()
+
+ def test_vehicle_log_fuel_expense(self):
+ vehicle_log = frappe.get_doc({
+ "doctype": "Vehicle Log",
+ "license_plate": cstr(self.license_plate),
+ "employee": self.employee_id,
+ "date": frappe.utils.nowdate(),
+ "odometer":5010,
+ "fuel_qty":frappe.utils.flt(50),
+ "price": frappe.utils.flt(500)
+ })
+ vehicle_log.save()
+ vehicle_log.submit()
+
+ expense_claim = make_expense_claim(vehicle_log.name)
+ fuel_expense = expense_claim.expenses[0].amount
+ self.assertEqual(fuel_expense, 50*500)
+
+ vehicle_log.cancel()
+ frappe.delete_doc("Expense Claim", expense_claim.name)
+ frappe.delete_doc("Vehicle Log", vehicle_log.name)
def get_vehicle(employee_id):
license_plate=random_string(10).upper()
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py
index 8affab2..04c94e3 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py
@@ -32,7 +32,7 @@
vehicle_log = frappe.get_doc("Vehicle Log", docname)
service_expense = sum([flt(d.expense_amount) for d in vehicle_log.service_detail])
- claim_amount = service_expense + flt(vehicle_log.price)
+ claim_amount = service_expense + (flt(vehicle_log.price) * flt(vehicle_log.fuel_qty) or 1)
if not claim_amount:
frappe.throw(_("No additional expenses has been added"))
diff --git a/erpnext/hr/page/team_updates/team_updates.js b/erpnext/hr/page/team_updates/team_updates.js
index da1f531..3583297 100644
--- a/erpnext/hr/page/team_updates/team_updates.js
+++ b/erpnext/hr/page/team_updates/team_updates.js
@@ -36,12 +36,12 @@
start: me.start
},
callback: function(r) {
- if(r.message) {
+ if (r.message && r.message.length > 0) {
r.message.forEach(function(d) {
me.add_row(d);
});
} else {
- frappe.show_alert({message:__('No more updates'), indicator:'darkgrey'});
+ frappe.show_alert({message: __('No more updates'), indicator: 'gray'});
me.more.parent().addClass('hidden');
}
}
@@ -75,6 +75,6 @@
}
me.last_feed_date = date;
- $(frappe.render_template('team_update_row', data)).appendTo(me.body)
+ $(frappe.render_template('team_update_row', data)).appendTo(me.body);
}
-}
\ No newline at end of file
+}
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 1b92358..06f9160 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -40,17 +40,17 @@
'fieldname': 'opening_balance',
'width': 130,
}, {
- 'label': _('Leaves Allocated'),
+ 'label': _('Leave Allocated'),
'fieldtype': 'float',
'fieldname': 'leaves_allocated',
'width': 130,
}, {
- 'label': _('Leaves Taken'),
+ 'label': _('Leave Taken'),
'fieldtype': 'float',
'fieldname': 'leaves_taken',
'width': 130,
}, {
- 'label': _('Leaves Expired'),
+ 'label': _('Leave Expired'),
'fieldtype': 'float',
'fieldname': 'leaves_expired',
'width': 130,
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 4608212..c5929c6 100644
--- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
+++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
@@ -36,6 +36,8 @@
conditions, filters = get_conditions(filters)
columns, days = get_columns(filters)
att_map = get_attendance_list(conditions, filters)
+ if not att_map:
+ return columns, [], None, None
if filters.group_by:
emp_map, group_by_parameters = get_employee_details(filters.group_by, filters.company)
@@ -65,10 +67,14 @@
if filters.group_by:
emp_att_map = {}
for parameter in group_by_parameters:
- data.append([ "<b>"+ parameter + "</b>"])
- record, aaa = add_data(emp_map[parameter], att_map, filters, holiday_map, conditions, default_holiday_list, leave_list=leave_list)
- emp_att_map.update(aaa)
- data += record
+ emp_map_set = set([key for key in emp_map[parameter].keys()])
+ att_map_set = set([key for key in att_map.keys()])
+ if (att_map_set & emp_map_set):
+ parameter_row = ["<b>"+ parameter + "</b>"] + ['' for day in range(filters["total_days_in_month"] + 2)]
+ data.append(parameter_row)
+ record, emp_att_data = add_data(emp_map[parameter], att_map, filters, holiday_map, conditions, default_holiday_list, leave_list=leave_list)
+ emp_att_map.update(emp_att_data)
+ data += record
else:
record, emp_att_map = add_data(emp_map, att_map, filters, holiday_map, conditions, default_holiday_list, leave_list=leave_list)
data += record
@@ -237,6 +243,9 @@
status from tabAttendance where docstatus = 1 %s order by employee, attendance_date""" %
conditions, filters, as_dict=1)
+ if not attendance_list:
+ msgprint(_("No attendance record found"), alert=True, indicator="orange")
+
att_map = {}
for d in attendance_list:
att_map.setdefault(d.employee, frappe._dict()).setdefault(d.day_of_month, "")
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 8d95924..0c4c1ca 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -1,16 +1,19 @@
# 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, erpnext
-from frappe import _
-from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate, flt, cstr, add_days, today
-from frappe.model.document import Document
-from frappe.desk.form import assign_to
+import erpnext
+import frappe
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from frappe import _
+from frappe.desk.form import assign_to
+from frappe.model.document import Document
+from frappe.utils import (add_days, cstr, flt, format_datetime, formatdate,
+ get_datetime, getdate, nowdate, today, unique)
+
class DuplicateDeclarationError(frappe.ValidationError): pass
+
class EmployeeBoardingController(Document):
'''
Create the project and the task for the boarding process
@@ -48,27 +51,38 @@
continue
task = frappe.get_doc({
- "doctype": "Task",
- "project": self.project,
- "subject": activity.activity_name + " : " + self.employee_name,
- "description": activity.description,
- "department": self.department,
- "company": self.company,
- "task_weight": activity.task_weight
- }).insert(ignore_permissions=True)
+ "doctype": "Task",
+ "project": self.project,
+ "subject": activity.activity_name + " : " + self.employee_name,
+ "description": activity.description,
+ "department": self.department,
+ "company": self.company,
+ "task_weight": activity.task_weight
+ }).insert(ignore_permissions=True)
activity.db_set("task", task.name)
+
users = [activity.user] if activity.user else []
if activity.role:
- user_list = frappe.db.sql_list('''select distinct(parent) from `tabHas Role`
- where parenttype='User' and role=%s''', activity.role)
- users = users + user_list
+ user_list = frappe.db.sql_list('''
+ SELECT
+ DISTINCT(has_role.parent)
+ FROM
+ `tabHas Role` has_role
+ LEFT JOIN `tabUser` user
+ ON has_role.parent = user.name
+ WHERE
+ has_role.parenttype = 'User'
+ AND user.enabled = 1
+ AND has_role.role = %s
+ ''', activity.role)
+ users = unique(users + user_list)
if "Administrator" in users:
users.remove("Administrator")
# assign the task the users
if users:
- self.assign_task_to_users(task, set(users))
+ self.assign_task_to_users(task, users)
def assign_task_to_users(self, task, users):
for user in users:
@@ -211,23 +225,10 @@
def throw_overlap_error(doc, exists_for, overlap_doc, from_date, to_date):
msg = _("A {0} exists between {1} and {2} (").format(doc.doctype,
formatdate(from_date), formatdate(to_date)) \
- + """ <b><a href="#Form/{0}/{1}">{1}</a></b>""".format(doc.doctype, overlap_doc) \
+ + """ <b><a href="/app/Form/{0}/{1}">{1}</a></b>""".format(doc.doctype, overlap_doc) \
+ _(") for {0}").format(exists_for)
frappe.throw(msg)
-def get_employee_leave_policy(employee):
- leave_policy = frappe.db.get_value("Employee", employee, "leave_policy")
- if not leave_policy:
- employee_grade = frappe.db.get_value("Employee", employee, "grade")
- if employee_grade:
- leave_policy = frappe.db.get_value("Employee Grade", employee_grade, "default_leave_policy")
- if not leave_policy:
- frappe.throw(_("Employee {0} of grade {1} have no default leave policy").format(employee, employee_grade))
- if leave_policy:
- return frappe.get_doc("Leave Policy", leave_policy)
- else:
- frappe.throw(_("Please set leave policy for employee {0} in Employee / Grade record").format(employee))
-
def validate_duplicate_exemption_for_payroll_period(doctype, docname, payroll_period, employee):
existing_record = frappe.db.exists(doctype, {
"payroll_period": payroll_period,
@@ -300,43 +301,77 @@
def allocate_earned_leaves():
'''Allocate earned leaves to Employees'''
- e_leave_types = frappe.get_all("Leave Type",
- fields=["name", "max_leaves_allowed", "earned_leave_frequency", "rounding"],
- filters={'is_earned_leave' : 1})
+ e_leave_types = get_earned_leaves()
today = getdate()
- divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
for e_leave_type in e_leave_types:
- leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where %s
- between from_date and to_date and docstatus=1 and leave_type=%s""", (today, e_leave_type.name), as_dict=1)
+
+ leave_allocations = get_leave_allocations(today, e_leave_type.name)
+
for allocation in leave_allocations:
- leave_policy = get_employee_leave_policy(allocation.employee)
- if not leave_policy:
+
+ if not allocation.leave_policy_assignment and not allocation.leave_policy:
continue
- if not e_leave_type.earned_leave_frequency == "Monthly":
- if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
- continue
+
+ leave_policy = allocation.leave_policy if allocation.leave_policy else frappe.db.get_value(
+ "Leave Policy Assignment", allocation.leave_policy_assignment, ["leave_policy"])
+
annual_allocation = frappe.db.get_value("Leave Policy Detail", filters={
- 'parent': leave_policy.name,
+ 'parent': leave_policy,
'leave_type': e_leave_type.name
}, fieldname=['annual_allocation'])
- if annual_allocation:
- earned_leaves = flt(annual_allocation) / divide_by_frequency[e_leave_type.earned_leave_frequency]
- if e_leave_type.rounding == "0.5":
- earned_leaves = round(earned_leaves * 2) / 2
- else:
- earned_leaves = round(earned_leaves)
- allocation = frappe.get_doc('Leave Allocation', allocation.name)
- new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
+ from_date=allocation.from_date
- if new_allocation > e_leave_type.max_leaves_allowed and e_leave_type.max_leaves_allowed > 0:
- new_allocation = e_leave_type.max_leaves_allowed
+ if e_leave_type.based_on_date_of_joining_date:
+ from_date = frappe.db.get_value("Employee", allocation.employee, "date_of_joining")
- if new_allocation == allocation.total_leaves_allocated:
- continue
- allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False)
- create_additional_leave_ledger_entry(allocation, earned_leaves, today)
+ if check_effective_date(from_date, today, e_leave_type.earned_leave_frequency, e_leave_type.based_on_date_of_joining_date):
+ update_previous_leave_allocation(allocation, annual_allocation, e_leave_type)
+
+def update_previous_leave_allocation(allocation, annual_allocation, e_leave_type):
+ earned_leaves = get_monthly_earned_leave(annual_allocation, e_leave_type.earned_leave_frequency, e_leave_type.rounding)
+
+ allocation = frappe.get_doc('Leave Allocation', allocation.name)
+ new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
+
+ if new_allocation > e_leave_type.max_leaves_allowed and e_leave_type.max_leaves_allowed > 0:
+ new_allocation = e_leave_type.max_leaves_allowed
+
+ if new_allocation != allocation.total_leaves_allocated:
+ allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False)
+ today_date = today()
+ create_additional_leave_ledger_entry(allocation, earned_leaves, today_date)
+
+def get_monthly_earned_leave(annual_leaves, frequency, rounding):
+ earned_leaves = 0.0
+ divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
+ if annual_leaves:
+ earned_leaves = flt(annual_leaves) / divide_by_frequency[frequency]
+ if rounding:
+ if rounding == "0.25":
+ earned_leaves = round(earned_leaves * 4) / 4
+ elif rounding == "0.5":
+ earned_leaves = round(earned_leaves * 2) / 2
+ else:
+ earned_leaves = round(earned_leaves)
+
+ return earned_leaves
+
+
+def get_leave_allocations(date, leave_type):
+ return frappe.db.sql("""select name, employee, from_date, to_date, leave_policy_assignment, leave_policy
+ from `tabLeave Allocation`
+ where
+ %s between from_date and to_date and docstatus=1
+ and leave_type=%s""",
+ (date, leave_type), as_dict=1)
+
+
+def get_earned_leaves():
+ return frappe.get_all("Leave Type",
+ fields=["name", "max_leaves_allowed", "earned_leave_frequency", "rounding", "based_on_date_of_joining"],
+ filters={'is_earned_leave' : 1})
def create_additional_leave_ledger_entry(allocation, leaves, date):
''' Create leave ledger entry for leave types '''
@@ -345,24 +380,32 @@
allocation.unused_leaves = 0
allocation.create_leave_ledger_entry()
-def check_frequency_hit(from_date, to_date, frequency):
- '''Return True if current date matches frequency'''
- from_dt = get_datetime(from_date)
- to_dt = get_datetime(to_date)
+def check_effective_date(from_date, to_date, frequency, based_on_date_of_joining_date):
+ import calendar
from dateutil import relativedelta
- rd = relativedelta.relativedelta(to_dt, from_dt)
- months = rd.months
- if frequency == "Quarterly":
- if not months % 3:
+
+ from_date = get_datetime(from_date)
+ to_date = get_datetime(to_date)
+ rd = relativedelta.relativedelta(to_date, from_date)
+ #last day of month
+ last_day = calendar.monthrange(to_date.year, to_date.month)[1]
+
+ if (from_date.day == to_date.day and based_on_date_of_joining_date) or (not based_on_date_of_joining_date and to_date.day == last_day):
+ if frequency == "Monthly":
return True
- elif frequency == "Half-Yearly":
- if not months % 6:
+ elif frequency == "Quarterly" and rd.months % 3:
return True
- elif frequency == "Yearly":
- if not months % 12:
+ elif frequency == "Half-Yearly" and rd.months % 6:
return True
+ elif frequency == "Yearly" and rd.months % 12:
+ return True
+
+ if frappe.flags.in_test:
+ return True
+
return False
+
def get_salary_assignment(employee, date):
assignment = frappe.db.sql("""
select * from `tabSalary Structure Assignment`
@@ -454,3 +497,10 @@
if sum_of_claimed_amount and flt(sum_of_claimed_amount[0].total_amount) > 0:
total_claimed_amount = sum_of_claimed_amount[0].total_amount
return total_claimed_amount
+
+def grant_leaves_automatically():
+ automatically_allocate_leaves_based_on_leave_policy = frappe.db.get_singles_value("HR Settings", "automatically_allocate_leaves_based_on_leave_policy")
+ if automatically_allocate_leaves_based_on_leave_policy:
+ lpa = frappe.db.get_all("Leave Policy Assignment", filters={"effective_from": getdate(), "docstatus": 1, "leaves_allocated":0})
+ for assignment in lpa:
+ frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee()
diff --git a/erpnext/hr/web_form/job_application/job_application.json b/erpnext/hr/web_form/job_application/job_application.json
index f630570..512ba5c 100644
--- a/erpnext/hr/web_form/job_application/job_application.json
+++ b/erpnext/hr/web_form/job_application/job_application.json
@@ -1,86 +1,200 @@
{
- "accept_payment": 0,
- "allow_comments": 1,
- "allow_delete": 0,
- "allow_edit": 1,
- "allow_incomplete": 0,
- "allow_multiple": 1,
- "allow_print": 0,
- "amount": 0.0,
- "amount_based_on_field": 0,
- "creation": "2016-09-10 02:53:16.598314",
- "doc_type": "Job Applicant",
- "docstatus": 0,
- "doctype": "Web Form",
- "idx": 0,
- "introduction_text": "",
- "is_standard": 1,
- "login_required": 0,
- "max_attachment_size": 0,
- "modified": "2016-12-20 00:21:44.081622",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "job-application",
- "owner": "Administrator",
- "published": 1,
- "route": "job_application",
- "show_sidebar": 1,
- "sidebar_items": [],
- "success_message": "Thank you for applying.",
- "success_url": "/jobs",
- "title": "Job Application",
+ "accept_payment": 0,
+ "allow_comments": 1,
+ "allow_delete": 0,
+ "allow_edit": 1,
+ "allow_incomplete": 0,
+ "allow_multiple": 1,
+ "allow_print": 0,
+ "amount": 0.0,
+ "amount_based_on_field": 0,
+ "apply_document_permissions": 0,
+ "client_script": "frappe.web_form.on('resume_link', (field, value) => {\n if (!frappe.utils.is_url(value)) {\n frappe.msgprint(__('Resume link not valid'));\n }\n});\n",
+ "creation": "2016-09-10 02:53:16.598314",
+ "doc_type": "Job Applicant",
+ "docstatus": 0,
+ "doctype": "Web Form",
+ "idx": 0,
+ "introduction_text": "",
+ "is_standard": 1,
+ "login_required": 0,
+ "max_attachment_size": 0,
+ "modified": "2020-10-07 19:27:17.143355",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "job-application",
+ "owner": "Administrator",
+ "published": 1,
+ "route": "job_application",
+ "route_to_success_link": 0,
+ "show_attachments": 0,
+ "show_in_grid": 0,
+ "show_sidebar": 1,
+ "sidebar_items": [],
+ "success_message": "Thank you for applying.",
+ "success_url": "/jobs",
+ "title": "Job Application",
"web_form_fields": [
{
- "fieldname": "job_title",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Job Opening",
- "max_length": 0,
- "max_value": 0,
- "options": "",
- "read_only": 1,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "job_title",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Job Opening",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 1,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "applicant_name",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Applicant Name",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 1
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "applicant_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Applicant Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
{
- "fieldname": "email_id",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Email Address",
- "max_length": 0,
- "max_value": 0,
- "options": "Email",
- "read_only": 0,
- "reqd": 1
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "email_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Email Address",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Email",
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
{
- "fieldname": "cover_letter",
- "fieldtype": "Text",
- "hidden": 0,
- "label": "Cover Letter",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "phone_number",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Phone Number",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Phone",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "resume_attachment",
- "fieldtype": "Attach",
- "hidden": 0,
- "label": "Resume Attachment",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "country",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Country of Residence",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Country",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "cover_letter",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "label": "Cover Letter",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "resume_link",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Resume Link",
+ "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": "Expected Salary Range per month",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Currency",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Currency",
+ "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": "lower_range",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "label": "Lower Range",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "currency",
+ "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": "upper_range",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "label": "Upper Range",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "currency",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
}
]
}
\ No newline at end of file
diff --git a/erpnext/hr/workspace/hr/hr.json b/erpnext/hr/workspace/hr/hr.json
new file mode 100644
index 0000000..f650b24
--- /dev/null
+++ b/erpnext/hr/workspace/hr/hr.json
@@ -0,0 +1,829 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Outgoing Salary",
+ "label": "Outgoing Salary"
+ }
+ ],
+ "creation": "2020-03-02 15:48:58.322521",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "hr",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "HR",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee",
+ "link_to": "Employee",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employment Type",
+ "link_to": "Employment Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Branch",
+ "link_to": "Branch",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Department",
+ "link_to": "Department",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Designation",
+ "link_to": "Designation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Grade",
+ "link_to": "Employee Grade",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Group",
+ "link_to": "Employee Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Health Insurance",
+ "link_to": "Employee Health Insurance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Lifecycle",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Job Applicant",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Onboarding",
+ "link_to": "Employee Onboarding",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Skill Map",
+ "link_to": "Employee Skill Map",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Promotion",
+ "link_to": "Employee Promotion",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Transfer",
+ "link_to": "Employee Transfer",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Separation",
+ "link_to": "Employee Separation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Onboarding Template",
+ "link_to": "Employee Onboarding Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Separation Template",
+ "link_to": "Employee Separation Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shift Management",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shift Type",
+ "link_to": "Shift Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shift Request",
+ "link_to": "Shift Request",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shift Assignment",
+ "link_to": "Shift Assignment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leaves",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Application",
+ "link_to": "Leave Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Allocation",
+ "link_to": "Leave Allocation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Leave Type",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Policy",
+ "link_to": "Leave Policy",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Period",
+ "link_to": "Leave Period",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Type",
+ "link_to": "Leave Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Holiday List",
+ "link_to": "Holiday List",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Compensatory Leave Request",
+ "link_to": "Compensatory Leave Request",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Encashment",
+ "link_to": "Leave Encashment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Leave Block List",
+ "link_to": "Leave Block List",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Leave Application",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Employee Leave Balance",
+ "link_to": "Employee Leave Balance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Attendance",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Attendance Tool",
+ "link_to": "Employee Attendance Tool",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Attendance",
+ "link_to": "Attendance",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Attendance Request",
+ "link_to": "Attendance Request",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Upload Attendance",
+ "link_to": "Upload Attendance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Checkin",
+ "link_to": "Employee Checkin",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Monthly Attendance Sheet",
+ "link_to": "Monthly Attendance Sheet",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Expense Claims",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Expense Claim",
+ "link_to": "Expense Claim",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Advance",
+ "link_to": "Employee Advance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "HR Settings",
+ "link_to": "HR Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Daily Work Summary Group",
+ "link_to": "Daily Work Summary Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Team Updates",
+ "link_to": "team-updates",
+ "link_type": "Page",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fleet Management",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Vehicle",
+ "link_to": "Vehicle",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Vehicle Log",
+ "link_to": "Vehicle Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Vehicle",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Vehicle Expenses",
+ "link_to": "Vehicle Expenses",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Recruitment",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Job Opening",
+ "link_to": "Job Opening",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Job Applicant",
+ "link_to": "Job Applicant",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Job Offer",
+ "link_to": "Job Offer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Staffing Plan",
+ "link_to": "Staffing Plan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loans",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Application",
+ "link_to": "Loan Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan",
+ "link_to": "Loan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Type",
+ "link_to": "Loan Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Training",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Training Program",
+ "link_to": "Training Program",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Training Event",
+ "link_to": "Training Event",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Training Result",
+ "link_to": "Training Result",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Training Feedback",
+ "link_to": "Training Feedback",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Employee Birthday",
+ "link_to": "Employee Birthday",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Employees working on a holiday",
+ "link_to": "Employees working on a holiday",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Performance",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Appraisal",
+ "link_to": "Appraisal",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Appraisal Template",
+ "link_to": "Appraisal Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Energy Point Rule",
+ "link_to": "Energy Point Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Energy Point Log",
+ "link_to": "Energy Point Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax and Benefits",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Declaration",
+ "link_to": "Employee Tax Exemption Declaration",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Proof Submission",
+ "link_to": "Employee Tax Exemption Proof Submission",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee, Payroll Period",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Other Income",
+ "link_to": "Employee Other Income",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Benefit Application",
+ "link_to": "Employee Benefit Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Benefit Claim",
+ "link_to": "Employee Benefit Claim",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Category",
+ "link_to": "Employee Tax Exemption Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Sub Category",
+ "link_to": "Employee Tax Exemption Sub Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2021-01-21 13:38:38.941001",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "HR",
+ "onboarding": "Human Resource",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Green",
+ "format": "{} Active",
+ "label": "Employee",
+ "link_to": "Employee",
+ "stats_filter": "{\"status\":\"Active\"}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} Open",
+ "label": "Leave Application",
+ "link_to": "Leave Application",
+ "stats_filter": "{\"status\":\"Open\"}",
+ "type": "DocType"
+ },
+ {
+ "label": "Attendance",
+ "link_to": "Attendance",
+ "stats_filter": "",
+ "type": "DocType"
+ },
+ {
+ "label": "Job Applicant",
+ "link_to": "Job Applicant",
+ "type": "DocType"
+ },
+ {
+ "label": "Monthly Attendance Sheet",
+ "link_to": "Monthly Attendance Sheet",
+ "type": "Report"
+ },
+ {
+ "format": "{} Open",
+ "label": "Dashboard",
+ "link_to": "Human Resource",
+ "stats_filter": "{\n \"status\": \"Open\"\n}",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/dashboard_chart/loan_disbursements/loan_disbursements.json b/erpnext/loan_management/dashboard_chart/loan_disbursements/loan_disbursements.json
new file mode 100644
index 0000000..b8abf21
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart/loan_disbursements/loan_disbursements.json
@@ -0,0 +1,29 @@
+{
+ "based_on": "disbursement_date",
+ "chart_name": "Loan Disbursements",
+ "chart_type": "Sum",
+ "creation": "2021-02-06 18:40:36.148470",
+ "docstatus": 0,
+ "doctype": "Dashboard Chart",
+ "document_type": "Loan Disbursement",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Disbursement\",\"docstatus\",\"=\",\"1\",false]]",
+ "group_by_type": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "modified": "2021-02-06 18:40:49.308663",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Disbursements",
+ "number_of_groups": 0,
+ "owner": "Administrator",
+ "source": "",
+ "time_interval": "Daily",
+ "timeseries": 1,
+ "timespan": "Last Month",
+ "type": "Line",
+ "use_report_chart": 0,
+ "value_based_on": "disbursed_amount",
+ "y_axis": []
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/dashboard_chart/loan_interest_accrual/loan_interest_accrual.json b/erpnext/loan_management/dashboard_chart/loan_interest_accrual/loan_interest_accrual.json
new file mode 100644
index 0000000..aa0f78a
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart/loan_interest_accrual/loan_interest_accrual.json
@@ -0,0 +1,31 @@
+{
+ "based_on": "posting_date",
+ "chart_name": "Loan Interest Accrual",
+ "chart_type": "Sum",
+ "color": "#39E4A5",
+ "creation": "2021-02-18 20:07:04.843876",
+ "docstatus": 0,
+ "doctype": "Dashboard Chart",
+ "document_type": "Loan Interest Accrual",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Interest Accrual\",\"docstatus\",\"=\",\"1\",false]]",
+ "group_by_type": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "last_synced_on": "2021-02-21 21:01:26.022634",
+ "modified": "2021-02-21 21:01:44.930712",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Interest Accrual",
+ "number_of_groups": 0,
+ "owner": "Administrator",
+ "source": "",
+ "time_interval": "Monthly",
+ "timeseries": 1,
+ "timespan": "Last Year",
+ "type": "Line",
+ "use_report_chart": 0,
+ "value_based_on": "interest_amount",
+ "y_axis": []
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/dashboard_chart/new_loans/new_loans.json b/erpnext/loan_management/dashboard_chart/new_loans/new_loans.json
new file mode 100644
index 0000000..35bd43b
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart/new_loans/new_loans.json
@@ -0,0 +1,31 @@
+{
+ "based_on": "creation",
+ "chart_name": "New Loans",
+ "chart_type": "Count",
+ "color": "#449CF0",
+ "creation": "2021-02-06 16:59:27.509170",
+ "docstatus": 0,
+ "doctype": "Dashboard Chart",
+ "document_type": "Loan",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan\",\"docstatus\",\"=\",\"1\",false]]",
+ "group_by_type": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "last_synced_on": "2021-02-21 20:55:33.515025",
+ "modified": "2021-02-21 21:00:33.900821",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "New Loans",
+ "number_of_groups": 0,
+ "owner": "Administrator",
+ "source": "",
+ "time_interval": "Daily",
+ "timeseries": 1,
+ "timespan": "Last Month",
+ "type": "Bar",
+ "use_report_chart": 0,
+ "value_based_on": "",
+ "y_axis": []
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/dashboard_chart/top_10_pledged_loan_securities/top_10_pledged_loan_securities.json b/erpnext/loan_management/dashboard_chart/top_10_pledged_loan_securities/top_10_pledged_loan_securities.json
new file mode 100644
index 0000000..76c27b0
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart/top_10_pledged_loan_securities/top_10_pledged_loan_securities.json
@@ -0,0 +1,31 @@
+{
+ "based_on": "",
+ "chart_name": "Top 10 Pledged Loan Securities",
+ "chart_type": "Custom",
+ "color": "#EC864B",
+ "creation": "2021-02-06 22:02:46.284479",
+ "docstatus": 0,
+ "doctype": "Dashboard Chart",
+ "document_type": "",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[]",
+ "group_by_type": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "last_synced_on": "2021-02-21 21:00:57.043034",
+ "modified": "2021-02-21 21:01:10.048623",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Top 10 Pledged Loan Securities",
+ "number_of_groups": 0,
+ "owner": "Administrator",
+ "source": "Top 10 Pledged Loan Securities",
+ "time_interval": "Yearly",
+ "timeseries": 0,
+ "timespan": "Last Year",
+ "type": "Bar",
+ "use_report_chart": 0,
+ "value_based_on": "",
+ "y_axis": []
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/loan_management/dashboard_chart_source/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/loan_management/dashboard_chart_source/__init__.py
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/__init__.py
diff --git a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js
new file mode 100644
index 0000000..cf75cc8
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.js
@@ -0,0 +1,14 @@
+frappe.provide('frappe.dashboards.chart_sources');
+
+frappe.dashboards.chart_sources["Top 10 Pledged Loan Securities"] = {
+ method: "erpnext.loan_management.dashboard_chart_source.top_10_pledged_loan_securities.top_10_pledged_loan_securities.get_data",
+ filters: [
+ {
+ 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/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.json b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.json
new file mode 100644
index 0000000..42c9b1c
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.json
@@ -0,0 +1,13 @@
+{
+ "creation": "2021-02-06 22:01:01.332628",
+ "docstatus": 0,
+ "doctype": "Dashboard Chart Source",
+ "idx": 0,
+ "modified": "2021-02-06 22:01:01.332628",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Top 10 Pledged Loan Securities",
+ "owner": "Administrator",
+ "source_name": "Top 10 Pledged Loan Securities ",
+ "timeseries": 0
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..6bb0440
--- /dev/null
+++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
@@ -0,0 +1,76 @@
+# 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 erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
+ import get_loan_security_details
+from six import iteritems
+
+@frappe.whitelist()
+@cache_source
+def get_data(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 = {}
+ current_pledges = {}
+
+ if filters:
+ filters = frappe.parse_json(filters)[0]
+
+ conditions = ""
+ labels = []
+ values = []
+
+ if filters.get('company'):
+ conditions = "AND company = %(company)s"
+
+ loan_security_details = get_loan_security_details()
+
+ unpledges = frappe._dict(frappe.db.sql("""
+ SELECT u.loan_security, sum(u.qty) as qty
+ FROM `tabLoan Security Unpledge` up, `tabUnpledge` u
+ WHERE u.parent = up.name
+ AND up.status = 'Approved'
+ {conditions}
+ GROUP BY u.loan_security
+ """.format(conditions=conditions), filters, as_list=1))
+
+ pledges = frappe._dict(frappe.db.sql("""
+ SELECT p.loan_security, sum(p.qty) as qty
+ FROM `tabLoan Security Pledge` lp, `tabPledge`p
+ WHERE p.parent = lp.name
+ AND lp.status = 'Pledged'
+ {conditions}
+ GROUP BY p.loan_security
+ """.format(conditions=conditions), filters, as_list=1))
+
+ for security, qty in iteritems(pledges):
+ 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):
+ values.append(qty * loan_security_details.get(security, {}).get('latest_price', 0))
+ labels.append(security)
+ count +=1
+
+ ## Just need top 10 securities
+ if count == 10:
+ break
+
+ return {
+ 'labels': labels,
+ 'datasets': [{
+ 'name': 'Top 10 Securities',
+ 'chartType': 'bar',
+ 'values': values
+ }]
+ }
\ No newline at end of file
diff --git a/erpnext/loan_management/desk_page/loan/loan.json b/erpnext/loan_management/desk_page/loan/loan.json
deleted file mode 100644
index 3bdd1ce..0000000
--- a/erpnext/loan_management/desk_page/loan/loan.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Loan",
- "links": "[\n {\n \"description\": \"Loan Type for interest and penalty rates\",\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loan Applications from customers and employees.\",\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n { \"dependencies\": [\n \"Loan Type\"\n ],\n \"description\": \"Loans provided to customers and employees.\",\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Loan Processes",
- "links": "[\n {\n \"label\": \"Process Loan Security Shortfall\",\n \"name\": \"Process Loan Security Shortfall\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Process Loan Interest Accrual\",\n \"name\": \"Process Loan Interest Accrual\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Disbursement and Repayment",
- "links": "[\n {\n \"label\": \"Loan Disbursement\",\n \"name\": \"Loan Disbursement\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Repayment\",\n \"name\": \"Loan Repayment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Interest Accrual\",\n \"name\": \"Loan Interest Accrual\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Loan Security",
- "links": "[\n {\n \"label\": \"Loan Security Type\",\n \"name\": \"Loan Security Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Security Price\",\n \"name\": \"Loan Security Price\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Security\",\n \"name\": \"Loan Security\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Security Pledge\",\n \"name\": \"Loan Security Pledge\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Security Unpledge\",\n \"name\": \"Loan Security Unpledge\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Security Shortfall\",\n \"name\": \"Loan Security Shortfall\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"doctype\": \"Loan Repayment\",\n \"is_query_report\": true,\n \"label\": \"Loan Repayment and Closure\",\n \"name\": \"Loan Repayment and Closure\",\n \"route\": \"#query-report/Loan Repayment and Closure\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Security Pledge\",\n \"is_query_report\": true,\n \"label\": \"Loan Security Status\",\n \"name\": \"Loan Security Status\",\n \"route\": \"#query-report/Loan Security Status\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [],
- "creation": "2020-03-12 16:35:55.299820",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends_another_page": 0,
- "idx": 0,
- "is_standard": 1,
- "label": "Loan",
- "modified": "2020-06-07 19:42:14.947902",
- "modified_by": "Administrator",
- "module": "Loan Management",
- "name": "Loan",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#ffe8cd",
- "format": "{} Open",
- "label": "Loan Application",
- "link_to": "Loan Application",
- "stats_filter": "{ \"status\": \"Open\" }",
- "type": "DocType"
- },
- {
- "label": "Loan",
- "link_to": "Loan",
- "type": "DocType"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan/loan.js b/erpnext/loan_management/doctype/loan/loan.js
index 9b4c217..28af3a9 100644
--- a/erpnext/loan_management/doctype/loan/loan.js
+++ b/erpnext/loan_management/doctype/loan/loan.js
@@ -7,10 +7,14 @@
setup: function(frm) {
frm.make_methods = {
'Loan Disbursement': function() { frm.trigger('make_loan_disbursement') },
- 'Loan Security Unpledge': function() { frm.trigger('create_loan_security_unpledge') }
+ 'Loan Security Unpledge': function() { frm.trigger('create_loan_security_unpledge') },
+ 'Loan Write Off': function() { frm.trigger('make_loan_write_off_entry') }
}
},
onload: function (frm) {
+ // Ignore loan security pledge on cancel of loan
+ frm.ignore_doctypes_on_cancel_all = ["Loan Security Pledge"];
+
frm.set_query("loan_application", function () {
return {
"filters": {
@@ -21,6 +25,14 @@
};
});
+ frm.set_query("loan_type", function () {
+ return {
+ "filters": {
+ "docstatus": 1
+ }
+ };
+ });
+
$.each(["penalty_income_account", "interest_income_account"], function(i, field) {
frm.set_query(field, function () {
return {
@@ -49,24 +61,33 @@
refresh: function (frm) {
if (frm.doc.docstatus == 1) {
- if (frm.doc.status == "Sanctioned" || frm.doc.status == 'Partially Disbursed') {
+ if (["Disbursed", "Partially Disbursed"].includes(frm.doc.status) && (!frm.doc.repay_from_salary)) {
+ frm.add_custom_button(__('Request Loan Closure'), function() {
+ frm.trigger("request_loan_closure");
+ },__('Status'));
+
+ frm.add_custom_button(__('Loan Repayment'), function() {
+ frm.trigger("make_repayment_entry");
+ },__('Create'));
+ }
+
+ if (["Sanctioned", "Partially Disbursed"].includes(frm.doc.status)) {
frm.add_custom_button(__('Loan Disbursement'), function() {
frm.trigger("make_loan_disbursement");
},__('Create'));
}
- if (["Disbursed", "Partially Disbursed"].includes(frm.doc.status) && (!frm.doc.repay_from_salary)) {
- frm.add_custom_button(__('Loan Repayment'), function() {
- frm.trigger("make_repayment_entry");
- },__('Create'));
-
- }
-
if (frm.doc.status == "Loan Closure Requested") {
frm.add_custom_button(__('Loan Security Unpledge'), function() {
frm.trigger("create_loan_security_unpledge");
},__('Create'));
}
+
+ if (["Loan Closure Requested", "Disbursed", "Partially Disbursed"].includes(frm.doc.status)) {
+ frm.add_custom_button(__('Loan Write Off'), function() {
+ frm.trigger("make_loan_write_off_entry");
+ },__('Create'));
+ }
}
frm.trigger("toggle_fields");
},
@@ -117,6 +138,38 @@
})
},
+ make_loan_write_off_entry: function(frm) {
+ frappe.call({
+ args: {
+ "loan": frm.doc.name,
+ "company": frm.doc.company,
+ "as_dict": 1
+ },
+ method: "erpnext.loan_management.doctype.loan.loan.make_loan_write_off",
+ callback: function (r) {
+ if (r.message)
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ })
+ },
+
+ request_loan_closure: function(frm) {
+ frappe.confirm(__("Do you really want to close this loan"),
+ function() {
+ frappe.call({
+ args: {
+ 'loan': frm.doc.name
+ },
+ method: "erpnext.loan_management.doctype.loan.loan.request_loan_closure",
+ callback: function() {
+ frm.reload_doc();
+ }
+ });
+ }
+ );
+ },
+
create_loan_security_unpledge: function(frm) {
frappe.call({
method: "erpnext.loan_management.doctype.loan.loan.unpledge_security",
diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json
index aa5e21b..acf09f5 100644
--- a/erpnext/loan_management/doctype/loan/loan.json
+++ b/erpnext/loan_management/doctype/loan/loan.json
@@ -26,11 +26,11 @@
"disbursed_amount",
"column_break_11",
"maximum_loan_amount",
- "is_term_loan",
"repayment_method",
"repayment_periods",
"monthly_repayment_amount",
"repayment_start_date",
+ "is_term_loan",
"account_info",
"mode_of_payment",
"payment_account",
@@ -43,6 +43,7 @@
"section_break_17",
"total_payment",
"total_principal_paid",
+ "written_off_amount",
"column_break_19",
"total_interest_payable",
"total_amount_paid",
@@ -75,6 +76,7 @@
"fieldname": "loan_application",
"fieldtype": "Link",
"label": "Loan Application",
+ "no_copy": 1,
"options": "Loan Application"
},
{
@@ -134,6 +136,7 @@
"fieldname": "loan_amount",
"fieldtype": "Currency",
"label": "Loan Amount",
+ "non_negative": 1,
"options": "Company:company:default_currency"
},
{
@@ -148,7 +151,8 @@
"depends_on": "eval:doc.status==\"Disbursed\"",
"fieldname": "disbursement_date",
"fieldtype": "Date",
- "label": "Disbursement Date"
+ "label": "Disbursement Date",
+ "no_copy": 1
},
{
"depends_on": "is_term_loan",
@@ -252,6 +256,7 @@
"fieldname": "total_payment",
"fieldtype": "Currency",
"label": "Total Payable Amount",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
@@ -265,6 +270,7 @@
"fieldname": "total_interest_payable",
"fieldtype": "Currency",
"label": "Total Interest Payable",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
@@ -273,6 +279,7 @@
"fieldname": "total_amount_paid",
"fieldtype": "Currency",
"label": "Total Amount Paid",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
@@ -289,8 +296,7 @@
"default": "0",
"fieldname": "is_secured_loan",
"fieldtype": "Check",
- "label": "Is Secured Loan",
- "read_only": 1
+ "label": "Is Secured Loan"
},
{
"default": "0",
@@ -313,6 +319,7 @@
"fieldname": "total_principal_paid",
"fieldtype": "Currency",
"label": "Total Principal Paid",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
@@ -320,21 +327,33 @@
"fieldname": "disbursed_amount",
"fieldtype": "Currency",
"label": "Disbursed Amount",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
{
+ "depends_on": "eval:doc.is_secured_loan",
"fetch_from": "loan_application.maximum_loan_amount",
"fieldname": "maximum_loan_amount",
"fieldtype": "Currency",
"label": "Maximum Loan Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "written_off_amount",
+ "fieldtype": "Currency",
+ "label": "Written Off Amount",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-01 12:36:11.255233",
+ "modified": "2020-11-24 12:27:23.208240",
"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 d1b7589..83a813f 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -6,12 +6,16 @@
import frappe, math, json
import erpnext
from frappe import _
+from six import string_types
from frappe.utils import flt, rounded, add_months, nowdate, getdate, now_datetime
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
class Loan(AccountsController):
def validate(self):
+ if self.applicant_type == 'Employee' and self.repay_from_salary:
+ validate_employee_currency_with_company_currency(self.applicant, self.company)
self.set_loan_amount()
self.validate_loan_amount()
self.set_missing_fields()
@@ -137,9 +141,12 @@
})
def unlink_loan_security_pledge(self):
- frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET
- loan = '', status = 'Unpledged'
- where name = %s """, (self.loan_security_pledge))
+ pledges = frappe.get_all('Loan Security Pledge', fields=['name'], filters={'loan': self.name})
+ pledge_list = [d.name for d in pledges]
+ if pledge_list:
+ frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET
+ loan = '', status = 'Unpledged'
+ where name in (%s) """ % (', '.join(['%s']*len(pledge_list))), tuple(pledge_list)) #nosec
def update_total_amount_paid(doc):
total_amount_paid = 0
@@ -183,6 +190,28 @@
return monthly_repayment_amount
@frappe.whitelist()
+def request_loan_closure(loan, posting_date=None):
+ if not posting_date:
+ posting_date = getdate()
+
+ amounts = calculate_amounts(loan, posting_date)
+ pending_amount = amounts['payable_amount'] + amounts['unaccrued_interest']
+
+ loan_type = frappe.get_value('Loan', loan, 'loan_type')
+ write_off_limit = frappe.get_value('Loan Type', loan_type, 'write_off_amount')
+
+ # checking greater than 0 as there may be some minor precision error
+ if not pending_amount:
+ frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
+ elif pending_amount < write_off_limit:
+ # Auto create loan write off and update status as loan closure requested
+ write_off = make_loan_write_off(loan)
+ write_off.submit()
+ frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
+ else:
+ frappe.throw(_("Cannot close loan as there is an outstanding of {0}").format(pending_amount))
+
+@frappe.whitelist()
def get_loan_application(loan_application):
loan = frappe.get_doc("Loan Application", loan_application)
if loan:
@@ -200,6 +229,7 @@
disbursement_entry.applicant = applicant
disbursement_entry.company = company
disbursement_entry.disbursement_date = nowdate()
+ disbursement_entry.posting_date = nowdate()
disbursement_entry.disbursed_amount = pending_amount
if as_dict:
@@ -223,10 +253,45 @@
return repayment_entry
@frappe.whitelist()
-def unpledge_security(loan=None, loan_security_pledge=None, as_dict=0, save=0, submit=0, approve=0):
- # if loan is passed it will be considered as full unpledge
+def make_loan_write_off(loan, company=None, posting_date=None, amount=0, as_dict=0):
+ if not company:
+ company = frappe.get_value('Loan', loan, 'company')
+
+ if not posting_date:
+ posting_date = getdate()
+
+ amounts = calculate_amounts(loan, posting_date)
+ pending_amount = amounts['pending_principal_amount']
+
+ if amount and (amount > pending_amount):
+ frappe.throw('Write Off amount cannot be greater than pending loan amount')
+
+ if not amount:
+ amount = pending_amount
+
+ # get default write off account from company master
+ write_off_account = frappe.get_value('Company', company, 'write_off_account')
+
+ write_off = frappe.new_doc('Loan Write Off')
+ write_off.loan = loan
+ write_off.posting_date = posting_date
+ write_off.write_off_account = write_off_account
+ write_off.write_off_amount = amount
+ write_off.save()
+
+ if as_dict:
+ return write_off.as_dict()
+ else:
+ return write_off
+
+@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):
+ security_map = json.loads(security_map)
+
if loan:
- pledge_qty_map = get_pledged_security_qty(loan)
+ pledge_qty_map = security_map or get_pledged_security_qty(loan)
loan_doc = frappe.get_doc('Loan', loan)
unpledge_request = create_loan_security_unpledge(pledge_qty_map, loan_doc.name, loan_doc.company,
loan_doc.applicant_type, loan_doc.applicant)
@@ -274,5 +339,24 @@
return unpledge_request
+def validate_employee_currency_with_company_currency(applicant, company):
+ from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_employee_currency
+ if not applicant:
+ frappe.throw(_("Please select Applicant"))
+ if not company:
+ frappe.throw(_("Please select Company"))
+ employee_currency = get_employee_currency(applicant)
+ company_currency = erpnext.get_company_currency(company)
+ if employee_currency != company_currency:
+ frappe.throw(_("Loan cannot be repayed from salary for Employee {0} because salary is processed in currency {1}")
+ .format(applicant, employee_currency))
+@frappe.whitelist()
+def get_shortfall_applicants():
+ loans = frappe.get_all('Loan Security Shortfall', {'status': 'Pending'}, pluck='loan')
+ applicants = set(frappe.get_all('Loan', {'name': ('in', loans)}, pluck='name'))
+ return {
+ "value": len(applicants),
+ "fieldtype": "Int"
+ }
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan/loan_dashboard.py b/erpnext/loan_management/doctype/loan/loan_dashboard.py
index 90d5ae2..7a8190f 100644
--- a/erpnext/loan_management/doctype/loan/loan_dashboard.py
+++ b/erpnext/loan_management/doctype/loan/loan_dashboard.py
@@ -13,7 +13,7 @@
'items': ['Loan Security Pledge', 'Loan Security Shortfall', 'Loan Disbursement']
},
{
- 'items': ['Loan Repayment', 'Loan Interest Accrual', 'Loan Security Unpledge']
+ 'items': ['Loan Repayment', 'Loan Interest Accrual', 'Loan Write Off', 'Loan Security Unpledge']
}
]
}
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan/loan_list.js b/erpnext/loan_management/doctype/loan/loan_list.js
new file mode 100644
index 0000000..6591b72
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan/loan_list.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.listview_settings['Loan'] = {
+ get_indicator: function(doc) {
+ var status_color = {
+ "Draft": "red",
+ "Sanctioned": "blue",
+ "Disbursed": "orange",
+ "Partially Disbursed": "yellow",
+ "Loan Closure Requested": "green",
+ "Closed": "green"
+ };
+ return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
+ },
+};
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 5a4a19a..4b9a894 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -14,11 +14,12 @@
process_loan_interest_accrual_for_term_loans)
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
-from erpnext.loan_management.doctype.loan.loan import unpledge_security
+from erpnext.loan_management.doctype.loan.loan import unpledge_security, request_loan_closure, make_loan_write_off
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import get_disbursal_amount
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
class TestLoan(unittest.TestCase):
def setUp(self):
@@ -44,6 +45,7 @@
create_loan_security_price("Test Security 2", 250, "Nos", get_datetime() , get_datetime(add_to_date(nowdate(), hours=24)))
self.applicant1 = make_employee("robert_loan@loan.com")
+ make_salary_structure("Test Salary Structure Loan", "Monthly", employee=self.applicant1, currency='INR', company="_Test Company")
if not frappe.db.exists("Customer", "_Test Loan Customer"):
frappe.get_doc(get_customer_dict('_Test Loan Customer')).insert(ignore_permissions=True)
@@ -132,7 +134,7 @@
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
create_pledge(loan_application)
- loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
self.assertEquals(loan.loan_amount, 1000000)
@@ -142,30 +144,30 @@
no_of_days = date_diff(last_date, first_date) + 1
- accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
- / (days_in_year(get_datetime(first_date).year) * 100)
+ accrued_interest_amount = flt((loan.loan_amount * loan.rate_of_interest * no_of_days)
+ / (days_in_year(get_datetime(first_date).year) * 100), 2)
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
- repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), "Regular Payment", 111118.68)
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), 111119)
repayment_entry.save()
repayment_entry.submit()
- penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
- self.assertEquals(flt(repayment_entry.penalty_amount, 2), flt(penalty_amount, 2))
+ penalty_amount = (accrued_interest_amount * 5 * 25) / 100
+ self.assertEquals(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
- amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
- 'paid_principal_amount'])
+ amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
loan.load_from_db()
- self.assertEquals(amounts[0], repayment_entry.interest_payable)
- self.assertEquals(flt(loan.total_principal_paid, 2), flt(repayment_entry.amount_paid -
- penalty_amount - amounts[0], 2))
+ total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
+ self.assertEquals(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
+ self.assertEquals(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
+ penalty_amount - total_interest_paid, 0))
- def test_loan_closure_repayment(self):
+ def test_loan_closure(self):
pledge = [{
"loan_security": "Test Security 1",
"qty": 4000.00
@@ -174,7 +176,7 @@
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
create_pledge(loan_application)
- loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
self.assertEquals(loan.loan_amount, 1000000)
@@ -184,10 +186,10 @@
no_of_days = date_diff(last_date, first_date) + 1
- # Adding 6 since repayment is made 5 days late after due date
+ # Adding 5 since repayment is made 5 days late after due date
# and since payment type is loan closure so interest should be considered for those
- # 6 days as well though in grace period
- no_of_days += 6
+ # 5 days as well though in grace period
+ no_of_days += 5
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
/ (days_in_year(get_datetime(first_date).year) * 100)
@@ -195,15 +197,17 @@
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
- repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
- "Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+ flt(loan.loan_amount + accrued_interest_amount))
+
repayment_entry.submit()
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 2),flt(accrued_interest_amount, 2))
+ self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ request_loan_closure(loan.name)
loan.load_from_db()
self.assertEquals(loan.status, "Loan Closure Requested")
@@ -230,8 +234,7 @@
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
- repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(nowdate(), 5),
- "Regular Payment", 89768.75)
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(nowdate(), 5), 89768.75)
repayment_entry.submit()
@@ -272,6 +275,11 @@
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
where loan_security='Test Security 2'""")
+ create_process_loan_security_shortfall()
+ loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
+ self.assertEquals(loan_security_shortfall.status, "Completed")
+ self.assertEquals(loan_security_shortfall.shortfall_amount, 0)
+
def test_loan_security_unpledge(self):
pledge = [{
"loan_security": "Test Security 1",
@@ -281,7 +289,7 @@
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
create_pledge(loan_application)
- loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
self.assertEquals(loan.loan_amount, 1000000)
@@ -291,7 +299,7 @@
no_of_days = date_diff(last_date, first_date) + 1
- no_of_days += 6
+ no_of_days += 5
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
/ (days_in_year(get_datetime(first_date).year) * 100)
@@ -299,10 +307,10 @@
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
- repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
- "Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), flt(loan.loan_amount + accrued_interest_amount))
repayment_entry.submit()
+ request_loan_closure(loan.name)
loan.load_from_db()
self.assertEquals(loan.status, "Loan Closure Requested")
@@ -317,11 +325,69 @@
self.assertEqual(loan.status, 'Closed')
self.assertEquals(sum(pledged_qty.values()), 0)
- amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
+ amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
self.assertEqual(amounts['pending_principal_amount'], 0)
- self.assertEqual(amounts['payable_principal_amount'], 0)
+ self.assertEquals(amounts['payable_principal_amount'], 0.0)
self.assertEqual(amounts['interest_amount'], 0)
+ def test_partial_loan_security_unpledge(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 2000.00
+ },
+ {
+ "loan_security": "Test Security 2",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), 600000)
+ repayment_entry.submit()
+
+ unpledge_map = {'Test Security 2': 2000}
+
+ unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
+ unpledge_request.submit()
+ unpledge_request.status = 'Approved'
+ unpledge_request.save()
+ unpledge_request.submit()
+ unpledge_request.load_from_db()
+ self.assertEqual(unpledge_request.docstatus, 1)
+
+ def test_santined_loan_security_unpledge(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ unpledge_map = {'Test Security 1': 4000}
+ unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
+ unpledge_request.submit()
+ unpledge_request.status = 'Approved'
+ unpledge_request.save()
+ unpledge_request.submit()
+
def test_disbursal_check_with_shortfall(self):
pledges = [{
"loan_security": "Test Security 2",
@@ -381,7 +447,7 @@
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
create_pledge(loan_application)
- loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
self.assertEquals(loan.loan_amount, 1000000)
@@ -391,7 +457,7 @@
no_of_days = date_diff(last_date, first_date) + 1
- no_of_days += 6
+ no_of_days += 5
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
/ (days_in_year(get_datetime(first_date).year) * 100)
@@ -399,20 +465,192 @@
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
- amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
+ amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
- "Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), flt(loan.loan_amount + accrued_interest_amount))
repayment_entry.submit()
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
'paid_principal_amount'])
+ request_loan_closure(loan.name)
loan.load_from_db()
self.assertEquals(loan.status, "Loan Closure Requested")
- amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
- self.assertEquals(amounts['pending_principal_amount'], 0.0)
+ amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+ self.assertEqual(amounts['pending_principal_amount'], 0.0)
+
+ def test_partial_unaccrued_interest_payment(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ no_of_days = date_diff(last_date, first_date) + 1
+
+ no_of_days += 5.5
+
+ # get partial unaccrued interest amount
+ paid_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+ / (days_in_year(get_datetime(first_date).year) * 100)
+
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+ amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+ paid_amount)
+
+ repayment_entry.submit()
+ repayment_entry.load_from_db()
+
+ partial_accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * 5) \
+ / (days_in_year(get_datetime(first_date).year) * 100)
+
+ interest_amount = flt(amounts['interest_amount'] + partial_accrued_interest_amount, 2)
+ self.assertEqual(flt(repayment_entry.total_interest_paid, 0), flt(interest_amount, 0))
+
+ def test_penalty(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+ amounts = calculate_amounts(loan.name, add_days(last_date, 1))
+ paid_amount = amounts['interest_amount']/2
+
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+ paid_amount)
+
+ repayment_entry.submit()
+
+ # 30 days - grace period
+ penalty_days = 30 - 4
+ penalty_applicable_amount = flt(amounts['interest_amount']/2)
+ penalty_amount = flt((((penalty_applicable_amount * 25) / 100) * penalty_days), 2)
+ process = process_loan_interest_accrual_for_demand_loans(posting_date = '2019-11-30')
+
+ calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
+ {'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
+
+ self.assertEquals(calculated_penalty_amount, penalty_amount)
+
+ def test_loan_write_off_limit(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ no_of_days = date_diff(last_date, first_date) + 1
+ no_of_days += 5
+
+ accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+ / (days_in_year(get_datetime(first_date).year) * 100)
+
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+ # repay 50 less so that it can be automatically written off
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+ flt(loan.loan_amount + accrued_interest_amount - 50))
+
+ repayment_entry.submit()
+
+ amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
+
+ self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+
+ amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+ self.assertEquals(flt(amounts['pending_principal_amount'], 0), 50)
+
+ request_loan_closure(loan.name)
+ loan.load_from_db()
+ self.assertEquals(loan.status, "Loan Closure Requested")
+
+ def test_loan_amount_write_off(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ no_of_days = date_diff(last_date, first_date) + 1
+ no_of_days += 5
+
+ accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+ / (days_in_year(get_datetime(first_date).year) * 100)
+
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+ # repay 100 less so that it can be automatically written off
+ repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+ flt(loan.loan_amount + accrued_interest_amount - 100))
+
+ repayment_entry.submit()
+
+ amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
+
+ self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+
+ amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+ self.assertEquals(flt(amounts['pending_principal_amount'], 0), 100)
+
+ we = make_loan_write_off(loan.name, amount=amounts['pending_principal_amount'])
+ we.submit()
+
+ amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+ self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
+
def create_loan_accounts():
if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):
@@ -496,7 +734,8 @@
"interest_income_account": interest_income_account,
"penalty_income_account": penalty_income_account,
"repayment_method": repayment_method,
- "repayment_periods": repayment_periods
+ "repayment_periods": repayment_periods,
+ "write_off_amount": 100
}).insert()
loan_type.submit()
@@ -532,7 +771,7 @@
"haircut": 50.00,
}).insert(ignore_permissions=True)
-def create_loan_security_pledge(applicant, pledges, loan_application):
+def create_loan_security_pledge(applicant, pledges, loan_application=None, loan=None):
lsp = frappe.new_doc("Loan Security Pledge")
lsp.applicant_type = 'Customer'
@@ -540,11 +779,13 @@
lsp.company = "_Test Company"
lsp.loan_application = loan_application
+ if loan:
+ lsp.loan = loan
+
for pledge in pledges:
lsp.append('securities', {
"loan_security": pledge['loan_security'],
- "qty": pledge['qty'],
- "haircut": pledge['haircut']
+ "qty": pledge['qty']
})
lsp.save()
@@ -582,12 +823,11 @@
"valid_upto": to_date
}).insert(ignore_permissions=True)
-def create_repayment_entry(loan, applicant, posting_date, payment_type, paid_amount):
+def create_repayment_entry(loan, applicant, posting_date, paid_amount):
lr = frappe.get_doc({
"doctype": "Loan Repayment",
"against_loan": loan,
- "payment_type": payment_type,
"company": "_Test Company",
"posting_date": posting_date or nowdate(),
"applicant": applicant,
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.py b/erpnext/loan_management/doctype/loan_application/loan_application.py
index bac6e63..9c0147e 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application.py
+++ b/erpnext/loan_management/doctype/loan_application/loan_application.py
@@ -127,6 +127,7 @@
target_doc.loan_account = account_details.loan_account
target_doc.interest_income_account = account_details.interest_income_account
target_doc.penalty_income_account = account_details.penalty_income_account
+ target_doc.loan_application = source_name
doclist = get_mapped_doc("Loan Application", source_name, {
@@ -196,7 +197,7 @@
security.qty = cint(security.amount/security.loan_security_price)
security.amount = security.qty * security.loan_security_price
- security.post_haircut_amount = security.amount - (security.amount * security.haircut/100)
+ security.post_haircut_amount = cint(security.amount - (security.amount * security.haircut/100))
maximum_loan_amount += security.post_haircut_amount
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 687c580..2a659e9 100644
--- a/erpnext/loan_management/doctype/loan_application/test_loan_application.py
+++ b/erpnext/loan_management/doctype/loan_application/test_loan_application.py
@@ -5,7 +5,7 @@
import frappe
import unittest
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee, make_salary_structure
from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan_accounts
class TestLoanApplication(unittest.TestCase):
@@ -14,6 +14,7 @@
create_loan_type("Home Loan", 500000, 9.2, 0, 1, 0, 'Cash', 'Payment Account - _TC', 'Loan Account - _TC',
'Interest Income Account - _TC', 'Penalty Income Account - _TC', 'Repay Over Number of Periods', 18)
self.applicant = make_employee("kate_loan@loan.com", "_Test Company")
+ make_salary_structure("Test Salary Structure Loan", "Monthly", employee=self.applicant, currency='INR')
self.create_loan_application()
def create_loan_application(self):
@@ -29,7 +30,6 @@
})
loan_application.insert()
-
def test_loan_totals(self):
loan_application = frappe.get_doc("Loan Application", {"applicant":self.applicant})
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
index c437a98..cd5df4d 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
@@ -26,19 +26,24 @@
{
"fieldname": "against_loan",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Against Loan ",
- "options": "Loan"
+ "options": "Loan",
+ "reqd": 1
},
{
"fieldname": "disbursement_date",
"fieldtype": "Date",
- "label": "Disbursement Date"
+ "label": "Disbursement Date",
+ "reqd": 1
},
{
"fieldname": "disbursed_amount",
"fieldtype": "Currency",
"label": "Disbursed Amount",
- "options": "Company:company:default_currency"
+ "non_negative": 1,
+ "options": "Company:company:default_currency",
+ "reqd": 1
},
{
"fieldname": "amended_from",
@@ -53,17 +58,21 @@
"fetch_from": "against_loan.company",
"fieldname": "company",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Company",
"options": "Company",
- "read_only": 1
+ "read_only": 1,
+ "reqd": 1
},
{
"fetch_from": "against_loan.applicant",
"fieldname": "applicant",
"fieldtype": "Dynamic Link",
+ "in_list_view": 1,
"label": "Applicant",
"options": "applicant_type",
- "read_only": 1
+ "read_only": 1,
+ "reqd": 1
},
{
"collapsible": 1,
@@ -102,9 +111,11 @@
"fetch_from": "against_loan.applicant_type",
"fieldname": "applicant_type",
"fieldtype": "Select",
+ "in_list_view": 1,
"label": "Applicant Type",
"options": "Employee\nMember\nCustomer",
- "read_only": 1
+ "read_only": 1,
+ "reqd": 1
},
{
"fieldname": "bank_account",
@@ -117,9 +128,10 @@
"fieldtype": "Column Break"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-04-29 05:20:41.629911",
+ "modified": "2020-11-06 10:04:30.882322",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Disbursement",
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index 260fada..f341e81 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -17,6 +17,7 @@
def validate(self):
self.set_missing_values()
+ self.validate_disbursal_amount()
def on_submit(self):
self.set_status_and_amounts()
@@ -40,57 +41,21 @@
if not self.bank_account and self.applicant_type == "Customer":
self.bank_account = frappe.db.get_value("Customer", self.applicant, "default_bank_account")
- def set_status_and_amounts(self, cancel=0):
+ def validate_disbursal_amount(self):
+ possible_disbursal_amount = get_disbursal_amount(self.against_loan)
+ if self.disbursed_amount > possible_disbursal_amount:
+ frappe.throw(_("Disbursed Amount cannot be greater than {0}").format(possible_disbursal_amount))
+
+ def set_status_and_amounts(self, cancel=0):
loan_details = frappe.get_all("Loan",
fields = ["loan_amount", "disbursed_amount", "total_payment", "total_principal_paid", "total_interest_payable",
"status", "is_term_loan", "is_secured_loan"], filters= { "name": self.against_loan })[0]
if cancel:
- disbursed_amount = loan_details.disbursed_amount - self.disbursed_amount
- total_payment = loan_details.total_payment
-
- if loan_details.disbursed_amount > loan_details.loan_amount:
- topup_amount = loan_details.disbursed_amount - loan_details.loan_amount
- if topup_amount > self.disbursed_amount:
- topup_amount = self.disbursed_amount
-
- total_payment = total_payment - topup_amount
-
- if disbursed_amount == 0:
- status = "Sanctioned"
- elif disbursed_amount >= loan_details.loan_amount:
- status = "Disbursed"
- else:
- status = "Partially Disbursed"
+ disbursed_amount, status, total_payment = self.get_values_on_cancel(loan_details)
else:
- disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount
- total_payment = loan_details.total_payment
-
- possible_disbursal_amount = get_disbursal_amount(self.against_loan)
-
- if self.disbursed_amount > possible_disbursal_amount:
- frappe.throw(_("Disbursed Amount cannot be greater than {0}").format(possible_disbursal_amount))
-
- if loan_details.status == "Disbursed" and not loan_details.is_term_loan:
- process_loan_interest_accrual_for_demand_loans(posting_date=add_days(self.disbursement_date, -1),
- loan=self.against_loan)
-
- if disbursed_amount > loan_details.loan_amount:
- topup_amount = disbursed_amount - loan_details.loan_amount
-
- if topup_amount < 0:
- topup_amount = 0
-
- if topup_amount > self.disbursed_amount:
- topup_amount = self.disbursed_amount
-
- total_payment = total_payment + topup_amount
-
- if flt(disbursed_amount) >= loan_details.loan_amount:
- status = "Disbursed"
- else:
- status = "Partially Disbursed"
+ disbursed_amount, status, total_payment = self.get_values_on_submit(loan_details)
frappe.db.set_value("Loan", self.against_loan, {
"disbursement_date": self.disbursement_date,
@@ -99,6 +64,53 @@
"total_payment": total_payment
})
+ def get_values_on_cancel(self, loan_details):
+ disbursed_amount = loan_details.disbursed_amount - self.disbursed_amount
+ total_payment = loan_details.total_payment
+
+ if loan_details.disbursed_amount > loan_details.loan_amount:
+ topup_amount = loan_details.disbursed_amount - loan_details.loan_amount
+ if topup_amount > self.disbursed_amount:
+ topup_amount = self.disbursed_amount
+
+ total_payment = total_payment - topup_amount
+
+ if disbursed_amount == 0:
+ status = "Sanctioned"
+
+ elif disbursed_amount >= loan_details.loan_amount:
+ status = "Disbursed"
+ else:
+ status = "Partially Disbursed"
+
+ return disbursed_amount, status, total_payment
+
+ def get_values_on_submit(self, loan_details):
+ disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount
+ total_payment = loan_details.total_payment
+
+ if loan_details.status in ("Disbursed", "Partially Disbursed") and not loan_details.is_term_loan:
+ process_loan_interest_accrual_for_demand_loans(posting_date=add_days(self.disbursement_date, -1),
+ loan=self.against_loan, accrual_type="Disbursement")
+
+ if disbursed_amount > loan_details.loan_amount:
+ topup_amount = disbursed_amount - loan_details.loan_amount
+
+ if topup_amount < 0:
+ topup_amount = 0
+
+ if topup_amount > self.disbursed_amount:
+ topup_amount = self.disbursed_amount
+
+ total_payment = total_payment + topup_amount
+
+ if flt(disbursed_amount) >= loan_details.loan_amount:
+ status = "Disbursed"
+ else:
+ status = "Partially Disbursed"
+
+ return disbursed_amount, status, total_payment
+
def make_gl_entries(self, cancel=0, adv_adj=0):
gle_map = []
loan_details = frappe.get_doc("Loan", self.against_loan)
@@ -111,7 +123,7 @@
"debit_in_account_currency": self.disbursed_amount,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
- "remarks": "Against Loan:" + self.against_loan,
+ "remarks": _("Disbursement against loan:") + self.against_loan,
"cost_center": self.cost_center,
"party_type": self.applicant_type,
"party": self.applicant,
@@ -127,10 +139,8 @@
"credit_in_account_currency": self.disbursed_amount,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
- "remarks": "Against Loan:" + self.against_loan,
+ "remarks": _("Disbursement against loan:") + self.against_loan,
"cost_center": self.cost_center,
- "party_type": self.applicant_type,
- "party": self.applicant,
"posting_date": self.disbursement_date
})
)
@@ -155,15 +165,16 @@
pledged_securities = get_pledged_security_qty(loan)
for security, qty in pledged_securities.items():
- security_value += (loan_security_price_map.get(security) * qty * hair_cut_map.get(security))/100
+ after_haircut_percentage = 100 - hair_cut_map.get(security)
+ security_value += (loan_security_price_map.get(security) * qty * after_haircut_percentage)/100
return security_value
@frappe.whitelist()
-def get_disbursal_amount(loan):
- loan_details = frappe.get_all("Loan", fields = ["loan_amount", "disbursed_amount", "total_payment",
- "total_principal_paid", "total_interest_payable", "status", "is_term_loan", "is_secured_loan"],
- filters= { "name": loan })[0]
+def get_disbursal_amount(loan, on_current_security_price=0):
+ loan_details = frappe.get_value("Loan", loan, ["loan_amount", "disbursed_amount", "total_payment",
+ "total_principal_paid", "total_interest_payable", "status", "is_term_loan", "is_secured_loan",
+ "maximum_loan_amount"], as_dict=1)
if loan_details.is_secured_loan and frappe.get_all('Loan Security Shortfall', filters={'loan': loan,
'status': 'Pending'}):
@@ -173,17 +184,24 @@
pending_principal_amount = flt(loan_details.total_payment) - flt(loan_details.total_interest_payable) \
- flt(loan_details.total_principal_paid)
else:
- pending_principal_amount = flt(loan_details.disbursed_amount)
+ pending_principal_amount = flt(loan_details.disbursed_amount) - flt(loan_details.total_interest_payable) \
+ - flt(loan_details.total_principal_paid)
security_value = 0.0
- if loan_details.is_secured_loan:
+ if loan_details.is_secured_loan and on_current_security_price:
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)
+
if not security_value and not loan_details.is_secured_loan:
security_value = flt(loan_details.loan_amount)
disbursal_amount = flt(security_value) - flt(pending_principal_amount)
+ if loan_details.is_term_loan and (disbursal_amount + loan_details.loan_amount) > loan_details.loan_amount:
+ disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount
+
return disbursal_amount
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 2cb2637..a875387 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
@@ -8,9 +8,10 @@
from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, create_loan_application,
make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price)
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year, get_per_day_interest
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
class TestLoanDisbursement(unittest.TestCase):
@@ -60,8 +61,7 @@
self.assertRaises(frappe.ValidationError, make_loan_disbursement_entry, loan.name,
500000, first_date)
- repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5),
- "Regular Payment", 611095.89)
+ repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5), 611095.89)
repayment_entry.submit()
loan.reload()
@@ -69,3 +69,50 @@
# After repayment loan disbursement entry should go through
make_loan_disbursement_entry(loan.name, 500000, disbursement_date=add_days(last_date, 16))
+ # check for disbursement accrual
+ loan_interest_accrual = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name,
+ 'accrual_type': 'Disbursement'})
+
+ self.assertTrue(loan_interest_accrual)
+
+ def test_loan_topup_with_additional_pledge(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+
+ loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
+ loan.submit()
+
+ self.assertEquals(loan.loan_amount, 1000000)
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ # Disbursed 10,00,000 amount
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+ amounts = calculate_amounts(loan.name, add_days(last_date, 1))
+
+ previous_interest = amounts['interest_amount']
+
+ pledge1 = [{
+ "loan_security": "Test Security 1",
+ "qty": 2000.00
+ }]
+
+ create_loan_security_pledge(self.applicant, pledge1, loan=loan.name)
+
+ # Topup 500000
+ make_loan_disbursement_entry(loan.name, 500000, disbursement_date=add_days(last_date, 1))
+ process_loan_interest_accrual_for_demand_loans(posting_date = add_days(last_date, 15))
+ amounts = calculate_amounts(loan.name, add_days(last_date, 15))
+
+ per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
+ interest = per_day_interest * 15
+
+ self.assertEquals(amounts['pending_principal_amount'], 1500000)
+ self.assertEquals(amounts['interest_amount'], flt(interest + previous_interest, 2))
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
index 5fc3e8f..185bf7a 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
@@ -14,6 +14,7 @@
"column_break_4",
"company",
"posting_date",
+ "accrual_type",
"is_term_loan",
"section_break_7",
"pending_principal_amount",
@@ -21,10 +22,13 @@
"paid_principal_amount",
"column_break_14",
"interest_amount",
+ "total_pending_interest_amount",
"paid_interest_amount",
+ "penalty_amount",
"section_break_15",
"process_loan_interest_accrual",
"repayment_schedule_name",
+ "last_accrual_date",
"amended_from"
],
"fields": [
@@ -139,6 +143,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.is_term_loan",
"fieldname": "paid_principal_amount",
"fieldtype": "Currency",
"label": "Paid Principal Amount",
@@ -149,12 +154,38 @@
"fieldtype": "Currency",
"label": "Paid Interest Amount",
"options": "Company:company:default_currency"
+ },
+ {
+ "fieldname": "accrual_type",
+ "fieldtype": "Select",
+ "label": "Accrual Type",
+ "options": "Regular\nRepayment\nDisbursement"
+ },
+ {
+ "fieldname": "penalty_amount",
+ "fieldtype": "Currency",
+ "label": "Penalty Amount",
+ "options": "Company:company:default_currency"
+ },
+ {
+ "fieldname": "last_accrual_date",
+ "fieldtype": "Date",
+ "hidden": 1,
+ "label": "Last Accrual Date",
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_pending_interest_amount",
+ "fieldtype": "Currency",
+ "label": "Total Pending Interest Amount",
+ "options": "Company:company:default_currency"
}
],
"in_create": 1,
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-04-16 11:24:23.258404",
+ "modified": "2021-01-10 00:15:21.544140",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Interest Accrual",
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 2d959bf..7978350 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
@@ -22,6 +22,8 @@
if not self.interest_amount and not self.payable_principal_amount:
frappe.throw(_("Interest Amount or Principal Amount is mandatory"))
+ if not self.last_accrual_date:
+ self.last_accrual_date = get_last_accrual_date(self.loan)
def on_submit(self):
self.make_gl_entries()
@@ -50,7 +52,8 @@
"debit_in_account_currency": self.interest_amount,
"against_voucher_type": "Loan",
"against_voucher": self.loan,
- "remarks": _("Against Loan:") + self.loan,
+ "remarks": _("Interest accrued from {0} to {1} against loan: {2}").format(
+ self.last_accrual_date, self.posting_date, self.loan),
"cost_center": erpnext.get_default_cost_center(self.company),
"posting_date": self.posting_date
})
@@ -59,14 +62,13 @@
gle_map.append(
self.get_gl_dict({
"account": self.interest_income_account,
- "party_type": self.applicant_type,
- "party": self.applicant,
"against": self.loan_account,
"credit": self.interest_amount,
"credit_in_account_currency": self.interest_amount,
"against_voucher_type": "Loan",
"against_voucher": self.loan,
- "remarks": _("Against Loan:") + self.loan,
+ "remarks": ("Interest accrued from {0} to {1} against loan: {2}").format(
+ self.last_accrual_date, self.posting_date, self.loan),
"cost_center": erpnext.get_default_cost_center(self.company),
"posting_date": self.posting_date
})
@@ -79,21 +81,27 @@
# For Eg: If Loan disbursement date is '01-09-2019' and disbursed amount is 1000000 and
# rate of interest is 13.5 then first loan interest accural will be on '01-10-2019'
# which means interest will be accrued for 30 days which should be equal to 11095.89
-def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest):
+def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest, accrual_type):
+ from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
+
no_of_days = get_no_of_days_for_interest_accural(loan, posting_date)
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
if no_of_days <= 0:
return
if loan.status == 'Disbursed':
pending_principal_amount = flt(loan.total_payment) - flt(loan.total_interest_payable) \
- - flt(loan.total_principal_paid)
+ - flt(loan.total_principal_paid) - flt(loan.written_off_amount)
else:
- pending_principal_amount = loan.disbursed_amount
+ pending_principal_amount = flt(loan.disbursed_amount) - flt(loan.total_interest_payable) \
+ - flt(loan.total_principal_paid) - flt(loan.written_off_amount)
- interest_per_day = (pending_principal_amount * loan.rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100)
+ interest_per_day = get_per_day_interest(pending_principal_amount, loan.rate_of_interest, posting_date)
payable_interest = interest_per_day * no_of_days
+ pending_amounts = calculate_amounts(loan.name, posting_date, payment_type='Loan Closure')
+
args = frappe._dict({
'loan': loan.name,
'applicant_type': loan.applicant_type,
@@ -102,13 +110,17 @@
'loan_account': loan.loan_account,
'pending_principal_amount': pending_principal_amount,
'interest_amount': payable_interest,
+ 'total_pending_interest_amount': pending_amounts['interest_amount'],
+ 'penalty_amount': pending_amounts['penalty_amount'],
'process_loan_interest': process_loan_interest,
- 'posting_date': posting_date
+ 'posting_date': posting_date,
+ 'accrual_type': accrual_type
})
- make_loan_interest_accrual_entry(args)
+ if flt(payable_interest, precision) > 0.0:
+ make_loan_interest_accrual_entry(args)
-def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None):
+def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None, accrual_type="Regular"):
query_filters = {
"status": ('in', ['Disbursed', 'Partially Disbursed']),
"docstatus": 1
@@ -123,13 +135,13 @@
open_loans = frappe.get_all("Loan",
fields=["name", "total_payment", "total_amount_paid", "loan_account", "interest_income_account",
"is_term_loan", "status", "disbursement_date", "disbursed_amount", "applicant_type", "applicant",
- "rate_of_interest", "total_interest_payable", "total_principal_paid", "repayment_start_date"],
+ "rate_of_interest", "total_interest_payable", "written_off_amount", "total_principal_paid", "repayment_start_date"],
filters=query_filters)
for loan in open_loans:
- calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest)
+ calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest, accrual_type)
-def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None):
+def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None, accrual_type="Regular"):
curr_date = posting_date or add_days(nowdate(), 1)
term_loans = get_term_loans(curr_date, term_loan, loan_type)
@@ -148,7 +160,8 @@
'payable_principal': loan.principal_amount,
'process_loan_interest': process_loan_interest,
'repayment_schedule_name': loan.payment_entry,
- 'posting_date': posting_date
+ 'posting_date': posting_date,
+ 'accrual_type': accrual_type
})
make_loan_interest_accrual_entry(args)
@@ -192,31 +205,34 @@
loan_interest_accrual.loan_account = args.loan_account
loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, precision)
loan_interest_accrual.interest_amount = flt(args.interest_amount, precision)
+ loan_interest_accrual.total_pending_interest_amount = flt(args.total_pending_interest_amount, precision)
+ loan_interest_accrual.penalty_amount = flt(args.penalty_amount, precision)
loan_interest_accrual.posting_date = args.posting_date or nowdate()
loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
loan_interest_accrual.repayment_schedule_name = args.repayment_schedule_name
loan_interest_accrual.payable_principal_amount = args.payable_principal
+ loan_interest_accrual.accrual_type = args.accrual_type
loan_interest_accrual.save()
loan_interest_accrual.submit()
def get_no_of_days_for_interest_accural(loan, posting_date):
- last_interest_accrual_date = get_last_accural_date_in_current_month(loan)
+ last_interest_accrual_date = get_last_accrual_date(loan.name)
no_of_days = date_diff(posting_date or nowdate(), last_interest_accrual_date) + 1
return no_of_days
-def get_last_accural_date_in_current_month(loan):
+def get_last_accrual_date(loan):
last_posting_date = frappe.db.sql(""" SELECT MAX(posting_date) from `tabLoan Interest Accrual`
- WHERE loan = %s""", (loan.name))
+ WHERE loan = %s and docstatus = 1""", (loan))
if last_posting_date[0][0]:
# interest for last interest accrual date is already booked, so add 1 day
return add_days(last_posting_date[0][0], 1)
else:
- return loan.disbursement_date
+ return frappe.db.get_value('Loan', loan, 'disbursement_date')
def days_in_year(year):
days = 365
@@ -226,3 +242,9 @@
return days
+def get_per_day_interest(principal_amount, rate_of_interest, posting_date=None):
+ if not posting_date:
+ posting_date = getdate()
+
+ return flt((principal_amount * rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100))
+
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 4b85b21..85e008a 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
@@ -5,7 +5,7 @@
import frappe
import unittest
from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
-from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_loan_security_price,
+from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_price,
make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_application)
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
@@ -37,10 +37,8 @@
loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
create_pledge(loan_application)
-
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application,
posting_date=get_first_day(nowdate()))
-
loan.submit()
first_date = '2019-10-01'
@@ -50,11 +48,46 @@
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
/ (days_in_year(get_datetime(first_date).year) * 100)
-
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
-
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
-
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
- self.assertEquals(flt(loan_interest_accural.interest_amount, 2), flt(accrued_interest_amount, 2))
+ self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
+
+ def test_accumulated_amounts(self):
+ pledge = [{
+ "loan_security": "Test Security 1",
+ "qty": 4000.00
+ }]
+
+ loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
+ create_pledge(loan_application)
+ loan = create_demand_loan(self.applicant, "Demand Loan", loan_application,
+ posting_date=get_first_day(nowdate()))
+ loan.submit()
+
+ first_date = '2019-10-01'
+ last_date = '2019-10-30'
+
+ no_of_days = date_diff(last_date, first_date) + 1
+ accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+ / (days_in_year(get_datetime(first_date).year) * 100)
+ make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+ process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
+ loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
+
+ self.assertEquals(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
+
+ next_start_date = '2019-10-31'
+ next_end_date = '2019-11-29'
+
+ no_of_days = date_diff(next_end_date, next_start_date) + 1
+ process = process_loan_interest_accrual_for_demand_loans(posting_date=next_end_date)
+ new_accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+ / (days_in_year(get_datetime(first_date).year) * 100)
+
+ total_pending_interest_amount = flt(accrued_interest_amount + new_accrued_interest_amount, 0)
+
+ loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name,
+ 'process_loan_interest_accrual': process})
+ self.assertEquals(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
index 5942455..2b5df4b 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
@@ -10,11 +10,11 @@
"applicant_type",
"applicant",
"loan_type",
- "payment_type",
"column_break_3",
"company",
"posting_date",
"is_term_loan",
+ "rate_of_interest",
"payment_details_section",
"due_date",
"pending_principal_amount",
@@ -31,6 +31,7 @@
"column_break_21",
"reference_date",
"principal_amount_paid",
+ "total_interest_paid",
"repayment_details",
"amended_from"
],
@@ -96,15 +97,6 @@
"fieldtype": "Column Break"
},
{
- "default": "Regular Payment",
- "fieldname": "payment_type",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Payment Type",
- "options": "\nRegular Payment\nLoan Closure",
- "reqd": 1
- },
- {
"fieldname": "payable_amount",
"fieldtype": "Currency",
"label": "Payable Amount",
@@ -116,6 +108,7 @@
"fieldname": "amount_paid",
"fieldtype": "Currency",
"label": "Amount Paid",
+ "non_negative": 1,
"options": "Company:company:default_currency",
"reqd": 1
},
@@ -195,6 +188,7 @@
"fieldtype": "Currency",
"hidden": 1,
"label": "Principal Amount Paid",
+ "options": "Company:company:default_currency",
"read_only": 1
},
{
@@ -217,11 +211,27 @@
"hidden": 1,
"label": "Repayment Details",
"options": "Loan Repayment Detail"
+ },
+ {
+ "fieldname": "total_interest_paid",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Total Interest Paid",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "loan_type.rate_of_interest",
+ "fieldname": "rate_of_interest",
+ "fieldtype": "Percent",
+ "label": "Rate Of Interest",
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-05-16 09:40:15.581165",
+ "modified": "2020-11-05 10:06:58.792841",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Repayment",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 97dbc44..bac06c4 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -14,14 +14,15 @@
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import update_shortfall_status
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import get_per_day_interest, get_last_accrual_date
class LoanRepayment(AccountsController):
def validate(self):
- amounts = calculate_amounts(self.against_loan, self.posting_date, self.payment_type)
+ amounts = calculate_amounts(self.against_loan, self.posting_date)
self.set_missing_values(amounts)
self.validate_amount()
- self.allocate_amounts(amounts['pending_accrual_entries'])
+ self.allocate_amounts(amounts)
def before_submit(self):
self.book_unaccrued_interest()
@@ -32,8 +33,8 @@
def on_cancel(self):
self.mark_as_unpaid()
- self.make_gl_entries(cancel=1)
self.ignore_linked_doctypes = ['GL Entry']
+ self.make_gl_entries(cancel=1)
def set_missing_values(self, amounts):
precision = cint(frappe.db.get_default("currency_precision")) or 2
@@ -72,33 +73,38 @@
msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
frappe.throw(msg)
- if self.payment_type == "Loan Closure" and flt(self.amount_paid, precision) < flt(self.payable_amount, precision):
- msg = _("Amount of {0} is required for Loan closure").format(self.payable_amount)
- frappe.throw(msg)
-
def book_unaccrued_interest(self):
- if self.payment_type == 'Loan Closure':
- total_interest_paid = 0
- for payment in self.repayment_details:
- total_interest_paid += payment.paid_interest_amount
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
+ if self.total_interest_paid > self.interest_payable:
+ if not self.is_term_loan:
+ # get last loan interest accrual date
+ last_accrual_date = get_last_accrual_date(self.against_loan)
- if total_interest_paid < self.interest_payable:
- if not self.is_term_loan:
- process = process_loan_interest_accrual_for_demand_loans(posting_date=self.posting_date,
- loan=self.against_loan)
+ # get posting date upto which interest has to be accrued
+ per_day_interest = get_per_day_interest(self.pending_principal_amount,
+ self.rate_of_interest, self.posting_date)
- lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
- process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
+ no_of_days = flt(flt(self.total_interest_paid - self.interest_payable,
+ precision)/per_day_interest, 0) - 1
- self.append('repayment_details', {
- 'loan_interest_accrual': lia.name,
- 'paid_interest_amount': lia.interest_amount,
- 'paid_principal_amount': lia.payable_principal_amount
- })
+ posting_date = add_days(last_accrual_date, no_of_days)
+
+ # book excess interest paid
+ process = process_loan_interest_accrual_for_demand_loans(posting_date=posting_date,
+ loan=self.against_loan, accrual_type="Repayment")
+
+ # get loan interest accrual to update paid amount
+ lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
+ process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
+
+ self.append('repayment_details', {
+ 'loan_interest_accrual': lia.name,
+ 'paid_interest_amount': flt(self.total_interest_paid - self.interest_payable, precision),
+ 'paid_principal_amount': 0.0,
+ 'accrual_type': 'Repayment'
+ })
def update_paid_amount(self):
- precision = cint(frappe.db.get_default("currency_precision")) or 2
-
loan = frappe.get_doc("Loan", self.against_loan)
for payment in self.repayment_details:
@@ -106,13 +112,7 @@
SET paid_principal_amount = `paid_principal_amount` + %s,
paid_interest_amount = `paid_interest_amount` + %s
WHERE name = %s""",
- (flt(payment.paid_principal_amount, precision), flt(payment.paid_interest_amount, precision), payment.loan_interest_accrual))
-
- if flt(loan.total_principal_paid + self.principal_amount_paid, precision) >= flt(loan.total_payment, precision):
- if loan.is_secured_loan:
- frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
- else:
- frappe.db.set_value("Loan", self.against_loan, "status", "Closed")
+ (flt(payment.paid_principal_amount), flt(payment.paid_interest_amount), payment.loan_interest_accrual))
frappe.db.sql(""" UPDATE `tabLoan` SET total_amount_paid = %s, total_principal_paid = %s
WHERE name = %s """, (loan.total_amount_paid + self.amount_paid,
@@ -123,6 +123,8 @@
def mark_as_unpaid(self):
loan = frappe.get_doc("Loan", self.against_loan)
+ no_of_repayments = len(self.repayment_details)
+
for payment in self.repayment_details:
frappe.db.sql(""" UPDATE `tabLoan Interest Accrual`
SET paid_principal_amount = `paid_principal_amount` - %s,
@@ -130,6 +132,12 @@
WHERE name = %s""",
(payment.paid_principal_amount, payment.paid_interest_amount, payment.loan_interest_accrual))
+ # Cancel repayment interest accrual
+ # checking idx as a preventive measure, repayment accrual will always be the last entry
+ if payment.accrual_type == 'Repayment' and payment.idx == no_of_repayments:
+ lia_doc = frappe.get_doc('Loan Interest Accrual', payment.loan_interest_accrual)
+ lia_doc.cancel()
+
frappe.db.sql(""" UPDATE `tabLoan` SET total_amount_paid = %s, total_principal_paid = %s
WHERE name = %s """, (loan.total_amount_paid - self.amount_paid,
loan.total_principal_paid - self.principal_amount_paid, self.against_loan))
@@ -137,15 +145,15 @@
if loan.status == "Loan Closure Requested":
frappe.db.set_value("Loan", self.against_loan, "status", "Disbursed")
- def allocate_amounts(self, paid_entries):
+ def allocate_amounts(self, repayment_details):
self.set('repayment_details', [])
self.principal_amount_paid = 0
total_interest_paid = 0
interest_paid = self.amount_paid - self.penalty_amount
- if self.amount_paid - self.penalty_amount > 0 and paid_entries:
+ if self.amount_paid - self.penalty_amount > 0:
interest_paid = self.amount_paid - self.penalty_amount
- for lia, amounts in iteritems(paid_entries):
+ for lia, amounts in iteritems(repayment_details.get('pending_accrual_entries', [])):
if amounts['interest_amount'] + amounts['payable_principal_amount'] <= interest_paid:
interest_amount = amounts['interest_amount']
paid_principal = amounts['payable_principal_amount']
@@ -169,10 +177,22 @@
'paid_principal_amount': paid_principal
})
- if self.payment_type == 'Loan Closure' and total_interest_paid < self.interest_payable:
- unaccrued_interest = self.interest_payable - total_interest_paid
- interest_paid -= unaccrued_interest
+ if repayment_details['unaccrued_interest'] and interest_paid:
+ # no of days for which to accrue interest
+ # Interest can only be accrued for an entire day and not partial
+ if interest_paid > repayment_details['unaccrued_interest']:
+ interest_paid -= repayment_details['unaccrued_interest']
+ total_interest_paid += repayment_details['unaccrued_interest']
+ else:
+ # get no of days for which interest can be paid
+ per_day_interest = get_per_day_interest(self.pending_principal_amount,
+ self.rate_of_interest, self.posting_date)
+ no_of_days = cint(interest_paid/per_day_interest)
+ total_interest_paid += no_of_days * per_day_interest
+ interest_paid -= no_of_days * per_day_interest
+
+ self.total_interest_paid = total_interest_paid
if interest_paid:
self.principal_amount_paid += interest_paid
@@ -189,7 +209,7 @@
"debit_in_account_currency": self.penalty_amount,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
- "remarks": _("Against Loan:") + self.against_loan,
+ "remarks": _("Penalty against loan:") + self.against_loan,
"cost_center": self.cost_center,
"party_type": self.applicant_type,
"party": self.applicant,
@@ -205,10 +225,8 @@
"credit_in_account_currency": self.penalty_amount,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
- "remarks": _("Against Loan:") + self.against_loan,
+ "remarks": _("Penalty against loan:") + self.against_loan,
"cost_center": self.cost_center,
- "party_type": self.applicant_type,
- "party": self.applicant,
"posting_date": getdate(self.posting_date)
})
)
@@ -219,13 +237,11 @@
"against": loan_details.loan_account + ", " + loan_details.interest_income_account
+ ", " + loan_details.penalty_income_account,
"debit": self.amount_paid,
- "debit_in_account_currency": self.amount_paid ,
+ "debit_in_account_currency": self.amount_paid,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
- "remarks": _("Against Loan:") + self.against_loan,
+ "remarks": _("Repayment against Loan: ") + self.against_loan,
"cost_center": self.cost_center,
- "party_type": self.applicant_type,
- "party": self.applicant,
"posting_date": getdate(self.posting_date)
})
)
@@ -240,7 +256,7 @@
"credit_in_account_currency": self.amount_paid,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
- "remarks": _("Against Loan:") + self.against_loan,
+ "remarks": _("Repayment against Loan: ") + self.against_loan,
"cost_center": self.cost_center,
"posting_date": getdate(self.posting_date)
})
@@ -273,7 +289,8 @@
unpaid_accrued_entries = frappe.db.sql(
"""
SELECT name, posting_date, interest_amount - paid_interest_amount as interest_amount,
- payable_principal_amount - paid_principal_amount as payable_principal_amount
+ payable_principal_amount - paid_principal_amount as payable_principal_amount,
+ accrual_type
FROM
`tabLoan Interest Accrual`
WHERE
@@ -282,6 +299,7 @@
payable_principal_amount - paid_principal_amount > 0)
AND
docstatus = 1
+ ORDER BY posting_date
""", (against_loan), as_dict=1)
return unpaid_accrued_entries
@@ -289,7 +307,7 @@
# This function returns the amounts that are payable at the time of loan repayment based on posting date
# So it pulls all the unpaid Loan Interest Accrual Entries and calculates the penalty if applicable
-def get_amounts(amounts, against_loan, posting_date, payment_type):
+def get_amounts(amounts, against_loan, posting_date):
precision = cint(frappe.db.get_default("currency_precision")) or 2
against_loan_doc = frappe.get_doc("Loan", against_loan)
@@ -311,10 +329,10 @@
due_date = add_days(entry.posting_date, 1)
no_of_late_days = date_diff(posting_date,
- add_days(due_date, loan_type_details.grace_period_in_days))
+ add_days(due_date, loan_type_details.grace_period_in_days)) + 1
- if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary):
- penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)/365
+ if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary) and entry.accrual_type == 'Regular':
+ penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)
total_pending_interest += entry.interest_amount
payable_principal_amount += entry.payable_principal_amount
@@ -324,23 +342,27 @@
'payable_principal_amount': flt(entry.payable_principal_amount, precision)
})
- if not final_due_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'):
- pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable
+ 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:
- pending_principal_amount = against_loan_doc.disbursed_amount
+ pending_principal_amount = against_loan_doc.disbursed_amount - against_loan_doc.total_principal_paid \
+ - against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount
- if payment_type == "Loan Closure":
- if due_date:
- pending_days = date_diff(posting_date, due_date) + 1
- else:
- pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
+ unaccrued_interest = 0
+ if due_date:
+ pending_days = date_diff(posting_date, due_date) + 1
+ else:
+ last_accrual_date = get_last_accrual_date(against_loan_doc.name)
+ pending_days = date_diff(posting_date, last_accrual_date) + 1
- payable_principal_amount = pending_principal_amount
- per_day_interest = (payable_principal_amount * (loan_type_details.rate_of_interest / 100))/365
- total_pending_interest += (pending_days * per_day_interest)
+ if pending_days > 0:
+ principal_amount = flt(pending_principal_amount, precision)
+ per_day_interest = get_per_day_interest(principal_amount, loan_type_details.rate_of_interest, posting_date)
+ unaccrued_interest += (pending_days * per_day_interest)
amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
@@ -348,6 +370,7 @@
amounts["penalty_amount"] = flt(penalty_amount, precision)
amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
amounts["pending_accrual_entries"] = pending_accrual_entries
+ amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)
if final_due_date:
amounts["due_date"] = final_due_date
@@ -355,7 +378,7 @@
return amounts
@frappe.whitelist()
-def calculate_amounts(against_loan, posting_date, payment_type):
+def calculate_amounts(against_loan, posting_date, payment_type=''):
amounts = {
'penalty_amount': 0.0,
@@ -363,10 +386,17 @@
'pending_principal_amount': 0.0,
'payable_principal_amount': 0.0,
'payable_amount': 0.0,
+ 'unaccrued_interest': 0.0,
'due_date': ''
}
- amounts = get_amounts(amounts, against_loan, posting_date, payment_type)
+ amounts = get_amounts(amounts, against_loan, posting_date)
+
+ # update values for closure
+ if payment_type == 'Loan Closure':
+ amounts['payable_principal_amount'] = amounts['pending_principal_amount']
+ amounts['interest_amount'] += amounts['unaccrued_interest']
+ amounts['payable_amount'] = amounts['payable_principal_amount'] + amounts['interest_amount']
return amounts
diff --git a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json
index cff1dbb..4b9b191 100644
--- a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json
+++ b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json
@@ -7,7 +7,8 @@
"field_order": [
"loan_interest_accrual",
"paid_principal_amount",
- "paid_interest_amount"
+ "paid_interest_amount",
+ "accrual_type"
],
"fields": [
{
@@ -27,11 +28,20 @@
"fieldtype": "Currency",
"label": "Paid Interest Amount",
"options": "Company:company:default_currency"
+ },
+ {
+ "fetch_from": "loan_interest_accrual.accrual_type",
+ "fetch_if_empty": 1,
+ "fieldname": "accrual_type",
+ "fieldtype": "Select",
+ "label": "Accrual Type",
+ "options": "Regular\nRepayment\nDisbursement"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-15 21:50:03.837019",
+ "modified": "2020-10-23 08:09:18.267030",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Repayment Detail",
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.json b/erpnext/loan_management/doctype/loan_security/loan_security.json
index 1d0bb30..c698601 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.json
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.json
@@ -25,6 +25,7 @@
},
{
"fetch_from": "loan_security_type.haircut",
+ "fetch_if_empty": 1,
"fieldname": "haircut",
"fieldtype": "Percent",
"label": "Haircut %"
@@ -64,8 +65,9 @@
"reqd": 1
}
],
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-04-29 13:21:26.043492",
+ "modified": "2020-10-26 07:34:48.601766",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Security",
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 2bb6fd8..cbc8376 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
@@ -78,7 +78,7 @@
self.maximum_loan_value = maximum_loan_value
def update_loan(loan, maximum_value_against_pledge):
- maximum_loan_value = frappe.db.get_value('Loan', {'name': loan}, ['maximum_loan_value'])
+ maximum_loan_value = frappe.db.get_value('Loan', {'name': loan}, ['maximum_loan_amount'])
- frappe.db.sql(""" UPDATE `tabLoan` SET maximum_loan_value=%s, is_secured_loan=1
+ frappe.db.sql(""" UPDATE `tabLoan` SET maximum_loan_amount=%s, is_secured_loan=1
WHERE name=%s""", (maximum_loan_value + maximum_value_against_pledge, loan))
diff --git a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.json b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.json
index a55b482..b6e8763 100644
--- a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.json
+++ b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.json
@@ -7,6 +7,7 @@
"engine": "InnoDB",
"field_order": [
"loan_security",
+ "loan_security_name",
"loan_security_type",
"column_break_2",
"uom",
@@ -79,10 +80,18 @@
"label": "Loan Security Type",
"options": "Loan Security Type",
"read_only": 1
+ },
+ {
+ "fetch_from": "loan_security.loan_security_name",
+ "fieldname": "loan_security_name",
+ "fieldtype": "Data",
+ "label": "Loan Security Name",
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-06-11 03:41:33.900340",
+ "modified": "2021-01-17 07:41:49.598086",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Security Price",
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 0f42bde..b5e7898 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
@@ -22,7 +22,7 @@
if security_value >= loan_security_shortfall.shortfall_amount:
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name, {
"status": "Completed",
- "shortfall_value": loan_security_shortfall.shortfall_amount})
+ "shortfall_amount": loan_security_shortfall.shortfall_amount})
else:
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name,
"shortfall_amount", loan_security_shortfall.shortfall_amount - security_value)
@@ -55,6 +55,9 @@
'total_interest_payable', 'disbursed_amount', 'status'],
filters={'status': ('in',['Disbursed','Partially Disbursed']), 'is_secured_loan': 1})
+ loan_shortfall_map = frappe._dict(frappe.get_all("Loan Security Shortfall",
+ fields=["loan", "name"], filters={"status": "Pending"}, as_list=1))
+
loan_security_map = {}
for loan in loans:
@@ -71,17 +74,21 @@
for security, qty in pledged_securities.items():
if not ltv_ratio:
ltv_ratio = get_ltv_ratio(security)
- security_value += loan_security_price_map.get(security) * qty
+ security_value += flt(loan_security_price_map.get(security)) * flt(qty)
- current_ratio = (outstanding_amount/security_value) * 100
+ current_ratio = (outstanding_amount/security_value) * 100 if security_value else 0
if current_ratio > ltv_ratio:
shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
create_loan_security_shortfall(loan.name, outstanding_amount, security_value, shortfall_amount,
process_loan_security_shortfall)
+ elif loan_shortfall_map.get(loan.name):
+ shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
+ if shortfall_amount <= 0:
+ shortfall = loan_shortfall_map.get(loan.name)
+ update_pending_shortfall(shortfall)
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, process_loan_security_shortfall):
-
existing_shortfall = frappe.db.get_value("Loan Security Shortfall", {"loan": loan, "status": "Pending"}, "name")
if existing_shortfall:
@@ -102,3 +109,11 @@
ltv_ratio = frappe.db.get_value('Loan Security Type', loan_security_type, 'loan_to_value_ratio')
return ltv_ratio
+def update_pending_shortfall(shortfall):
+ # Get all pending loan security shortfall
+ frappe.db.set_value("Loan Security Shortfall", shortfall,
+ {
+ "status": "Completed",
+ "shortfall_amount": 0
+ })
+
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 b3eb600..c4c2d68 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
@@ -30,6 +30,8 @@
d.idx, frappe.bold(d.loan_security)))
def validate_unpledge_qty(self):
+ from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import get_ltv_ratio
+
pledge_qty_map = get_pledged_security_qty(self.loan)
ltv_ratio_map = frappe._dict(frappe.get_all("Loan Security Type",
@@ -42,33 +44,53 @@
"valid_upto": (">=", get_datetime())
}, as_list=1))
- total_payment, principal_paid, interest_payable = frappe.get_value("Loan", self.loan, ['total_payment', 'total_principal_paid',
- 'total_interest_payable'])
+ loan_details = frappe.get_value("Loan", self.loan, ['total_payment', 'total_principal_paid',
+ 'total_interest_payable', 'written_off_amount', 'disbursed_amount', 'status'], as_dict=1)
- pending_principal_amount = flt(total_payment) - flt(interest_payable) - flt(principal_paid)
+ if loan_details.status == 'Disbursed':
+ pending_principal_amount = flt(loan_details.total_payment) - flt(loan_details.total_interest_payable) \
+ - flt(loan_details.total_principal_paid) - flt(loan_details.written_off_amount)
+ else:
+ pending_principal_amount = flt(loan_details.disbursed_amount) - flt(loan_details.total_interest_payable) \
+ - flt(loan_details.total_principal_paid) - flt(loan_details.written_off_amount)
+
security_value = 0
+ unpledge_qty_map = {}
+ ltv_ratio = 0
for security in self.securities:
pledged_qty = pledge_qty_map.get(security.loan_security, 0)
if security.qty > pledged_qty:
- frappe.throw(_("""Row {0}: {1} {2} of {3} is pledged against Loan {4}.
- You are trying to unpledge more""").format(security.idx, pledged_qty, security.uom,
- frappe.bold(security.loan_security), frappe.bold(self.loan)))
+ msg = _("Row {0}: {1} {2} of {3} is pledged against Loan {4}.").format(security.idx, pledged_qty, security.uom,
+ frappe.bold(security.loan_security), frappe.bold(self.loan))
+ msg += "<br>"
+ msg += _("You are trying to unpledge more.")
+ frappe.throw(msg, title=_("Loan Security Unpledge Error"))
- qty_after_unpledge = pledged_qty - security.qty
- ltv_ratio = ltv_ratio_map.get(security.loan_security_type)
+ unpledge_qty_map.setdefault(security.loan_security, 0)
+ unpledge_qty_map[security.loan_security] += security.qty
- current_price = loan_security_price_map.get(security.loan_security)
- if not current_price:
- frappe.throw(_("No valid Loan Security Price found for {0}").format(frappe.bold(security.loan_security)))
+ for security in pledge_qty_map:
+ if not ltv_ratio:
+ ltv_ratio = get_ltv_ratio(security)
+ qty_after_unpledge = pledge_qty_map.get(security, 0) - unpledge_qty_map.get(security, 0)
+ current_price = loan_security_price_map.get(security)
security_value += qty_after_unpledge * current_price
if not security_value and flt(pending_principal_amount, 2) > 0:
- frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
+ self._throw(security_value, pending_principal_amount, ltv_ratio)
if security_value and flt(pending_principal_amount/security_value) * 100 > ltv_ratio:
- frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
+ self._throw(security_value, pending_principal_amount, ltv_ratio)
+
+ def _throw(self, security_value, pending_principal_amount, ltv_ratio):
+ msg = _("Loan Security Value after unpledge is {0}").format(frappe.bold(security_value))
+ msg += '<br>'
+ msg += _("Pending principal amount is {0}").format(frappe.bold(flt(pending_principal_amount, 2)))
+ msg += '<br>'
+ msg += _("Loan To Security Value ratio must always be {0}").format(frappe.bold(ltv_ratio))
+ frappe.throw(msg, title=_("Loan To Value ratio breach"))
def on_update_after_submit(self):
self.approve()
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json
index 669490a..3ef5304 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type.json
+++ b/erpnext/loan_management/doctype/loan_type/loan_type.json
@@ -11,6 +11,7 @@
"rate_of_interest",
"penalty_interest_rate",
"grace_period_in_days",
+ "write_off_amount",
"column_break_2",
"company",
"is_term_loan",
@@ -76,7 +77,6 @@
"reqd": 1
},
{
- "description": "This account is used for booking loan repayments from the borrower and also disbursing loans to the borrower",
"fieldname": "payment_account",
"fieldtype": "Link",
"label": "Payment Account",
@@ -84,7 +84,6 @@
"reqd": 1
},
{
- "description": "This account is capital account which is used to allocate capital for loan disbursal account ",
"fieldname": "loan_account",
"fieldtype": "Link",
"label": "Loan Account",
@@ -96,7 +95,6 @@
"fieldtype": "Column Break"
},
{
- "description": "This account will be used for booking loan interest accruals",
"fieldname": "interest_income_account",
"fieldtype": "Link",
"label": "Interest Income Account",
@@ -104,7 +102,6 @@
"reqd": 1
},
{
- "description": "This account will be used for booking penalties levied due to delayed repayments",
"fieldname": "penalty_income_account",
"fieldtype": "Link",
"label": "Penalty Income Account",
@@ -113,7 +110,6 @@
},
{
"default": "0",
- "description": "If this is not checked the loan by default will be considered as a Demand Loan",
"fieldname": "is_term_loan",
"fieldtype": "Check",
"label": "Is Term Loan"
@@ -145,17 +141,27 @@
"label": "Company",
"options": "Company",
"reqd": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "description": "Loan Write Off will be automatically created on loan closure request if pending amount is below this limit",
+ "fieldname": "write_off_amount",
+ "fieldtype": "Currency",
+ "label": "Auto Write Off Amount ",
+ "options": "Company:company:default_currency"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-06-07 18:55:59.346292",
+ "modified": "2021-01-17 06:51:26.082879",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Type",
"owner": "Administrator",
"permissions": [
{
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -165,6 +171,7 @@
"report": 1,
"role": "Loan Manager",
"share": 1,
+ "submit": 1,
"write": 1
},
{
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/loan_management/doctype/loan_write_off/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/loan_management/doctype/loan_write_off/__init__.py
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.js b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.js
new file mode 100644
index 0000000..4e3319c
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.js
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+{% include 'erpnext/loan_management/loan_common.js' %};
+
+frappe.ui.form.on('Loan Write Off', {
+ loan: function(frm) {
+ frm.trigger('show_pending_principal_amount');
+ },
+ onload: function(frm) {
+ frm.trigger('show_pending_principal_amount');
+ },
+ refresh: function(frm) {
+ frm.set_query('write_off_account', function(){
+ return {
+ filters: {
+ 'company': frm.doc.company,
+ 'root_type': 'Expense',
+ 'is_group': 0
+ }
+ }
+ });
+ },
+ show_pending_principal_amount: function(frm) {
+ if (frm.doc.loan && frm.doc.docstatus === 0) {
+ frappe.db.get_value('Loan', frm.doc.loan, ['total_payment', 'total_interest_payable',
+ 'total_principal_paid', 'written_off_amount'], function(values) {
+ frm.set_df_property('write_off_amount', 'description',
+ "Pending principal amount is " + cstr(flt(values.total_payment - values.total_interest_payable
+ - values.total_principal_paid - values.written_off_amount, 2)));
+ frm.refresh_field('write_off_amount');
+ });
+
+ }
+ }
+});
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.json b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.json
new file mode 100644
index 0000000..4617a62
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.json
@@ -0,0 +1,157 @@
+{
+ "actions": [],
+ "autoname": "LM-WO-.#####",
+ "creation": "2020-10-16 11:09:14.495066",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "loan",
+ "applicant_type",
+ "applicant",
+ "column_break_3",
+ "company",
+ "posting_date",
+ "accounting_dimensions_section",
+ "cost_center",
+ "section_break_9",
+ "write_off_account",
+ "column_break_11",
+ "write_off_amount",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "loan",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Loan",
+ "options": "Loan",
+ "reqd": 1
+ },
+ {
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "loan.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fetch_from": "loan.applicant_type",
+ "fieldname": "applicant_type",
+ "fieldtype": "Select",
+ "label": "Applicant Type",
+ "options": "Employee\nMember\nCustomer",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "loan.applicant",
+ "fieldname": "applicant",
+ "fieldtype": "Dynamic Link",
+ "label": "Applicant ",
+ "options": "applicant_type",
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
+ {
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break",
+ "label": "Write Off Details"
+ },
+ {
+ "fieldname": "write_off_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Write Off Account",
+ "options": "Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "write_off_amount",
+ "fieldtype": "Currency",
+ "label": "Write Off Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Loan Write Off",
+ "print_hide": 1,
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-10-26 07:13:43.663924",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Write Off",
+ "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": "Loan Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..54a3f2c
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
@@ -0,0 +1,88 @@
+# -*- 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, erpnext
+from frappe import _
+from frappe.utils import getdate, flt, cint
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.accounts.general_ledger import make_gl_entries
+
+class LoanWriteOff(AccountsController):
+ def validate(self):
+ self.set_missing_values()
+ self.validate_write_off_amount()
+
+ def set_missing_values(self):
+ if not self.cost_center:
+ self.cost_center = erpnext.get_default_cost_center(self.company)
+
+ def validate_write_off_amount(self):
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
+ total_payment, principal_paid, interest_payable, written_off_amount = frappe.get_value("Loan", self.loan,
+ ['total_payment', 'total_principal_paid','total_interest_payable', 'written_off_amount'])
+
+ pending_principal_amount = flt(flt(total_payment) - flt(interest_payable) - flt(principal_paid) - flt(written_off_amount),
+ precision)
+
+ if self.write_off_amount > pending_principal_amount:
+ frappe.throw(_("Write off amount cannot be greater than pending principal amount"))
+
+ def on_submit(self):
+ self.update_outstanding_amount()
+ self.make_gl_entries()
+
+ def on_cancel(self):
+ self.update_outstanding_amount(cancel=1)
+ self.ignore_linked_doctypes = ['GL Entry']
+ self.make_gl_entries(cancel=1)
+
+ def update_outstanding_amount(self, cancel=0):
+ written_off_amount = frappe.db.get_value('Loan', self.loan, 'written_off_amount')
+
+ if cancel:
+ written_off_amount -= self.write_off_amount
+ else:
+ written_off_amount += self.write_off_amount
+
+ frappe.db.set_value('Loan', self.loan, 'written_off_amount', written_off_amount)
+
+
+ def make_gl_entries(self, cancel=0):
+ gl_entries = []
+ loan_details = frappe.get_doc("Loan", self.loan)
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.write_off_account,
+ "against": loan_details.loan_account,
+ "debit": self.write_off_amount,
+ "debit_in_account_currency": self.write_off_amount,
+ "against_voucher_type": "Loan",
+ "against_voucher": self.loan,
+ "remarks": _("Against Loan:") + self.loan,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(self.posting_date)
+ })
+ )
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": loan_details.loan_account,
+ "party_type": loan_details.applicant_type,
+ "party": loan_details.applicant,
+ "against": self.write_off_account,
+ "credit": self.write_off_amount,
+ "credit_in_account_currency": self.write_off_amount,
+ "against_voucher_type": "Loan",
+ "against_voucher": self.loan,
+ "remarks": _("Against Loan:") + self.loan,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(self.posting_date)
+ })
+ )
+
+ make_gl_entries(gl_entries, cancel=cancel, merge_entries=False)
+
+
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
index 2ad7984..9f6700e 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestLoanWriteOff(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/pledge/pledge.json b/erpnext/loan_management/doctype/pledge/pledge.json
index f22a21e..c23479c 100644
--- a/erpnext/loan_management/doctype/pledge/pledge.json
+++ b/erpnext/loan_management/doctype/pledge/pledge.json
@@ -1,10 +1,12 @@
{
+ "actions": [],
"creation": "2019-09-09 17:06:16.756573",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"loan_security",
+ "loan_security_name",
"loan_security_type",
"loan_security_code",
"uom",
@@ -49,7 +51,8 @@
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Quantity"
+ "label": "Quantity",
+ "non_negative": 1
},
{
"fieldname": "loan_security_price",
@@ -83,10 +86,18 @@
"label": "Post Haircut Amount",
"options": "Company:company:default_currency",
"read_only": 1
+ },
+ {
+ "fetch_from": "loan_security.loan_security_name",
+ "fieldname": "loan_security_name",
+ "fieldtype": "Data",
+ "label": "Loan Security Name",
+ "read_only": 1
}
],
"istable": 1,
- "modified": "2019-12-03 10:59:58.001421",
+ "links": [],
+ "modified": "2021-01-17 07:41:12.452514",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Pledge",
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
index 0ef098f..828df2e 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
@@ -10,6 +10,7 @@
"loan_type",
"loan",
"process_type",
+ "accrual_type",
"amended_from"
],
"fields": [
@@ -47,17 +48,27 @@
"hidden": 1,
"label": "Process Type",
"read_only": 1
+ },
+ {
+ "fieldname": "accrual_type",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Accrual Type",
+ "options": "Regular\nRepayment\nDisbursement",
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-04-09 22:52:53.911416",
+ "modified": "2020-11-06 13:28:51.478909",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Process Loan Interest Accrual",
"owner": "Administrator",
"permissions": [
{
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -67,9 +78,11 @@
"report": 1,
"role": "System Manager",
"share": 1,
+ "submit": 1,
"write": 1
},
{
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -79,6 +92,7 @@
"report": 1,
"role": "Loan Manager",
"share": 1,
+ "submit": 1,
"write": 1
}
],
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 0fa9686..11333dc 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
@@ -20,19 +20,20 @@
if (not self.loan or not loan_doc.is_term_loan) and self.process_type != 'Term Loans':
make_accrual_interest_entry_for_demand_loans(self.posting_date, self.name,
- open_loans = open_loans, loan_type = self.loan_type)
+ open_loans = open_loans, loan_type = self.loan_type, accrual_type=self.accrual_type)
if (not self.loan or loan_doc.is_term_loan) and self.process_type != 'Demand Loans':
make_accrual_interest_entry_for_term_loans(self.posting_date, self.name, term_loan=self.loan,
- loan_type=self.loan_type)
+ loan_type=self.loan_type, accrual_type=self.accrual_type)
-def process_loan_interest_accrual_for_demand_loans(posting_date=None, loan_type=None, loan=None):
+def process_loan_interest_accrual_for_demand_loans(posting_date=None, loan_type=None, loan=None, accrual_type="Regular"):
loan_process = frappe.new_doc('Process Loan Interest Accrual')
loan_process.posting_date = posting_date or nowdate()
loan_process.loan_type = loan_type
loan_process.process_type = 'Demand Loans'
loan_process.loan = loan
+ loan_process.accrual_type = accrual_type
loan_process.submit()
diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.json b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.json
index ffc3671..3feb305 100644
--- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.json
+++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.json
@@ -30,7 +30,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-02-01 08:14:05.845161",
+ "modified": "2021-01-17 03:59:14.494557",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Process Loan Security Shortfall",
@@ -45,7 +45,9 @@
"read": 1,
"report": 1,
"role": "System Manager",
+ "select": 1,
"share": 1,
+ "submit": 1,
"write": 1
},
{
@@ -57,7 +59,9 @@
"read": 1,
"report": 1,
"role": "Loan Manager",
+ "select": 1,
"share": 1,
+ "submit": 1,
"write": 1
}
],
diff --git a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json
index aee7c2c..a0b3a79 100644
--- a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json
+++ b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json
@@ -1,10 +1,12 @@
{
+ "actions": [],
"creation": "2019-08-29 22:29:37.628178",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"loan_security",
+ "loan_security_name",
"qty",
"loan_security_price",
"amount",
@@ -39,7 +41,8 @@
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Quantity"
+ "label": "Quantity",
+ "non_negative": 1
},
{
"fieldname": "loan_security",
@@ -54,10 +57,19 @@
"label": "Post Haircut Amount",
"options": "Company:company:default_currency",
"read_only": 1
+ },
+ {
+ "fetch_from": "loan_security.loan_security_name",
+ "fieldname": "loan_security_name",
+ "fieldtype": "Data",
+ "label": "Loan Security Name",
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-12-02 10:23:11.498308",
+ "links": [],
+ "modified": "2021-01-17 07:29:01.671722",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Proposed Pledge",
diff --git a/erpnext/loan_management/doctype/unpledge/unpledge.json b/erpnext/loan_management/doctype/unpledge/unpledge.json
index ee192d7..0091e6c 100644
--- a/erpnext/loan_management/doctype/unpledge/unpledge.json
+++ b/erpnext/loan_management/doctype/unpledge/unpledge.json
@@ -6,6 +6,7 @@
"engine": "InnoDB",
"field_order": [
"loan_security",
+ "loan_security_name",
"loan_security_type",
"loan_security_code",
"haircut",
@@ -52,6 +53,7 @@
"fieldtype": "Float",
"in_list_view": 1,
"label": "Quantity",
+ "non_negative": 1,
"reqd": 1
},
{
@@ -60,11 +62,19 @@
"fieldtype": "Percent",
"label": "Haircut",
"read_only": 1
+ },
+ {
+ "fetch_from": "loan_security.loan_security_name",
+ "fieldname": "loan_security_name",
+ "fieldtype": "Data",
+ "label": "Loan Security Name",
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-06 10:50:18.448552",
+ "modified": "2021-01-17 07:36:20.212342",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Unpledge",
diff --git a/erpnext/loan_management/loan_common.js b/erpnext/loan_management/loan_common.js
index d9dd415..50b68da 100644
--- a/erpnext/loan_management/loan_common.js
+++ b/erpnext/loan_management/loan_common.js
@@ -8,14 +8,14 @@
frm.refresh_field('applicant_type');
}
- if (['Loan Disbursement', 'Loan Repayment', 'Loan Interest Accrual'].includes(frm.doc.doctype)
+ if (['Loan Disbursement', 'Loan Repayment', 'Loan Interest Accrual', 'Loan Write Off'].includes(frm.doc.doctype)
&& frm.doc.docstatus > 0) {
frm.add_custom_button(__("Accounting Ledger"), function() {
frappe.route_options = {
voucher_no: frm.doc.name,
company: frm.doc.company,
- from_date: frm.doc.posting_date,
+ from_date: moment(frm.doc.posting_date).format('YYYY-MM-DD'),
to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
show_cancelled_entries: frm.doc.docstatus === 2
};
diff --git a/erpnext/loan_management/loan_management_dashboard/loan_dashboard/loan_dashboard.json b/erpnext/loan_management/loan_management_dashboard/loan_dashboard/loan_dashboard.json
new file mode 100644
index 0000000..e060253
--- /dev/null
+++ b/erpnext/loan_management/loan_management_dashboard/loan_dashboard/loan_dashboard.json
@@ -0,0 +1,70 @@
+{
+ "cards": [
+ {
+ "card": "New Loans"
+ },
+ {
+ "card": "Active Loans"
+ },
+ {
+ "card": "Closed Loans"
+ },
+ {
+ "card": "Total Disbursed"
+ },
+ {
+ "card": "Open Loan Applications"
+ },
+ {
+ "card": "New Loan Applications"
+ },
+ {
+ "card": "Total Sanctioned Amount"
+ },
+ {
+ "card": "Active Securities"
+ },
+ {
+ "card": "Applicants With Unpaid Shortfall"
+ },
+ {
+ "card": "Total Shortfall Amount"
+ },
+ {
+ "card": "Total Repayment"
+ },
+ {
+ "card": "Total Write Off"
+ }
+ ],
+ "charts": [
+ {
+ "chart": "New Loans",
+ "width": "Half"
+ },
+ {
+ "chart": "Loan Disbursements",
+ "width": "Half"
+ },
+ {
+ "chart": "Top 10 Pledged Loan Securities",
+ "width": "Half"
+ },
+ {
+ "chart": "Loan Interest Accrual",
+ "width": "Half"
+ }
+ ],
+ "creation": "2021-02-06 16:52:43.484752",
+ "dashboard_name": "Loan Dashboard",
+ "docstatus": 0,
+ "doctype": "Dashboard",
+ "idx": 0,
+ "is_default": 0,
+ "is_standard": 1,
+ "modified": "2021-02-21 20:53:47.531699",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Dashboard",
+ "owner": "Administrator"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/active_loans/active_loans.json b/erpnext/loan_management/number_card/active_loans/active_loans.json
new file mode 100644
index 0000000..7e0db47
--- /dev/null
+++ b/erpnext/loan_management/number_card/active_loans/active_loans.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "",
+ "creation": "2021-02-06 17:10:26.132493",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan\",\"docstatus\",\"=\",\"1\",false],[\"Loan\",\"status\",\"in\",[\"Disbursed\",\"Partially Disbursed\",null],false]]",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Active Loans",
+ "modified": "2021-02-06 17:29:20.304087",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Active Loans",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/active_securities/active_securities.json b/erpnext/loan_management/number_card/active_securities/active_securities.json
new file mode 100644
index 0000000..298e410
--- /dev/null
+++ b/erpnext/loan_management/number_card/active_securities/active_securities.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "",
+ "creation": "2021-02-06 19:07:21.344199",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Security",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Security\",\"disabled\",\"=\",0,false]]",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Active Securities",
+ "modified": "2021-02-06 19:07:26.671516",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Active Securities",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/applicants_with_unpaid_shortfall/applicants_with_unpaid_shortfall.json b/erpnext/loan_management/number_card/applicants_with_unpaid_shortfall/applicants_with_unpaid_shortfall.json
new file mode 100644
index 0000000..3b9eba1
--- /dev/null
+++ b/erpnext/loan_management/number_card/applicants_with_unpaid_shortfall/applicants_with_unpaid_shortfall.json
@@ -0,0 +1,21 @@
+{
+ "creation": "2021-02-07 18:55:12.632616",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "filters_json": "null",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Applicants With Unpaid Shortfall",
+ "method": "erpnext.loan_management.doctype.loan.loan.get_shortfall_applicants",
+ "modified": "2021-02-07 21:46:27.369795",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Applicants With Unpaid Shortfall",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Custom"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/closed_loans/closed_loans.json b/erpnext/loan_management/number_card/closed_loans/closed_loans.json
new file mode 100644
index 0000000..c2f2244
--- /dev/null
+++ b/erpnext/loan_management/number_card/closed_loans/closed_loans.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "",
+ "creation": "2021-02-21 19:51:49.261813",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan\",\"docstatus\",\"=\",\"1\",false],[\"Loan\",\"status\",\"=\",\"Closed\",false]]",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Closed Loans",
+ "modified": "2021-02-21 19:51:54.087903",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Closed Loans",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/last_interest_accrual/last_interest_accrual.json b/erpnext/loan_management/number_card/last_interest_accrual/last_interest_accrual.json
new file mode 100644
index 0000000..65c8ce6
--- /dev/null
+++ b/erpnext/loan_management/number_card/last_interest_accrual/last_interest_accrual.json
@@ -0,0 +1,21 @@
+{
+ "creation": "2021-02-07 21:57:14.758007",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "filters_json": "null",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Last Interest Accrual",
+ "method": "erpnext.loan_management.doctype.loan.loan.get_last_accrual_date",
+ "modified": "2021-02-07 21:59:47.525197",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Last Interest Accrual",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Custom"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/new_loan_applications/new_loan_applications.json b/erpnext/loan_management/number_card/new_loan_applications/new_loan_applications.json
new file mode 100644
index 0000000..7e655ff
--- /dev/null
+++ b/erpnext/loan_management/number_card/new_loan_applications/new_loan_applications.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "",
+ "creation": "2021-02-06 17:59:10.051269",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Application",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Application\",\"docstatus\",\"=\",\"1\",false],[\"Loan Application\",\"creation\",\"Timespan\",\"today\",false]]",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "New Loan Applications",
+ "modified": "2021-02-06 17:59:21.880979",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "New Loan Applications",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/new_loans/new_loans.json b/erpnext/loan_management/number_card/new_loans/new_loans.json
new file mode 100644
index 0000000..424f0f1
--- /dev/null
+++ b/erpnext/loan_management/number_card/new_loans/new_loans.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "",
+ "creation": "2021-02-06 17:56:34.624031",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan\",\"docstatus\",\"=\",\"1\",false],[\"Loan\",\"creation\",\"Timespan\",\"today\",false]]",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "New Loans",
+ "modified": "2021-02-06 17:58:20.209166",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "New Loans",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/open_loan_applications/open_loan_applications.json b/erpnext/loan_management/number_card/open_loan_applications/open_loan_applications.json
new file mode 100644
index 0000000..1d5e84e
--- /dev/null
+++ b/erpnext/loan_management/number_card/open_loan_applications/open_loan_applications.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "",
+ "creation": "2021-02-06 17:23:32.509899",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Application",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Application\",\"docstatus\",\"=\",\"1\",false],[\"Loan Application\",\"status\",\"=\",\"Open\",false]]",
+ "function": "Count",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Open Loan Applications",
+ "modified": "2021-02-06 17:29:09.761011",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Open Loan Applications",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/total_disbursed/total_disbursed.json b/erpnext/loan_management/number_card/total_disbursed/total_disbursed.json
new file mode 100644
index 0000000..4a3f869
--- /dev/null
+++ b/erpnext/loan_management/number_card/total_disbursed/total_disbursed.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "disbursed_amount",
+ "creation": "2021-02-06 16:52:19.505462",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Disbursement",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Disbursement\",\"docstatus\",\"=\",\"1\",false]]",
+ "function": "Sum",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Total Disbursed Amount",
+ "modified": "2021-02-06 17:29:38.453870",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Total Disbursed",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/total_repayment/total_repayment.json b/erpnext/loan_management/number_card/total_repayment/total_repayment.json
new file mode 100644
index 0000000..38de42b
--- /dev/null
+++ b/erpnext/loan_management/number_card/total_repayment/total_repayment.json
@@ -0,0 +1,24 @@
+{
+ "aggregate_function_based_on": "amount_paid",
+ "color": "#29CD42",
+ "creation": "2021-02-21 19:27:45.989222",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Repayment",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Repayment\",\"docstatus\",\"=\",\"1\",false]]",
+ "function": "Sum",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Total Repayment",
+ "modified": "2021-02-21 19:34:59.656546",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Total Repayment",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/total_sanctioned_amount/total_sanctioned_amount.json b/erpnext/loan_management/number_card/total_sanctioned_amount/total_sanctioned_amount.json
new file mode 100644
index 0000000..dfb9d24
--- /dev/null
+++ b/erpnext/loan_management/number_card/total_sanctioned_amount/total_sanctioned_amount.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "loan_amount",
+ "creation": "2021-02-06 17:05:04.704162",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan\",\"docstatus\",\"=\",\"1\",false],[\"Loan\",\"status\",\"=\",\"Sanctioned\",false]]",
+ "function": "Sum",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Total Sanctioned Amount",
+ "modified": "2021-02-06 17:29:29.930557",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Total Sanctioned Amount",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/total_shortfall_amount/total_shortfall_amount.json b/erpnext/loan_management/number_card/total_shortfall_amount/total_shortfall_amount.json
new file mode 100644
index 0000000..aa6b093
--- /dev/null
+++ b/erpnext/loan_management/number_card/total_shortfall_amount/total_shortfall_amount.json
@@ -0,0 +1,23 @@
+{
+ "aggregate_function_based_on": "shortfall_amount",
+ "creation": "2021-02-09 08:07:20.096995",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Security Shortfall",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[]",
+ "function": "Sum",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Total Unpaid Shortfall Amount",
+ "modified": "2021-02-09 08:09:00.355547",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Total Shortfall Amount",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/number_card/total_write_off/total_write_off.json b/erpnext/loan_management/number_card/total_write_off/total_write_off.json
new file mode 100644
index 0000000..c85169a
--- /dev/null
+++ b/erpnext/loan_management/number_card/total_write_off/total_write_off.json
@@ -0,0 +1,24 @@
+{
+ "aggregate_function_based_on": "write_off_amount",
+ "color": "#CB2929",
+ "creation": "2021-02-21 19:48:29.004429",
+ "docstatus": 0,
+ "doctype": "Number Card",
+ "document_type": "Loan Write Off",
+ "dynamic_filters_json": "[]",
+ "filters_json": "[[\"Loan Write Off\",\"docstatus\",\"=\",\"1\",false]]",
+ "function": "Sum",
+ "idx": 0,
+ "is_public": 0,
+ "is_standard": 1,
+ "label": "Total Write Off",
+ "modified": "2021-02-21 19:48:58.604159",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Total Write Off",
+ "owner": "Administrator",
+ "report_function": "Sum",
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Daily",
+ "type": "Document Type"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/loan_management/report/applicant_wise_loan_security_exposure/__init__.py
diff --git a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.js b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.js
new file mode 100644
index 0000000..73d60c4
--- /dev/null
+++ b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Applicant-Wise Loan Security Exposure"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ }
+ ]
+};
diff --git a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.json b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.json
new file mode 100644
index 0000000..a778cd7
--- /dev/null
+++ b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.json
@@ -0,0 +1,29 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-01-15 23:48:38.913514",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-01-15 23:48:38.913514",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Applicant-Wise Loan Security Exposure",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Loan Security",
+ "report_name": "Applicant-Wise Loan Security Exposure",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "System Manager"
+ },
+ {
+ "role": "Loan Manager"
+ }
+ ]
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..0ccd149
--- /dev/null
+++ b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
@@ -0,0 +1,139 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import erpnext
+from frappe import _
+from frappe.utils import get_datetime, flt
+from six import iteritems
+
+def execute(filters=None):
+ columns = get_columns(filters)
+ data = get_data(filters)
+ return columns, data
+
+
+def get_columns(filters):
+ columns = [
+ {"label": _("Applicant Type"), "fieldname": "applicant_type", "options": "DocType", "width": 100},
+ {"label": _("Applicant Name"), "fieldname": "applicant_name", "fieldtype": "Dynamic Link", "options": "applicant_type", "width": 150},
+ {"label": _("Loan Security"), "fieldname": "loan_security", "fieldtype": "Link", "options": "Loan Security", "width": 160},
+ {"label": _("Loan Security Code"), "fieldname": "loan_security_code", "fieldtype": "Data", "width": 100},
+ {"label": _("Loan Security Name"), "fieldname": "loan_security_name", "fieldtype": "Data", "width": 150},
+ {"label": _("Haircut"), "fieldname": "haircut", "fieldtype": "Percent", "width": 100},
+ {"label": _("Loan Security Type"), "fieldname": "loan_security_type", "fieldtype": "Link", "options": "Loan Security Type", "width": 120},
+ {"label": _("Disabled"), "fieldname": "disabled", "fieldtype": "Check", "width": 80},
+ {"label": _("Total Qty"), "fieldname": "total_qty", "fieldtype": "Float", "width": 100},
+ {"label": _("Latest Price"), "fieldname": "latest_price", "fieldtype": "Currency", "options": "currency", "width": 100},
+ {"label": _("Price Valid Upto"), "fieldname": "price_valid_upto", "fieldtype": "Datetime", "width": 100},
+ {"label": _("Current Value"), "fieldname": "current_value", "fieldtype": "Currency", "options": "currency", "width": 100},
+ {"label": _("% Of Applicant Portfolio"), "fieldname": "portfolio_percent", "fieldtype": "Percentage", "width": 100},
+ {"label": _("Currency"), "fieldname": "currency", "fieldtype": "Currency", "options": "Currency", "hidden": 1, "width": 100},
+ ]
+
+ return columns
+
+def get_data(filters):
+ data = []
+ loan_security_details = get_loan_security_details()
+ pledge_values, total_value_map, applicant_type_map = get_applicant_wise_total_loan_security_qty(filters,
+ loan_security_details)
+
+ currency = erpnext.get_company_currency(filters.get('company'))
+
+ for key, qty in iteritems(pledge_values):
+ if qty:
+ row = {}
+ current_value = flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0))
+ valid_upto = loan_security_details.get(key[1], {}).get('valid_upto')
+
+ row.update(loan_security_details.get(key[1]))
+ row.update({
+ 'applicant_type': applicant_type_map.get(key[0]),
+ 'applicant_name': key[0],
+ 'total_qty': qty,
+ 'current_value': current_value,
+ 'price_valid_upto': valid_upto,
+ 'portfolio_percent': flt(current_value * 100 / total_value_map.get(key[0]), 2) if total_value_map.get(key[0]) \
+ else 0.0,
+ 'currency': currency
+ })
+
+ data.append(row)
+
+ return data
+
+def get_loan_security_details():
+ security_detail_map = {}
+ loan_security_price_map = {}
+ lsp_validity_map = {}
+
+ loan_security_prices = frappe.db.sql("""
+ SELECT loan_security, loan_security_price, valid_upto
+ FROM `tabLoan Security Price` t1
+ WHERE valid_from >= (SELECT MAX(valid_from) FROM `tabLoan Security Price` t2
+ WHERE t1.loan_security = t2.loan_security)
+ """, as_dict=1)
+
+ for security in loan_security_prices:
+ loan_security_price_map.setdefault(security.loan_security, security.loan_security_price)
+ lsp_validity_map.setdefault(security.loan_security, security.valid_upto)
+
+ loan_security_details = frappe.get_all('Loan Security', fields=['name as loan_security',
+ 'loan_security_code', 'loan_security_name', 'haircut', 'loan_security_type',
+ 'disabled'])
+
+ for security in loan_security_details:
+ security.update({
+ 'latest_price': flt(loan_security_price_map.get(security.loan_security)),
+ 'valid_upto': lsp_validity_map.get(security.loan_security)
+ })
+
+ security_detail_map.setdefault(security.loan_security, security)
+
+ return security_detail_map
+
+def get_applicant_wise_total_loan_security_qty(filters, loan_security_details):
+ current_pledges = {}
+ total_value_map = {}
+ applicant_type_map = {}
+ applicant_wise_unpledges = {}
+ conditions = ""
+
+ if filters.get('company'):
+ conditions = "AND company = %(company)s"
+
+ unpledges = frappe.db.sql("""
+ SELECT up.applicant, u.loan_security, sum(u.qty) as qty
+ FROM `tabLoan Security Unpledge` up, `tabUnpledge` u
+ WHERE u.parent = up.name
+ AND up.status = 'Approved'
+ {conditions}
+ GROUP BY up.applicant, u.loan_security
+ """.format(conditions=conditions), filters, as_dict=1)
+
+ for unpledge in unpledges:
+ applicant_wise_unpledges.setdefault((unpledge.applicant, unpledge.loan_security), unpledge.qty)
+
+ pledges = frappe.db.sql("""
+ SELECT lp.applicant_type, lp.applicant, p.loan_security, sum(p.qty) as qty
+ FROM `tabLoan Security Pledge` lp, `tabPledge`p
+ WHERE p.parent = lp.name
+ AND lp.status = 'Pledged'
+ {conditions}
+ GROUP BY lp.applicant, p.loan_security
+ """.format(conditions=conditions), filters, as_dict=1)
+
+ for security in pledges:
+ current_pledges.setdefault((security.applicant, security.loan_security), security.qty)
+ total_value_map.setdefault(security.applicant, 0.0)
+ applicant_type_map.setdefault(security.applicant, security.applicant_type)
+
+ current_pledges[(security.applicant, security.loan_security)] -= \
+ applicant_wise_unpledges.get((security.applicant, security.loan_security), 0.0)
+
+ total_value_map[security.applicant] += current_pledges.get((security.applicant, security.loan_security)) \
+ * loan_security_details.get(security.loan_security, {}).get('latest_price', 0)
+
+ return current_pledges, total_value_map, applicant_type_map
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/loan_management/report/loan_interest_report/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/loan_management/report/loan_interest_report/__init__.py
diff --git a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.js b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.js
new file mode 100644
index 0000000..a227b6d
--- /dev/null
+++ b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Loan Interest Report"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ }
+ ]
+};
diff --git a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.json b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.json
new file mode 100644
index 0000000..321d606
--- /dev/null
+++ b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.json
@@ -0,0 +1,29 @@
+{
+ "add_total_row": 1,
+ "columns": [],
+ "creation": "2021-01-10 02:03:26.742693",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-01-10 02:03:26.742693",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Interest Report",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Loan Interest Accrual",
+ "report_name": "Loan Interest Report",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "System Manager"
+ },
+ {
+ "role": "Loan Manager"
+ }
+ ]
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..0f72c3c
--- /dev/null
+++ b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
@@ -0,0 +1,183 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import erpnext
+from frappe import _
+from frappe.utils import flt, getdate, add_days
+from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
+ import get_loan_security_details
+
+
+def execute(filters=None):
+ columns = get_columns(filters)
+ data = get_active_loan_details(filters)
+ return columns, data
+
+def get_columns(filters):
+ columns = [
+ {"label": _("Loan"), "fieldname": "loan", "fieldtype": "Link", "options": "Loan", "width": 160},
+ {"label": _("Status"), "fieldname": "status", "fieldtype": "Data", "width": 160},
+ {"label": _("Applicant Type"), "fieldname": "applicant_type", "options": "DocType", "width": 100},
+ {"label": _("Applicant Name"), "fieldname": "applicant_name", "fieldtype": "Dynamic Link", "options": "applicant_type", "width": 150},
+ {"label": _("Loan Type"), "fieldname": "loan_type", "fieldtype": "Link", "options": "Loan Type", "width": 100},
+ {"label": _("Sanctioned Amount"), "fieldname": "sanctioned_amount", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Disbursed Amount"), "fieldname": "disbursed_amount", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Penalty Amount"), "fieldname": "penalty", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Accrued Interest"), "fieldname": "accrued_interest", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Total Repayment"), "fieldname": "total_repayment", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Principal Outstanding"), "fieldname": "principal_outstanding", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Interest Outstanding"), "fieldname": "interest_outstanding", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Total Outstanding"), "fieldname": "total_outstanding", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Undue Booked Interest"), "fieldname": "undue_interest", "fieldtype": "Currency", "options": "currency", "width": 120},
+ {"label": _("Interest %"), "fieldname": "rate_of_interest", "fieldtype": "Percent", "width": 100},
+ {"label": _("Penalty Interest %"), "fieldname": "penalty_interest", "fieldtype": "Percent", "width": 100},
+ {"label": _("Loan To Value Ratio"), "fieldname": "loan_to_value", "fieldtype": "Percent", "width": 100},
+ {"label": _("Currency"), "fieldname": "currency", "fieldtype": "Currency", "options": "Currency", "hidden": 1, "width": 100},
+ ]
+
+ return columns
+
+def get_active_loan_details(filters):
+
+ filter_obj = {"status": ("!=", "Closed")}
+ if filters.get('company'):
+ filter_obj.update({'company': filters.get('company')})
+
+ loan_details = frappe.get_all("Loan",
+ fields=["name as loan", "applicant_type", "applicant as applicant_name", "loan_type",
+ "disbursed_amount", "rate_of_interest", "total_payment", "total_principal_paid",
+ "total_interest_payable", "written_off_amount", "status"],
+ filters=filter_obj)
+
+ loan_list = [d.loan for d in loan_details]
+
+ current_pledges = get_loan_wise_pledges(filters)
+ loan_wise_security_value = get_loan_wise_security_value(filters, current_pledges)
+
+ sanctioned_amount_map = get_sanctioned_amount_map()
+ penal_interest_rate_map = get_penal_interest_rate_map()
+ payments = get_payments(loan_list)
+ accrual_map = get_interest_accruals(loan_list)
+ currency = erpnext.get_company_currency(filters.get('company'))
+
+ for loan in loan_details:
+ loan.update({
+ "sanctioned_amount": flt(sanctioned_amount_map.get(loan.applicant_name)),
+ "principal_outstanding": flt(loan.total_payment) - flt(loan.total_principal_paid) \
+ - flt(loan.total_interest_payable) - flt(loan.written_off_amount),
+ "total_repayment": flt(payments.get(loan.loan)),
+ "accrued_interest": flt(accrual_map.get(loan.loan, {}).get("accrued_interest")),
+ "interest_outstanding": flt(accrual_map.get(loan.loan, {}).get("interest_outstanding")),
+ "penalty": flt(accrual_map.get(loan.loan, {}).get("penalty")),
+ "penalty_interest": penal_interest_rate_map.get(loan.loan_type),
+ "undue_interest": flt(accrual_map.get(loan.loan, {}).get("undue_interest")),
+ "loan_to_value": 0.0,
+ "currency": currency
+ })
+
+ loan['total_outstanding'] = loan['principal_outstanding'] + loan['interest_outstanding'] \
+ + loan['penalty']
+
+ if loan_wise_security_value.get(loan.loan):
+ loan['loan_to_value'] = flt((loan['principal_outstanding'] * 100) / loan_wise_security_value.get(loan.loan))
+
+ return loan_details
+
+def get_sanctioned_amount_map():
+ return frappe._dict(frappe.get_all("Sanctioned Loan Amount", fields=["applicant", "sanctioned_amount_limit"],
+ as_list=1))
+
+def get_payments(loans):
+ return frappe._dict(frappe.get_all("Loan Repayment", fields=["against_loan", "sum(amount_paid)"],
+ filters={"against_loan": ("in", loans)}, group_by="against_loan", as_list=1))
+
+def get_interest_accruals(loans):
+ accrual_map = {}
+
+ interest_accruals = frappe.get_all("Loan Interest Accrual",
+ fields=["loan", "interest_amount", "posting_date", "penalty_amount",
+ "paid_interest_amount", "accrual_type"], filters={"loan": ("in", loans)}, order_by="posting_date desc")
+
+ for entry in interest_accruals:
+ accrual_map.setdefault(entry.loan, {
+ "accrued_interest": 0.0,
+ "undue_interest": 0.0,
+ "interest_outstanding": 0.0,
+ "last_accrual_date": '',
+ "due_date": ''
+ })
+
+ if entry.accrual_type == 'Regular':
+ if not accrual_map[entry.loan]['due_date']:
+ accrual_map[entry.loan]['due_date'] = add_days(entry.posting_date, 1)
+ if not accrual_map[entry.loan]['last_accrual_date']:
+ accrual_map[entry.loan]['last_accrual_date'] = entry.posting_date
+
+ due_date = accrual_map[entry.loan]['due_date']
+ last_accrual_date = accrual_map[entry.loan]['last_accrual_date']
+
+ if due_date and getdate(entry.posting_date) < getdate(due_date):
+ accrual_map[entry.loan]["interest_outstanding"] += entry.interest_amount - entry.paid_interest_amount
+ else:
+ accrual_map[entry.loan]['undue_interest'] += entry.interest_amount - entry.paid_interest_amount
+
+ accrual_map[entry.loan]["accrued_interest"] += entry.interest_amount
+
+ if last_accrual_date and getdate(entry.posting_date) == last_accrual_date:
+ accrual_map[entry.loan]["penalty"] = entry.penalty_amount
+
+ return accrual_map
+
+def get_penal_interest_rate_map():
+ return frappe._dict(frappe.get_all("Loan Type", fields=["name", "penalty_interest_rate"], as_list=1))
+
+def get_loan_wise_pledges(filters):
+ loan_wise_unpledges = {}
+ current_pledges = {}
+
+ conditions = ""
+
+ if filters.get('company'):
+ conditions = "AND company = %(company)s"
+
+ unpledges = frappe.db.sql("""
+ SELECT up.loan, u.loan_security, sum(u.qty) as qty
+ FROM `tabLoan Security Unpledge` up, `tabUnpledge` u
+ WHERE u.parent = up.name
+ AND up.status = 'Approved'
+ {conditions}
+ GROUP BY up.loan, u.loan_security
+ """.format(conditions=conditions), filters, as_dict=1)
+
+ for unpledge in unpledges:
+ loan_wise_unpledges.setdefault((unpledge.loan, unpledge.loan_security), unpledge.qty)
+
+ pledges = frappe.db.sql("""
+ SELECT lp.loan, p.loan_security, sum(p.qty) as qty
+ FROM `tabLoan Security Pledge` lp, `tabPledge`p
+ WHERE p.parent = lp.name
+ AND lp.status = 'Pledged'
+ {conditions}
+ GROUP BY lp.loan, p.loan_security
+ """.format(conditions=conditions), filters, as_dict=1)
+
+ for security in pledges:
+ current_pledges.setdefault((security.loan, security.loan_security), security.qty)
+ current_pledges[(security.loan, security.loan_security)] -= \
+ loan_wise_unpledges.get((security.loan, security.loan_security), 0.0)
+
+ return current_pledges
+
+def get_loan_wise_security_value(filters, current_pledges):
+ loan_security_details = get_loan_security_details()
+ loan_wise_security_value = {}
+
+ for key in current_pledges:
+ qty = current_pledges.get(key)
+ loan_wise_security_value.setdefault(key[0], 0.0)
+ loan_wise_security_value[key[0]] += \
+ flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0))
+
+ return loan_wise_security_value
\ No newline at end of file
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 b63cc8e..c6f6b99 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
@@ -103,7 +103,7 @@
loan_repayments = frappe.get_all("Loan Repayment",
filters = query_filters,
- fields=["posting_date", "applicant", "name", "against_loan", "payment_type", "payable_amount",
+ fields=["posting_date", "applicant", "name", "against_loan", "payable_amount",
"pending_principal_amount", "interest_payable", "penalty_amount", "amount_paid"]
)
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/loan_management/report/loan_security_exposure/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/loan_management/report/loan_security_exposure/__init__.py
diff --git a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.js b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.js
new file mode 100644
index 0000000..777f296
--- /dev/null
+++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Loan Security Exposure"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ }
+ ]
+};
diff --git a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.json b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.json
new file mode 100644
index 0000000..d4dca08
--- /dev/null
+++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.json
@@ -0,0 +1,29 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-01-16 08:08:01.694583",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-01-16 08:08:01.694583",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Security Exposure",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Loan Security",
+ "report_name": "Loan Security Exposure",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "System Manager"
+ },
+ {
+ "role": "Loan Manager"
+ }
+ ]
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..887a86a
--- /dev/null
+++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
@@ -0,0 +1,84 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import erpnext
+from frappe import _
+from frappe.utils import flt
+from six import iteritems
+from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
+ import get_loan_security_details, get_applicant_wise_total_loan_security_qty
+
+def execute(filters=None):
+ columns = get_columns(filters)
+ data = get_data(filters)
+ return columns, data
+
+def get_columns(filters):
+ columns = [
+ {"label": _("Loan Security"), "fieldname": "loan_security", "fieldtype": "Link", "options": "Loan Security", "width": 160},
+ {"label": _("Loan Security Code"), "fieldname": "loan_security_code", "fieldtype": "Data", "width": 100},
+ {"label": _("Loan Security Name"), "fieldname": "loan_security_name", "fieldtype": "Data", "width": 150},
+ {"label": _("Haircut"), "fieldname": "haircut", "fieldtype": "Percent", "width": 100},
+ {"label": _("Loan Security Type"), "fieldname": "loan_security_type", "fieldtype": "Link", "options": "Loan Security Type", "width": 120},
+ {"label": _("Disabled"), "fieldname": "disabled", "fieldtype": "Check", "width": 80},
+ {"label": _("Total Qty"), "fieldname": "total_qty", "fieldtype": "Float", "width": 100},
+ {"label": _("Latest Price"), "fieldname": "latest_price", "fieldtype": "Currency", "options": "currency", "width": 100},
+ {"label": _("Price Valid Upto"), "fieldname": "price_valid_upto", "fieldtype": "Datetime", "width": 100},
+ {"label": _("Current Value"), "fieldname": "current_value", "fieldtype": "Currency", "options": "currency", "width": 100},
+ {"label": _("% Of Total Portfolio"), "fieldname": "portfolio_percent", "fieldtype": "Percentage", "width": 100},
+ {"label": _("Pledged Applicant Count"), "fieldname": "pledged_applicant_count", "fieldtype": "Percentage", "width": 100},
+ {"label": _("Currency"), "fieldname": "currency", "fieldtype": "Currency", "options": "Currency", "hidden": 1, "width": 100},
+ ]
+
+ return columns
+
+def get_data(filters):
+ data = []
+ loan_security_details = get_loan_security_details()
+ 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):
+ if value.get('qty'):
+ row = {}
+ current_value = flt(value.get('qty', 0) * loan_security_details.get(security, {}).get('latest_price', 0))
+ valid_upto = loan_security_details.get(security, {}).get('valid_upto')
+
+ row.update(loan_security_details.get(security))
+ row.update({
+ 'total_qty': value.get('qty'),
+ 'current_value': current_value,
+ 'price_valid_upto': valid_upto,
+ 'portfolio_percent': flt(current_value * 100 / total_portfolio_value, 2),
+ 'pledged_applicant_count': value.get('applicant_count'),
+ 'currency': currency
+ })
+
+ data.append(row)
+
+ return data
+
+
+def get_company_wise_loan_security_details(filters, loan_security_details):
+ pledge_values, total_value_map, applicant_type_map = get_applicant_wise_total_loan_security_qty(filters,
+ loan_security_details)
+
+ total_portfolio_value = 0
+ security_wise_map = {}
+ for key, qty in iteritems(pledge_values):
+ security_wise_map.setdefault(key[1], {
+ 'qty': 0.0,
+ 'applicant_count': 0.0
+ })
+
+ security_wise_map[key[1]]['qty'] += qty
+ if qty:
+ security_wise_map[key[1]]['applicant_count'] += 1
+
+ total_portfolio_value += flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0))
+
+ return security_wise_map, total_portfolio_value
+
+
+
diff --git a/erpnext/loan_management/workspace/loan_management/loan_management.json b/erpnext/loan_management/workspace/loan_management/loan_management.json
new file mode 100644
index 0000000..18559dc
--- /dev/null
+++ b/erpnext/loan_management/workspace/loan_management/loan_management.json
@@ -0,0 +1,251 @@
+{
+ "category": "Modules",
+ "charts": [],
+ "creation": "2020-03-12 16:35:55.299820",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "loan",
+ "idx": 0,
+ "is_default": 0,
+ "is_standard": 1,
+ "label": "Loan Management",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Type",
+ "link_to": "Loan Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Application",
+ "link_to": "Loan Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan",
+ "link_to": "Loan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Processes",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Process Loan Security Shortfall",
+ "link_to": "Process Loan Security Shortfall",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Process Loan Interest Accrual",
+ "link_to": "Process Loan Interest Accrual",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Disbursement and Repayment",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Disbursement",
+ "link_to": "Loan Disbursement",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Repayment",
+ "link_to": "Loan Repayment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Write Off",
+ "link_to": "Loan Write Off",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Interest Accrual",
+ "link_to": "Loan Interest Accrual",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security Type",
+ "link_to": "Loan Security Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security Price",
+ "link_to": "Loan Security Price",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security",
+ "link_to": "Loan Security",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security Pledge",
+ "link_to": "Loan Security Pledge",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security Unpledge",
+ "link_to": "Loan Security Unpledge",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Security Shortfall",
+ "link_to": "Loan Security Shortfall",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Loan Repayment and Closure",
+ "link_to": "Loan Repayment and Closure",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Loan Security Status",
+ "link_to": "Loan Security Status",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2021-02-18 17:31:53.586508",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Management",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Green",
+ "format": "{} Open",
+ "label": "Loan Application",
+ "link_to": "Loan Application",
+ "stats_filter": "{ \"status\": \"Open\" }",
+ "type": "DocType"
+ },
+ {
+ "label": "Loan",
+ "link_to": "Loan",
+ "type": "DocType"
+ },
+ {
+ "doc_view": "",
+ "label": "Dashboard",
+ "link_to": "Loan Dashboard",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index e940b60..ddbcdfd 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -66,7 +66,7 @@
company: me.frm.doc.company
}
});
- }, __("Get items from"));
+ }, __("Get Items From"));
} else if (this.frm.doc.docstatus === 1) {
this.frm.add_custom_button(__('Create Maintenance Visit'), function() {
frappe.model.open_mapped_doc({
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 2e2a9ce..4cbb02a 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -62,7 +62,7 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
this.frm.add_custom_button(__('Warranty Claim'),
function() {
erpnext.utils.map_current_doc({
@@ -78,7 +78,7 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
this.frm.add_custom_button(__('Sales Order'),
function() {
erpnext.utils.map_current_doc({
@@ -94,7 +94,7 @@
order_type: me.frm.doc.order_type,
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
}
},
});
diff --git a/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json b/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json
deleted file mode 100644
index 8d11294..0000000
--- a/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json
+++ /dev/null
@@ -1,124 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Production",
- "links": "[\n {\n \"dependencies\": [\n \"Item\",\n \"BOM\"\n ],\n \"description\": \"Orders released for production.\",\n \"label\": \"Work Order\",\n \"name\": \"Work Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"BOM\"\n ],\n \"description\": \"Generate Material Requests (MRP) and Work Orders.\",\n \"label\": \"Production Plan\",\n \"name\": \"Production Plan\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Entry\",\n \"name\": \"Stock Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Card\",\n \"name\": \"Job Card\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Downtime Entry\",\n \"name\": \"Downtime Entry\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Bill of Materials",
- "links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Bill of Materials (BOM)\",\n \"label\": \"Bill of Materials\",\n \"name\": \"BOM\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Where manufacturing operations are carried.\",\n \"label\": \"Workstation\",\n \"name\": \"Workstation\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Details of the operations carried out.\",\n \"label\": \"Operation\",\n \"name\": \"Operation\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Routing\",\n \"name\": \"Routing\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[{\n\t\"dependencies\": [\"Work Order\"],\n\t\"name\": \"Production Planning Report\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Work Order\",\n\t\"label\": \"Production Planning Report\"\n}, {\n\t\"dependencies\": [\"Work Order\"],\n\t\"name\": \"Work Order Summary\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Work Order\",\n\t\"label\": \"Work Order Summary\"\n}, {\n\t\"dependencies\": [\"Quality Inspection\"],\n\t\"name\": \"Quality Inspection Summary\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Quality Inspection\",\n\t\"label\": \"Quality Inspection Summary\"\n}, {\n\t\"dependencies\": [\"Downtime Entry\"],\n\t\"name\": \"Downtime Analysis\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Downtime Entry\",\n\t\"label\": \"Downtime Analysis\"\n}, {\n\t\"dependencies\": [\"Job Card\"],\n\t\"name\": \"Job Card Summary\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Job Card\",\n\t\"label\": \"Job Card Summary\"\n}, {\n\t\"dependencies\": [\"BOM\"],\n\t\"name\": \"BOM Search\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"BOM\",\n\t\"label\": \"BOM Search\"\n}, {\n\t\"dependencies\": [\"BOM\"],\n\t\"name\": \"BOM Stock Report\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"BOM\",\n\t\"label\": \"BOM Stock Report\"\n}, {\n\t\"dependencies\": [\"Work Order\"],\n\t\"name\": \"Production Analytics\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Work Order\",\n\t\"label\": \"Production Analytics\"\n}, {\n\t\"dependencies\": [\"BOM\"],\n\t\"name\": \"BOM Operations Time\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"BOM\",\n\t\"label\": \"BOM Operations Time\"\n}]"
- },
- {
- "hidden": 0,
- "label": "Tools",
- "links": "[\n {\n \"description\": \"Replace BOM and update latest price in all BOMs\",\n \"label\": \"BOM Update Tool\",\n \"name\": \"BOM Update Tool\",\n \"type\": \"doctype\"\n },\n {\n \"data_doctype\": \"BOM\",\n \"description\": \"Compare BOMs for changes in Raw Materials and Operations\",\n \"label\": \"BOM Comparison Tool\",\n \"name\": \"bom-comparison-tool\",\n \"type\": \"page\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"description\": \"Global settings for all manufacturing processes.\",\n \"label\": \"Manufacturing Settings\",\n \"name\": \"Manufacturing Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Help",
- "links": "[\n {\n \"label\": \"Work Order\",\n \"name\": \"Work Order\",\n \"type\": \"help\",\n \"youtube_id\": \"ZotgLyp2YFY\"\n }\n]"
- }
- ],
- "category": "Domains",
- "charts": [
- {
- "chart_name": "Produced Quantity"
- }
- ],
- "creation": "2020-03-02 17:11:37.032604",
- "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": "Manufacturing",
- "modified": "2020-05-28 13:54:02.048419",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Manufacturing",
- "onboarding": "Manufacturing",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "restrict_to_domain": "Manufacturing",
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Active",
- "label": "Item",
- "link_to": "Item",
- "restrict_to_domain": "Manufacturing",
- "stats_filter": "{\n \"disabled\": 0\n}",
- "type": "DocType"
- },
- {
- "color": "#cef6d1",
- "format": "{} Active",
- "label": "BOM",
- "link_to": "BOM",
- "restrict_to_domain": "Manufacturing",
- "stats_filter": "{\n \"is_active\": 1\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Open",
- "label": "Work Order",
- "link_to": "Work Order",
- "restrict_to_domain": "Manufacturing",
- "stats_filter": "{ \n \"status\": [\"in\", \n [\"Draft\", \"Not Started\", \"In Process\"]\n ]\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Open",
- "label": "Production Plan",
- "link_to": "Production Plan",
- "restrict_to_domain": "Manufacturing",
- "stats_filter": "{ \n \"status\": [\"not in\", [\"Completed\"]]\n}",
- "type": "DocType"
- },
- {
- "label": "Forecasting",
- "link_to": "Exponential Smoothing Forecasting",
- "type": "Report"
- },
- {
- "label": "Work Order Summary",
- "link_to": "Work Order Summary",
- "restrict_to_domain": "Manufacturing",
- "type": "Report"
- },
- {
- "label": "BOM Stock Report",
- "link_to": "BOM Stock Report",
- "type": "Report"
- },
- {
- "label": "Production Planning Report",
- "link_to": "Production Planning Report",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Manufacturing",
- "restrict_to_domain": "Manufacturing",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 47b4207..fbfd801 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -134,7 +134,7 @@
frm.set_intro(__('This is a Template BOM and will be used to make the work order for {0} of the item {1}',
[
`<a class="variants-intro">variants</a>`,
- `<a href="#Form/Item/${frm.doc.item}">${frm.doc.item}</a>`,
+ `<a href="/app/item/${frm.doc.item}">${frm.doc.item}</a>`,
]), true);
frm.$wrapper.find(".variants-intro").on("click", () => {
@@ -411,7 +411,7 @@
cur_frm.cscript.time_in_mins = cur_frm.cscript.hour_rate;
-cur_frm.cscript.bom_no = function(doc, cdt, cdn) {
+cur_frm.cscript.bom_no = function(doc, cdt, cdn) {
get_bom_material_detail(doc, cdt, cdn, false);
};
@@ -419,22 +419,28 @@
if (doc.is_default) cur_frm.set_value("is_active", 1);
};
-var get_bom_material_detail= function(doc, cdt, cdn, scrap_items) {
+var get_bom_material_detail = function(doc, cdt, cdn, scrap_items) {
+ if (!doc.company) {
+ frappe.throw({message: __("Please select a Company first."), title: __("Mandatory")});
+ }
+
var d = locals[cdt][cdn];
if (d.item_code) {
return frappe.call({
doc: doc,
method: "get_bom_material_detail",
args: {
- 'item_code': d.item_code,
- 'bom_no': d.bom_no != null ? d.bom_no: '',
+ "company": doc.company,
+ "item_code": d.item_code,
+ "bom_no": d.bom_no != null ? d.bom_no: '',
"scrap_items": scrap_items,
- 'qty': d.qty,
+ "qty": d.qty,
"stock_qty": d.stock_qty,
"include_item_in_manufacturing": d.include_item_in_manufacturing,
"uom": d.uom,
"stock_uom": d.stock_uom,
- "conversion_factor": d.conversion_factor
+ "conversion_factor": d.conversion_factor,
+ "sourced_by_supplier": d.sourced_by_supplier
},
callback: function(r) {
d = locals[cdt][cdn];
@@ -467,7 +473,7 @@
}
if (d.bom_no) {
- frappe.msgprint(__("You can not change rate if BOM mentioned agianst any item"));
+ frappe.msgprint(__("You cannot change the rate if BOM is mentioned against any Item."));
get_bom_material_detail(doc, cdt, cdn, scrap_items);
} else {
erpnext.bom.calculate_rm_cost(doc);
@@ -616,6 +622,22 @@
refresh_field("allow_alternative_item", d.name, d.parentfield);
});
+frappe.ui.form.on("BOM Item", "sourced_by_supplier", function(frm, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ if (d.sourced_by_supplier) {
+ d.rate = 0;
+ refresh_field("rate", d.name, d.parentfield);
+ }
+});
+
+frappe.ui.form.on("BOM Item", "rate", function(frm, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ if (d.sourced_by_supplier) {
+ d.rate = 0;
+ refresh_field("rate", d.name, d.parentfield);
+ }
+});
+
frappe.ui.form.on("BOM Operation", "operations_remove", function(frm) {
erpnext.bom.calculate_op_cost(frm.doc);
erpnext.bom.calculate_total(frm.doc);
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 3189433..03beedb 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -55,15 +55,20 @@
conflicting_bom = frappe.get_doc("BOM", name)
if conflicting_bom.item != self.item:
+ msg = (_("A BOM with name {0} already exists for item {1}.")
+ .format(frappe.bold(name), frappe.bold(conflicting_bom.item)))
- frappe.throw(_("""A BOM with name {0} already exists for item {1}.
- <br> Did you rename the item? Please contact Administrator / Tech support
- """).format(frappe.bold(name), frappe.bold(conflicting_bom.item)))
+ frappe.throw(_("{0}{1} Did you rename the item? Please contact Administrator / Tech support")
+ .format(msg, "<br>"))
self.name = name
def validate(self):
self.route = frappe.scrub(self.name).replace('_', '-')
+
+ if not self.company:
+ frappe.throw(_("Please select a Company first."), title=_("Mandatory"))
+
self.clear_operations()
self.validate_main_item()
self.validate_currency()
@@ -72,8 +77,10 @@
self.validate_uom_is_interger()
self.set_bom_material_details()
self.validate_materials()
+ self.set_routing_operations()
self.validate_operations()
self.calculate_cost()
+ self.update_stock_qty()
self.update_cost(update_parent=False, from_child_bom=True, save=False)
def get_context(self, context):
@@ -82,8 +89,6 @@
def on_update(self):
frappe.cache().hdel('bom_children', self.name)
self.check_recursion()
- self.update_stock_qty()
- self.update_exploded_items()
def on_submit(self):
self.manage_default_bom()
@@ -111,24 +116,20 @@
def get_routing(self):
if self.routing:
self.set("operations", [])
- for d in frappe.get_all("BOM Operation", fields = ["*"],
- filters = {'parenttype': 'Routing', 'parent': self.routing}, order_by="idx"):
- child = self.append('operations', {
- "operation": d.operation,
- "workstation": d.workstation,
- "description": d.description,
- "time_in_mins": d.time_in_mins,
- "batch_size": d.batch_size,
- "operating_cost": d.operating_cost,
- "idx": d.idx
- })
- child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2)
+ fields = ["sequence_id", "operation", "workstation", "description",
+ "time_in_mins", "batch_size", "operating_cost", "idx", "hour_rate"]
+
+ for row in frappe.get_all("BOM Operation", fields = fields,
+ filters = {'parenttype': 'Routing', 'parent': self.routing}, order_by="sequence_id, idx"):
+ child = self.append('operations', row)
+ child.hour_rate = flt(row.hour_rate / self.conversion_rate, 2)
def set_bom_material_details(self):
for item in self.get("items"):
self.validate_bom_currecny(item)
ret = self.get_bom_material_detail({
+ "company": self.company,
"item_code": item.item_code,
"item_name": item.item_name,
"bom_no": item.bom_no,
@@ -137,7 +138,8 @@
"qty": item.qty,
"uom": item.uom,
"stock_uom": item.stock_uom,
- "conversion_factor": item.conversion_factor
+ "conversion_factor": item.conversion_factor,
+ "sourced_by_supplier": item.sourced_by_supplier
})
for r in ret:
if not item.get(r):
@@ -172,7 +174,8 @@
'qty' : args.get("qty") or args.get("stock_qty") or 1,
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : flt(rate) * (flt(self.conversion_rate) or 1),
- 'include_item_in_manufacturing': cint(args['transfer_for_manufacture']) or 0
+ 'include_item_in_manufacturing': cint(args.get('transfer_for_manufacture')),
+ 'sourced_by_supplier' : args.get('sourced_by_supplier', 0)
}
return ret_item
@@ -191,8 +194,8 @@
if arg.get('scrap_items'):
rate = get_valuation_rate(arg)
elif arg:
- #Customer Provided parts will have zero rate
- if not frappe.db.get_value('Item', arg["item_code"], 'is_customer_provided_item'):
+ #Customer Provided parts and Supplier sourced parts will have zero rate
+ if not frappe.db.get_value('Item', arg["item_code"], 'is_customer_provided_item') and not arg.get('sourced_by_supplier'):
if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom:
rate = flt(self.get_bom_unitcost(arg['bom_no'])) * (arg.get("conversion_factor") or 1)
else:
@@ -205,7 +208,6 @@
else:
frappe.msgprint(_("{0} not found for item {1}")
.format(self.rm_cost_as_per, arg["item_code"]), alert=True)
-
return flt(rate) * flt(self.plc_conversion_rate or 1) / (self.conversion_rate or 1)
def update_cost(self, update_parent=True, from_child_bom=False, save=True):
@@ -216,12 +218,14 @@
for d in self.get("items"):
rate = self.get_rm_rate({
+ "company": self.company,
"item_code": d.item_code,
"bom_no": d.bom_no,
"qty": d.qty,
"uom": d.uom,
"stock_uom": d.stock_uom,
- "conversion_factor": d.conversion_factor
+ "conversion_factor": d.conversion_factor,
+ "sourced_by_supplier": d.sourced_by_supplier
})
if rate:
@@ -238,7 +242,8 @@
self.calculate_cost()
if save:
self.db_update()
- self.update_exploded_items()
+
+ self.update_exploded_items(save=save)
# update parent BOMs
if self.total_cost != existing_bom_cost and update_parent:
@@ -319,8 +324,6 @@
m.uom = m.stock_uom
m.qty = m.stock_qty
- m.db_update()
-
def validate_uom_is_interger(self):
from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "uom", "qty", "BOM Item")
@@ -373,15 +376,6 @@
if raise_exception:
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name))
- def update_cost_and_exploded_items(self, bom_list=[]):
- bom_list = self.traverse_tree(bom_list)
- for bom in bom_list:
- bom_obj = frappe.get_doc("BOM", bom)
- bom_obj.check_recursion(bom_list=bom_list)
- bom_obj.update_exploded_items()
-
- return bom_list
-
def traverse_tree(self, bom_list=None):
def _get_children(bom_no):
children = frappe.cache().hget('bom_children', bom_no)
@@ -473,10 +467,10 @@
d.rate = rate
d.amount = (d.stock_qty or d.qty) * rate
- def update_exploded_items(self):
+ def update_exploded_items(self, save=True):
""" Update Flat BOM, following will be correct data"""
self.get_exploded_items()
- self.add_exploded_items()
+ self.add_exploded_items(save=save)
def get_exploded_items(self):
""" Get all raw materials including items from child bom"""
@@ -495,7 +489,8 @@
'stock_uom' : d.stock_uom,
'stock_qty' : flt(d.stock_qty),
'rate' : flt(d.base_rate) / (flt(d.conversion_factor) or 1.0),
- 'include_item_in_manufacturing': d.include_item_in_manufacturing
+ 'include_item_in_manufacturing': d.include_item_in_manufacturing,
+ 'sourced_by_supplier': d.sourced_by_supplier
}))
def company_currency(self):
@@ -521,6 +516,7 @@
bom_item.stock_qty,
bom_item.rate,
bom_item.include_item_in_manufacturing,
+ bom_item.sourced_by_supplier,
bom_item.stock_qty / ifnull(bom.quantity, 1) AS qty_consumed_per_unit
FROM `tabBOM Explosion Item` bom_item, tabBOM bom
WHERE
@@ -539,14 +535,17 @@
'stock_uom' : d['stock_uom'],
'stock_qty' : d['qty_consumed_per_unit'] * stock_qty,
'rate' : flt(d['rate']),
- 'include_item_in_manufacturing': d.get('include_item_in_manufacturing', 0)
+ 'include_item_in_manufacturing': d.get('include_item_in_manufacturing', 0),
+ 'sourced_by_supplier': d.get('sourced_by_supplier', 0)
}))
- def add_exploded_items(self):
+ def add_exploded_items(self, save=True):
"Add items to Flat BOM table"
- frappe.db.sql("""delete from `tabBOM Explosion Item` where parent=%s""", self.name)
self.set('exploded_items', [])
+ if save:
+ frappe.db.sql("""delete from `tabBOM Explosion Item` where parent=%s""", self.name)
+
for d in sorted(self.cur_exploded_items, key=itemgetter(0)):
ch = self.append('exploded_items', {})
for i in self.cur_exploded_items[d].keys():
@@ -554,7 +553,9 @@
ch.amount = flt(ch.stock_qty) * flt(ch.rate)
ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity)
ch.docstatus = self.docstatus
- ch.db_insert()
+
+ if save:
+ ch.db_insert()
def validate_bom_links(self):
if not self.is_active:
@@ -566,6 +567,10 @@
if act_pbom and act_pbom[0][0]:
frappe.throw(_("Cannot deactivate or cancel BOM as it is linked with other BOMs"))
+ def set_routing_operations(self):
+ if self.routing and self.with_operations and not self.operations:
+ self.get_routing()
+
def validate_operations(self):
if self.with_operations and not self.get('operations'):
frappe.throw(_("Operations cannot be left blank"))
@@ -612,10 +617,20 @@
""" Get weighted average of valuation rate from all warehouses """
total_qty, total_value, valuation_rate = 0.0, 0.0, 0.0
- for d in frappe.db.sql("""select actual_qty, stock_value from `tabBin`
- where item_code=%s""", args['item_code'], as_dict=1):
- total_qty += flt(d.actual_qty)
- total_value += flt(d.stock_value)
+ item_bins = frappe.db.sql("""
+ select
+ bin.actual_qty, bin.stock_value
+ from
+ `tabBin` bin, `tabWarehouse` warehouse
+ where
+ bin.item_code=%(item)s
+ and bin.warehouse = warehouse.name
+ and warehouse.company=%(company)s""",
+ {"item": args['item_code'], "company": args['company']}, as_dict=1)
+
+ for d in item_bins:
+ total_qty += flt(d.actual_qty)
+ total_value += flt(d.stock_value)
if total_qty:
valuation_rate = total_value / total_qty
@@ -679,7 +694,7 @@
is_stock_item=is_stock_item,
qty_field="stock_qty",
select_columns = """, bom_item.source_warehouse, bom_item.operation,
- bom_item.include_item_in_manufacturing, bom_item.description, bom_item.rate,
+ bom_item.include_item_in_manufacturing, bom_item.description, bom_item.rate, bom_item.sourced_by_supplier,
(Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s limit 1) as idx""")
items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True)
@@ -692,7 +707,7 @@
query = query.format(table="BOM Item", where_conditions="", is_stock_item=is_stock_item,
qty_field="stock_qty" if fetch_qty_in_stock_uom else "qty",
select_columns = """, bom_item.uom, bom_item.conversion_factor, bom_item.source_warehouse,
- bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing,
+ bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing, bom_item.sourced_by_supplier,
bom_item.description, bom_item.base_rate as rate """)
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
diff --git a/erpnext/manufacturing/doctype/bom/bom_item_preview.html b/erpnext/manufacturing/doctype/bom/bom_item_preview.html
index c782f7b..6cd5f8c 100644
--- a/erpnext/manufacturing/doctype/bom/bom_item_preview.html
+++ b/erpnext/manufacturing/doctype/bom/bom_item_preview.html
@@ -12,11 +12,11 @@
<hr style="margin: 15px -15px;">
<p>
{% if data.value %}
- <a style="margin-right: 7px; margin-bottom: 7px" class="btn btn-default btn-xs" href="#Form/BOM/{{ data.value }}">
+ <a style="margin-right: 7px; margin-bottom: 7px" class="btn btn-default btn-xs" href="/app/Form/BOM/{{ data.value }}">
{{ __("Open BOM {0}", [data.value.bold()]) }}</a>
{% endif %}
{% if data.item_code %}
- <a class="btn btn-default btn-xs" href="#Form/Item/{{ data.item_code }}">
+ <a class="btn btn-default btn-xs" href="/app/Form/Item/{{ data.item_code }}">
{{ __("Open Item {0}", [data.item_code.bold()]) }}</a>
{% endif %}
</p>
diff --git a/erpnext/manufacturing/doctype/bom/bom_list.js b/erpnext/manufacturing/doctype/bom/bom_list.js
index 94cb466..4b5887f 100644
--- a/erpnext/manufacturing/doctype/bom/bom_list.js
+++ b/erpnext/manufacturing/doctype/bom/bom_list.js
@@ -8,7 +8,7 @@
} else if(doc.is_active) {
return [__("Active"), "blue", "is_active,=,Yes"];
} else if(!doc.is_active) {
- return [__("Not active"), "darkgrey", "is_active,=,No"];
+ return [__("Not active"), "gray", "is_active,=,No"];
}
}
};
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 3dfd03b..3239478 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -10,6 +10,8 @@
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
from six import string_types
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
test_records = frappe.get_test_records('BOM')
@@ -138,6 +140,73 @@
self.assertEqual(bom.items[0].rate, 20)
+ def test_subcontractor_sourced_item(self):
+ item_code = "_Test Subcontracted FG Item 1"
+
+ if not frappe.db.exists('Item', item_code):
+ make_item(item_code, {
+ 'is_stock_item': 1,
+ 'is_sub_contracted_item': 1,
+ 'stock_uom': 'Nos'
+ })
+
+ if not frappe.db.exists('Item', "Test Extra Item 1"):
+ make_item("Test Extra Item 1", {
+ 'is_stock_item': 1,
+ 'stock_uom': 'Nos'
+ })
+
+ if not frappe.db.exists('Item', "Test Extra Item 2"):
+ make_item("Test Extra Item 2", {
+ 'is_stock_item': 1,
+ 'stock_uom': 'Nos'
+ })
+
+ if not frappe.db.exists('Item', "Test Extra Item 3"):
+ make_item("Test Extra Item 3", {
+ 'is_stock_item': 1,
+ 'stock_uom': 'Nos'
+ })
+ bom = frappe.get_doc({
+ 'doctype': 'BOM',
+ 'is_default': 1,
+ 'item': item_code,
+ 'currency': 'USD',
+ 'quantity': 1,
+ 'company': '_Test Company'
+ })
+
+ for item in ["Test Extra Item 1", "Test Extra Item 2"]:
+ item_doc = frappe.get_doc('Item', item)
+
+ bom.append('items', {
+ 'item_code': item,
+ 'qty': 1,
+ 'uom': item_doc.stock_uom,
+ 'stock_uom': item_doc.stock_uom,
+ 'rate': item_doc.valuation_rate
+ })
+
+ bom.append('items', {
+ 'item_code': "Test Extra Item 3",
+ 'qty': 1,
+ 'uom': item_doc.stock_uom,
+ 'stock_uom': item_doc.stock_uom,
+ 'rate': 0,
+ 'sourced_by_supplier': 1
+ })
+ bom.insert(ignore_permissions=True)
+ bom.update_cost()
+ bom.submit()
+ # test that sourced_by_supplier rate is zero even after updating cost
+ self.assertEqual(bom.items[2].rate, 0)
+ # test in Purchase Order sourced_by_supplier is not added to Supplied Item
+ po = create_purchase_order(item_code=item_code, qty=1,
+ is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
+ bom_items = sorted([d.item_code for d in bom.items if d.sourced_by_supplier != 1])
+ supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
+ self.assertEquals(bom_items, supplied_items)
+
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/bom_explosion_item.json b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
index 9fadbef..f01d856 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
@@ -1,626 +1,181 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "hash",
- "beta": 0,
- "creation": "2013-03-07 11:42:57",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2013-03-07 11:42:57",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "item_name",
+ "cb",
+ "source_warehouse",
+ "operation",
+ "section_break_3",
+ "description",
+ "column_break_2",
+ "image",
+ "image_view",
+ "section_break_4",
+ "stock_qty",
+ "rate",
+ "qty_consumed_per_unit",
+ "column_break_8",
+ "stock_uom",
+ "amount",
+ "include_item_in_manufacturing",
+ "sourced_by_supplier"
+ ],
"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": 1,
- "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": 1,
- "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_global_search": 1,
+ "in_list_view": 1,
+ "label": "Item Code",
+ "oldfieldname": "item_code",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "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,
- "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": "item_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Item Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cb",
- "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": "cb",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "source_warehouse",
- "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": "Source Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "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": "source_warehouse",
+ "fieldtype": "Link",
+ "label": "Source Warehouse",
+ "options": "Warehouse",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "operation",
- "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": "Operation",
- "length": 0,
- "no_copy": 0,
- "options": "Operation",
- "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": "operation",
+ "fieldtype": "Link",
+ "label": "Operation",
+ "options": "Operation",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_3",
- "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_3",
+ "fieldtype": "Section Break"
+ },
{
- "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": 1,
- "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": 1,
- "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",
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text",
+ "print_width": "300px",
+ "read_only": 1,
"width": "300px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "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_2",
+ "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,
- "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",
+ "fieldtype": "Attach",
+ "hidden": 1,
+ "label": "Image",
+ "print_hide": 1
+ },
{
- "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": 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_view",
+ "fieldtype": "Image",
+ "label": "Image View",
+ "options": "image"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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_4",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "stock_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": "Stock Qty",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "qty",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "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": "stock_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Stock Qty",
+ "oldfieldname": "qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rate",
- "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": "Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "standard_rate",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "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": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "oldfieldname": "standard_rate",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "qty_consumed_per_unit",
- "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 Consumed Per Unit",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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": "qty_consumed_per_unit",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Qty Consumed Per Unit",
+ "read_only": 1
+ },
{
- "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": "stock_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": "Stock UOM",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Link",
- "options": "UOM",
- "permlevel": 0,
- "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": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Link",
+ "options": "UOM",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "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": "Amount",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "amount_as_per_sr",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "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": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "oldfieldname": "amount_as_per_sr",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "include_item_in_manufacturing",
- "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": "Include Item In Manufacturing",
- "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
+ "default": "0",
+ "fieldname": "include_item_in_manufacturing",
+ "fieldtype": "Check",
+ "label": "Include Item In Manufacturing",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "sourced_by_supplier",
+ "fieldtype": "Check",
+ "label": "Sourced by Supplier",
+ "read_only": 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-11-20 19:04:59.813773",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "BOM Explosion 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,
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-10-08 16:21:29.386212",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "BOM Explosion Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json
index e34be61..4c9877f 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -37,7 +37,9 @@
"section_break_27",
"has_variants",
"include_item_in_manufacturing",
- "original_item"
+ "original_item",
+ "column_break_33",
+ "sourced_by_supplier"
],
"fields": [
{
@@ -272,12 +274,23 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "column_break_33",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "sourced_by_supplier",
+ "fieldtype": "Check",
+ "label": "Sourced by Supplier"
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-09 14:30:26.535546",
+ "modified": "2020-10-08 14:19:37.563300",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
index 0350e2c..07464e3 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
@@ -1,10 +1,12 @@
{
+ "actions": [],
"creation": "2013-02-22 01:27:49",
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
+ "sequence_id",
"operation",
"workstation",
"description",
@@ -106,11 +108,19 @@
"fieldname": "batch_size",
"fieldtype": "Int",
"label": "Batch Size"
+ },
+ {
+ "depends_on": "eval:doc.parenttype == \"Routing\"",
+ "fieldname": "sequence_id",
+ "fieldtype": "Int",
+ "label": "Sequence ID"
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2020-06-16 17:01:11.128420",
+ "links": [],
+ "modified": "2020-10-13 18:14:10.018774",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index b051b32..4e8dd41 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -31,6 +31,16 @@
}
}
+ frm.set_query("quality_inspection", function() {
+ return {
+ query: "erpnext.stock.doctype.quality_inspection.quality_inspection.quality_inspection_query",
+ filters: {
+ "item_code": frm.doc.production_item,
+ "reference_name": frm.doc.name
+ }
+ };
+ });
+
frm.trigger("toggle_operation_number");
if (frm.doc.docstatus == 0 && (frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json
index 087ab6b..5713f69 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.json
+++ b/erpnext/manufacturing/doctype/job_card/job_card.json
@@ -20,6 +20,7 @@
"production_item",
"item_name",
"for_quantity",
+ "quality_inspection",
"wip_warehouse",
"column_break_12",
"employee",
@@ -36,6 +37,7 @@
"items",
"more_information",
"operation_id",
+ "sequence_id",
"transferred_qty",
"requested_qty",
"column_break_20",
@@ -297,10 +299,26 @@
"fieldname": "operation_row_number",
"fieldtype": "Select",
"label": "Operation Row Number"
+ },
+ {
+ "fieldname": "sequence_id",
+ "fieldtype": "Int",
+ "label": "Sequence Id",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:!doc.__islocal;",
+ "fieldname": "quality_inspection",
+ "fieldtype": "Link",
+ "label": "Quality Inspection",
+ "no_copy": 1,
+ "options": "Quality Inspection"
}
],
"is_submittable": 1,
- "modified": "2020-08-24 15:21:21.398267",
+ "links": [],
+ "modified": "2020-11-19 18:26:50.531664",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 8855e0a..7aaf2a0 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
import datetime
-from frappe import _
+from frappe import _, bold
from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
from frappe.utils import (flt, cint, time_diff_in_hours, get_datetime, getdate,
@@ -16,12 +16,15 @@
class OverlapError(frappe.ValidationError): pass
class OperationMismatchError(frappe.ValidationError): pass
+class OperationSequenceError(frappe.ValidationError): pass
+class JobCardCancelError(frappe.ValidationError): pass
class JobCard(Document):
def validate(self):
self.validate_time_logs()
self.set_status()
self.validate_operation_id()
+ self.validate_sequence_id()
def validate_time_logs(self):
self.total_completed_qty = 0.0
@@ -196,14 +199,14 @@
def validate_job_card(self):
if not self.time_logs:
frappe.throw(_("Time logs are required for {0} {1}")
- .format(frappe.bold("Job Card"), get_link_to_form("Job Card", self.name)))
+ .format(bold("Job Card"), get_link_to_form("Job Card", self.name)))
if self.for_quantity and self.total_completed_qty != self.for_quantity:
- total_completed_qty = frappe.bold(_("Total Completed Qty"))
- qty_to_manufacture = frappe.bold(_("Qty to Manufacture"))
+ total_completed_qty = bold(_("Total Completed Qty"))
+ qty_to_manufacture = bold(_("Qty to Manufacture"))
- frappe.throw(_("The {0} ({1}) must be equal to {2} ({3})"
- .format(total_completed_qty, frappe.bold(self.total_completed_qty), qty_to_manufacture,frappe.bold(self.for_quantity))))
+ frappe.throw(_("The {0} ({1}) must be equal to {2} ({3})")
+ .format(total_completed_qty, bold(self.total_completed_qty), qty_to_manufacture,bold(self.for_quantity)))
def update_work_order(self):
if not self.work_order:
@@ -213,38 +216,70 @@
from_time_list, to_time_list = [], []
field = "operation_id"
- data = frappe.get_all('Job Card',
- fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
- filters = {"docstatus": 1, "work_order": self.work_order, field: self.get(field)})
-
+ data = self.get_current_operation_data()
if data and len(data) > 0:
- for_quantity = data[0].completed_qty
- time_in_mins = data[0].time_in_mins
+ for_quantity = flt(data[0].completed_qty)
+ time_in_mins = flt(data[0].time_in_mins)
- if self.get(field):
- time_data = frappe.db.sql("""
+ wo = frappe.get_doc('Work Order', self.work_order)
+ if self.operation_id:
+ self.validate_produced_quantity(for_quantity, wo)
+ self.update_work_order_data(for_quantity, time_in_mins, wo)
+
+ def validate_produced_quantity(self, for_quantity, wo):
+ if self.docstatus < 2: return
+
+ if wo.produced_qty > for_quantity:
+ first_part_msg = (_("The {0} {1} is used to calculate the valuation cost for the finished good {2}.")
+ .format(frappe.bold(_("Job Card")), frappe.bold(self.name), frappe.bold(self.production_item)))
+
+ second_part_msg = (_("Kindly cancel the Manufacturing Entries first against the work order {0}.")
+ .format(frappe.bold(get_link_to_form("Work Order", self.work_order))))
+
+ frappe.throw(_("{0} {1}").format(first_part_msg, second_part_msg),
+ JobCardCancelError, title = _("Error"))
+
+ def update_work_order_data(self, for_quantity, time_in_mins, wo):
+ time_data = frappe.db.sql("""
SELECT
min(from_time) as start_time, max(to_time) as end_time
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
WHERE
jctl.parent = jc.name and jc.work_order = %s
- and jc.{0} = %s and jc.docstatus = 1
- """.format(field), (self.work_order, self.get(field)), as_dict=1)
+ and jc.operation_id = %s and jc.docstatus = 1
+ """, (self.work_order, self.operation_id), as_dict=1)
- wo = frappe.get_doc('Work Order', self.work_order)
+ for data in wo.operations:
+ if data.get("name") == self.operation_id:
+ data.completed_qty = for_quantity
+ data.actual_operation_time = time_in_mins
+ data.actual_start_time = time_data[0].start_time if time_data else None
+ data.actual_end_time = time_data[0].end_time if time_data else None
+ if data.get("workstation") != self.workstation:
+ # workstations can change in a job card
+ data.workstation = self.workstation
- for data in wo.operations:
- if data.get("name") == self.get(field):
- data.completed_qty = for_quantity
- data.actual_operation_time = time_in_mins
- data.actual_start_time = time_data[0].start_time if time_data else None
- data.actual_end_time = time_data[0].end_time if time_data else None
+ wo.flags.ignore_validate_update_after_submit = True
+ wo.update_operation_status()
+ wo.calculate_operating_cost()
+ wo.set_actual_dates()
+ wo.save()
- wo.flags.ignore_validate_update_after_submit = True
- wo.update_operation_status()
- wo.calculate_operating_cost()
- wo.set_actual_dates()
- wo.save()
+ def get_current_operation_data(self):
+ return frappe.get_all('Job Card',
+ fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
+ filters = {"docstatus": 1, "work_order": self.work_order, "operation_id": self.operation_id})
+
+ def set_transferred_qty_in_job_card(self, ste_doc):
+ for row in ste_doc.items:
+ if not row.job_card_item: continue
+
+ qty = frappe.db.sql(""" SELECT SUM(qty) from `tabStock Entry Detail` sed, `tabStock Entry` se
+ WHERE sed.job_card_item = %s and se.docstatus = 1 and sed.parent = se.name and
+ se.purpose = 'Material Transfer for Manufacture'
+ """, (row.job_card_item))[0][0]
+
+ frappe.db.set_value('Job Card Item', row.job_card_item, 'transferred_qty', flt(qty))
def set_transferred_qty(self, update_status=False):
if not self.items:
@@ -258,7 +293,8 @@
self.transferred_qty = frappe.db.get_value('Stock Entry', {
'job_card': self.name,
'work_order': self.work_order,
- 'docstatus': 1
+ 'docstatus': 1,
+ 'purpose': 'Material Transfer for Manufacture'
}, 'sum(fg_completed_qty)') or 0
self.db_set("transferred_qty", self.transferred_qty)
@@ -310,9 +346,32 @@
def validate_operation_id(self):
if (self.get("operation_id") and self.get("operation_row_number") and self.operation and self.work_order and
frappe.get_cached_value("Work Order Operation", self.operation_row_number, "name") != self.operation_id):
- work_order = frappe.bold(get_link_to_form("Work Order", self.work_order))
+ work_order = bold(get_link_to_form("Work Order", self.work_order))
frappe.throw(_("Operation {0} does not belong to the work order {1}")
- .format(frappe.bold(self.operation), work_order), OperationMismatchError)
+ .format(bold(self.operation), work_order), OperationMismatchError)
+
+ def validate_sequence_id(self):
+ if not (self.work_order and self.sequence_id): return
+
+ current_operation_qty = 0.0
+ data = self.get_current_operation_data()
+ if data and len(data) > 0:
+ current_operation_qty = flt(data[0].completed_qty)
+
+ current_operation_qty += flt(self.total_completed_qty)
+
+ data = frappe.get_all("Work Order Operation",
+ fields = ["operation", "status", "completed_qty"],
+ filters={"docstatus": 1, "parent": self.work_order, "sequence_id": ('<', self.sequence_id)},
+ order_by = "sequence_id, idx")
+
+ message = "Job Card {0}: As per the sequence of the operations in the work order {1}".format(bold(self.name),
+ bold(get_link_to_form("Work Order", self.work_order)))
+
+ for row in data:
+ if row.status != "Completed" and row.completed_qty < current_operation_qty:
+ frappe.throw(_("{0}, complete the operation {1} before the operation {2}.")
+ .format(message, bold(row.operation), bold(self.operation)), OperationSequenceError)
@frappe.whitelist()
def get_operation_details(work_order, operation):
@@ -326,17 +385,19 @@
@frappe.whitelist()
def get_operations(doctype, txt, searchfield, start, page_len, filters):
- if filters.get("work_order"):
- args = {"parent": filters.get("work_order")}
- if txt:
- args["operation"] = ("like", "%{0}%".format(txt))
+ if not filters.get("work_order"):
+ frappe.msgprint(_("Please select a Work Order first."))
+ return []
+ args = {"parent": filters.get("work_order")}
+ if txt:
+ args["operation"] = ("like", "%{0}%".format(txt))
- return frappe.get_all("Work Order Operation",
- filters = args,
- fields = ["distinct operation as operation"],
- limit_start = start,
- limit_page_length = page_len,
- order_by="idx asc", as_list=1)
+ return frappe.get_all("Work Order Operation",
+ filters = args,
+ fields = ["distinct operation as operation"],
+ limit_start = start,
+ limit_page_length = page_len,
+ order_by="idx asc", as_list=1)
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):
@@ -374,6 +435,7 @@
target.purpose = "Material Transfer for Manufacture"
target.from_bom = 1
target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
+ target.set_transfer_qty()
target.calculate_rate_and_amount()
target.set_missing_values()
target.set_stock_entry_type()
@@ -391,9 +453,10 @@
"field_map": {
"source_warehouse": "s_warehouse",
"required_qty": "qty",
- "uom": "stock_uom"
+ "name": "job_card_item"
},
"postprocess": update_item,
+ "condition": lambda doc: doc.required_qty > 0
}
}, target_doc, set_missing_values)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card_calendar.js b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js
index cf07698..f4877fd 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card_calendar.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js
@@ -8,7 +8,17 @@
"allDay": "allDay",
"progress": "progress"
},
- gantt: true,
+ gantt: {
+ field_map: {
+ "start": "started_time",
+ "end": "started_time",
+ "id": "name",
+ "title": "subject",
+ "color": "color",
+ "allDay": "allDay",
+ "progress": "progress"
+ }
+ },
filters: [
{
"fieldtype": "Link",
diff --git a/erpnext/manufacturing/doctype/job_card_item/job_card_item.json b/erpnext/manufacturing/doctype/job_card_item/job_card_item.json
index bc9fe10..100ef4c 100644
--- a/erpnext/manufacturing/doctype/job_card_item/job_card_item.json
+++ b/erpnext/manufacturing/doctype/job_card_item/job_card_item.json
@@ -1,363 +1,120 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-07-09 17:20:44.737289",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2018-07-09 17:20:44.737289",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "source_warehouse",
+ "uom",
+ "item_group",
+ "column_break_3",
+ "stock_uom",
+ "item_name",
+ "description",
+ "qty_section",
+ "required_qty",
+ "column_break_9",
+ "transferred_qty",
+ "allow_alternative_item"
+ ],
"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,
- "options": "Item",
- "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": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "source_warehouse",
- "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": "Source Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "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": "source_warehouse",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_list_view": 1,
+ "label": "Source Warehouse",
+ "options": "Warehouse"
+ },
{
- "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,
- "options": "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
- },
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM"
+ },
{
- "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
- },
+ "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": "item_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": "Item Name",
- "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
- },
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "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": "Description",
- "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
- },
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "label": "Description",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "qty_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": "Qty",
- "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": "qty_section",
+ "fieldtype": "Section Break",
+ "label": "Qty"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "required_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": "Required Qty",
- "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
- },
+ "fieldname": "required_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Required Qty",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_alternative_item",
- "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": "Allow Alternative Item",
- "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": "allow_alternative_item",
+ "fieldtype": "Check",
+ "label": "Allow Alternative Item"
+ },
+ {
+ "fetch_from": "item_code.item_group",
+ "fieldname": "item_group",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "item_code.stock_uom",
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "options": "UOM"
+ },
+ {
+ "fieldname": "transferred_qty",
+ "fieldtype": "Float",
+ "label": "Transferred Qty",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 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-08-28 15:23:48.099459",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Job Card Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-11 13:50:13.804108",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Job Card 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/manufacturing_settings/manufacturing_settings.json b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
index 86fa7a8..b7634da 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2014-11-27 14:12:07.542534",
"doctype": "DocType",
"document_type": "Document",
@@ -36,7 +37,7 @@
{
"default": "0",
"depends_on": "eval:!doc.disable_capacity_planning",
- "description": "Plan time logs outside Workstation Working Hours.",
+ "description": "Plan time logs outside Workstation working hours",
"fieldname": "allow_overtime",
"fieldtype": "Check",
"label": "Allow Overtime"
@@ -56,17 +57,17 @@
{
"default": "30",
"depends_on": "eval:!doc.disable_capacity_planning",
- "description": "Try planning operations for X days in advance.",
+ "description": "Plan operations X days in advance",
"fieldname": "capacity_planning_for_days",
"fieldtype": "Int",
"label": "Capacity Planning For (Days)"
},
{
"depends_on": "eval:!doc.disable_capacity_planning",
- "description": "Default 10 mins",
+ "description": "Default: 10 mins",
"fieldname": "mins_between_operations",
"fieldtype": "Int",
- "label": "Time Between Operations (in mins)"
+ "label": "Time Between Operations (Mins)"
},
{
"fieldname": "section_break_6",
@@ -92,14 +93,14 @@
},
{
"default": "0",
- "description": "Allow multiple Material Consumption against a Work Order",
+ "description": "Allow multiple material consumptions against a Work Order",
"fieldname": "material_consumption",
"fieldtype": "Check",
"label": "Allow Multiple Material Consumption"
},
{
"default": "0",
- "description": "Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",
+ "description": "Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",
"fieldname": "update_bom_costs_automatically",
"fieldtype": "Check",
"label": "Update BOM Cost Automatically"
@@ -135,7 +136,7 @@
{
"fieldname": "over_production_for_sales_and_work_order_section",
"fieldtype": "Section Break",
- "label": "Over Production for Sales and Work Order"
+ "label": "Overproduction for Sales and Work Order"
},
{
"fieldname": "raw_materials_consumption_section",
@@ -157,8 +158,10 @@
}
],
"icon": "icon-wrench",
+ "index_web_pages_for_search": 1,
"issingle": 1,
- "modified": "2019-11-26 13:10:45.569341",
+ "links": [],
+ "modified": "2020-10-13 10:55:43.996581",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Manufacturing Settings",
@@ -175,4 +178,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
index f93b244..6c60bbd 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
@@ -11,10 +11,14 @@
"from_warehouse",
"warehouse",
"column_break_4",
+ "required_bom_qty",
"quantity",
"uom",
"projected_qty",
"actual_qty",
+ "ordered_qty",
+ "reserved_qty_for_production",
+ "safety_stock",
"item_details",
"description",
"min_order_qty",
@@ -129,11 +133,40 @@
"fieldtype": "Link",
"label": "From Warehouse",
"options": "Warehouse"
+ },
+ {
+ "fetch_from": "item_code.safety_stock",
+ "fieldname": "safety_stock",
+ "fieldtype": "Float",
+ "label": "Safety Stock",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "ordered_qty",
+ "fieldtype": "Float",
+ "label": "Ordered Qty",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "reserved_qty_for_production",
+ "fieldtype": "Float",
+ "label": "Reserved Qty for Production",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "required_bom_qty",
+ "fieldtype": "Float",
+ "label": "Required Qty as per BOM",
+ "no_copy": 1,
+ "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-02-03 12:22:29.913302",
+ "modified": "2021-03-26 12:41:13.013149",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Material Request Plan Item",
diff --git a/erpnext/manufacturing/doctype/operation/test_operation.py b/erpnext/manufacturing/doctype/operation/test_operation.py
index 17d206a..0067231 100644
--- a/erpnext/manufacturing/doctype/operation/test_operation.py
+++ b/erpnext/manufacturing/doctype/operation/test_operation.py
@@ -9,3 +9,23 @@
class TestOperation(unittest.TestCase):
pass
+
+def make_operation(*args, **kwargs):
+ args = args if args else kwargs
+ if isinstance(args, tuple):
+ args = args[0]
+
+ args = frappe._dict(args)
+
+ try:
+ 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)
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 1a64bc5..15ec620 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -56,23 +56,35 @@
refresh: function(frm) {
if (frm.doc.docstatus === 1) {
frm.trigger("show_progress");
+
+ if (frm.doc.status !== "Completed") {
+ if (frm.doc.po_items && frm.doc.status !== "Closed") {
+ frm.add_custom_button(__("Work Order"), ()=> {
+ frm.trigger("make_work_order");
+ }, __('Create'));
+ }
+
+ if (frm.doc.mr_items && !in_list(['Material Requested', 'Closed'], frm.doc.status)) {
+ frm.add_custom_button(__("Material Request"), ()=> {
+ frm.trigger("make_material_request");
+ }, __('Create'));
+ }
+
+ if (frm.doc.status === "Closed") {
+ frm.add_custom_button(__("Re-open"), function() {
+ frm.events.close_open_production_plan(frm, false);
+ }, __("Status"));
+ } else {
+ frm.add_custom_button(__("Close"), function() {
+ frm.events.close_open_production_plan(frm, true);
+ }, __("Status"));
+ }
+ }
}
- if (frm.doc.docstatus === 1 && frm.doc.po_items
- && frm.doc.status != 'Completed') {
- frm.add_custom_button(__("Work Order"), ()=> {
- frm.trigger("make_work_order");
- }, __('Create'));
+ if (frm.doc.status !== "Closed") {
+ frm.page.set_inner_btn_group_as_primary(__('Create'));
}
-
- if (frm.doc.docstatus === 1 && frm.doc.mr_items
- && !in_list(['Material Requested', 'Completed'], frm.doc.status)) {
- frm.add_custom_button(__("Material Request"), ()=> {
- frm.trigger("make_material_request");
- }, __('Create'));
- }
-
- frm.page.set_inner_btn_group_as_primary(__('Create'));
frm.trigger("material_requirement");
const projected_qty_formula = ` <table class="table table-bordered" style="background-color: #f9f9f9;">
@@ -121,6 +133,18 @@
set_field_options("projected_qty_formula", projected_qty_formula);
},
+ close_open_production_plan: (frm, close=false) => {
+ frappe.call({
+ method: "set_status",
+ freeze: true,
+ doc: frm.doc,
+ args: {close : close},
+ callback: function() {
+ frm.reload_doc();
+ }
+ });
+ },
+
make_work_order: function(frm) {
frappe.call({
method: "make_work_order",
@@ -227,7 +251,8 @@
get_items_for_material_requests: function(frm, warehouses) {
const set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom', 'from_warehouse',
- 'min_order_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'material_request_type'];
+ 'min_order_qty', 'required_bom_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'ordered_qty',
+ 'reserved_qty_for_production', 'material_request_type'];
frappe.call({
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index 90e8b22..f114700 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -19,6 +19,7 @@
"column_break2",
"from_date",
"to_date",
+ "sales_order_status",
"sales_orders_detail",
"get_sales_orders",
"sales_orders",
@@ -31,6 +32,7 @@
"material_request_planning",
"include_non_stock_items",
"include_subcontracted_items",
+ "include_safety_stock",
"ignore_existing_ordered_qty",
"column_break_25",
"for_warehouse",
@@ -275,7 +277,7 @@
"fieldtype": "Select",
"label": "Status",
"no_copy": 1,
- "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested",
+ "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nClosed\nCancelled\nMaterial Requested",
"print_hide": 1,
"read_only": 1
},
@@ -301,12 +303,26 @@
"label": "Warehouses",
"options": "Production Plan Material Request Warehouse",
"read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
+ "fieldname": "sales_order_status",
+ "fieldtype": "Select",
+ "label": "Sales Order Status",
+ "options": "\nTo Deliver and Bill\nTo Bill\nTo Deliver"
+ },
+ {
+ "default": "0",
+ "fieldname": "include_safety_stock",
+ "fieldtype": "Check",
+ "label": "Include Safety Stock in Required Qty Calculation"
}
],
"icon": "fa fa-calendar",
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-02-03 00:25:25.934202",
+ "modified": "2021-03-08 11:17:25.470147",
"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 c889237..109c8b5 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -219,13 +219,17 @@
filters = {'docstatus': 0, 'production_plan': ("=", self.name)}):
frappe.delete_doc('Work Order', d.name)
- def set_status(self):
+ def set_status(self, close=None):
self.status = {
0: 'Draft',
1: 'Submitted',
2: 'Cancelled'
}.get(self.docstatus)
+ if close:
+ self.db_set('status', 'Closed')
+ return
+
if self.total_produced_qty > 0:
self.status = "In Process"
if self.total_produced_qty == self.total_planned_qty:
@@ -235,6 +239,9 @@
self.update_ordered_status()
self.update_requested_status()
+ if close is not None:
+ self.db_set('status', self.status)
+
def update_ordered_status(self):
update_status = False
for d in self.po_items:
@@ -312,7 +319,7 @@
frappe.flags.mute_messages = False
if wo_list:
- wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \
+ wo_list = ["""<a href="/app/Form/Work Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in wo_list]
msgprint(_("{0} created").format(comma_and(wo_list)))
else :
@@ -322,12 +329,13 @@
work_orders = []
bom_data = {}
- get_sub_assembly_items(item.get("bom_no"), bom_data)
+ get_sub_assembly_items(item.get("bom_no"), bom_data, item.get("qty"))
for key, data in bom_data.items():
data.update({
- 'qty': data.get("stock_qty") * item.get("qty"),
+ 'qty': data.get("stock_qty"),
'production_plan': self.name,
+ 'use_multi_level_bom': item.get("use_multi_level_bom"),
'company': self.company,
'fg_warehouse': item.get("fg_warehouse"),
'update_consumed_material_cost_in_project': 0
@@ -381,7 +389,6 @@
"transaction_date": nowdate(),
"status": "Draft",
"company": self.company,
- "requested_by": frappe.session.user,
'material_request_type': material_request_type,
'customer': item_doc.customer or ''
})
@@ -416,7 +423,7 @@
frappe.flags.mute_messages = False
if material_request_list:
- material_request_list = ["""<a href="#Form/Material Request/{0}">{1}</a>""".format(m.name, m.name) \
+ material_request_list = ["""<a href="/app/Form/Material Request/{0}">{1}</a>""".format(m.name, m.name) \
for m in material_request_list]
msgprint(_("{0} created").format(comma_and(material_request_list)))
else :
@@ -427,12 +434,14 @@
if isinstance(doc, string_types):
doc = frappe._dict(json.loads(doc))
- item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
- 'projected Qty', 'Actual Qty']]
+ item_list = [['Item Code', 'Description', 'Stock UOM', 'Warehouse', 'Required Qty as per BOM',
+ 'Projected Qty', 'Actual Qty', 'Ordered Qty', 'Reserved Qty for Production',
+ 'Safety Stock', 'Required Qty']]
for d in get_items_for_material_requests(doc):
- item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('quantity'),
- d.get('warehouse'), d.get('projected_qty'), d.get('actual_qty')])
+ item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('warehouse'),
+ d.get('required_bom_qty'), d.get('projected_qty'), d.get('actual_qty'), d.get('ordered_qty'),
+ d.get('reserved_qty_for_production'), d.get('safety_stock'), d.get('quantity')])
if not doc.get('for_warehouse'):
row = {'item_code': d.get('item_code')}
@@ -440,8 +449,9 @@
if d.get("warehouse") == bin_dict.get('warehouse'):
continue
- item_list.append(['', '', '', '', bin_dict.get('warehouse'),
- bin_dict.get('projected_qty', 0), bin_dict.get('actual_qty', 0)])
+ item_list.append(['', '', '', bin_dict.get('warehouse'), '',
+ bin_dict.get('projected_qty', 0), bin_dict.get('actual_qty', 0),
+ bin_dict.get('ordered_qty', 0), bin_dict.get('reserved_qty_for_production', 0)])
build_csv_response(item_list, doc.name)
@@ -475,7 +485,7 @@
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(planned_qty)s, 0) as qty,
item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse,
item.default_bom as default_bom, bom_item.description as description,
- bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty,
+ bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, item.safety_stock as safety_stock,
item_default.default_warehouse, item.purchase_uom, item_uom.conversion_factor
FROM
`tabBOM Item` bom_item
@@ -511,8 +521,8 @@
include_non_stock_items, include_subcontracted_items, d.qty)
return item_details
-def get_material_request_items(row, sales_order,
- company, ignore_existing_ordered_qty, warehouse, bin_dict):
+def get_material_request_items(row, sales_order, company,
+ ignore_existing_ordered_qty, include_safety_stock, warehouse, bin_dict):
total_qty = row['qty']
required_qty = 0
@@ -536,17 +546,24 @@
if frappe.db.get_value("UOM", row['purchase_uom'], "must_be_whole_number"):
required_qty = ceil(required_qty)
+ if include_safety_stock:
+ required_qty += flt(row['safety_stock'])
+
if required_qty > 0:
return {
'item_code': row.item_code,
'item_name': row.item_name,
'quantity': required_qty,
+ 'required_bom_qty': total_qty,
'description': row.description,
'stock_uom': row.get("stock_uom"),
'warehouse': warehouse or row.get('source_warehouse') \
or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"),
+ 'safety_stock': row.safety_stock,
'actual_qty': bin_dict.get("actual_qty", 0),
'projected_qty': bin_dict.get("projected_qty", 0),
+ 'ordered_qty': bin_dict.get("ordered_qty", 0),
+ 'reserved_qty_for_production': bin_dict.get("reserved_qty_for_production", 0),
'min_order_qty': row['min_order_qty'],
'material_request_type': row.get("default_material_request_type"),
'sales_order': sales_order,
@@ -564,6 +581,8 @@
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"
if self.item_code:
item_filter += " and so_item.item_code = %(item)s"
@@ -587,8 +606,8 @@
"customer": self.customer,
"project": self.project,
"item": self.item_code,
- "company": self.company
-
+ "company": self.company,
+ "sales_order_status": self.sales_order_status
}, as_dict=1)
return open_so
@@ -611,7 +630,8 @@
""".format(lft, rgt, company)
return frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
- ifnull(sum(actual_qty),0) as actual_qty, warehouse from `tabBin`
+ ifnull(sum(actual_qty),0) as actual_qty, ifnull(sum(ordered_qty),0) as ordered_qty,
+ ifnull(sum(reserved_qty_for_production),0) as reserved_qty_for_production, warehouse from `tabBin`
where item_code = %(item_code)s {conditions}
group by item_code, warehouse
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
@@ -651,6 +671,7 @@
company = doc.get('company')
ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty')
+ include_safety_stock = doc.get('include_safety_stock')
so_item_details = frappe._dict()
for data in po_items:
@@ -702,6 +723,7 @@
'description' : item_master.description,
'stock_uom' : item_master.stock_uom,
'conversion_factor' : conversion_factor,
+ 'safety_stock': item_master.safety_stock
}
)
@@ -723,7 +745,7 @@
if details.qty > 0:
items = get_material_request_items(details, sales_order, company,
- ignore_existing_ordered_qty, warehouse, bin_dict)
+ ignore_existing_ordered_qty, include_safety_stock, warehouse, bin_dict)
if items:
mr_items.append(items)
@@ -735,10 +757,12 @@
mr_items = new_mr_items
if not mr_items:
- frappe.msgprint(_("""As raw materials projected quantity is more than required quantity,
- there is no need to create material request for the warehouse {0}.
- Still if you want to make material request,
- kindly enable <b>Ignore Existing Projected Quantity</b> checkbox""").format(doc.get('for_warehouse')))
+ to_enable = frappe.bold(_("Ignore Existing Projected Quantity"))
+ warehouse = frappe.bold(doc.get('for_warehouse'))
+ message = _("As there are sufficient raw materials, Material Request is not required for Warehouse {0}.").format(warehouse) + "<br><br>"
+ message += _(" If you still want to proceed, please enable {0}.").format(to_enable)
+
+ frappe.msgprint(message, title=_("Note"))
return mr_items
@@ -782,7 +806,7 @@
# "description": item_details.get("description")
}
-def get_sub_assembly_items(bom_no, bom_data):
+def get_sub_assembly_items(bom_no, bom_data, to_produce_qty):
data = get_children('BOM', parent = bom_no)
for d in data:
if d.expandable:
@@ -799,6 +823,6 @@
})
bom_item = bom_data.get(key)
- bom_item["stock_qty"] += d.stock_qty / d.parent_bom_qty
+ bom_item["stock_qty"] += (d.stock_qty / d.parent_bom_qty) * flt(to_produce_qty)
- get_sub_assembly_items(bom_item.get("bom_no"), bom_data)
+ get_sub_assembly_items(bom_item.get("bom_no"), bom_data, bom_item["stock_qty"])
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_list.js b/erpnext/manufacturing/doctype/production_plan/production_plan_list.js
index d377ef0..c2e3e6d 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan_list.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan_list.js
@@ -1,16 +1,17 @@
frappe.listview_settings['Production Plan'] = {
add_fields: ["status"],
- filters: [["status", "!=", "Stopped"]],
- get_indicator: function(doc) {
- if(doc.status==="Submitted") {
+ filters: [["status", "!=", "Closed"]],
+ get_indicator: function (doc) {
+ if (doc.status === "Submitted") {
return [__("Not Started"), "orange", "status,=,Submitted"];
} else {
return [__(doc.status), {
"Draft": "red",
"In Process": "orange",
"Completed": "green",
- "Material Requested": "darkgrey",
- "Cancelled": "darkgrey"
+ "Material Requested": "yellow",
+ "Cancelled": "gray",
+ "Closed": "grey"
}[doc.status], "status,=," + doc.status];
}
}
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index ca67d71..27335aa 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -137,7 +137,8 @@
'from_date': so.transaction_date,
'to_date': so.transaction_date,
'customer': so.customer,
- 'item_code': item
+ 'item_code': item,
+ 'sales_order_status': so.status
})
sales_orders = get_sales_orders(pln) or {}
sales_orders = [d.get('name') for d in sales_orders if d.get('name') == sales_order]
@@ -158,6 +159,46 @@
self.assertTrue(mr.material_request_type, 'Customer Provided')
self.assertTrue(mr.customer, '_Test Customer')
+ def test_production_plan_with_multi_level_bom(self):
+ #|Item Code | Qty |
+ #|Test BOM 1 | 1 |
+ #| Test BOM 2 | 2 |
+ #| Test BOM 3 | 3 |
+
+ for item_code in ["Test BOM 1", "Test BOM 2", "Test BOM 3", "Test RM BOM 1"]:
+ create_item(item_code, is_stock_item=1)
+
+ # created bom upto 3 level
+ if not frappe.db.get_value('BOM', {'item': "Test BOM 3"}):
+ make_bom(item = "Test BOM 3", raw_materials = ["Test RM BOM 1"], rm_qty=3)
+
+ if not frappe.db.get_value('BOM', {'item': "Test BOM 2"}):
+ make_bom(item = "Test BOM 2", raw_materials = ["Test BOM 3"], rm_qty=3)
+
+ if not frappe.db.get_value('BOM', {'item': "Test BOM 1"}):
+ make_bom(item = "Test BOM 1", raw_materials = ["Test BOM 2"], rm_qty=2)
+
+ item_code = "Test BOM 1"
+ pln = frappe.new_doc('Production Plan')
+ pln.company = "_Test Company"
+ pln.append("po_items", {
+ "item_code": item_code,
+ "bom_no": frappe.db.get_value('BOM', {'item': "Test BOM 1"}),
+ "planned_qty": 3,
+ "make_work_order_for_sub_assembly_items": 1
+ })
+
+ pln.submit()
+ pln.make_work_order()
+
+ #last level sub-assembly work order produce qty
+ to_produce_qty = frappe.db.get_value("Work Order",
+ {"production_plan": pln.name, "production_item": "Test BOM 3"}, "qty")
+
+ self.assertEqual(to_produce_qty, 18.0)
+ pln.cancel()
+ frappe.delete_doc("Production Plan", pln.name)
+
def create_production_plan(**args):
args = frappe._dict(args)
@@ -197,7 +238,9 @@
'item': args.item,
'currency': args.currency or 'USD',
'quantity': args.quantity or 1,
- 'company': args.company or '_Test Company'
+ 'company': args.company or '_Test Company',
+ 'routing': args.routing,
+ 'with_operations': args.with_operations or 0
})
for item in args.raw_materials:
@@ -205,12 +248,16 @@
bom.append('items', {
'item_code': item,
- 'qty': 1,
+ 'qty': args.rm_qty or 1.0,
'uom': item_doc.stock_uom,
'stock_uom': item_doc.stock_uom,
'rate': item_doc.valuation_rate or args.rate,
})
- bom.insert(ignore_permissions=True)
- bom.submit()
- return bom
\ No newline at end of file
+ if not args.do_not_save:
+ bom.insert(ignore_permissions=True)
+
+ if not args.do_not_submit:
+ bom.submit()
+
+ return bom
diff --git a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.json b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.json
index 53e33c0..e72f489 100644
--- a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.json
+++ b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.json
@@ -11,30 +11,20 @@
{
"fieldname": "warehouse",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Warehouse",
"options": "Warehouse"
}
],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
"links": [],
- "modified": "2020-02-02 10:37:16.650836",
+ "modified": "2020-10-26 12:55:00.778201",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan Material Request Warehouse",
"owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- }
- ],
+ "permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
diff --git a/erpnext/manufacturing/doctype/routing/routing.js b/erpnext/manufacturing/doctype/routing/routing.js
index d7589fa..9b1a8ca 100644
--- a/erpnext/manufacturing/doctype/routing/routing.js
+++ b/erpnext/manufacturing/doctype/routing/routing.js
@@ -2,6 +2,21 @@
// For license information, please see license.txt
frappe.ui.form.on('Routing', {
+ refresh: function(frm) {
+ frm.trigger("display_sequence_id_column");
+ },
+
+ onload: function(frm) {
+ frm.trigger("display_sequence_id_column");
+ },
+
+ display_sequence_id_column: function(frm) {
+ frappe.meta.get_docfield("BOM Operation", "sequence_id",
+ frm.doc.name).in_list_view = true;
+
+ frm.fields_dict.operations.grid.refresh();
+ },
+
calculate_operating_cost: function(frm, child) {
const operating_cost = flt(flt(child.hour_rate) * flt(child.time_in_mins) / 60, 2);
frappe.model.set_value(child.doctype, child.name, "operating_cost", operating_cost);
diff --git a/erpnext/manufacturing/doctype/routing/routing.py b/erpnext/manufacturing/doctype/routing/routing.py
index ecd0ba8..8312d74 100644
--- a/erpnext/manufacturing/doctype/routing/routing.py
+++ b/erpnext/manufacturing/doctype/routing/routing.py
@@ -3,7 +3,22 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+import frappe
+from frappe.utils import cint
+from frappe import _
from frappe.model.document import Document
class Routing(Document):
- pass
+ def validate(self):
+ self.set_routing_id()
+
+ def set_routing_id(self):
+ sequence_id = 0
+ for row in self.operations:
+ if not row.sequence_id:
+ row.sequence_id = sequence_id + 1
+ elif sequence_id and row.sequence_id and cint(sequence_id) > cint(row.sequence_id):
+ frappe.throw(_("At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2}")
+ .format(row.idx, row.sequence_id, sequence_id))
+
+ sequence_id = row.sequence_id
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/routing/test_routing.py b/erpnext/manufacturing/doctype/routing/test_routing.py
index 53ad152..73d05a6 100644
--- a/erpnext/manufacturing/doctype/routing/test_routing.py
+++ b/erpnext/manufacturing/doctype/routing/test_routing.py
@@ -4,6 +4,88 @@
from __future__ import unicode_literals
import unittest
+import frappe
+from frappe.test_runner import make_test_records
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.manufacturing.doctype.operation.test_operation import make_operation
+from erpnext.manufacturing.doctype.job_card.job_card import OperationSequenceError
+from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
+from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
class TestRouting(unittest.TestCase):
- pass
+ def test_sequence_id(self):
+ item_code = "Test Routing Item - A"
+ operations = [{"operation": "Test Operation A", "workstation": "Test Workstation A", "time_in_mins": 30},
+ {"operation": "Test Operation B", "workstation": "Test Workstation A", "time_in_mins": 20}]
+
+ make_test_records("UOM")
+
+ setup_operations(operations)
+ routing_doc = create_routing(routing_name="Testing Route", operations=operations)
+ bom_doc = setup_bom(item_code=item_code, routing=routing_doc.name)
+ wo_doc = make_wo_order_test_record(production_item = item_code, bom_no=bom_doc.name)
+
+ for row in routing_doc.operations:
+ self.assertEqual(row.sequence_id, row.idx)
+
+ for data in frappe.get_all("Job Card",
+ filters={"work_order": wo_doc.name}, order_by="sequence_id desc"):
+ job_card_doc = frappe.get_doc("Job Card", data.name)
+ job_card_doc.time_logs[0].completed_qty = 10
+ if job_card_doc.sequence_id != 1:
+ self.assertRaises(OperationSequenceError, job_card_doc.save)
+ else:
+ job_card_doc.save()
+ self.assertEqual(job_card_doc.total_completed_qty, 10)
+
+ wo_doc.cancel()
+ wo_doc.delete()
+
+def setup_operations(rows):
+ for row in rows:
+ make_workstation(row)
+ make_operation(row)
+
+def create_routing(**args):
+ args = frappe._dict(args)
+
+ doc = frappe.new_doc("Routing")
+ doc.update(args)
+
+ if not args.do_not_save:
+ try:
+ for operation in args.operations:
+ doc.append("operations", operation)
+
+ doc.insert()
+ except frappe.DuplicateEntryError:
+ doc = frappe.get_doc("Routing", args.routing_name)
+
+ return doc
+
+def setup_bom(**args):
+ from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
+ args = frappe._dict(args)
+
+ if not frappe.db.exists('Item', args.item_code):
+ make_item(args.item_code, {
+ 'is_stock_item': 1
+ })
+
+ if not args.raw_materials:
+ if not frappe.db.exists('Item', "Test Extra Item 1"):
+ make_item("Test Extra Item N-1", {
+ 'is_stock_item': 1,
+ })
+
+ args.raw_materials = ['Test Extra Item N-1']
+
+ name = frappe.db.get_value('BOM', {'item': args.item_code}, 'name')
+ if not name:
+ bom_doc = make_bom(item = args.item_code, raw_materials = args.get("raw_materials"),
+ routing = args.routing, with_operations=1)
+ else:
+ bom_doc = frappe.get_doc("BOM", name)
+
+ return bom_doc
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index b7c7c32..08291d1 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -5,8 +5,7 @@
from __future__ import unicode_literals
import unittest
import frappe
-from frappe.utils import flt, time_diff_in_hours, now, add_months, cint, today
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
+from frappe.utils import flt, now, add_months, cint, today, add_to_date
from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError, CapacityError)
from erpnext.stock.doctype.stock_entry import test_stock_entry
@@ -15,10 +14,10 @@
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
class TestWorkOrder(unittest.TestCase):
def setUp(self):
- set_perpetual_inventory(0)
self.warehouse = '_Test Warehouse 2 - _TC'
self.item = '_Test Item'
@@ -83,7 +82,7 @@
wo_order.set_work_order_operations()
self.assertEqual(wo_order.planned_operating_cost, cost*2)
- def test_resered_qty_for_partial_completion(self):
+ def test_reserved_qty_for_partial_completion(self):
item = "_Test Item"
warehouse = create_warehouse("Test Warehouse for reserved_qty - _TC")
@@ -95,11 +94,11 @@
wo_order = make_wo_order_test_record(item="_Test FG Item", qty=2,
source_warehouse=warehouse, skip_transfer=1)
- bin1_on_submit = get_bin(item, warehouse)
+ reserved_qty_on_submission = cint(get_bin(item, warehouse).reserved_qty_for_production)
# reserved qty for production is updated
- self.assertEqual(cint(bin1_at_start.reserved_qty_for_production) + 2,
- cint(bin1_on_submit.reserved_qty_for_production))
+ self.assertEqual(cint(bin1_at_start.reserved_qty_for_production) + 2, reserved_qty_on_submission)
+
test_stock_entry.make_stock_entry(item_code="_Test Item",
target=warehouse, qty=100, basic_rate=100)
@@ -112,7 +111,7 @@
bin1_at_completion = get_bin(item, warehouse)
self.assertEqual(cint(bin1_at_completion.reserved_qty_for_production),
- cint(bin1_on_submit.reserved_qty_for_production) - 1)
+ reserved_qty_on_submission - 1)
def test_production_item(self):
wo_order = make_wo_order_test_record(item="_Test FG Item", qty=1, do_not_save=True)
@@ -193,6 +192,42 @@
self.assertEqual(cint(bin1_on_end_production.projected_qty),
cint(bin1_on_end_production.projected_qty))
+ def test_backflush_qty_for_overpduction_manufacture(self):
+ cancel_stock_entry = []
+ allow_overproduction("overproduction_percentage_for_work_order", 30)
+ wo_order = make_wo_order_test_record(planned_start_date=now(), qty=100)
+ ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item",
+ target="_Test Warehouse - _TC", qty=120, basic_rate=5000.0)
+ ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
+ target="_Test Warehouse - _TC", qty=240, basic_rate=1000.0)
+
+ cancel_stock_entry.extend([ste1.name, ste2.name])
+
+ s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 60))
+ s.submit()
+ cancel_stock_entry.append(s.name)
+
+ s = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 60))
+ s.submit()
+ cancel_stock_entry.append(s.name)
+
+ s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 60))
+ s.submit()
+ cancel_stock_entry.append(s.name)
+
+ s1 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 50))
+ s1.submit()
+ cancel_stock_entry.append(s1.name)
+
+ self.assertEqual(s1.items[0].qty, 50)
+ self.assertEqual(s1.items[1].qty, 100)
+ cancel_stock_entry.reverse()
+ for ste in cancel_stock_entry:
+ doc = frappe.get_doc("Stock Entry", ste)
+ doc.cancel()
+
+ allow_overproduction("overproduction_percentage_for_work_order", 0)
+
def test_reserved_qty_for_stopped_production(self):
test_stock_entry.make_stock_entry(item_code="_Test Item",
target= self.warehouse, qty=100, basic_rate=100)
@@ -335,21 +370,49 @@
self.assertEqual(ste.total_additional_costs, 1000)
def test_job_card(self):
+ stock_entries = []
data = frappe.get_cached_value('BOM',
{'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
- if data:
- frappe.db.set_value("Manufacturing Settings",
- None, "disable_capacity_planning", 0)
+ bom, bom_item = data
- bom, bom_item = data
+ bom_doc = frappe.get_doc('BOM', bom)
+ work_order = make_wo_order_test_record(item=bom_item, qty=1,
+ bom_no=bom, source_warehouse="_Test Warehouse - _TC")
- bom_doc = frappe.get_doc('BOM', bom)
- work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
- self.assertTrue(work_order.planned_end_date)
+ for row in work_order.required_items:
+ stock_entry_doc = test_stock_entry.make_stock_entry(item_code=row.item_code,
+ target="_Test Warehouse - _TC", qty=row.required_qty, basic_rate=100)
+ stock_entries.append(stock_entry_doc)
- job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order.name})
- self.assertEqual(len(job_cards), len(bom_doc.operations))
+ ste = frappe.get_doc(make_stock_entry(work_order.name, "Material Transfer for Manufacture", 1))
+ ste.submit()
+ stock_entries.append(ste)
+
+ job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order.name})
+ self.assertEqual(len(job_cards), len(bom_doc.operations))
+
+ for i, job_card in enumerate(job_cards):
+ doc = frappe.get_doc("Job Card", job_card)
+ doc.append("time_logs", {
+ "from_time": now(),
+ "hours": i,
+ "to_time": add_to_date(now(), i),
+ "completed_qty": doc.for_quantity
+ })
+ doc.submit()
+
+ ste1 = frappe.get_doc(make_stock_entry(work_order.name, "Manufacture", 1))
+ ste1.submit()
+ stock_entries.append(ste1)
+
+ for job_card in job_cards:
+ doc = frappe.get_doc("Job Card", job_card)
+ self.assertRaises(JobCardCancelError, doc.cancel)
+
+ stock_entries.reverse()
+ for stock_entry in stock_entries:
+ stock_entry.cancel()
def test_capcity_planning(self):
frappe.db.set_value("Manufacturing Settings", None, {
@@ -407,6 +470,177 @@
ste1 = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 1))
self.assertEqual(len(ste1.items), 3)
+ def test_cost_center_for_manufacture(self):
+ wo_order = make_wo_order_test_record()
+ ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
+ self.assertEquals(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
+
+ def test_operation_time_with_batch_size(self):
+ fg_item = "Test Batch Size Item For BOM"
+ rm1 = "Test Batch Size Item RM 1 For BOM"
+
+ for item in ["Test Batch Size Item For BOM", "Test Batch Size Item RM 1 For BOM"]:
+ make_item(item, {
+ "include_item_in_manufacturing": 1,
+ "is_stock_item": 1
+ })
+
+ bom_name = frappe.db.get_value("BOM",
+ {"item": fg_item, "is_active": 1, "with_operations": 1}, "name")
+
+ if not bom_name:
+ bom = make_bom(item=fg_item, rate=1000, raw_materials = [rm1], do_not_save=True)
+ bom.with_operations = 1
+ bom.append("operations", {
+ "operation": "_Test Operation 1",
+ "workstation": "_Test Workstation 1",
+ "description": "Test Data",
+ "operating_cost": 100,
+ "time_in_mins": 40,
+ "batch_size": 5
+ })
+
+ bom.save()
+ bom.submit()
+ bom_name = bom.name
+
+ work_order = make_wo_order_test_record(item=fg_item,
+ planned_start_date=now(), qty=1, do_not_save=True)
+
+ work_order.set_work_order_operations()
+ work_order.save()
+ self.assertEqual(work_order.operations[0].time_in_mins, 8.0)
+
+ work_order1 = make_wo_order_test_record(item=fg_item,
+ planned_start_date=now(), qty=5, do_not_save=True)
+
+ work_order1.set_work_order_operations()
+ work_order1.save()
+ self.assertEqual(work_order1.operations[0].time_in_mins, 40.0)
+
+ def test_partial_material_consumption(self):
+ frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 1)
+ wo_order = make_wo_order_test_record(planned_start_date=now(), qty=4)
+
+ ste_cancel_list = []
+ ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item",
+ target="_Test Warehouse - _TC", qty=20, basic_rate=5000.0)
+ ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
+ target="_Test Warehouse - _TC", qty=20, basic_rate=1000.0)
+
+ ste_cancel_list.extend([ste1, ste2])
+
+ s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 4))
+ s.submit()
+ ste_cancel_list.append(s)
+
+ ste1 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
+ ste1.submit()
+ ste_cancel_list.append(ste1)
+
+ ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
+ self.assertEquals(ste3.fg_completed_qty, 2)
+
+ expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
+ for row in ste3.items:
+ self.assertEquals(row.qty, expected_qty.get(row.item_code))
+ ste_cancel_list.reverse()
+ for ste_doc in ste_cancel_list:
+ ste_doc.cancel()
+
+ frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
+
+ def test_extra_material_transfer(self):
+ frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
+ frappe.db.set_value("Manufacturing Settings", None, "backflush_raw_materials_based_on",
+ "Material Transferred for Manufacture")
+
+ wo_order = make_wo_order_test_record(planned_start_date=now(), qty=4)
+
+ ste_cancel_list = []
+ ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item",
+ target="_Test Warehouse - _TC", qty=20, basic_rate=5000.0)
+ ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
+ target="_Test Warehouse - _TC", qty=20, basic_rate=1000.0)
+
+ ste_cancel_list.extend([ste1, ste2])
+
+ itemwise_qty = {}
+ s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 4))
+ for row in s.items:
+ row.qty = row.qty + 2
+ itemwise_qty.setdefault(row.item_code, row.qty)
+
+ s.submit()
+ ste_cancel_list.append(s)
+
+ ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
+ for ste_row in ste3.items:
+ if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
+ self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
+
+ ste3.submit()
+ ste_cancel_list.append(ste3)
+
+ ste2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
+ for ste_row in ste2.items:
+ if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
+ self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
+ ste_cancel_list.reverse()
+ for ste_doc in ste_cancel_list:
+ ste_doc.cancel()
+
+ frappe.db.set_value("Manufacturing Settings", None, "backflush_raw_materials_based_on", "BOM")
+
+ def test_make_stock_entry_for_customer_provided_item(self):
+ finished_item = 'Test Item for Make Stock Entry 1'
+ make_item(finished_item, {
+ "include_item_in_manufacturing": 1,
+ "is_stock_item": 1
+ })
+
+ customer_provided_item = 'CUST-0987'
+ make_item(customer_provided_item, {
+ 'is_purchase_item': 0,
+ 'is_customer_provided_item': 1,
+ "is_stock_item": 1,
+ "include_item_in_manufacturing": 1,
+ 'customer': '_Test Customer'
+ })
+
+ if not frappe.db.exists('BOM', {'item': finished_item}):
+ make_bom(item=finished_item, raw_materials=[customer_provided_item], rm_qty=1)
+
+ company = "_Test Company with perpetual inventory"
+ customer_warehouse = create_warehouse("Test Customer Provided Warehouse", company=company)
+ wo = make_wo_order_test_record(item=finished_item, qty=1, source_warehouse=customer_warehouse,
+ company=company)
+
+ ste = frappe.get_doc(make_stock_entry(wo.name, purpose='Material Transfer for Manufacture'))
+ ste.insert()
+
+ self.assertEqual(len(ste.items), 1)
+ for item in ste.items:
+ self.assertEqual(item.allow_zero_valuation_rate, 1)
+ self.assertEqual(item.valuation_rate, 0)
+
+ def test_valuation_rate_missing_on_make_stock_entry(self):
+ item_name = 'Test Valuation Rate Missing'
+ make_item(item_name, {
+ "is_stock_item": 1,
+ "include_item_in_manufacturing": 1,
+ })
+
+ if not frappe.db.get_value('BOM', {'item': item_name}):
+ make_bom(item=item_name, raw_materials=[item_name], rm_qty=1)
+
+ company = "_Test Company with perpetual inventory"
+ source_warehouse = create_warehouse("Test Valuation Rate Missing Warehouse", company=company)
+ wo = make_wo_order_test_record(item=item_name, qty=1, source_warehouse=source_warehouse,
+ company=company)
+
+ self.assertRaises(frappe.ValidationError, make_stock_entry, wo.name, 'Material Transfer for Manufacture')
+
def get_scrap_item_details(bom_no):
scrap_items = {}
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
@@ -424,6 +658,15 @@
def make_wo_order_test_record(**args):
args = frappe._dict(args)
+ if args.company and args.company != "_Test Company":
+ warehouse_map = {
+ "fg_warehouse": "_Test FG Warehouse",
+ "wip_warehouse": "_Test WIP Warehouse"
+ }
+
+ for attr, wh_name in warehouse_map.items():
+ if not args.get(attr):
+ args[attr] = create_warehouse(wh_name, company=args.company)
wo_order = frappe.new_doc("Work Order")
wo_order.production_item = args.production_item or args.item or args.item_code or "_Test FG Item"
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index a244f58..a6086fb 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -545,7 +545,8 @@
var tbl = frm.doc.required_items || [];
var tbl_lenght = tbl.length;
for (var i = 0, len = tbl_lenght; i < len; i++) {
- if (flt(frm.doc.required_items[i].required_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
+ let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
+ if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
counter += 1;
}
}
@@ -636,7 +637,7 @@
description: __('Max: {0}', [max]),
default: max
}, data => {
- max += (max * (frm.doc.__onload.overproduction_percentage || 0.0)) / 100;
+ max += (frm.doc.qty * (frm.doc.__onload.overproduction_percentage || 0.0)) / 100;
if (data.qty > max) {
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index 585a09d..cd9edee 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -333,8 +333,7 @@
"fieldname": "operations",
"fieldtype": "Table",
"label": "Operations",
- "options": "Work Order Operation",
- "read_only": 1
+ "options": "Work Order Operation"
},
{
"depends_on": "operations",
@@ -496,7 +495,7 @@
"image_field": "image",
"is_submittable": 1,
"links": [],
- "modified": "2020-05-05 19:32:43.323054",
+ "modified": "2021-03-16 13:27:51.116484",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index b7d968e..3d64ad4 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -378,7 +378,7 @@
select
operation, description, workstation, idx,
base_hour_rate as hour_rate, time_in_mins,
- "Pending" as status, parent as bom, batch_size
+ "Pending" as status, parent as bom, batch_size, sequence_id
from
`tabBOM Operation`
where
@@ -403,7 +403,7 @@
bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
for d in self.get("operations"):
- d.time_in_mins = flt(d.time_in_mins) / flt(bom_qty) * math.ceil(flt(self.qty) / flt(d.batch_size))
+ d.time_in_mins = flt(d.time_in_mins) / flt(bom_qty) * (flt(self.qty) / flt(d.batch_size))
self.calculate_operating_cost()
@@ -434,7 +434,7 @@
elif flt(d.completed_qty) <= max_allowed_qty_for_wo:
d.status = "Completed"
else:
- frappe.throw(_("Completed Qty can not be greater than 'Qty to Manufacture'"))
+ frappe.throw(_("Completed Qty cannot be greater than 'Qty to Manufacture'"))
def set_actual_dates(self):
if self.get("operations"):
@@ -456,10 +456,10 @@
if data and len(data):
dates = [d.posting_datetime for d in data]
- self.actual_start_date = min(dates)
+ self.db_set('actual_start_date', min(dates))
if self.status == "Completed":
- self.actual_end_date = max(dates)
+ self.db_set('actual_end_date', max(dates))
self.set_lead_time()
@@ -528,6 +528,10 @@
if not reset_only_qty:
self.required_items = []
+ operation = None
+ if self.get('operations') and len(self.operations) == 1:
+ operation = self.operations[0].operation
+
if self.bom_no and self.qty:
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
fetch_exploded = self.use_multi_level_bom)
@@ -536,6 +540,9 @@
for d in self.get("required_items"):
if item_dict.get(d.item_code):
d.required_qty = item_dict.get(d.item_code).get("qty")
+
+ 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
@@ -543,7 +550,7 @@
self.append('required_items', {
'rate': item.rate,
'amount': item.amount,
- 'operation': item.operation,
+ 'operation': item.operation or operation,
'item_code': item.item_code,
'item_name': item.item_name,
'description': item.description,
@@ -725,6 +732,7 @@
args.update(item_data)
args["rate"] = get_bom_item_rate({
+ "company": wo_doc.company,
"item_code": args.get("item_code"),
"qty": args.get("required_qty"),
"uom": args.get("stock_uom"),
@@ -865,6 +873,7 @@
'bom_no': work_order.bom_no,
'project': work_order.project,
'company': work_order.company,
+ 'sequence_id': row.get("sequence_id"),
'wip_warehouse': work_order.wip_warehouse
})
@@ -877,7 +886,7 @@
doc.schedule_time_logs(row)
doc.insert()
- frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)))
+ frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)), alert=True)
return doc
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_list.js b/erpnext/manufacturing/doctype/work_order/work_order_list.js
index 8d18395..81c23bb 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_list.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order_list.js
@@ -12,7 +12,7 @@
"Not Started": "red",
"In Process": "orange",
"Completed": "green",
- "Cancelled": "darkgrey"
+ "Cancelled": "gray"
}[doc.status], "status,=," + doc.status];
}
}
diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
index 3f5e18e..8c5cde9 100644
--- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
+++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
@@ -8,6 +8,7 @@
"details",
"operation",
"bom",
+ "sequence_id",
"description",
"col_break1",
"completed_qty",
@@ -187,11 +188,19 @@
"fieldtype": "Int",
"label": "Batch Size",
"read_only": 1
+ },
+ {
+ "fieldname": "sequence_id",
+ "fieldtype": "Int",
+ "label": "Sequence ID",
+ "print_hide": 1,
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2019-12-03 19:24:29.594189",
+ "modified": "2020-10-14 12:58:49.241252",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order Operation",
diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py
index 8266cf7..c6699be 100644
--- a/erpnext/manufacturing/doctype/workstation/test_workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py
@@ -21,17 +21,22 @@
self.assertRaises(WorkstationHolidayError, check_if_within_operating_hours,
"_Test Workstation 1", "Operation 1", "2013-02-01 10:00:00", "2013-02-02 20:00:00")
-def make_workstation(**args):
+def make_workstation(*args, **kwargs):
+ args = args if args else kwargs
+ if isinstance(args, tuple):
+ args = args[0]
+
args = frappe._dict(args)
+ workstation_name = args.workstation_name or args.workstation
try:
doc = frappe.get_doc({
"doctype": "Workstation",
- "workstation_name": args.workstation_name
+ "workstation_name": workstation_name
})
doc.insert()
return doc
except frappe.DuplicateEntryError:
- return frappe.get_doc("Workstation", args.workstation_name)
\ No newline at end of file
+ return frappe.get_doc("Workstation", workstation_name)
\ No newline at end of file
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 f7b407b..ffd9242 100644
--- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
+++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
@@ -88,11 +88,11 @@
GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom), as_dict=1)
def get_manufacturer_records():
- details = frappe.get_list('Item Manufacturer', fields = ["manufacturer", "manufacturer_part_no, parent"])
+ details = frappe.get_list('Item Manufacturer', fields = ["manufacturer", "manufacturer_part_no", "parent"])
manufacture_details = frappe._dict()
for detail in details:
dic = manufacture_details.setdefault(detail.get('parent'), {})
dic.setdefault('manufacturer', []).append(detail.get('manufacturer'))
dic.setdefault('manufacturer_part', []).append(detail.get('manufacturer_part_no'))
- return manufacture_details
\ No newline at end of file
+ return manufacture_details
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
index 2ac6fa0..7beecac 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
@@ -25,11 +25,11 @@
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
- if (column.id == "Item"){
- if (data["Enough Parts to Build"] > 0){
- value = `<a style='color:green' href="#Form/Item/${data['Item']}" data-doctype="Item">${data['Item']}</a>`
+ if (column.id == "item") {
+ if (data["enough_parts_to_build"] > 0) {
+ value = `<a style='color:green' href="/app/item/${data['item']}" data-doctype="Item">${data['item']}</a>`;
} else {
- value = `<a style='color:red' href="#Form/Item/${data['Item']}" data-doctype="Item">${data['Item']}</a>`
+ value = `<a style='color:red' href="/app/item/${data['item']}" data-doctype="Item">${data['item']}</a>`;
}
}
return value
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 75ebcbc..1c6758e 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
@@ -20,6 +20,7 @@
_("Item") + ":Link/Item:150",
_("Description") + "::300",
_("BOM Qty") + ":Float:160",
+ _("BOM UoM") + "::160",
_("Required Qty") + ":Float:120",
_("In Stock Qty") + ":Float:120",
_("Enough Parts to Build") + ":Float:200",
@@ -32,7 +33,7 @@
bom = filters.get("bom")
table = "`tabBOM Item`"
- qty_field = "qty"
+ qty_field = "stock_qty"
qty_to_produce = filters.get("qty_to_produce", 1)
if int(qty_to_produce) <= 0:
@@ -40,7 +41,6 @@
if filters.get("show_exploded_view"):
table = "`tabBOM Explosion Item`"
- qty_field = "stock_qty"
if filters.get("warehouse"):
warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1)
@@ -59,6 +59,7 @@
bom_item.item_code,
bom_item.description ,
bom_item.{qty_field},
+ bom_item.stock_uom,
bom_item.{qty_field} * {qty_to_produce} / bom.quantity,
sum(ledger.actual_qty) as actual_qty,
sum(FLOOR(ledger.actual_qty / (bom_item.{qty_field} * {qty_to_produce} / bom.quantity)))
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 2ca9f16..fc27d35 100644
--- a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
+++ b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
@@ -61,7 +61,7 @@
from_date = add_years(self.filters.from_date, cint(self.filters.no_of_years) * -1)
self.period_list = get_period_list(from_date, self.filters.to_date,
- from_date, self.filters.to_date, None, self.filters.periodicity, ignore_fiscal_year=True)
+ from_date, self.filters.to_date, "Date Range", self.filters.periodicity, ignore_fiscal_year=True)
order_data = self.get_data_for_forecast() or []
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 ebc01c6..806d268 100644
--- a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
+++ b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
@@ -124,7 +124,7 @@
if self.filters.include_subassembly_raw_materials else "(bom_item.qty / bom.quantity)")
raw_materials = frappe.db.sql(""" SELECT bom_item.parent, bom_item.item_code,
- bom_item.item_name as raw_material_name, {0} as required_qty
+ bom_item.item_name as raw_material_name, {0} as required_qty_per_unit
FROM
`tabBOM` as bom, `tab{1}` as bom_item
WHERE
@@ -208,7 +208,7 @@
warehouses = self.mrp_warehouses or []
for d in self.raw_materials_dict.get(key):
if self.filters.based_on != "Work Order":
- d.required_qty = d.required_qty * data.qty_to_manufacture
+ d.required_qty = d.required_qty_per_unit * data.qty_to_manufacture
if not warehouses:
warehouses = [data.warehouse]
diff --git a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
new file mode 100644
index 0000000..a355203
--- /dev/null
+++ b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
@@ -0,0 +1,350 @@
+{
+ "category": "Domains",
+ "charts": [
+ {
+ "chart_name": "Produced Quantity"
+ }
+ ],
+ "creation": "2020-03-02 17:11:37.032604",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "organization",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Manufacturing",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Production",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Item, BOM",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Work Order",
+ "link_to": "Work Order",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, BOM",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Production Plan",
+ "link_to": "Production Plan",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Entry",
+ "link_to": "Stock Entry",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Job Card",
+ "link_to": "Job Card",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Downtime Entry",
+ "link_to": "Downtime Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bill of Materials",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item",
+ "link_to": "Item",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bill of Materials",
+ "link_to": "BOM",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Workstation",
+ "link_to": "Workstation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Operation",
+ "link_to": "Operation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Routing",
+ "link_to": "Routing",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Work Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Production Planning Report",
+ "link_to": "Production Planning Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Work Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Work Order Summary",
+ "link_to": "Work Order Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Quality Inspection",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Quality Inspection Summary",
+ "link_to": "Quality Inspection Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Downtime Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Downtime Analysis",
+ "link_to": "Downtime Analysis",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Job Card",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Job Card Summary",
+ "link_to": "Job Card Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "BOM",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "BOM Search",
+ "link_to": "BOM Search",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "BOM",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "BOM Stock Report",
+ "link_to": "BOM Stock Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Work Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Production Analytics",
+ "link_to": "Production Analytics",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "BOM",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "BOM Operations Time",
+ "link_to": "BOM Operations Time",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tools",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "BOM Update Tool",
+ "link_to": "BOM Update Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "BOM Comparison Tool",
+ "link_to": "bom-comparison-tool",
+ "link_type": "Page",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Manufacturing Settings",
+ "link_to": "Manufacturing Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:39.365928",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Manufacturing",
+ "onboarding": "Manufacturing",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "restrict_to_domain": "Manufacturing",
+ "shortcuts": [
+ {
+ "color": "Green",
+ "format": "{} Active",
+ "label": "Item",
+ "link_to": "Item",
+ "restrict_to_domain": "Manufacturing",
+ "stats_filter": "{\n \"disabled\": 0\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Green",
+ "format": "{} Active",
+ "label": "BOM",
+ "link_to": "BOM",
+ "restrict_to_domain": "Manufacturing",
+ "stats_filter": "{\n \"is_active\": 1\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} Open",
+ "label": "Work Order",
+ "link_to": "Work Order",
+ "restrict_to_domain": "Manufacturing",
+ "stats_filter": "{ \n \"status\": [\"in\", \n [\"Draft\", \"Not Started\", \"In Process\"]\n ]\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} Open",
+ "label": "Production Plan",
+ "link_to": "Production Plan",
+ "restrict_to_domain": "Manufacturing",
+ "stats_filter": "{ \n \"status\": [\"not in\", [\"Completed\"]]\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Forecasting",
+ "link_to": "Exponential Smoothing Forecasting",
+ "type": "Report"
+ },
+ {
+ "label": "Work Order Summary",
+ "link_to": "Work Order Summary",
+ "restrict_to_domain": "Manufacturing",
+ "type": "Report"
+ },
+ {
+ "label": "BOM Stock Report",
+ "link_to": "BOM Stock Report",
+ "type": "Report"
+ },
+ {
+ "label": "Production Planning Report",
+ "link_to": "Production Planning Report",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Manufacturing",
+ "restrict_to_domain": "Manufacturing",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/modules.txt b/erpnext/modules.txt
index 1e2aeea..62f5dce 100644
--- a/erpnext/modules.txt
+++ b/erpnext/modules.txt
@@ -25,4 +25,5 @@
Quality Management
Communication
Loan Management
-Payroll
\ No newline at end of file
+Payroll
+Telephony
\ No newline at end of file
diff --git a/erpnext/non_profit/desk_page/non_profit/non_profit.json b/erpnext/non_profit/desk_page/non_profit/non_profit.json
deleted file mode 100644
index ebe6194..0000000
--- a/erpnext/non_profit/desk_page/non_profit/non_profit.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Loan Management",
- "links": "[\n {\n \"description\": \"Define various loan types\",\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loan Application\",\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Grant Application",
- "links": "[\n {\n \"description\": \"Grant information.\",\n \"label\": \"Grant Application\",\n \"name\": \"Grant Application\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Membership",
- "links": "[\n {\n \"description\": \"Member information.\",\n \"label\": \"Member\",\n \"name\": \"Member\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Membership Details\",\n \"label\": \"Membership\",\n \"name\": \"Membership\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Membership Type Details\",\n \"label\": \"Membership Type\",\n \"name\": \"Membership Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Billing and Gateway Settings\",\n \"label\": \"Membership Settings\",\n \"name\": \"Membership Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Volunteer",
- "links": "[\n {\n \"description\": \"Volunteer information.\",\n \"label\": \"Volunteer\",\n \"name\": \"Volunteer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Volunteer Type information.\",\n \"label\": \"Volunteer Type\",\n \"name\": \"Volunteer Type\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Chapter",
- "links": "[\n {\n \"description\": \"Chapter information.\",\n \"label\": \"Chapter\",\n \"name\": \"Chapter\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Donor",
- "links": "[\n {\n \"description\": \"Donor information.\",\n \"label\": \"Donor\",\n \"name\": \"Donor\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Donor Type information.\",\n \"label\": \"Donor Type\",\n \"name\": \"Donor Type\",\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Domains",
- "charts": [],
- "creation": "2020-03-02 17:23:47.811421",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends_another_page": 0,
- "idx": 0,
- "is_standard": 1,
- "label": "Non Profit",
- "modified": "2020-04-13 13:41:52.373705",
- "modified_by": "Administrator",
- "module": "Non Profit",
- "name": "Non Profit",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "restrict_to_domain": "Non Profit",
- "shortcuts": [
- {
- "label": "Member",
- "link_to": "Member",
- "type": "DocType"
- },
- {
- "label": "Membership Settings",
- "link_to": "Membership Settings",
- "type": "DocType"
- },
- {
- "label": "Membership",
- "link_to": "Membership",
- "type": "DocType"
- },
- {
- "label": "Chapter",
- "link_to": "Chapter",
- "type": "DocType"
- },
- {
- "label": "Chapter Member",
- "link_to": "Chapter Member",
- "type": "DocType"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/__init__.py b/erpnext/non_profit/doctype/donation/__init__.py
similarity index 100%
copy from erpnext/non_profit/doctype/membership_settings/__init__.py
copy to erpnext/non_profit/doctype/donation/__init__.py
diff --git a/erpnext/non_profit/doctype/donation/donation.js b/erpnext/non_profit/doctype/donation/donation.js
new file mode 100644
index 0000000..10e8220
--- /dev/null
+++ b/erpnext/non_profit/doctype/donation/donation.js
@@ -0,0 +1,26 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Donation', {
+ refresh: function(frm) {
+ if (frm.doc.docstatus === 1 && !frm.doc.paid) {
+ frm.add_custom_button(__('Create Payment Entry'), function() {
+ frm.events.make_payment_entry(frm);
+ });
+ }
+ },
+
+ make_payment_entry: function(frm) {
+ return frappe.call({
+ method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry',
+ args: {
+ 'dt': frm.doc.doctype,
+ 'dn': frm.doc.name
+ },
+ callback: function(r) {
+ var doc = frappe.model.sync(r.message);
+ frappe.set_route('Form', doc[0].doctype, doc[0].name);
+ }
+ });
+ },
+});
diff --git a/erpnext/non_profit/doctype/donation/donation.json b/erpnext/non_profit/doctype/donation/donation.json
new file mode 100644
index 0000000..6759569
--- /dev/null
+++ b/erpnext/non_profit/doctype/donation/donation.json
@@ -0,0 +1,156 @@
+{
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2021-02-17 10:28:52.645731",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "donor",
+ "donor_name",
+ "email",
+ "column_break_4",
+ "company",
+ "date",
+ "payment_details_section",
+ "paid",
+ "amount",
+ "mode_of_payment",
+ "razorpay_payment_id",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "donor",
+ "fieldtype": "Link",
+ "label": "Donor",
+ "options": "Donor",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "donor.donor_name",
+ "fieldname": "donor_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Donor Name",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "donor.email",
+ "fieldname": "email",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Email",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "payment_details_section",
+ "fieldtype": "Section Break",
+ "label": "Payment Details"
+ },
+ {
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Amount",
+ "reqd": 1
+ },
+ {
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment"
+ },
+ {
+ "fieldname": "razorpay_payment_id",
+ "fieldtype": "Data",
+ "label": "Razorpay Payment ID",
+ "read_only": 1
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "NPO-DTN-.YYYY.-"
+ },
+ {
+ "default": "0",
+ "fieldname": "paid",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Paid"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Donation",
+ "print_hide": 1,
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-03-11 10:53:11.269005",
+ "modified_by": "Administrator",
+ "module": "Non Profit",
+ "name": "Donation",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "select": 1,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Non Profit Manager",
+ "select": 1,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "search_fields": "donor_name, email",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "donor_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/donation/donation.py b/erpnext/non_profit/doctype/donation/donation.py
new file mode 100644
index 0000000..4fd1a30
--- /dev/null
+++ b/erpnext/non_profit/doctype/donation/donation.py
@@ -0,0 +1,220 @@
+# -*- 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
+import six
+import json
+from frappe.model.document import Document
+from frappe import _
+from frappe.utils import getdate, flt, get_link_to_form
+from frappe.email import sendmail_to_system_managers
+from erpnext.non_profit.doctype.membership.membership import verify_signature
+
+class Donation(Document):
+ def validate(self):
+ if not self.donor or not frappe.db.exists('Donor', self.donor):
+ # for web forms
+ user_type = frappe.db.get_value('User', frappe.session.user, 'user_type')
+ if user_type == 'Website User':
+ self.create_donor_for_website_user()
+ else:
+ frappe.throw(_('Please select a Member'))
+
+ def create_donor_for_website_user(self):
+ donor_name = frappe.get_value('Donor', dict(email=frappe.session.user))
+
+ if not donor_name:
+ user = frappe.get_doc('User', frappe.session.user)
+ donor = frappe.get_doc(dict(
+ doctype='Donor',
+ donor_type=self.get('donor_type'),
+ email=frappe.session.user,
+ member_name=user.get_fullname()
+ )).insert(ignore_permissions=True)
+ donor_name = donor.name
+
+ if self.get('__islocal'):
+ self.donor = donor_name
+
+ def on_payment_authorized(self, *args, **kwargs):
+ self.load_from_db()
+ self.create_payment_entry()
+
+ def create_payment_entry(self, date=None):
+ settings = frappe.get_doc('Non Profit Settings')
+ if not settings.automate_donation_payment_entries:
+ return
+
+ if not settings.donation_payment_account:
+ frappe.throw(_('You need to set <b>Payment Account</b> for Donation in {0}').format(
+ get_link_to_form('Non Profit Settings', 'Non Profit Settings')))
+
+ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+
+ frappe.flags.ignore_account_permission = True
+ pe = get_payment_entry(dt=self.doctype, dn=self.name)
+ frappe.flags.ignore_account_permission = False
+ pe.paid_from = settings.donation_debit_account
+ pe.paid_to = settings.donation_payment_account
+ pe.posting_date = date or getdate()
+ pe.reference_no = self.name
+ pe.reference_date = date or getdate()
+ pe.flags.ignore_mandatory = True
+ pe.insert()
+ pe.submit()
+
+
+@frappe.whitelist(allow_guest=True)
+def capture_razorpay_donations(*args, **kwargs):
+ """
+ Creates Donation from Razorpay Webhook Request Data on payment.captured event
+ Creates Donor from email if not found
+ """
+ data = frappe.request.get_data(as_text=True)
+
+ try:
+ verify_signature(data, endpoint='Donation')
+ except Exception as e:
+ log = frappe.log_error(e, 'Donation Webhook Verification Error')
+ notify_failure(log)
+ return { 'status': 'Failed', 'reason': e }
+
+ if isinstance(data, six.string_types):
+ data = json.loads(data)
+ data = frappe._dict(data)
+
+ payment = data.payload.get('payment', {}).get('entity', {})
+ payment = frappe._dict(payment)
+
+ try:
+ if not data.event == 'payment.captured':
+ return
+
+ # to avoid capturing subscription payments as donations
+ if payment.description and 'subscription' in str(payment.description).lower():
+ return
+
+ donor = get_donor(payment.email)
+ if not donor:
+ donor = create_donor(payment)
+
+ donation = create_donation(donor, payment)
+ donation.run_method('create_payment_entry')
+
+ except Exception as e:
+ message = '{0}\n\n{1}\n\n{2}: {3}'.format(e, frappe.get_traceback(), _('Payment ID'), payment.id)
+ log = frappe.log_error(message, _('Error creating donation entry for {0}').format(donor.name))
+ notify_failure(log)
+ return { 'status': 'Failed', 'reason': e }
+
+ return { 'status': 'Success' }
+
+
+def create_donation(donor, payment):
+ if not frappe.db.exists('Mode of Payment', payment.method):
+ create_mode_of_payment(payment.method)
+
+ company = get_company_for_donations()
+ donation = frappe.get_doc({
+ 'doctype': 'Donation',
+ 'company': company,
+ 'donor': donor.name,
+ 'donor_name': donor.donor_name,
+ 'email': donor.email,
+ 'date': getdate(),
+ 'amount': flt(payment.amount) / 100, # Convert to rupees from paise
+ 'mode_of_payment': payment.method,
+ 'razorpay_payment_id': payment.id
+ }).insert(ignore_mandatory=True)
+
+ donation.submit()
+ return donation
+
+
+def get_donor(email):
+ donors = frappe.get_all('Donor',
+ filters={'email': email},
+ order_by='creation desc')
+
+ try:
+ return frappe.get_doc('Donor', donors[0]['name'])
+ except Exception:
+ return None
+
+
+@frappe.whitelist()
+def create_donor(payment):
+ donor_details = frappe._dict(payment)
+ donor_type = frappe.db.get_single_value('Non Profit Settings', 'default_donor_type')
+
+ donor = frappe.new_doc('Donor')
+ donor.update({
+ 'donor_name': donor_details.email,
+ 'donor_type': donor_type,
+ 'email': donor_details.email,
+ 'contact': donor_details.contact
+ })
+
+ if donor_details.get('notes'):
+ donor = get_additional_notes(donor, donor_details)
+
+ donor.insert(ignore_mandatory=True)
+ return donor
+
+
+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
+ company = get_company()
+ return company
+
+
+def get_additional_notes(donor, donor_details):
+ if type(donor_details.notes) == dict:
+ for k, v in donor_details.notes.items():
+ notes = '\n'.join('{}: {}'.format(k, v))
+
+ # extract donor name from notes
+ if 'name' in k.lower():
+ donor.update({
+ 'donor_name': donor_details.notes.get(k)
+ })
+
+ # extract pan from notes
+ if 'pan' in k.lower():
+ donor.update({
+ 'pan_number': donor_details.notes.get(k)
+ })
+
+ donor.add_comment('Comment', notes)
+
+ elif type(donor_details.notes) == str:
+ donor.add_comment('Comment', donor_details.notes)
+
+ return donor
+
+
+def create_mode_of_payment(method):
+ frappe.get_doc({
+ 'doctype': 'Mode of Payment',
+ 'mode_of_payment': method
+ }).insert(ignore_mandatory=True)
+
+
+def notify_failure(log):
+ try:
+ content = '''
+ Dear System Manager,
+ Razorpay webhook for creating donation failed due to some reason.
+ Please check the error log linked below
+ Error Log: {0}
+ Regards, Administrator
+ '''.format(get_link_to_form('Error Log', log.name))
+
+ sendmail_to_system_managers(_('[Important] [ERPNext] Razorpay donation webhook failed, please check.'), content)
+ except Exception:
+ pass
+
diff --git a/erpnext/non_profit/doctype/donation/donation_dashboard.py b/erpnext/non_profit/doctype/donation/donation_dashboard.py
new file mode 100644
index 0000000..7e25c8d
--- /dev/null
+++ b/erpnext/non_profit/doctype/donation/donation_dashboard.py
@@ -0,0 +1,16 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'donation',
+ 'non_standard_fieldnames': {
+ 'Payment Entry': 'reference_name'
+ },
+ 'transactions': [
+ {
+ 'label': _('Payment'),
+ 'items': ['Payment Entry']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py
new file mode 100644
index 0000000..c6a534d
--- /dev/null
+++ b/erpnext/non_profit/doctype/donation/test_donation.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.non_profit.doctype.donation.donation import create_donation
+
+class TestDonation(unittest.TestCase):
+ def setUp(self):
+ create_donor_type()
+ settings = frappe.get_doc('Non Profit Settings')
+ settings.company = '_Test Company'
+ settings.donation_company = '_Test Company'
+ settings.default_donor_type = '_Test Donor'
+ settings.automate_donation_payment_entries = 1
+ settings.donation_debit_account = 'Debtors - _TC'
+ settings.donation_payment_account = 'Cash - _TC'
+ settings.creation_user = 'Administrator'
+ settings.flags.ignore_permissions = True
+ settings.save()
+
+ def test_payment_entry_for_donations(self):
+ donor = create_donor()
+ create_mode_of_payment()
+ payment = frappe._dict({
+ 'amount': 100,
+ 'method': 'Debit Card',
+ 'id': 'pay_MeXAmsgeKOhq7O'
+ })
+ donation = create_donation(donor, payment)
+
+ self.assertTrue(donation.name)
+
+ # Naive test to check if at all payment entry is generated
+ # This method is actually triggered from Payment Gateway
+ # In any case if details were missing, this would throw an error
+ donation.on_payment_authorized()
+ donation.reload()
+
+ self.assertEquals(donation.paid, 1)
+ self.assertTrue(frappe.db.exists('Payment Entry', {'reference_no': donation.name}))
+
+
+def create_donor_type():
+ if not frappe.db.exists('Donor Type', '_Test Donor'):
+ frappe.get_doc({
+ 'doctype': 'Donor Type',
+ 'donor_type': '_Test Donor'
+ }).insert()
+
+
+def create_donor():
+ donor = frappe.db.exists('Donor', 'donor@test.com')
+ if donor:
+ return frappe.get_doc('Donor', 'donor@test.com')
+ else:
+ return frappe.get_doc({
+ 'doctype': 'Donor',
+ 'donor_name': '_Test Donor',
+ 'donor_type': '_Test Donor',
+ 'email': 'donor@test.com'
+ }).insert()
+
+
+def create_mode_of_payment():
+ if not frappe.db.exists('Mode of Payment', 'Debit Card'):
+ frappe.get_doc({
+ 'doctype': 'Mode of Payment',
+ 'mode_of_payment': 'Debit Card',
+ 'accounts': [{
+ 'company': '_Test Company',
+ 'default_account': 'Cash - _TC'
+ }]
+ }).insert()
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/donor/donor.json b/erpnext/non_profit/doctype/donor/donor.json
index 9639265..72f24ef 100644
--- a/erpnext/non_profit/doctype/donor/donor.json
+++ b/erpnext/non_profit/doctype/donor/donor.json
@@ -76,8 +76,13 @@
}
],
"image_field": "image",
- "links": [],
- "modified": "2020-09-16 23:46:04.083274",
+ "links": [
+ {
+ "link_doctype": "Donation",
+ "link_fieldname": "donor"
+ }
+ ],
+ "modified": "2021-02-17 16:36:33.470731",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Donor",
diff --git a/erpnext/non_profit/doctype/donor/donor.py b/erpnext/non_profit/doctype/donor/donor.py
index 9121d0c..fb70e59 100644
--- a/erpnext/non_profit/doctype/donor/donor.py
+++ b/erpnext/non_profit/doctype/donor/donor.py
@@ -11,3 +11,8 @@
"""Load address and contacts in `__onload`"""
load_address_and_contact(self)
+ def validate(self):
+ from frappe.utils import validate_email_address
+ if self.email:
+ validate_email_address(self.email.strip(), True)
+
diff --git a/erpnext/non_profit/doctype/member/member.js b/erpnext/non_profit/doctype/member/member.js
index 199dcfc..6b8f1b1 100644
--- a/erpnext/non_profit/doctype/member/member.js
+++ b/erpnext/non_profit/doctype/member/member.js
@@ -3,7 +3,7 @@
frappe.ui.form.on('Member', {
setup: function(frm) {
- frappe.db.get_single_value("Membership Settings", "enable_razorpay").then(val => {
+ frappe.db.get_single_value('Non Profit Settings', 'enable_razorpay_for_memberships').then(val => {
if (val && (frm.doc.subscription_id || frm.doc.customer_id)) {
frm.set_df_property('razorpay_details_section', 'hidden', false);
}
diff --git a/erpnext/non_profit/doctype/member/member.json b/erpnext/non_profit/doctype/member/member.json
index 992ef16..f190cfa 100644
--- a/erpnext/non_profit/doctype/member/member.json
+++ b/erpnext/non_profit/doctype/member/member.json
@@ -12,7 +12,6 @@
"membership_expiry_date",
"column_break_5",
"membership_type",
- "email",
"email_id",
"image",
"customer_section",
@@ -65,13 +64,6 @@
"reqd": 1
},
{
- "fieldname": "email",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "User",
- "options": "User"
- },
- {
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -178,7 +170,7 @@
],
"image_field": "image",
"links": [],
- "modified": "2020-09-16 23:44:13.596948",
+ "modified": "2020-11-09 12:12:10.174647",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Member",
diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py
index 44b975e..3ba2ee7 100644
--- a/erpnext/non_profit/doctype/member/member.py
+++ b/erpnext/non_profit/doctype/member/member.py
@@ -7,7 +7,7 @@
from frappe import _
from frappe.model.document import Document
from frappe.contacts.address_and_contact import load_address_and_contact
-from frappe.utils import cint
+from frappe.utils import cint, get_link_to_form
from frappe.integrations.utils import get_payment_gateway_controller
from erpnext.non_profit.doctype.membership_type.membership_type import get_membership_type
@@ -18,8 +18,6 @@
def validate(self):
- if self.email:
- self.validate_email_type(self.email)
if self.email_id:
self.validate_email_type(self.email_id)
@@ -28,9 +26,10 @@
validate_email_address(email.strip(), True)
def setup_subscription(self):
- membership_settings = frappe.get_doc("Membership Settings")
- if not membership_settings.enable_razorpay:
- frappe.throw("Please enable Razorpay to setup subscription")
+ non_profit_settings = frappe.get_doc('Non Profit Settings')
+ if not non_profit_settings.enable_razorpay_for_memberships:
+ frappe.throw('Please check Enable Razorpay for Memberships in {0} to setup subscription').format(
+ get_link_to_form('Non Profit Settings', 'Non Profit Settings'))
controller = get_payment_gateway_controller("Razorpay")
settings = controller.get_settings({})
@@ -42,7 +41,7 @@
subscription_details = {
"plan_id": plan_id,
- "billing_frequency": cint(membership_settings.billing_frequency),
+ "billing_frequency": cint(non_profit_settings.billing_frequency),
"customer_notify": 1
}
@@ -57,14 +56,16 @@
def make_customer_and_link(self):
if self.customer:
frappe.msgprint(_("A customer is already linked to this Member"))
- cust = create_customer(frappe._dict({
+
+ customer = create_customer(frappe._dict({
'fullname': self.member_name,
- 'email': self.email_id or self.user,
+ 'email': self.email_id,
'phone': None
}))
- self.customer = cust
+ self.customer = customer
self.save()
+ frappe.msgprint(_("Customer {0} has been created succesfully.").format(self.customer))
def get_or_create_member(user_details):
@@ -177,4 +178,4 @@
mobile=mobile
))
- return member.name
\ No newline at end of file
+ return member.name
diff --git a/erpnext/non_profit/doctype/membership/membership.js b/erpnext/non_profit/doctype/membership/membership.js
index ee8a8c0..3187204 100644
--- a/erpnext/non_profit/doctype/membership/membership.js
+++ b/erpnext/non_profit/doctype/membership/membership.js
@@ -3,21 +3,30 @@
frappe.ui.form.on('Membership', {
setup: function(frm) {
- frappe.db.get_single_value("Membership Settings", "enable_razorpay").then(val => {
- if (val) frm.set_df_property('razorpay_details_section', 'hidden', false);
+ frappe.db.get_single_value("Non Profit Settings", "enable_razorpay_for_memberships").then(val => {
+ if (val) frm.set_df_property("razorpay_details_section", "hidden", false);
})
},
refresh: function(frm) {
+ if (frm.doc.__islocal)
+ return;
+
!frm.doc.invoice && frm.add_custom_button("Generate Invoice", () => {
- frm.call("generate_invoice", {
- save: true
- }).then(() => {
- frm.reload_doc();
+ frm.call({
+ doc: frm.doc,
+ method: "generate_invoice",
+ args: {save: true},
+ freeze: true,
+ freeze_message: __("Creating Membership Invoice"),
+ callback: function(r) {
+ if (r.invoice)
+ frm.reload_doc();
+ }
});
});
- frappe.db.get_single_value("Membership Settings", "send_email").then(val => {
+ frappe.db.get_single_value("Non Profit Settings", "send_email").then(val => {
if (val) frm.add_custom_button("Send Acknowledgement", () => {
frm.call("send_acknowlement").then(() => {
frm.reload_doc();
@@ -27,6 +36,6 @@
},
onload: function(frm) {
- frm.add_fetch('membership_type', 'amount', 'amount');
+ frm.add_fetch("membership_type", "amount", "amount");
}
});
diff --git a/erpnext/non_profit/doctype/membership/membership.json b/erpnext/non_profit/doctype/membership/membership.json
index 7f21896..11d32f9 100644
--- a/erpnext/non_profit/doctype/membership/membership.json
+++ b/erpnext/non_profit/doctype/membership/membership.json
@@ -7,8 +7,10 @@
"engine": "InnoDB",
"field_order": [
"member",
+ "member_name",
"membership_type",
"column_break_3",
+ "company",
"membership_status",
"membership_validity_section",
"from_date",
@@ -46,6 +48,8 @@
{
"fieldname": "membership_status",
"fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Membership Status",
"options": "New\nCurrent\nExpired\nPending\nCancelled"
},
@@ -122,11 +126,25 @@
"fieldtype": "Link",
"label": "Invoice",
"options": "Sales Invoice"
+ },
+ {
+ "fetch_from": "member.member_name",
+ "fieldname": "member_name",
+ "fieldtype": "Data",
+ "label": "Member Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-09-19 14:28:11.532696",
+ "modified": "2021-02-19 14:33:44.925122",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Membership",
@@ -158,7 +176,9 @@
}
],
"restrict_to_domain": "Non Profit",
+ "search_fields": "member, member_name",
"sort_field": "modified",
"sort_order": "DESC",
+ "title_field": "member_name",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership/membership.py b/erpnext/non_profit/doctype/membership/membership.py
index 4c85cb6..52447e4 100644
--- a/erpnext/non_profit/doctype/membership/membership.py
+++ b/erpnext/non_profit/doctype/membership/membership.py
@@ -6,6 +6,7 @@
import json
import frappe
import six
+import os
from datetime import datetime
from frappe.model.document import Document
from frappe.email import sendmail_to_system_managers
@@ -14,33 +15,43 @@
from frappe import _
import erpnext
-
class Membership(Document):
def validate(self):
if not self.member or not frappe.db.exists("Member", self.member):
- member_name = frappe.get_value('Member', dict(email=frappe.session.user))
+ # for web forms
+ user_type = frappe.db.get_value("User", frappe.session.user, "user_type")
+ if user_type == "Website User":
+ self.create_member_from_website_user()
+ else:
+ frappe.throw(_("Please select a Member"))
- if not member_name:
- user = frappe.get_doc('User', frappe.session.user)
- member = frappe.get_doc(dict(
- doctype='Member',
- email=frappe.session.user,
- membership_type=self.membership_type,
- member_name=user.get_fullname()
- )).insert(ignore_permissions=True)
- member_name = member.name
+ self.validate_membership_period()
- if self.get("__islocal"):
- self.member = member_name
+ def create_member_from_website_user(self):
+ member_name = frappe.get_value("Member", dict(email_id=frappe.session.user))
+ if not member_name:
+ user = frappe.get_doc("User", frappe.session.user)
+ member = frappe.get_doc(dict(
+ doctype="Member",
+ email_id=frappe.session.user,
+ membership_type=self.membership_type,
+ member_name=user.get_fullname()
+ )).insert(ignore_permissions=True)
+ member_name = member.name
+
+ if self.get("__islocal"):
+ self.member = member_name
+
+ def validate_membership_period(self):
# get last membership (if active)
- last_membership = erpnext.get_last_membership()
+ last_membership = erpnext.get_last_membership(self.member)
# if person applied for offline membership
- if last_membership and not frappe.session.user == "Administrator":
+ if last_membership and last_membership.name != self.name and not frappe.session.user == "Administrator":
# if last membership does not expire in 30 days, then do not allow to renew
if getdate(add_days(last_membership.to_date, -30)) > getdate(nowdate()) :
- frappe.throw(_('You can only renew if your membership expires within 30 days'))
+ frappe.throw(_("You can only renew if your membership expires within 30 days"))
self.from_date = add_days(last_membership.to_date, 1)
elif frappe.session.user == "Administrator":
@@ -48,17 +59,22 @@
else:
self.from_date = nowdate()
- if frappe.db.get_single_value("Membership Settings", "billing_cycle") == "Yearly":
+ if frappe.db.get_single_value("Non Profit Settings", "billing_cycle") == "Yearly":
self.to_date = add_years(self.from_date, 1)
else:
self.to_date = add_months(self.from_date, 1)
def on_payment_authorized(self, status_changed_to=None):
- if status_changed_to in ("Completed", "Authorized"):
- self.load_from_db()
- self.db_set('paid', 1)
+ if status_changed_to not in ("Completed", "Authorized"):
+ return
+ self.load_from_db()
+ self.db_set("paid", 1)
+ settings = frappe.get_doc("Non Profit Settings")
+ if settings.allow_invoicing and settings.automate_membership_invoicing:
+ self.generate_invoice(with_payment_entry=settings.automate_membership_payment_entries, save=True)
- def generate_invoice(self, save=True):
+
+ def generate_invoice(self, save=True, with_payment_entry=False):
if not (self.paid or self.currency or self.amount):
frappe.throw(_("The payment for this membership is not paid. To generate invoice fill the payment details"))
@@ -66,34 +82,66 @@
frappe.throw(_("An invoice is already linked to this document"))
member = frappe.get_doc("Member", self.member)
- plan = frappe.get_doc("Membership Type", self.membership_type)
- settings = frappe.get_doc("Membership Settings")
-
if not member.customer:
- frappe.throw(_("No customer linked to member {}", [member.name]))
+ frappe.throw(_("No customer linked to member {0}").format(frappe.bold(self.member)))
- if not settings.debit_account:
- frappe.throw(_("You need to set <b>Debit Account</b> in Membership Settings"))
-
- if not settings.company:
- frappe.throw(_("You need to set <b>Default Company</b> for invoicing in Membership Settings"))
+ plan = frappe.get_doc("Membership Type", self.membership_type)
+ settings = frappe.get_doc("Non Profit Settings")
+ self.validate_membership_type_and_settings(plan, settings)
invoice = make_invoice(self, member, plan, settings)
+ self.reload()
self.invoice = invoice.name
+ if with_payment_entry:
+ self.make_payment_entry(settings, invoice)
+
if save:
self.save()
return invoice
+ def validate_membership_type_and_settings(self, plan, settings):
+ settings_link = get_link_to_form("Membership Type", self.membership_type)
+
+ if not settings.membership_debit_account:
+ frappe.throw(_("You need to set <b>Debit Account</b> in {0}").format(settings_link))
+
+ if not settings.company:
+ frappe.throw(_("You need to set <b>Default Company</b> for invoicing in {0}").format(settings_link))
+
+ if not plan.linked_item:
+ frappe.throw(_("Please set a Linked Item for the Membership Type {0}").format(
+ get_link_to_form("Membership Type", self.membership_type)))
+
+ def make_payment_entry(self, settings, invoice):
+ if not settings.membership_payment_account:
+ frappe.throw(_("You need to set <b>Payment Account</b> for Membership in {0}").format(
+ get_link_to_form("Non Profit Settings", "Non Profit Settings")))
+
+ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+ frappe.flags.ignore_account_permission = True
+ pe = get_payment_entry(dt="Sales Invoice", dn=invoice.name, bank_amount=invoice.grand_total)
+ frappe.flags.ignore_account_permission=False
+ pe.paid_to = settings.membership_payment_account
+ pe.reference_no = self.name
+ pe.reference_date = getdate()
+ pe.flags.ignore_mandatory = True
+ pe.save()
+ pe.submit()
+
def send_acknowlement(self):
- settings = frappe.get_doc("Membership Settings")
+ settings = frappe.get_doc("Non Profit Settings")
if not settings.send_email:
- frappe.throw(_("You need to enable <b>Send Acknowledge Email</b> in Membership Settings"))
+ frappe.throw(_("You need to enable <b>Send Acknowledge Email</b> in {0}").format(
+ get_link_to_form("Non Profit Settings", "Non Profit Settings")))
member = frappe.get_doc("Member", self.member)
+ if not member.email_id:
+ frappe.throw(_("Email address of member {0} is missing").format(frappe.utils.get_link_to_form("Member", self.member)))
+
plan = frappe.get_doc("Membership Type", self.membership_type)
- email = member.email_id if member.email_id else member.email
+ email = member.email_id
attachments = [frappe.attach_print("Membership", self.name, print_format=settings.membership_print_format)]
if self.invoice and settings.send_invoice:
@@ -112,55 +160,65 @@
}
if not frappe.flags.in_test:
- frappe.enqueue(method=frappe.sendmail, queue='short', timeout=300, is_async=True, **email_args)
+ frappe.enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args)
else:
frappe.sendmail(**email_args)
def generate_and_send_invoice(self):
- invoice = self.generate_invoice(False)
+ self.generate_invoice(save=False)
self.send_acknowlement()
+
def make_invoice(membership, member, plan, settings):
invoice = frappe.get_doc({
- 'doctype': 'Sales Invoice',
- 'customer': member.customer,
- 'debit_to': settings.debit_account,
- 'currency': membership.currency,
- 'is_pos': 0,
- 'items': [
+ "doctype": "Sales Invoice",
+ "customer": member.customer,
+ "debit_to": settings.membership_debit_account,
+ "currency": membership.currency,
+ "company": settings.company,
+ "is_pos": 0,
+ "items": [
{
- 'item_code': plan.linked_item,
- 'rate': membership.amount,
- 'qty': 1
+ "item_code": plan.linked_item,
+ "rate": membership.amount,
+ "qty": 1
}
]
})
-
- invoice.insert(ignore_permissions=True)
+ invoice.set_missing_values()
+ invoice.insert()
invoice.submit()
+ frappe.msgprint(_("Sales Invoice created successfully"))
+
return invoice
+
def get_member_based_on_subscription(subscription_id, email):
members = frappe.get_all("Member", filters={
- 'subscription_id': subscription_id,
- 'email_id': email
+ "subscription_id": subscription_id,
+ "email_id": email
}, order_by="creation desc")
try:
- return frappe.get_doc("Member", members[0]['name'])
+ return frappe.get_doc("Member", members[0]["name"])
except:
return None
-def verify_signature(data):
- signature = frappe.request.headers.get('X-Razorpay-Signature')
- settings = frappe.get_doc("Membership Settings")
- key = settings.get_webhook_secret()
+def verify_signature(data, endpoint="Membership"):
+ if frappe.flags.in_test or os.environ.get("CI"):
+ return True
+ signature = frappe.request.headers.get("X-Razorpay-Signature")
+
+ settings = frappe.get_doc("Non Profit Settings")
+ key = settings.get_webhook_secret(endpoint)
controller = frappe.get_doc("Razorpay Settings")
controller.verify_signature(data, signature, key)
+ frappe.set_user(settings.creation_user)
+
@frappe.whitelist(allow_guest=True)
def trigger_razorpay_subscription(*args, **kwargs):
@@ -168,18 +226,18 @@
try:
verify_signature(data)
except Exception as e:
- log = frappe.log_error(e, "Webhook Verification Error")
+ log = frappe.log_error(e, "Membership Webhook Verification Error")
notify_failure(log)
- return { 'status': 'Failed', 'reason': e}
+ return { "status": "Failed", "reason": e}
if isinstance(data, six.string_types):
data = json.loads(data)
data = frappe._dict(data)
- subscription = data.payload.get("subscription", {}).get('entity', {})
+ subscription = data.payload.get("subscription", {}).get("entity", {})
subscription = frappe._dict(subscription)
- payment = data.payload.get("payment", {}).get('entity', {})
+ payment = data.payload.get("payment", {}).get("entity", {})
payment = frappe._dict(payment)
try:
@@ -189,23 +247,22 @@
member = get_member_based_on_subscription(subscription.id, payment.email)
if not member:
member = create_member(frappe._dict({
- 'fullname': payment.email,
- 'email': payment.email,
- 'plan_id': get_plan_from_razorpay_id(subscription.plan_id)
+ "fullname": payment.email,
+ "email": payment.email,
+ "plan_id": get_plan_from_razorpay_id(subscription.plan_id)
}))
member.subscription_id = subscription.id
member.customer_id = payment.customer_id
- if subscription.notes and type(subscription.notes) == dict:
- notes = '\n'.join("{}: {}".format(k, v) for k, v in subscription.notes.items())
- member.add_comment("Comment", notes)
- elif subscription.notes and type(subscription.notes) == str:
- member.add_comment("Comment", subscription.notes)
+ if subscription.get("notes"):
+ member = get_additional_notes(member, subscription)
+ company = get_company_for_memberships()
# Update Membership
membership = frappe.new_doc("Membership")
membership.update({
+ "company": company,
"member": member.name,
"membership_status": "Current",
"membership_type": member.membership_type,
@@ -216,39 +273,91 @@
"to_date": datetime.fromtimestamp(subscription.current_end),
"amount": payment.amount / 100 # Convert to rupees from paise
})
- membership.insert(ignore_permissions=True)
+ membership.flags.ignore_mandatory = True
+ membership.insert()
# Update membership values
member.subscription_start = datetime.fromtimestamp(subscription.start_at)
member.subscription_end = datetime.fromtimestamp(subscription.end_at)
member.subscription_activated = 1
- member.save(ignore_permissions=True)
+ member.flags.ignore_mandatory = True
+ member.save()
+
+ settings = frappe.get_doc("Non Profit Settings")
+ if settings.allow_invoicing and settings.automate_membership_invoicing:
+ membership.reload()
+ membership.generate_invoice(with_payment_entry=settings.automate_membership_payment_entries, save=True)
+
except Exception as e:
- message = "{0}\n\n{1}\n\n{2}: {3}".format(e, frappe.get_traceback(), __("Payment ID"), payment.id)
+ message = "{0}\n\n{1}\n\n{2}: {3}".format(e, frappe.get_traceback(), _("Payment ID"), payment.id)
log = frappe.log_error(message, _("Error creating membership entry for {0}").format(member.name))
notify_failure(log)
- return { 'status': 'Failed', 'reason': e}
+ return { "status": "Failed", "reason": e}
- return { 'status': 'Success' }
+ return { "status": "Success" }
+
+
+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
+ company = get_company()
+ return company
+
+
+def get_additional_notes(member, subscription):
+ if type(subscription.notes) == dict:
+ for k, v in subscription.notes.items():
+ notes = "\n".join("{}: {}".format(k, v))
+
+ # extract member name from notes
+ if "name" in k.lower():
+ member.update({
+ "member_name": subscription.notes.get(k)
+ })
+
+ # extract pan number from notes
+ if "pan" in k.lower():
+ member.update({
+ "pan_number": subscription.notes.get(k)
+ })
+
+ member.add_comment("Comment", notes)
+
+ elif type(subscription.notes) == str:
+ member.add_comment("Comment", subscription.notes)
+
+ return member
def notify_failure(log):
try:
- content = """Dear System Manager,
-Razorpay webhook for creating renewing membership subscription failed due to some reason. Please check the following error log linked below
+ content = """
+ Dear System Manager,
+ Razorpay webhook for creating renewing membership subscription failed due to some reason.
+ Please check the following error log linked below
+ Error Log: {0}
+ Regards, Administrator
+ """.format(get_link_to_form("Error Log", log.name))
-Error Log: {0}
-
-Regards,
-Administrator""".format(get_link_to_form("Error Log", log.name))
sendmail_to_system_managers("[Important] [ERPNext] Razorpay membership webhook failed , please check.", content)
except:
pass
+
def get_plan_from_razorpay_id(plan_id):
- plan = frappe.get_all("Membership Type", filters={'razorpay_plan_id': plan_id}, order_by="creation desc")
+ plan = frappe.get_all("Membership Type", filters={"razorpay_plan_id": plan_id}, order_by="creation desc")
try:
- return plan[0]['name']
+ return plan[0]["name"]
except:
return None
+
+
+def set_expired_status():
+ frappe.db.sql("""
+ UPDATE
+ `tabMembership` SET `status` = 'Expired'
+ WHERE
+ `status` not in ('Cancelled') AND `to_date` < %s
+ """, (nowdate()))
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership/membership_list.js b/erpnext/non_profit/doctype/membership/membership_list.js
new file mode 100644
index 0000000..a959159
--- /dev/null
+++ b/erpnext/non_profit/doctype/membership/membership_list.js
@@ -0,0 +1,15 @@
+frappe.listview_settings['Membership'] = {
+ get_indicator: function(doc) {
+ if (doc.membership_status == 'New') {
+ return [__('New'), 'blue', 'membership_status,=,New'];
+ } else if (doc.membership_status === 'Current') {
+ return [__('Current'), 'green', 'membership_status,=,Current'];
+ } else if (doc.membership_status === 'Pending') {
+ return [__('Pending'), 'yellow', 'membership_status,=,Pending'];
+ } else if (doc.membership_status === 'Expired') {
+ return [__('Expired'), 'grey', 'membership_status,=,Expired'];
+ } else {
+ return [__('Cancelled'), 'red', 'membership_status,=,Cancelled'];
+ }
+ }
+};
diff --git a/erpnext/non_profit/doctype/membership/test_membership.py b/erpnext/non_profit/doctype/membership/test_membership.py
index b23f406..31da792 100644
--- a/erpnext/non_profit/doctype/membership/test_membership.py
+++ b/erpnext/non_profit/doctype/membership/test_membership.py
@@ -2,8 +2,117 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-
import unittest
+import frappe
+import erpnext
+from erpnext.non_profit.doctype.member.member import create_member
+from frappe.utils import nowdate, add_months
class TestMembership(unittest.TestCase):
- pass
+ def setUp(self):
+ plan = setup_membership()
+
+ # make test member
+ self.member_doc = create_member(frappe._dict({
+ 'fullname': "_Test_Member",
+ 'email': "_test_member_erpnext@example.com",
+ 'plan_id': plan.name
+ }))
+ self.member_doc.make_customer_and_link()
+ self.member = self.member_doc.name
+
+ def test_auto_generate_invoice_and_payment_entry(self):
+ entry = make_membership(self.member)
+
+ # Naive test to see if at all invoice was generated and attached to member
+ # In any case if details were missing, the invoicing would throw an error
+ invoice = entry.generate_invoice(save=True)
+ self.assertEqual(invoice.name, entry.invoice)
+
+ def test_renew_within_30_days(self):
+ # create a membership for two months
+ # Should work fine
+ make_membership(self.member, { "from_date": nowdate() })
+ make_membership(self.member, { "from_date": add_months(nowdate(), 1) })
+
+ from frappe.utils.user import add_role
+ add_role("test@example.com", "Non Profit Manager")
+ frappe.set_user("test@example.com")
+
+ # create next membership with expiry not within 30 days
+ self.assertRaises(frappe.ValidationError, make_membership, self.member, {
+ "from_date": add_months(nowdate(), 2),
+ })
+
+ frappe.set_user("Administrator")
+ # create the same membership but as administrator
+ make_membership(self.member, {
+ "from_date": add_months(nowdate(), 2),
+ "to_date": add_months(nowdate(), 3),
+ })
+
+def set_config(key, value):
+ frappe.db.set_value("Non Profit Settings", None, key, value)
+
+def make_membership(member, payload={}):
+ data = {
+ "doctype": "Membership",
+ "member": member,
+ "membership_status": "Current",
+ "membership_type": "_rzpy_test_milythm",
+ "currency": "INR",
+ "paid": 1,
+ "from_date": nowdate(),
+ "amount": 100
+ }
+ data.update(payload)
+ membership = frappe.get_doc(data)
+ membership.insert(ignore_permissions=True, ignore_if_duplicate=True)
+ return membership
+
+def create_item(item_code):
+ if not frappe.db.exists("Item", item_code):
+ item = frappe.new_doc("Item")
+ item.item_code = item_code
+ item.item_name = item_code
+ item.stock_uom = "Nos"
+ item.description = item_code
+ item.item_group = "All Item Groups"
+ item.is_stock_item = 0
+ item.save()
+ else:
+ item = frappe.get_doc("Item", item_code)
+ return item
+
+def setup_membership():
+ # Get default company
+ company = frappe.get_doc("Company", erpnext.get_default_company())
+
+ # update non profit settings
+ settings = frappe.get_doc("Non Profit Settings")
+ # Enable razorpay
+ settings.enable_razorpay_for_memberships = 1
+ settings.billing_cycle = "Monthly"
+ settings.billing_frequency = 24
+ # Enable invoicing
+ settings.allow_invoicing = 1
+ settings.automate_membership_payment_entries = 1
+ settings.company = company.name
+ settings.donation_company = company.name
+ settings.membership_payment_account = company.default_cash_account
+ settings.membership_debit_account = company.default_receivable_account
+ settings.flags.ignore_mandatory = True
+ settings.save()
+
+ # make test plan
+ if not frappe.db.exists("Membership Type", "_rzpy_test_milythm"):
+ plan = frappe.new_doc("Membership Type")
+ plan.membership_type = "_rzpy_test_milythm"
+ plan.amount = 100
+ plan.razorpay_plan_id = "_rzpy_test_milythm"
+ plan.linked_item = create_item("_Test Item for Non Profit Membership").name
+ plan.insert()
+ else:
+ plan = frappe.get_doc("Membership Type", "_rzpy_test_milythm")
+
+ return plan
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/membership_settings.js b/erpnext/non_profit/doctype/membership_settings/membership_settings.js
deleted file mode 100644
index 1d89402..0000000
--- a/erpnext/non_profit/doctype/membership_settings/membership_settings.js
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on("Membership Settings", {
- refresh: function(frm) {
- if (frm.doc.webhook_secret) {
- frm.add_custom_button(__("Revoke <Key></Key>"), () => {
- frm.call("revoke_key").then(() => {
- frm.refresh();
- })
- });
- }
-
- frm.set_query('inv_print_format', function(doc) {
- return {
- filters: {
- "doc_type": "Sales Invoice"
- }
- };
- });
-
- frm.set_query('membership_print_format', function(doc) {
- return {
- filters: {
- "doc_type": "Membership"
- }
- };
- });
-
- frm.set_query('debit_account', function(doc) {
- return {
- filters: {
- 'account_type': 'Receivable',
- 'is_group': 0,
- 'company': frm.doc.company
- }
- };
- });
-
- let docs_url = "https://docs.erpnext.com/docs/user/manual/en/non_profit/membership";
-
- frm.set_intro(__("You can learn more about memberships in the manual. ") + `<a href='${docs_url}'>${__('ERPNext Docs')}</a>`, true);
-
- frm.trigger("add_generate_button");
- frm.trigger("add_copy_buttonn");
- },
-
- add_generate_button: function(frm) {
- let label;
-
- if (frm.doc.webhook_secret) {
- label = __("Regenerate Webhook Secret");
- } else {
- label = __("Generate Webhook Secret");
- }
- frm.add_custom_button(label, () => {
- frm.call("generate_webhook_key").then(() => {
- frm.refresh();
- });
- });
- },
-
- add_copy_buttonn: function(frm) {
- if (frm.doc.webhook_secret) {
- frm.add_custom_button(__("Copy Webhook URL"), () => {
- frappe.utils.copy_to_clipboard(`https://${frappe.boot.sitename}/api/method/erpnext.non_profit.doctype.membership.membership.trigger_razorpay_subscription`);
- });
- }
- }
-});
diff --git a/erpnext/non_profit/doctype/membership_settings/membership_settings.json b/erpnext/non_profit/doctype/membership_settings/membership_settings.json
deleted file mode 100644
index 5b6bab5..0000000
--- a/erpnext/non_profit/doctype/membership_settings/membership_settings.json
+++ /dev/null
@@ -1,164 +0,0 @@
-{
- "actions": [],
- "creation": "2020-03-29 12:57:03.005120",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "enable_razorpay",
- "razorpay_settings_section",
- "billing_cycle",
- "billing_frequency",
- "webhook_secret",
- "column_break_6",
- "enable_auto_invoicing",
- "company",
- "debit_account",
- "column_break_9",
- "send_email",
- "send_invoice",
- "membership_print_format",
- "inv_print_format",
- "email_template"
- ],
- "fields": [
- {
- "fieldname": "billing_cycle",
- "fieldtype": "Select",
- "label": "Billing Cycle",
- "options": "Monthly\nYearly"
- },
- {
- "default": "0",
- "fieldname": "enable_razorpay",
- "fieldtype": "Check",
- "label": "Enable RazorPay For Memberships"
- },
- {
- "depends_on": "eval:doc.enable_razorpay",
- "fieldname": "razorpay_settings_section",
- "fieldtype": "Section Break",
- "label": "RazorPay Settings"
- },
- {
- "description": "The number of billing cycles for which the customer should be charged. For example, if a customer is buying a 1-year membership that should be billed on a monthly basis, this value should be 12.",
- "fieldname": "billing_frequency",
- "fieldtype": "Int",
- "label": "Billing Frequency"
- },
- {
- "fieldname": "webhook_secret",
- "fieldtype": "Password",
- "label": "Webhook Secret",
- "read_only": 1
- },
- {
- "fieldname": "column_break_6",
- "fieldtype": "Section Break",
- "label": "Invoicing"
- },
- {
- "default": "0",
- "fieldname": "enable_auto_invoicing",
- "fieldtype": "Check",
- "label": "Enable Auto Invoicing",
- "mandatory_depends_on": "eval:doc.send_invoice"
- },
- {
- "depends_on": "eval:doc.enable_auto_invoicing",
- "fieldname": "debit_account",
- "fieldtype": "Link",
- "label": "Debit Account",
- "mandatory_depends_on": "eval:doc.enable_auto_invoicing",
- "options": "Account"
- },
- {
- "fieldname": "column_break_9",
- "fieldtype": "Column Break"
- },
- {
- "depends_on": "eval:doc.enable_auto_invoicing",
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "mandatory_depends_on": "eval:doc.enable_auto_invoicing",
- "options": "Company"
- },
- {
- "default": "0",
- "depends_on": "eval:doc.enable_auto_invoicing && doc.send_email",
- "fieldname": "send_invoice",
- "fieldtype": "Check",
- "label": "Send Invoice with Email"
- },
- {
- "default": "0",
- "fieldname": "send_email",
- "fieldtype": "Check",
- "label": "Send Membership Acknowledgement"
- },
- {
- "depends_on": "eval: doc.send_invoice",
- "fieldname": "inv_print_format",
- "fieldtype": "Link",
- "label": "Invoice Print Format",
- "mandatory_depends_on": "eval: doc.send_invoice",
- "options": "Print Format"
- },
- {
- "depends_on": "eval:doc.send_email",
- "fieldname": "membership_print_format",
- "fieldtype": "Link",
- "label": "Membership Print Format",
- "options": "Print Format"
- },
- {
- "depends_on": "eval:doc.send_email",
- "fieldname": "email_template",
- "fieldtype": "Link",
- "label": "Email Template",
- "mandatory_depends_on": "eval:doc.send_email",
- "options": "Email Template"
- }
- ],
- "issingle": 1,
- "links": [],
- "modified": "2020-08-05 17:26:37.287395",
- "modified_by": "Administrator",
- "module": "Non Profit",
- "name": "Membership Settings",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "Non Profit Manager",
- "share": 1,
- "write": 1
- },
- {
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "Non Profit Member",
- "share": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/membership_settings.py b/erpnext/non_profit/doctype/membership_settings/membership_settings.py
deleted file mode 100644
index f3b2eee..0000000
--- a/erpnext/non_profit/doctype/membership_settings/membership_settings.py
+++ /dev/null
@@ -1,33 +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.integrations.utils import get_payment_gateway_controller
-from frappe.model.document import Document
-
-class MembershipSettings(Document):
- def generate_webhook_key(self):
- key = frappe.generate_hash(length=20)
- self.webhook_secret = key
- self.save()
-
- frappe.msgprint(
- _("Here is your webhook secret, this will be shown to you only once.") + "<br><br>" + key,
- _("Webhook Secret")
- );
-
- def revoke_key(self):
- self.webhook_secret = None;
- self.save()
-
- def get_webhook_secret(self):
- return self.get_password(fieldname="webhook_secret", raise_exception=False)
-
-@frappe.whitelist()
-def get_plans_for_membership(*args, **kwargs):
- controller = get_payment_gateway_controller("Razorpay")
- plans = controller.get_plans()
- return [plan.get("item") for plan in plans.get("items")]
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.js b/erpnext/non_profit/doctype/membership_type/membership_type.js
index 43311a2..2f24276 100644
--- a/erpnext/non_profit/doctype/membership_type/membership_type.js
+++ b/erpnext/non_profit/doctype/membership_type/membership_type.js
@@ -2,13 +2,21 @@
// For license information, please see license.txt
frappe.ui.form.on('Membership Type', {
- refresh: function(frm) {
- frappe.db.get_single_value("Membership Settings", "enable_razorpay").then(val => {
+ refresh: function (frm) {
+ frappe.db.get_single_value('Non Profit Settings', 'enable_razorpay_for_memberships').then(val => {
if (val) frm.set_df_property('razorpay_plan_id', 'hidden', false);
});
- frappe.db.get_single_value("Membership Settings", "enable_auto_invoicing").then(val => {
+ frappe.db.get_single_value('Non Profit Settings', 'allow_invoicing').then(val => {
if (val) frm.set_df_property('linked_item', 'hidden', false);
});
+
+ frm.set_query('linked_item', () => {
+ return {
+ filters: {
+ is_stock_item: 0
+ }
+ };
+ });
}
});
diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.py b/erpnext/non_profit/doctype/membership_type/membership_type.py
index b95b043..022829b 100644
--- a/erpnext/non_profit/doctype/membership_type/membership_type.py
+++ b/erpnext/non_profit/doctype/membership_type/membership_type.py
@@ -5,9 +5,14 @@
from __future__ import unicode_literals
from frappe.model.document import Document
import frappe
+from frappe import _
class MembershipType(Document):
- pass
+ def validate(self):
+ if self.linked_item:
+ is_stock_item = frappe.db.get_value("Item", self.linked_item, "is_stock_item")
+ if is_stock_item:
+ frappe.throw(_("The Linked Item should be a service item"))
def get_membership_type(razorpay_id):
return frappe.db.exists("Membership Type", {"razorpay_plan_id": razorpay_id})
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/__init__.py b/erpnext/non_profit/doctype/non_profit_settings/__init__.py
similarity index 100%
rename from erpnext/non_profit/doctype/membership_settings/__init__.py
rename to erpnext/non_profit/doctype/non_profit_settings/__init__.py
diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js
new file mode 100644
index 0000000..4c4ca98
--- /dev/null
+++ b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.js
@@ -0,0 +1,133 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Non Profit Settings", {
+ refresh: function(frm) {
+ frm.set_query("inv_print_format", function() {
+ return {
+ filters: {
+ "doc_type": "Sales Invoice"
+ }
+ };
+ });
+
+ frm.set_query("membership_print_format", function() {
+ return {
+ filters: {
+ "doc_type": "Membership"
+ }
+ };
+ });
+
+ frm.set_query("membership_debit_account", function() {
+ return {
+ filters: {
+ "account_type": "Receivable",
+ "is_group": 0,
+ "company": frm.doc.company
+ }
+ };
+ });
+
+ frm.set_query("donation_debit_account", function() {
+ return {
+ filters: {
+ "account_type": "Receivable",
+ "is_group": 0,
+ "company": frm.doc.donation_company
+ }
+ };
+ });
+
+ frm.set_query("membership_payment_account", function () {
+ var account_types = ["Bank", "Cash"];
+ return {
+ filters: {
+ "account_type": ["in", account_types],
+ "is_group": 0,
+ "company": frm.doc.company
+ }
+ };
+ });
+
+ frm.set_query("donation_payment_account", function () {
+ var account_types = ["Bank", "Cash"];
+ return {
+ filters: {
+ "account_type": ["in", account_types],
+ "is_group": 0,
+ "company": frm.doc.donation_company
+ }
+ };
+ });
+
+ let docs_url = "https://docs.erpnext.com/docs/user/manual/en/non_profit/membership";
+
+ frm.set_intro(__("You can learn more about memberships in the manual. ") + `<a href='${docs_url}'>${__('ERPNext Docs')}</a>`, true);
+ frm.trigger("setup_buttons_for_membership");
+ frm.trigger("setup_buttons_for_donation");
+ },
+
+ setup_buttons_for_membership: function(frm) {
+ let label;
+
+ if (frm.doc.membership_webhook_secret) {
+
+ frm.add_custom_button(__("Copy Webhook URL"), () => {
+ frappe.utils.copy_to_clipboard(`https://${frappe.boot.sitename}/api/method/erpnext.non_profit.doctype.membership.membership.trigger_razorpay_subscription`);
+ }, __("Memberships"));
+
+ frm.add_custom_button(__("Revoke Key"), () => {
+ frm.call("revoke_key", {
+ key: "membership_webhook_secret"
+ }).then(() => {
+ frm.refresh();
+ });
+ }, __("Memberships"));
+
+ label = __("Regenerate Webhook Secret");
+
+ } else {
+ label = __("Generate Webhook Secret");
+ }
+
+ frm.add_custom_button(label, () => {
+ frm.call("generate_webhook_secret", {
+ field: "membership_webhook_secret"
+ }).then(() => {
+ frm.refresh();
+ });
+ }, __("Memberships"));
+ },
+
+ setup_buttons_for_donation: function(frm) {
+ let label;
+
+ if (frm.doc.donation_webhook_secret) {
+ label = __("Regenerate Webhook Secret");
+
+ frm.add_custom_button(__("Copy Webhook URL"), () => {
+ frappe.utils.copy_to_clipboard(`https://${frappe.boot.sitename}/api/method/erpnext.non_profit.doctype.donation.donation.capture_razorpay_donations`);
+ }, __("Donations"));
+
+ frm.add_custom_button(__("Revoke Key"), () => {
+ frm.call("revoke_key", {
+ key: "donation_webhook_secret"
+ }).then(() => {
+ frm.refresh();
+ });
+ }, __("Donations"));
+
+ } else {
+ label = __("Generate Webhook Secret");
+ }
+
+ frm.add_custom_button(label, () => {
+ frm.call("generate_webhook_secret", {
+ field: "donation_webhook_secret"
+ }).then(() => {
+ frm.refresh();
+ });
+ }, __("Donations"));
+ }
+});
diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json
new file mode 100644
index 0000000..25ff0c1
--- /dev/null
+++ b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.json
@@ -0,0 +1,273 @@
+{
+ "actions": [],
+ "creation": "2020-03-29 12:57:03.005120",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "enable_razorpay_for_memberships",
+ "razorpay_settings_section",
+ "billing_cycle",
+ "billing_frequency",
+ "membership_webhook_secret",
+ "column_break_6",
+ "allow_invoicing",
+ "automate_membership_invoicing",
+ "automate_membership_payment_entries",
+ "company",
+ "membership_debit_account",
+ "membership_payment_account",
+ "column_break_9",
+ "send_email",
+ "send_invoice",
+ "membership_print_format",
+ "inv_print_format",
+ "email_template",
+ "donation_settings_section",
+ "donation_company",
+ "default_donor_type",
+ "donation_webhook_secret",
+ "column_break_22",
+ "automate_donation_payment_entries",
+ "donation_debit_account",
+ "donation_payment_account",
+ "section_break_27",
+ "creation_user"
+ ],
+ "fields": [
+ {
+ "fieldname": "billing_cycle",
+ "fieldtype": "Select",
+ "label": "Billing Cycle",
+ "options": "Monthly\nYearly"
+ },
+ {
+ "depends_on": "eval:doc.enable_razorpay_for_memberships",
+ "fieldname": "razorpay_settings_section",
+ "fieldtype": "Section Break",
+ "label": "RazorPay Settings for Memberships"
+ },
+ {
+ "description": "The number of billing cycles for which the customer should be charged. For example, if a customer is buying a 1-year membership that should be billed on a monthly basis, this value should be 12.",
+ "fieldname": "billing_frequency",
+ "fieldtype": "Int",
+ "label": "Billing Frequency"
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Section Break",
+ "label": "Membership Invoicing"
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
+ {
+ "description": "This company will be set for the Memberships created via webhook.",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.allow_invoicing && doc.send_email",
+ "fieldname": "send_invoice",
+ "fieldtype": "Check",
+ "label": "Send Invoice with Email"
+ },
+ {
+ "default": "0",
+ "fieldname": "send_email",
+ "fieldtype": "Check",
+ "label": "Send Membership Acknowledgement"
+ },
+ {
+ "depends_on": "eval: doc.send_invoice",
+ "fieldname": "inv_print_format",
+ "fieldtype": "Link",
+ "label": "Invoice Print Format",
+ "mandatory_depends_on": "eval: doc.send_invoice",
+ "options": "Print Format"
+ },
+ {
+ "depends_on": "eval:doc.send_email",
+ "fieldname": "membership_print_format",
+ "fieldtype": "Link",
+ "label": "Membership Print Format",
+ "options": "Print Format"
+ },
+ {
+ "depends_on": "eval:doc.send_email",
+ "fieldname": "email_template",
+ "fieldtype": "Link",
+ "label": "Email Template",
+ "mandatory_depends_on": "eval:doc.send_email",
+ "options": "Email Template"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_invoicing",
+ "fieldtype": "Check",
+ "label": "Allow Invoicing for Memberships",
+ "mandatory_depends_on": "eval:doc.send_invoice || doc.make_payment_entry"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.allow_invoicing",
+ "description": "Automatically create an invoice when payment is authorized from a web form entry",
+ "fieldname": "automate_membership_invoicing",
+ "fieldtype": "Check",
+ "label": "Automate Invoicing for Web Forms"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.allow_invoicing",
+ "description": "Auto creates Payment Entry for Sales Invoices created for Membership from web forms.",
+ "fieldname": "automate_membership_payment_entries",
+ "fieldtype": "Check",
+ "label": "Automate Payment Entry Creation"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_razorpay_for_memberships",
+ "fieldtype": "Check",
+ "label": "Enable RazorPay For Memberships"
+ },
+ {
+ "depends_on": "eval:doc.automate_membership_payment_entries",
+ "description": "Account for accepting membership payments",
+ "fieldname": "membership_payment_account",
+ "fieldtype": "Link",
+ "label": "Membership Payment To",
+ "mandatory_depends_on": "eval:doc.automate_membership_payment_entries",
+ "options": "Account"
+ },
+ {
+ "fieldname": "membership_webhook_secret",
+ "fieldtype": "Password",
+ "label": "Membership Webhook Secret",
+ "read_only": 1
+ },
+ {
+ "fieldname": "donation_webhook_secret",
+ "fieldtype": "Password",
+ "label": "Donation Webhook Secret",
+ "read_only": 1
+ },
+ {
+ "depends_on": "automate_donation_payment_entries",
+ "description": "Account for accepting donation payments",
+ "fieldname": "donation_payment_account",
+ "fieldtype": "Link",
+ "label": "Donation Payment To",
+ "mandatory_depends_on": "automate_donation_payment_entries",
+ "options": "Account"
+ },
+ {
+ "default": "0",
+ "description": "Auto creates Payment Entry for Donations created from web forms.",
+ "fieldname": "automate_donation_payment_entries",
+ "fieldtype": "Check",
+ "label": "Automate Donation Payment Entries"
+ },
+ {
+ "depends_on": "eval:doc.allow_invoicing",
+ "fieldname": "membership_debit_account",
+ "fieldtype": "Link",
+ "label": "Debit Account",
+ "mandatory_depends_on": "eval:doc.allow_invoicing",
+ "options": "Account"
+ },
+ {
+ "depends_on": "automate_donation_payment_entries",
+ "fieldname": "donation_debit_account",
+ "fieldtype": "Link",
+ "label": "Debit Account",
+ "mandatory_depends_on": "automate_donation_payment_entries",
+ "options": "Account"
+ },
+ {
+ "description": "This company will be set for the Donations created via webhook.",
+ "fieldname": "donation_company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "donation_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Donation Settings"
+ },
+ {
+ "fieldname": "column_break_22",
+ "fieldtype": "Column Break"
+ },
+ {
+ "description": "This Donor Type will be set for the Donor created via Donation web form entry.",
+ "fieldname": "default_donor_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Donor Type",
+ "options": "Donor Type",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_27",
+ "fieldtype": "Section Break"
+ },
+ {
+ "description": "The user that will be used to create Donations, Memberships, Invoices, and Payment Entries. This user should have the relevant permissions.",
+ "fieldname": "creation_user",
+ "fieldtype": "Link",
+ "label": "Creation User",
+ "options": "User",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-03-11 10:43:38.124240",
+ "modified_by": "Administrator",
+ "module": "Non Profit",
+ "name": "Non Profit Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Non Profit Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Non Profit Member",
+ "share": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..108554c
--- /dev/null
+++ b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
@@ -0,0 +1,36 @@
+# -*- 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.integrations.utils import get_payment_gateway_controller
+from frappe.model.document import Document
+
+class NonProfitSettings(Document):
+ def generate_webhook_secret(self, field="membership_webhook_secret"):
+ key = frappe.generate_hash(length=20)
+ self.set(field, key)
+ self.save()
+
+ secret_for = "Membership" if field == "membership_webhook_secret" else "Donation"
+
+ frappe.msgprint(
+ _("Here is your webhook secret for {0} API, this will be shown to you only once.").format(secret_for) + "<br><br>" + key,
+ _("Webhook Secret")
+ )
+
+ def revoke_key(self, key):
+ self.set(key, None)
+ self.save()
+
+ def get_webhook_secret(self, endpoint="Membership"):
+ fieldname = "membership_webhook_secret" if endpoint == "Membership" else "donation_webhook_secret"
+ return self.get_password(fieldname=fieldname, raise_exception=False)
+
+@frappe.whitelist()
+def get_plans_for_membership(*args, **kwargs):
+ controller = get_payment_gateway_controller("Razorpay")
+ plans = controller.get_plans()
+ return [plan.get("item") for plan in plans.get("items")]
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py
similarity index 79%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py
index 2ad7984..3f0ede3 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestNonProfitSettings(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/workspace/non_profit/non_profit.json b/erpnext/non_profit/workspace/non_profit/non_profit.json
new file mode 100644
index 0000000..2557d77
--- /dev/null
+++ b/erpnext/non_profit/workspace/non_profit/non_profit.json
@@ -0,0 +1,251 @@
+{
+ "category": "Domains",
+ "charts": [],
+ "creation": "2020-03-02 17:23:47.811421",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "non-profit",
+ "idx": 0,
+ "is_default": 0,
+ "is_standard": 1,
+ "label": "Non Profit",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Management",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Type",
+ "link_to": "Loan Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan Application",
+ "link_to": "Loan Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loan",
+ "link_to": "Loan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Grant Application",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Grant Application",
+ "link_to": "Grant Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Membership",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Member",
+ "link_to": "Member",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Membership",
+ "link_to": "Membership",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Membership Type",
+ "link_to": "Membership Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Membership Settings",
+ "link_to": "Non Profit Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Volunteer",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Volunteer",
+ "link_to": "Volunteer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Volunteer Type",
+ "link_to": "Volunteer Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chapter",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chapter",
+ "link_to": "Chapter",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Donation",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Donor",
+ "link_to": "Donor",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Donor Type",
+ "link_to": "Donor Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Donation",
+ "link_to": "Donation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tax Exemption Certification (India)",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tax Exemption 80G Certificate",
+ "link_to": "Tax Exemption 80G Certificate",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2021-03-11 11:38:09.140655",
+ "modified_by": "Administrator",
+ "module": "Non Profit",
+ "name": "Non Profit",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "restrict_to_domain": "Non Profit",
+ "shortcuts": [
+ {
+ "label": "Member",
+ "link_to": "Member",
+ "type": "DocType"
+ },
+ {
+ "label": "Non Profit Settings",
+ "link_to": "Non Profit Settings",
+ "type": "DocType"
+ },
+ {
+ "label": "Membership",
+ "link_to": "Membership",
+ "type": "DocType"
+ },
+ {
+ "label": "Chapter",
+ "link_to": "Chapter",
+ "type": "DocType"
+ },
+ {
+ "label": "Chapter Member",
+ "link_to": "Chapter Member",
+ "type": "DocType"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 6087ce2..46f0d4a 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -450,7 +450,6 @@
erpnext.patches.v9_0.add_user_to_child_table_in_pos_profile
erpnext.patches.v9_0.set_schedule_date_for_material_request_and_purchase_order
erpnext.patches.v9_0.student_admission_childtable_migrate
-erpnext.patches.v9_0.fix_subscription_next_date #2017-10-23
erpnext.patches.v9_0.add_healthcare_domain
erpnext.patches.v9_0.set_variant_item_description
erpnext.patches.v9_0.set_uoms_in_variant_field
@@ -632,7 +631,7 @@
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
-erpnext.patches.v12_0.generate_leave_ledger_entries #27-08-2020
+erpnext.patches.v12_0.generate_leave_ledger_entries #04-11-2020
execute:frappe.delete_doc_if_exists("Report", "Loan Repayment")
erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
erpnext.patches.v12_0.add_variant_of_in_item_attribute_table
@@ -678,7 +677,7 @@
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
+erpnext.patches.v13_0.replace_pos_payment_mode_table #2020-12-29
erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries #2020-05-22
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
execute:frappe.reload_doc("HR", "doctype", "Employee Advance")
@@ -691,6 +690,7 @@
erpnext.patches.v12_0.set_serial_no_status #2020-05-21
erpnext.patches.v12_0.update_price_list_currency_in_bom
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 #2020-05-25
@@ -711,6 +711,7 @@
execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation")
erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll #22-06-2020
erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings #22-06-2020
+execute:frappe.reload_doc("regional", "doctype", "e_invoice_settings")
erpnext.patches.v13_0.check_is_income_tax_component #22-06-2020
erpnext.patches.v13_0.loyalty_points_entry_for_pos_invoice #22-07-2020
erpnext.patches.v12_0.add_taxjar_integration_field
@@ -719,7 +720,7 @@
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 #4
+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
erpnext.patches.v12_0.rename_lost_reason_detail
@@ -729,3 +730,35 @@
erpnext.patches.v13_0.rename_issue_doctype_fields
erpnext.patches.v13_0.change_default_pos_print_format
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.v12_0.setup_einvoice_fields #2020-12-02
+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")
+erpnext.patches.v13_0.update_member_email_address
+erpnext.patches.v13_0.update_custom_fields_for_shopify
+erpnext.patches.v13_0.updates_for_multi_currency_payroll
+erpnext.patches.v13_0.create_leave_policy_assignment_based_on_employee_current_leave_policy
+erpnext.patches.v13_0.update_pos_closing_entry_in_merge_log
+erpnext.patches.v13_0.add_po_to_global_search
+erpnext.patches.v13_0.update_returned_qty_in_pr_dn
+execute:frappe.rename_doc("Workspace", "Loan", "Loan Management", ignore_if_exists=True, force=True)
+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.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.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
diff --git a/erpnext/patches/v11_0/create_salary_structure_assignments.py b/erpnext/patches/v11_0/create_salary_structure_assignments.py
index c51c381..a908c16 100644
--- a/erpnext/patches/v11_0/create_salary_structure_assignments.py
+++ b/erpnext/patches/v11_0/create_salary_structure_assignments.py
@@ -8,8 +8,8 @@
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import DuplicateAssignment
def execute():
- frappe.reload_doc('Payroll', 'doctype', 'salary_structure')
- frappe.reload_doc("Payroll", "doctype", "salary_structure_assignment")
+ frappe.reload_doc('Payroll', 'doctype', 'Salary Structure')
+ frappe.reload_doc("Payroll", "doctype", "Salary Structure Assignment")
frappe.db.sql("""
delete from `tabSalary Structure Assignment`
where salary_structure in (select name from `tabSalary Structure` where is_active='No' or docstatus!=1)
@@ -33,6 +33,13 @@
AND employee in (select name from `tabEmployee` where ifNull(status, '') != 'Left')
""".format(cols), as_dict=1)
+ all_companies = frappe.db.get_all("Company", fields=["name", "default_currency"])
+ for d in all_companies:
+ company = d.name
+ company_currency = d.default_currency
+
+ frappe.db.sql("""update `tabSalary Structure` set currency = %s where company=%s""", (company_currency, company))
+
for d in ss_details:
try:
joining_date, relieving_date = frappe.db.get_value("Employee", d.employee,
@@ -42,6 +49,7 @@
from_date = joining_date
elif relieving_date and getdate(from_date) > relieving_date:
continue
+ company_currency = frappe.db.get_value('Company', d.company, 'default_currency')
s = frappe.new_doc("Salary Structure Assignment")
s.employee = d.employee
@@ -52,6 +60,7 @@
s.base = d.get("base")
s.variable = d.get("variable")
s.company = d.company
+ s.currency = company_currency
# to migrate the data of the old employees
s.flags.old_employee = True
diff --git a/erpnext/patches/v11_0/refactor_autoname_naming.py b/erpnext/patches/v11_0/refactor_autoname_naming.py
index 5dc5d3b..b997ba2 100644
--- a/erpnext/patches/v11_0/refactor_autoname_naming.py
+++ b/erpnext/patches/v11_0/refactor_autoname_naming.py
@@ -20,7 +20,7 @@
'Certified Consultant': 'NPO-CONS-.YYYY.-.#####',
'Chat Room': 'CHAT-ROOM-.#####',
'Compensatory Leave Request': 'HR-CMP-.YY.-.MM.-.#####',
- 'Custom Script': 'SYS-SCR-.#####',
+ 'Client Script': 'SYS-SCR-.#####',
'Employee Benefit Application': 'HR-BEN-APP-.YY.-.MM.-.#####',
'Employee Benefit Application Detail': '',
'Employee Benefit Claim': 'HR-BEN-CLM-.YY.-.MM.-.#####',
diff --git a/erpnext/patches/v11_1/update_bank_transaction_status.py b/erpnext/patches/v11_1/update_bank_transaction_status.py
index 1acdfcc..544bc5e 100644
--- a/erpnext/patches/v11_1/update_bank_transaction_status.py
+++ b/erpnext/patches/v11_1/update_bank_transaction_status.py
@@ -7,9 +7,20 @@
def execute():
frappe.reload_doc("accounts", "doctype", "bank_transaction")
- frappe.db.sql(""" UPDATE `tabBank Transaction`
- SET status = 'Reconciled'
- WHERE
- status = 'Settled' and (debit = allocated_amount or credit = allocated_amount)
- and ifnull(allocated_amount, 0) > 0
- """)
\ No newline at end of file
+ bank_transaction_fields = frappe.get_meta("Bank Transaction").get_valid_columns()
+
+ if 'debit' in bank_transaction_fields:
+ frappe.db.sql(""" UPDATE `tabBank Transaction`
+ SET status = 'Reconciled'
+ WHERE
+ status = 'Settled' and (debit = allocated_amount or credit = allocated_amount)
+ and ifnull(allocated_amount, 0) > 0
+ """)
+
+ elif 'deposit' in bank_transaction_fields:
+ frappe.db.sql(""" UPDATE `tabBank Transaction`
+ SET status = 'Reconciled'
+ WHERE
+ status = 'Settled' and (deposit = allocated_amount or withdrawal = allocated_amount)
+ and ifnull(allocated_amount, 0) > 0
+ """)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/add_state_code_for_ladakh.py b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
new file mode 100644
index 0000000..29a7b4b
--- /dev/null
+++ b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
@@ -0,0 +1,17 @@
+import frappe
+from erpnext.regional.india import states
+
+def execute():
+
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ custom_fields = ['Address-gst_state', 'Tax Category-gst_state']
+
+ # Update options in gst_state custom fields
+ for field in custom_fields:
+ if frappe.db.exists('Custom Field', field):
+ gst_state_field = frappe.get_doc('Custom Field', field)
+ gst_state_field.options = '\n'.join(states)
+ gst_state_field.save()
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 342c129..fe072d7 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -11,8 +11,6 @@
frappe.reload_doc("HR", "doctype", "Leave Ledger Entry")
frappe.reload_doc("HR", "doctype", "Leave Encashment")
frappe.reload_doc("HR", "doctype", "Leave Type")
- if frappe.db.a_row_exists("Leave Ledger Entry"):
- return
if not frappe.get_meta("Leave Allocation").has_field("unused_leaves"):
frappe.reload_doc("HR", "doctype", "Leave Allocation")
@@ -53,7 +51,7 @@
for encashment in leave_encashments:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
- frappe.get_doc("Leave Enchashment", encashment).create_leave_ledger_entry()
+ frappe.get_doc("Leave Encashment", encashment).create_leave_ledger_entry()
def generate_expiry_allocation_ledger_entries():
''' fix ledger entries for missing leave allocation transaction '''
diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py
new file mode 100644
index 0000000..2474bc3
--- /dev/null
+++ b/erpnext/patches/v12_0/setup_einvoice_fields.py
@@ -0,0 +1,56 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from erpnext.regional.india.setup import add_permissions, add_print_formats
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ frappe.reload_doc("custom", "doctype", "custom_field")
+ frappe.reload_doc("regional", "doctype", "e_invoice_settings")
+ custom_fields = {
+ 'Sales Invoice': [
+ dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
+ depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
+
+ dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
+
+ dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
+
+ dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
+ depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+
+ dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
+ depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+
+ dict(fieldname='signed_einvoice', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
+
+ dict(fieldname='signed_qr_code', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
+
+ dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, no_copy=1, print_hide=1, read_only=1)
+ ]
+ }
+ create_custom_fields(custom_fields, update=True)
+ add_permissions()
+ add_print_formats()
+
+ einvoice_cond = 'in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
+ t = {
+ 'mode_of_transport': [{'default': None}],
+ 'distance': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.transporter'}],
+ 'gst_vehicle_type': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
+ 'lr_date': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
+ 'lr_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
+ 'vehicle_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
+ 'ewaybill': [
+ {'read_only_depends_on': 'eval:doc.irn && doc.ewaybill'},
+ {'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)'}
+ ]
+ }
+
+ for field, conditions in t.items():
+ for c in conditions:
+ [(prop, value)] = c.items()
+ frappe.db.set_value('Custom Field', { 'fieldname': field }, prop, value)
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
new file mode 100644
index 0000000..5ed9040
--- /dev/null
+++ b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
@@ -0,0 +1,13 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter, delete_property_setter
+
+def execute():
+ frappe.reload_doc("projects", "doctype", "project")
+
+ frappe.db.sql("""UPDATE `tabProject`
+ SET
+ naming_series = 'PROJ-.####'
+ WHERE
+ naming_series is NULL""")
+
diff --git a/erpnext/patches/v13_0/add_po_to_global_search.py b/erpnext/patches/v13_0/add_po_to_global_search.py
new file mode 100644
index 0000000..1c60b18
--- /dev/null
+++ b/erpnext/patches/v13_0/add_po_to_global_search.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+import frappe
+
+
+def execute():
+ global_search_settings = frappe.get_single("Global Search Settings")
+
+ if "Purchase Order" in (
+ dt.document_type for dt in global_search_settings.allowed_in_global_search
+ ):
+ return
+
+ global_search_settings.append(
+ "allowed_in_global_search", {"document_type": "Purchase Order"}
+ )
+
+ global_search_settings.save(ignore_permissions=True)
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
new file mode 100644
index 0000000..289b6a7
--- /dev/null
+++ b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
@@ -0,0 +1,23 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('stock', 'doctype', 'quality_inspection_parameter')
+
+ # get all distinct parameters from QI readigs table
+ reading_params = frappe.db.get_all("Quality Inspection Reading", fields=["distinct specification"])
+ reading_params = [d.specification for d in reading_params]
+
+ # get all distinct parameters from QI Template as some may be unused in QI
+ template_params = frappe.db.get_all("Item Quality Inspection Parameter", fields=["distinct specification"])
+ template_params = [d.specification for d in template_params]
+
+ params = list(set(reading_params + template_params))
+
+ for parameter in params:
+ if not frappe.db.exists("Quality Inspection Parameter", parameter):
+ frappe.get_doc({
+ "doctype": "Quality Inspection Parameter",
+ "parameter": parameter,
+ "description": parameter
+ }).insert(ignore_permissions=True)
\ No newline at end of file
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
new file mode 100644
index 0000000..585e540
--- /dev/null
+++ b/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
@@ -0,0 +1,10 @@
+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'])
\ No newline at end of file
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
new file mode 100644
index 0000000..90dc0e2
--- /dev/null
+++ b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
@@ -0,0 +1,79 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+
+def execute():
+ if "leave_policy" in frappe.db.get_table_columns("Employee"):
+ employees_with_leave_policy = frappe.db.sql("SELECT name, leave_policy FROM `tabEmployee` WHERE leave_policy IS NOT NULL and leave_policy != ''", as_dict = 1)
+
+ employee_with_assignment = []
+ leave_policy =[]
+
+ #for employee
+
+ for employee in employees_with_leave_policy:
+ alloc = frappe.db.exists("Leave Allocation", {"employee":employee.name, "leave_policy": employee.leave_policy, "docstatus": 1})
+ if not alloc:
+ create_assignment(employee.name, employee.leave_policy)
+
+ employee_with_assignment.append(employee.name)
+ leave_policy.append(employee.leave_policy)
+
+
+ if "default_leave_policy" in frappe.db.get_table_columns("Employee"):
+ employee_grade_with_leave_policy = frappe.db.sql("SELECT name, default_leave_policy FROM `tabEmployee Grade` WHERE default_leave_policy IS NOT NULL and default_leave_policy!=''", as_dict = 1)
+
+ #for whole employee Grade
+
+ for grade in employee_grade_with_leave_policy:
+ employees = get_employee_with_grade(grade.name)
+ for employee in employees:
+
+ if employee not in employee_with_assignment: #Will ensure no duplicate
+ alloc = frappe.db.exists("Leave Allocation", {"employee":employee.name, "leave_policy": grade.default_leave_policy, "docstatus": 1})
+ if not alloc:
+ create_assignment(employee.name, grade.default_leave_policy)
+ leave_policy.append(grade.default_leave_policy)
+
+ #for old Leave allocation and leave policy from allocation, which may got updated in employee grade.
+ leave_allocations = frappe.db.sql("SELECT leave_policy, leave_period, employee FROM `tabLeave Allocation` WHERE leave_policy IS NOT NULL and leave_policy != '' and docstatus = 1 ", as_dict = 1)
+
+ for allocation in leave_allocations:
+ if allocation.leave_policy not in leave_policy:
+ create_assignment(allocation.employee, allocation.leave_policy, leave_period=allocation.leave_period,
+ allocation_exists=True)
+
+def create_assignment(employee, leave_policy, leave_period=None, allocation_exists = False):
+
+ filters = {"employee":employee, "leave_policy": leave_policy}
+ if leave_period:
+ filters["leave_period"] = leave_period
+
+ frappe.reload_doc('hr', 'doctype', 'leave_policy_assignment')
+
+ if not frappe.db.exists("Leave Policy Assignment" , filters):
+ lpa = frappe.new_doc("Leave Policy Assignment")
+ lpa.employee = employee
+ lpa.leave_policy = leave_policy
+
+ lpa.flags.ignore_mandatory = True
+ if allocation_exists:
+ lpa.assignment_based_on = 'Leave Period'
+ lpa.leave_period = leave_period
+ lpa.leaves_allocated = 1
+
+ lpa.save()
+ if allocation_exists:
+ lpa.submit()
+ #Updating old Leave Allocation
+ frappe.db.sql("Update `tabLeave Allocation` set leave_policy_assignment = %s", lpa.name)
+
+
+def get_employee_with_grade(grade):
+ return frappe.get_list("Employee", filters = {"grade": grade})
+
+
+
diff --git a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
new file mode 100644
index 0000000..48d5cb4
--- /dev/null
+++ b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from erpnext.regional.united_arab_emirates.setup import make_custom_fields
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': ['in', ['Saudi Arabia', 'United Arab Emirates']]})
+ if not company:
+ return
+
+ make_custom_fields()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
new file mode 100644
index 0000000..af1f6e7
--- /dev/null
+++ b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
@@ -0,0 +1,26 @@
+# 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
+
+def execute():
+ doctypes = [
+ "Bank Statement Settings",
+ "Bank Statement Settings Item",
+ "Bank Statement Transaction Entry",
+ "Bank Statement Transaction Invoice Item",
+ "Bank Statement Transaction Payment Item",
+ "Bank Statement Transaction Settings Item",
+ "Bank Statement Transaction Settings",
+ ]
+
+ for doctype in doctypes:
+ frappe.delete_doc("DocType", doctype, force=1)
+
+ frappe.delete_doc("Page", "bank-reconciliation", force=1)
+
+ rename_field("Bank Transaction", "debit", "deposit")
+ rename_field("Bank Transaction", "credit", "withdrawal")
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
new file mode 100644
index 0000000..d968e1f
--- /dev/null
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -0,0 +1,63 @@
+import frappe
+from frappe import _
+from frappe.utils import getdate, get_time, today
+from erpnext.stock.stock_ledger import update_entries_after
+from erpnext.accounts.utils import update_gl_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')
+
+ reposting_project_deployed_on = get_creation_time()
+ posting_date = getdate(reposting_project_deployed_on)
+ posting_time = get_time(reposting_project_deployed_on)
+
+ if posting_date == today():
+ return
+
+ frappe.clear_cache()
+ frappe.flags.warehouse_account_map = {}
+
+ data = frappe.db.sql('''
+ SELECT
+ name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time
+ FROM
+ `tabStock Ledger Entry`
+ WHERE
+ creation > %s
+ and is_cancelled = 0
+ ORDER BY timestamp(posting_date, posting_time) asc, creation asc
+ ''', reposting_project_deployed_on, as_dict=1)
+
+ frappe.db.auto_commit_on_many_writes = 1
+ print("Reposting Stock Ledger Entries...")
+ total_sle = len(data)
+ i = 0
+ for d in data:
+ update_entries_after({
+ "item_code": d.item_code,
+ "warehouse": d.warehouse,
+ "posting_date": d.posting_date,
+ "posting_time": d.posting_time,
+ "voucher_type": d.voucher_type,
+ "voucher_no": d.voucher_no,
+ "sle_id": d.name
+ }, allow_negative_stock=True)
+
+ i += 1
+ if i%100 == 0:
+ print(i, "/", total_sle)
+
+
+ print("Reposting General Ledger Entries...")
+
+ for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
+ update_gl_entries_after(posting_date, posting_time, company=row.name)
+
+ frappe.db.auto_commit_on_many_writes = 0
+
+def get_creation_time():
+ return frappe.db.sql(''' SELECT create_time FROM
+ INFORMATION_SCHEMA.TABLES where TABLE_NAME = "tabRepost Item Valuation" ''', as_list=1)[0][0]
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/print_uom_after_quantity_patch.py b/erpnext/patches/v13_0/print_uom_after_quantity_patch.py
new file mode 100644
index 0000000..0de3728
--- /dev/null
+++ b/erpnext/patches/v13_0/print_uom_after_quantity_patch.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from erpnext.setup.install import create_print_uom_after_qty_custom_field
+
+def execute():
+ 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
new file mode 100644
index 0000000..491dc82
--- /dev/null
+++ b/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+ frappe.reload_doc("Healthcare", "doctype", "Inpatient Record")
+ if frappe.db.has_column("Inpatient Record", "discharge_date"):
+ rename_field("Inpatient Record", "discharge_date", "discharge_datetime")
diff --git a/erpnext/patches/v13_0/rename_issue_doctype_fields.py b/erpnext/patches/v13_0/rename_issue_doctype_fields.py
index 5bd6596..fa1dfed 100644
--- a/erpnext/patches/v13_0/rename_issue_doctype_fields.py
+++ b/erpnext/patches/v13_0/rename_issue_doctype_fields.py
@@ -29,7 +29,7 @@
'response_by_variance': response_by_variance,
'resolution_by_variance': resolution_by_variance,
'first_response_time': mins_to_first_response
- })
+ }, update_modified=False)
# commit after every 100 updates
count += 1
if count%100 == 0:
@@ -44,7 +44,7 @@
count = 0
for entry in opportunities:
mins_to_first_response = convert_to_seconds(entry.mins_to_first_response, 'Minutes')
- frappe.db.set_value('Opportunity', entry.name, 'first_response_time', mins_to_first_response)
+ frappe.db.set_value('Opportunity', entry.name, 'first_response_time', mins_to_first_response, update_modified=False)
# commit after every 100 updates
count += 1
if count%100 == 0:
@@ -53,7 +53,7 @@
# renamed reports from "Minutes to First Response for Issues" to "First Response Time for Issues". Same for Opportunity
for report in ['Minutes to First Response for Issues', 'Minutes to First Response for Opportunity']:
if frappe.db.exists('Report', report):
- frappe.delete_doc('Report', report)
+ frappe.delete_doc('Report', report, ignore_permissions=True)
def convert_to_seconds(value, unit):
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
new file mode 100644
index 0000000..3fa09a7
--- /dev/null
+++ b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
@@ -0,0 +1,22 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+ if frappe.db.table_exists("Membership Settings"):
+ frappe.rename_doc("DocType", "Membership Settings", "Non Profit Settings")
+ frappe.reload_doctype("Non Profit Settings", force=True)
+
+ if frappe.db.table_exists("Non Profit Settings"):
+ rename_fields_map = {
+ "enable_invoicing": "allow_invoicing",
+ "create_for_web_forms": "automate_membership_invoicing",
+ "make_payment_entry": "automate_membership_payment_entries",
+ "enable_razorpay": "enable_razorpay_for_memberships",
+ "debit_account": "membership_debit_account",
+ "payment_account": "membership_payment_account",
+ "webhook_secret": "membership_webhook_secret"
+ }
+
+ for old_name, new_name in rename_fields_map.items():
+ rename_field("Non Profit Settings", old_name, new_name)
\ No newline at end of file
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 1ca211b..7cb2648 100644
--- a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
+++ b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
@@ -6,12 +6,10 @@
import frappe
def execute():
- frappe.reload_doc("accounts", "doctype", "POS Payment Method")
+ frappe.reload_doc("accounts", "doctype", "pos_payment_method")
pos_profiles = frappe.get_all("POS Profile")
for pos_profile in pos_profiles:
- if not pos_profile.get("payments"): return
-
payments = frappe.db.sql("""
select idx, parentfield, parenttype, parent, mode_of_payment, `default` from `tabSales Invoice Payment` where parent=%s
""", pos_profile.name, as_dict=1)
diff --git a/erpnext/patches/v13_0/set_app_name.py b/erpnext/patches/v13_0/set_app_name.py
new file mode 100644
index 0000000..3f886f1
--- /dev/null
+++ b/erpnext/patches/v13_0/set_app_name.py
@@ -0,0 +1,7 @@
+import frappe
+from frappe import _
+
+def execute():
+ frappe.reload_doctype("System Settings")
+ settings = frappe.get_doc("System Settings")
+ settings.db_set("app_name", "ERPNext", commit=True)
diff --git a/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py b/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
new file mode 100644
index 0000000..66857c4
--- /dev/null
+++ b/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
@@ -0,0 +1,7 @@
+import frappe
+
+def execute():
+ frappe.reload_doc('HR', 'doctype', 'Leave Allocation')
+ frappe.reload_doc('HR', 'doctype', 'Leave Ledger Entry')
+ frappe.db.sql("""update `tabLeave Ledger Entry` as lle set company = (select company from `tabEmployee` where employee = lle.employee)""")
+ frappe.db.sql("""update `tabLeave Allocation` as la set company = (select company from `tabEmployee` where employee = la.employee)""")
\ No newline at end of file
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
new file mode 100644
index 0000000..edca238
--- /dev/null
+++ b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ """Set the payment gateway account as Email for all the existing payment channel."""
+ doc_meta = frappe.get_meta("Payment Gateway Account")
+ if doc_meta.get_field("payment_channel"):
+ return
+
+ frappe.reload_doc("Accounts", "doctype", "Payment Gateway Account")
+ set_payment_channel_as_email()
+
+def set_payment_channel_as_email():
+ frappe.db.sql("""
+ UPDATE `tabPayment Gateway Account`
+ SET `payment_channel` = "Email"
+ """)
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py b/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py
new file mode 100644
index 0000000..833c355
--- /dev/null
+++ b/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py
@@ -0,0 +1,13 @@
+import frappe
+from erpnext.regional.india.setup import make_custom_fields
+
+def execute():
+ if frappe.get_all('Company', filters = {'country': 'India'}):
+ make_custom_fields()
+
+ if not frappe.db.exists('Party Type', 'Donor'):
+ frappe.get_doc({
+ 'doctype': 'Party Type',
+ 'party_type': 'Donor',
+ 'account_type': 'Receivable'
+ }).insert(ignore_permissions=True)
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
new file mode 100644
index 0000000..01fd6a1
--- /dev/null
+++ b/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py
@@ -0,0 +1,16 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('payroll', 'doctype', 'gratuity_rule')
+ frappe.reload_doc('payroll', 'doctype', 'gratuity_rule_slab')
+ frappe.reload_doc('payroll', 'doctype', 'gratuity_applicable_component')
+ if frappe.db.exists("Company", {"country": "India"}):
+ from erpnext.regional.india.setup import create_gratuity_rule
+ create_gratuity_rule()
+ if frappe.db.exists("Company", {"country": "United Arab Emirates"}):
+ from erpnext.regional.united_arab_emirates.setup import create_gratuity_rule
+ create_gratuity_rule()
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
new file mode 100644
index 0000000..de08aa2
--- /dev/null
+++ b/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
@@ -0,0 +1,13 @@
+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", "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()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/setup_uae_vat_fields.py b/erpnext/patches/v13_0/setup_uae_vat_fields.py
new file mode 100644
index 0000000..d7a5c68
--- /dev/null
+++ b/erpnext/patches/v13_0/setup_uae_vat_fields.py
@@ -0,0 +1,12 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+from erpnext.regional.united_arab_emirates.setup import setup
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'United Arab Emirates'})
+ if not company:
+ return
+
+ setup()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/update_custom_fields_for_shopify.py b/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
new file mode 100644
index 0000000..f1d2ea2
--- /dev/null
+++ b/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import setup_custom_fields
+
+def execute():
+ if frappe.db.get_single_value('Shopify Settings', 'enable_shopify'):
+ setup_custom_fields()
diff --git a/erpnext/patches/v13_0/update_member_email_address.py b/erpnext/patches/v13_0/update_member_email_address.py
new file mode 100644
index 0000000..4056f84
--- /dev/null
+++ b/erpnext/patches/v13_0/update_member_email_address.py
@@ -0,0 +1,23 @@
+# 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
+
+def execute():
+ """add value to email_id column from email"""
+
+ if frappe.db.has_column("Member", "email"):
+ # Get all members
+ for member in frappe.db.get_all("Member", pluck="name"):
+ # Check if email_id already exists
+ if not frappe.db.get_value("Member", member, "email_id"):
+ # fetch email id from the user linked field email
+ email = frappe.db.get_value("Member", member, "email")
+
+ # Set the value for it
+ frappe.db.set_value("Member", member, "email_id", email)
+
+ if frappe.db.exists("DocType", "Membership Settings"):
+ rename_field("Membership Settings", "enable_auto_invoicing", "enable_invoicing")
diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py
index 7723942..8cf09aa 100644
--- a/erpnext/patches/v13_0/update_old_loans.py
+++ b/erpnext/patches/v13_0/update_old_loans.py
@@ -1,10 +1,12 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import nowdate
+from frappe.utils import nowdate, flt
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
from erpnext.loan_management.doctype.loan.loan import make_repayment_entry
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import get_accrued_interest_entries
+from frappe.model.naming import make_autoname
def execute():
@@ -18,15 +20,29 @@
frappe.reload_doc('loan_management', 'doctype', 'loan_repayment_detail')
frappe.reload_doc('loan_management', 'doctype', 'loan_interest_accrual')
frappe.reload_doc('accounts', 'doctype', 'gl_entry')
+ frappe.reload_doc('accounts', 'doctype', 'journal_entry_account')
updated_loan_types = []
+ loans_to_close = []
+
+ # Update old loan status as closed
+ if frappe.db.has_column('Repayment Schedule', 'paid'):
+ loans_list = frappe.db.sql("""SELECT distinct parent from `tabRepayment Schedule`
+ where paid = 0 and docstatus = 1""", as_dict=1)
+
+ loans_to_close = [d.parent for d in loans_list]
+
+ if loans_to_close:
+ frappe.db.sql("UPDATE `tabLoan` set status = 'Closed' where name not in (%s)" % (', '.join(['%s'] * len(loans_to_close))), tuple(loans_to_close))
loans = frappe.get_all('Loan', fields=['name', 'loan_type', 'company', 'status', 'mode_of_payment',
- 'applicant_type', 'applicant', 'loan_account', 'payment_account', 'interest_income_account'])
+ 'applicant_type', 'applicant', 'loan_account', 'payment_account', 'interest_income_account'],
+ filters={'docstatus': 1, 'status': ('!=', 'Closed')})
for loan in loans:
# Update details in Loan Types and Loan
loan_type_company = frappe.db.get_value('Loan Type', loan.loan_type, 'company')
+ loan_type = loan.loan_type
group_income_account = frappe.get_value('Account', {'company': loan.company,
'is_group': 1, 'root_type': 'Income', 'account_name': _('Indirect Income')})
@@ -38,7 +54,26 @@
penalty_account = create_account(company=loan.company, account_type='Income Account',
account_name='Penalty Account', parent_account=group_income_account)
- if not loan_type_company:
+ # Same loan type used for multiple companies
+ if loan_type_company and loan_type_company != loan.company:
+ # get loan type for appropriate company
+ loan_type_name = frappe.get_value('Loan Type', {'company': loan.company,
+ 'mode_of_payment': loan.mode_of_payment, 'loan_account': loan.loan_account,
+ 'payment_account': loan.payment_account, 'interest_income_account': loan.interest_income_account,
+ 'penalty_income_account': loan.penalty_income_account}, 'name')
+
+ if not loan_type_name:
+ loan_type_name = create_loan_type(loan, loan_type_name, penalty_account)
+
+ # update loan type in loan
+ frappe.db.sql("UPDATE `tabLoan` set loan_type = %s where name = %s", (loan_type_name,
+ loan.name))
+
+ loan_type = loan_type_name
+ if loan_type_name not in updated_loan_types:
+ updated_loan_types.append(loan_type_name)
+
+ elif not loan_type_company:
loan_type_doc = frappe.get_doc('Loan Type', loan.loan_type)
loan_type_doc.is_term_loan = 1
loan_type_doc.company = loan.company
@@ -49,8 +84,9 @@
loan_type_doc.penalty_income_account = penalty_account
loan_type_doc.submit()
updated_loan_types.append(loan.loan_type)
+ loan_type = loan.loan_type
- if loan.loan_type in updated_loan_types:
+ if loan_type in updated_loan_types:
if loan.status == 'Fully Disbursed':
status = 'Disbursed'
elif loan.status == 'Repaid/Closed':
@@ -64,25 +100,48 @@
'status': status
})
- process_loan_interest_accrual_for_term_loans(posting_date=nowdate(), loan_type=loan.loan_type,
+ process_loan_interest_accrual_for_term_loans(posting_date=nowdate(), loan_type=loan_type,
loan=loan.name)
- payments = frappe.db.sql(''' SELECT j.name, a.debit, a.debit_in_account_currency, j.posting_date
- FROM `tabJournal Entry` j, `tabJournal Entry Account` a
- WHERE a.parent = j.name and a.reference_type='Loan' and a.reference_name = %s
- and account = %s
- ''', (loan.name, loan.loan_account), as_dict=1)
- for payment in payments:
- repayment_entry = make_repayment_entry(loan.name, loan.loan_applicant_type, loan.applicant,
- loan.loan_type, loan.company)
+ if frappe.db.has_column('Repayment Schedule', 'paid'):
+ total_principal, total_interest = frappe.db.get_value('Repayment Schedule', {'paid': 1, 'parent': loan.name},
+ ['sum(principal_amount) as total_principal', 'sum(interest_amount) as total_interest'])
- repayment_entry.amount_paid = payment.debit_in_account_currency
- repayment_entry.posting_date = payment.posting_date
- repayment_entry.save()
- repayment_entry.submit()
+ accrued_entries = get_accrued_interest_entries(loan.name)
+ for entry in accrued_entries:
+ interest_paid = 0
+ principal_paid = 0
- jv = frappe.get_doc('Journal Entry', payment.name)
- jv.flags.ignore_links = True
- jv.cancel()
+ if flt(total_interest) > flt(entry.interest_amount):
+ interest_paid = flt(entry.interest_amount)
+ else:
+ interest_paid = flt(total_interest)
+ if flt(total_principal) > flt(entry.payable_principal_amount):
+ principal_paid = flt(entry.payable_principal_amount)
+ else:
+ principal_paid = flt(total_principal)
+
+ frappe.db.sql(""" UPDATE `tabLoan Interest Accrual`
+ SET paid_principal_amount = `paid_principal_amount` + %s,
+ paid_interest_amount = `paid_interest_amount` + %s
+ WHERE name = %s""",
+ (principal_paid, interest_paid, entry.name))
+
+ total_principal = flt(total_principal) - principal_paid
+ total_interest = flt(total_interest) - interest_paid
+
+def create_loan_type(loan, loan_type_name, penalty_account):
+ loan_type_doc = frappe.new_doc('Loan Type')
+ loan_type_doc.loan_name = make_autoname("Loan Type-.####")
+ loan_type_doc.is_term_loan = 1
+ loan_type_doc.company = loan.company
+ loan_type_doc.mode_of_payment = loan.mode_of_payment
+ loan_type_doc.payment_account = loan.payment_account
+ loan_type_doc.loan_account = loan.loan_account
+ loan_type_doc.interest_income_account = loan.interest_income_account
+ loan_type_doc.penalty_income_account = penalty_account
+ loan_type_doc.submit()
+
+ return loan_type_doc.name
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
new file mode 100644
index 0000000..262e38d
--- /dev/null
+++ b/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py
@@ -0,0 +1,25 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("accounts", "doctype", "POS Invoice Merge Log")
+ frappe.reload_doc("accounts", "doctype", "POS Closing Entry")
+ if frappe.db.count('POS Invoice Merge Log'):
+ frappe.db.sql('''
+ UPDATE
+ `tabPOS Invoice Merge Log` log, `tabPOS Invoice Reference` log_ref
+ SET
+ log.pos_closing_entry = (
+ SELECT clo_ref.parent FROM `tabPOS Invoice Reference` clo_ref
+ WHERE clo_ref.pos_invoice = log_ref.pos_invoice
+ AND clo_ref.parenttype = 'POS Closing Entry' LIMIT 1
+ )
+ WHERE
+ log_ref.parent = log.name
+ ''')
+
+ frappe.db.sql('''UPDATE `tabPOS Closing Entry` SET status = 'Submitted' where docstatus = 1''')
+ frappe.db.sql('''UPDATE `tabPOS Closing Entry` SET status = 'Cancelled' where docstatus = 2''')
diff --git a/erpnext/patches/v13_0/update_project_template_tasks.py b/erpnext/patches/v13_0/update_project_template_tasks.py
new file mode 100644
index 0000000..8cc27d2
--- /dev/null
+++ b/erpnext/patches/v13_0/update_project_template_tasks.py
@@ -0,0 +1,47 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("projects", "doctype", "project_template")
+ frappe.reload_doc("projects", "doctype", "project_template_task")
+ frappe.reload_doc("projects", "doctype", "task")
+
+ # Update property setter status if any
+ property_setter = frappe.db.get_value('Property Setter', {'doc_type': 'Task',
+ 'field_name': 'status', 'property': 'options'})
+
+ if property_setter:
+ property_setter_doc = frappe.get_doc('Property Setter', {'doc_type': 'Task',
+ 'field_name': 'status', 'property': 'options'})
+ property_setter_doc.value += "\nTemplate"
+ property_setter_doc.save()
+
+ for template_name in frappe.get_all('Project Template'):
+ template = frappe.get_doc("Project Template", template_name.name)
+ replace_tasks = False
+ new_tasks = []
+ for task in template.tasks:
+ if task.subject:
+ replace_tasks = True
+ new_task = frappe.get_doc(dict(
+ doctype = "Task",
+ subject = task.subject,
+ start = task.start,
+ duration = task.duration,
+ task_weight = task.task_weight,
+ description = task.description,
+ is_template = 1
+ )).insert()
+ new_tasks.append(new_task)
+
+ if replace_tasks:
+ template.tasks = []
+ for tsk in new_tasks:
+ template.append("tasks", {
+ "task": tsk.name,
+ "subject": tsk.subject
+ })
+ template.save()
\ No newline at end of file
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
new file mode 100644
index 0000000..792118f
--- /dev/null
+++ b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("hr", "doctype", "employee")
+
+ if frappe.db.has_column("Employee", "reason_for_resignation"):
+ frappe.db.sql(""" UPDATE `tabEmployee`
+ SET reason_for_leaving = reason_for_resignation
+ WHERE status = 'Left' and reason_for_leaving is null and reason_for_resignation is not null
+ """)
+
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
new file mode 100644
index 0000000..7f42cd9
--- /dev/null
+++ b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('stock', 'doctype', 'purchase_receipt')
+ frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item')
+ frappe.reload_doc('stock', 'doctype', 'delivery_note')
+ frappe.reload_doc('stock', 'doctype', 'delivery_note_item')
+
+ def update_from_return_docs(doctype):
+ for return_doc in frappe.get_all(doctype, filters={'is_return' : 1, 'docstatus' : 1}):
+ # Update original receipt/delivery document from return
+ return_doc = frappe.get_cached_doc(doctype, return_doc.name)
+ return_doc.update_prevdoc_status()
+ return_against = frappe.get_doc(doctype, return_doc.return_against)
+ return_against.update_billing_status()
+
+ # Set received qty in stock uom in PR, as returned qty is checked against it
+ frappe.db.sql(""" update `tabPurchase Receipt Item`
+ set received_stock_qty = received_qty * conversion_factor
+ where docstatus = 1 """)
+
+ for doctype in ('Purchase Receipt', 'Delivery Note'):
+ update_from_return_docs(doctype)
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py b/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py
new file mode 100644
index 0000000..c26cddb
--- /dev/null
+++ b/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ if frappe.db.exists('Custom Field', { 'fieldname': 'vehicle_no' }):
+ frappe.db.set_value('Custom Field', { 'fieldname': 'vehicle_no' }, 'mandatory_depends_on', '')
diff --git a/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py b/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
new file mode 100644
index 0000000..340bf49
--- /dev/null
+++ b/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
@@ -0,0 +1,136 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+from frappe import _
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+
+ frappe.reload_doc('Accounts', 'doctype', 'Salary Component Account')
+ if frappe.db.has_column('Salary Component Account', 'default_account'):
+ rename_field("Salary Component Account", "default_account", "account")
+
+ doctype_list = [
+ {
+ 'module':'HR',
+ 'doctype':'Employee Advance'
+ },
+ {
+ 'module':'HR',
+ 'doctype':'Leave Encashment'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Additional Salary'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Employee Benefit Application'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Employee Benefit Claim'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Employee Incentive'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Employee Tax Exemption Declaration'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Employee Tax Exemption Proof Submission'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Income Tax Slab'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Payroll Entry'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Retention Bonus'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Salary Structure'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Salary Structure Assignment'
+ },
+ {
+ 'module':'Payroll',
+ 'doctype':'Salary Slip'
+ },
+ ]
+
+ for item in doctype_list:
+ frappe.reload_doc(item['module'], 'doctype', item['doctype'])
+
+ # update company in employee advance based on employee company
+ for dt in ['Employee Incentive', 'Leave Encashment', 'Employee Benefit Application', 'Employee Benefit Claim']:
+ frappe.db.sql("""
+ update `tab{doctype}`
+ set company = (select company from tabEmployee where name=`tab{doctype}`.employee)
+ """.format(doctype=dt))
+
+ # update exchange rate for employee advance
+ frappe.db.sql("update `tabEmployee Advance` set exchange_rate=1")
+
+ # get all companies and it's currency
+ all_companies = frappe.db.get_all("Company", fields=["name", "default_currency", "default_payroll_payable_account"])
+ for d in all_companies:
+ company = d.name
+ company_currency = d.default_currency
+ default_payroll_payable_account = d.default_payroll_payable_account
+
+ if not default_payroll_payable_account:
+ default_payroll_payable_account = frappe.db.get_value("Account",
+ {"account_name": _("Payroll Payable"), "company": company, "account_currency": company_currency, "is_group": 0})
+
+ # update currency in following doctypes based on company currency
+ doctypes_for_currency = ['Employee Advance', 'Leave Encashment', 'Employee Benefit Application',
+ 'Employee Benefit Claim', 'Employee Incentive', 'Additional Salary',
+ 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission',
+ 'Income Tax Slab', 'Retention Bonus', 'Salary Structure']
+
+ for dt in doctypes_for_currency:
+ frappe.db.sql("""update `tab{doctype}` set currency = %s where company=%s"""
+ .format(doctype=dt), (company_currency, company))
+
+ # update fields in payroll entry
+ frappe.db.sql("""
+ update `tabPayroll Entry`
+ set currency = %s,
+ exchange_rate = 1,
+ payroll_payable_account=%s
+ where company=%s
+ """, (company_currency, default_payroll_payable_account, company))
+
+ # update fields in Salary Structure Assignment
+ frappe.db.sql("""
+ update `tabSalary Structure Assignment`
+ set currency = %s,
+ payroll_payable_account=%s
+ where company=%s
+ """, (company_currency, default_payroll_payable_account, company))
+
+ # update fields in Salary Slip
+ frappe.db.sql("""
+ update `tabSalary Slip`
+ set currency = %s,
+ exchange_rate = 1,
+ base_hour_rate = hour_rate,
+ base_gross_pay = gross_pay,
+ base_total_deduction = total_deduction,
+ base_net_pay = net_pay,
+ base_rounded_total = rounded_total,
+ base_total_in_words = total_in_words
+ where company=%s
+ """, (company_currency, company))
diff --git a/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py b/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py
index ad043dd..97e217a 100644
--- a/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py
+++ b/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py
@@ -5,11 +5,11 @@
import frappe
def execute():
- # udpate sales cycle
+ # update sales cycle
for d in ['Sales Invoice', 'Sales Order', 'Quotation', 'Delivery Note']:
frappe.db.sql("""update `tab%s` set taxes_and_charges=charge""" % d)
- # udpate purchase cycle
+ # update purchase cycle
for d in ['Purchase Invoice', 'Purchase Order', 'Supplier Quotation', 'Purchase Receipt']:
frappe.db.sql("""update `tab%s` set taxes_and_charges=purchase_other_charges""" % d)
diff --git a/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py b/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py
index ef3f1d6..c564f8b 100644
--- a/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py
+++ b/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py
@@ -9,7 +9,7 @@
# NOTE: sequence is important
renamed_fields = get_all_renamed_fields()
- for dt, script_field, ref_dt_field in (("Custom Script", "script", "dt"), ("Print Format", "html", "doc_type")):
+ for dt, script_field, ref_dt_field in (("Client Script", "script", "dt"), ("Print Format", "html", "doc_type")):
cond1 = " or ".join("""{0} like "%%{1}%%" """.format(script_field, d[0].replace("_", "\\_")) for d in renamed_fields)
cond2 = " and standard = 'No'" if dt == "Print Format" else ""
diff --git a/erpnext/patches/v7_0/po_status_issue_for_pr_return.py b/erpnext/patches/v7_0/po_status_issue_for_pr_return.py
index 6e92ffb..910814f 100644
--- a/erpnext/patches/v7_0/po_status_issue_for_pr_return.py
+++ b/erpnext/patches/v7_0/po_status_issue_for_pr_return.py
@@ -7,19 +7,23 @@
def execute():
parent_list = []
count = 0
- for data in frappe.db.sql("""
- select
+
+ frappe.reload_doc('stock', 'doctype', 'purchase_receipt')
+ frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item')
+
+ for data in frappe.db.sql("""
+ select
`tabPurchase Receipt Item`.purchase_order, `tabPurchase Receipt Item`.name,
`tabPurchase Receipt Item`.item_code, `tabPurchase Receipt Item`.idx,
`tabPurchase Receipt Item`.parent
- from
+ from
`tabPurchase Receipt Item`, `tabPurchase Receipt`
where
`tabPurchase Receipt Item`.parent = `tabPurchase Receipt`.name and
`tabPurchase Receipt Item`.purchase_order_item is null and
`tabPurchase Receipt Item`.purchase_order is not null and
`tabPurchase Receipt`.is_return = 1""", as_dict=1):
- name = frappe.db.get_value('Purchase Order Item',
+ name = frappe.db.get_value('Purchase Order Item',
{'item_code': data.item_code, 'parent': data.purchase_order, 'idx': data.idx}, 'name')
if name:
diff --git a/erpnext/patches/v7_0/remove_doctypes_and_reports.py b/erpnext/patches/v7_0/remove_doctypes_and_reports.py
index 746cae0..2356e2f 100644
--- a/erpnext/patches/v7_0/remove_doctypes_and_reports.py
+++ b/erpnext/patches/v7_0/remove_doctypes_and_reports.py
@@ -7,7 +7,7 @@
where name in('Time Log Batch', 'Time Log Batch Detail', 'Time Log')""")
frappe.db.sql("""delete from `tabDocField` where parent in ('Time Log', 'Time Log Batch')""")
- frappe.db.sql("""update `tabCustom Script` set dt = 'Timesheet' where dt = 'Time Log'""")
+ frappe.db.sql("""update `tabClient Script` set dt = 'Timesheet' where dt = 'Time Log'""")
for data in frappe.db.sql(""" select label, fieldname from `tabCustom Field` where dt = 'Time Log'""", as_dict=1):
custom_field = frappe.get_doc({
diff --git a/erpnext/patches/v9_0/fix_subscription_next_date.py b/erpnext/patches/v9_0/fix_subscription_next_date.py
deleted file mode 100644
index 4595c8d..0000000
--- a/erpnext/patches/v9_0/fix_subscription_next_date.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# 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 import getdate
-from frappe.automation.doctype.auto_repeat.auto_repeat import get_next_schedule_date
-
-def execute():
- frappe.reload_doc('accounts', 'doctype', 'subscription')
- fields = ["name", "reference_doctype", "reference_document",
- "start_date", "frequency", "repeat_on_day"]
-
- for d in fields:
- if not frappe.db.has_column('Subscription', d):
- return
-
- doctypes = ('Purchase Order', 'Sales Order', 'Purchase Invoice', 'Sales Invoice')
- for data in frappe.get_all('Subscription',
- fields = fields,
- filters = {'reference_doctype': ('in', doctypes), 'docstatus': 1}):
-
- recurring_id = frappe.db.get_value(data.reference_doctype, data.reference_document, "recurring_id")
- if recurring_id:
- frappe.db.sql("update `tab{0}` set subscription=%s where recurring_id=%s"
- .format(data.reference_doctype), (data.name, recurring_id))
-
- date_field = 'transaction_date'
- if data.reference_doctype in ['Sales Invoice', 'Purchase Invoice']:
- date_field = 'posting_date'
-
- start_date = frappe.db.get_value(data.reference_doctype, data.reference_document, date_field)
-
- if start_date and getdate(start_date) != getdate(data.start_date):
- last_ref_date = frappe.db.sql("""
- select {0}
- from `tab{1}`
- where subscription=%s and docstatus < 2
- order by creation desc
- limit 1
- """.format(date_field, data.reference_doctype), data.name)[0][0]
-
- next_schedule_date = get_next_schedule_date(last_ref_date, data.frequency, data.repeat_on_day)
-
- frappe.db.set_value("Subscription", data.name, {
- "start_date": start_date,
- "next_schedule_date": next_schedule_date
- }, None)
\ No newline at end of file
diff --git a/erpnext/payroll/desk_page/payroll/payroll.json b/erpnext/payroll/desk_page/payroll/payroll.json
deleted file mode 100644
index 285e3b3..0000000
--- a/erpnext/payroll/desk_page/payroll/payroll.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Payroll",
- "links": "[\n {\n \"label\": \"Salary Component\",\n \"name\": \"Salary Component\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Salary Structure\",\n \"name\": \"Salary Structure\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Structure Assignment\",\n \"name\": \"Salary Structure Assignment\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Payroll Entry\",\n \"name\": \"Payroll Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Slip\",\n \"name\": \"Salary Slip\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Taxation",
- "links": "[\n {\n \"label\": \"Payroll Period\",\n \"name\": \"Payroll Period\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Income Tax Slab\",\n \"name\": \"Income Tax Slab\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Other Income\",\n \"name\": \"Employee Other Income\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Declaration\",\n \"name\": \"Employee Tax Exemption Declaration\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Proof Submission\",\n \"name\": \"Employee Tax Exemption Proof Submission\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Category\",\n \"name\": \"Employee Tax Exemption Category\",\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Employee Tax Exemption Sub Category\",\n \"name\": \"Employee Tax Exemption Sub Category\",\n \"type\": \"doctype\"\n \n }\n]"
- },
- {
- "hidden": 0,
- "label": "Compensations",
- "links": "[\n {\n \"label\": \"Additional Salary\",\n \"name\": \"Additional Salary\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n \n },\n {\n \"label\": \"Retention Bonus\",\n \"name\": \"Retention Bonus\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Incentive\",\n \"name\": \"Employee Incentive\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Benefit Application\",\n \"name\": \"Employee Benefit Application\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Benefit Claim\",\n \"name\": \"Employee Benefit Claim\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"is_query_report\": true,\n \"label\": \"Salary Register\",\n \"name\": \"Salary Register\",\n \"type\": \"report\"\n \n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"label\": \"Salary Payments Based On Payment Mode\",\n \"is_query_report\": true,\n \"name\": \"Salary Payments Based On Payment Mode\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"label\": \"Salary Payments via ECS\",\n \"is_query_report\": true,\n \"name\": \"Salary Payments via ECS\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"label\": \"Income Tax Deductions\",\n \"is_query_report\": true,\n \"name\": \"Income Tax Deductions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"label\": \"Professional Tax Deductions\",\n \"is_query_report\": true,\n \"name\": \"Professional Tax Deductions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"label\": \"Provident Fund Deductions\",\n \"is_query_report\": true,\n \"name\": \"Provident Fund Deductions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Payroll Entry\"\n ],\n \"doctype\": \"Payroll Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Remittance\",\n \"name\": \"Bank Remittance\",\n \"type\": \"report\"\n \n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Outgoing Salary",
- "label": "Outgoing Salary"
- }
- ],
- "creation": "2020-05-27 19:54:23.405607",
- "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": "Payroll",
- "modified": "2020-08-10 19:38:45.976209",
- "modified_by": "Administrator",
- "module": "Payroll",
- "name": "Payroll",
- "onboarding": "Payroll",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "label": "Salary Structure",
- "link_to": "Salary Structure",
- "type": "DocType"
- },
- {
- "label": "Payroll Entry",
- "link_to": "Payroll Entry",
- "type": "DocType"
- },
- {
- "color": "",
- "format": "{} Pending",
- "label": "Salary Slip",
- "link_to": "Salary Slip",
- "stats_filter": "{\"status\": \"Draft\"}",
- "type": "DocType"
- },
- {
- "label": "Income Tax Slab",
- "link_to": "Income Tax Slab",
- "type": "DocType"
- },
- {
- "label": "Salary Register",
- "link_to": "Salary Register",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Payroll",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.js b/erpnext/payroll/doctype/additional_salary/additional_salary.js
index d56cd4e..d1ed91f 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.js
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.js
@@ -12,5 +12,64 @@
}
};
});
+
+ frm.trigger('set_earning_component');
+ },
+
+ employee: function(frm) {
+ if (frm.doc.employee) {
+ frappe.run_serially([
+ () => frm.trigger('get_employee_currency'),
+ () => frm.trigger('set_company')
+ ]);
+ } else {
+ frm.set_value("company", null);
+ }
+ },
+
+ set_company: function(frm) {
+ frappe.call({
+ method: "frappe.client.get_value",
+ args: {
+ doctype: "Employee",
+ fieldname: "company",
+ filters: {
+ name: frm.doc.employee
+ }
+ },
+ callback: function(data) {
+ if (data.message) {
+ frm.set_value("company", data.message.company);
+ }
+ }
+ });
+ },
+
+ company: function(frm) {
+ frm.trigger('set_earning_component');
+ },
+
+ set_earning_component: function(frm) {
+ if (!frm.doc.company) return;
+ frm.set_query("salary_component", function() {
+ return {
+ filters: {type: ["in", ["earning", "deduction"]], company: frm.doc.company}
+ };
+ });
+ },
+
+ get_employee_currency: function(frm) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.refresh_fields();
+ }
+ }
+ });
},
});
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.json b/erpnext/payroll/doctype/additional_salary/additional_salary.json
index 69cb5da..2b29f66 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.json
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.json
@@ -11,20 +11,21 @@
"employee",
"employee_name",
"salary_component",
- "overwrite_salary_structure_amount",
- "deduct_full_tax_on_selected_payroll_date",
+ "type",
+ "amount",
"ref_doctype",
"ref_docname",
+ "amended_from",
"column_break_5",
"company",
- "is_recurring",
+ "department",
+ "currency",
"from_date",
"to_date",
"payroll_date",
- "type",
- "department",
- "amount",
- "amended_from"
+ "is_recurring",
+ "overwrite_salary_structure_amount",
+ "deduct_full_tax_on_selected_payroll_date"
],
"fields": [
{
@@ -59,6 +60,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
+ "options": "currency",
"reqd": 1
},
{
@@ -159,11 +161,22 @@
"label": "Reference Document",
"options": "ref_doctype",
"read_only": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.employee)",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 21:10:50.374063",
+ "modified": "2020-10-20 17:51:13.419716",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Additional Salary",
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index e3dc907..13b6c05 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -9,23 +9,21 @@
from frappe.utils import getdate, date_diff, comma_and, formatdate
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)
- def before_insert(self):
- if frappe.db.exists("Additional Salary", {"employee": self.employee, "salary_component": self.salary_component,
- "amount": self.amount, "payroll_date": self.payroll_date, "company": self.company, "docstatus": 1}):
-
- frappe.throw(_("Additional Salary Component Exists."))
-
def validate(self):
self.validate_dates()
+ self.validate_salary_structure()
self.validate_recurring_additional_salary_overlap()
if self.amount < 0:
frappe.throw(_("Amount should not be less than zero."))
+ def validate_salary_structure(self):
+ if not frappe.db.exists('Salary Structure Assignment', {'employee': self.employee}):
+ frappe.throw(_("There is no Salary Structure assigned to {0}. First assign a Salary Stucture.").format(self.employee))
+
def validate_recurring_additional_salary_overlap(self):
if self.is_recurring:
additional_salaries = frappe.db.sql("""
@@ -84,10 +82,11 @@
no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
return amount_per_day * no_of_days
-@frappe.whitelist()
-def get_additional_salary_component(employee, start_date, end_date, component_type):
- additional_salaries = frappe.db.sql("""
- select name, salary_component, type, amount, overwrite_salary_structure_amount, deduct_full_tax_on_selected_payroll_date
+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
@@ -97,7 +96,7 @@
from_date <= %(to_date)s and to_date >= %(to_date)s
)
and type = %(component_type)s
- order by salary_component, overwrite_salary_structure_amount DESC
+ order by salary_component, overwrite ASC
""", {
'employee': employee,
'from_date': start_date,
@@ -105,38 +104,18 @@
'component_type': "Earning" if component_type == "earnings" else "Deduction"
}, as_dict=1)
- existing_salary_components= []
- salary_components_details = {}
- additional_salary_details = []
+ additional_salaries = []
+ components_to_overwrite = []
- overwrites_components = [ele.salary_component for ele in additional_salaries if ele.overwrite_salary_structure_amount == 1]
+ for d in additional_salary_list:
+ if d.overwrite:
+ if d.component in components_to_overwrite:
+ frappe.throw(_("Multiple Additional Salaries with overwrite "
+ "property exist for Salary Component {0} between {1} and {2}.").format(
+ frappe.bold(d.component), start_date, end_date), title=_("Error"))
- component_fields = ["depends_on_payment_days", "salary_component_abbr", "is_tax_applicable", "variable_based_on_taxable_salary", 'type']
- for d in additional_salaries:
+ components_to_overwrite.append(d.component)
- if d.salary_component not in existing_salary_components:
- component = frappe.get_all("Salary Component", filters={'name': d.salary_component}, fields=component_fields)
- struct_row = frappe._dict({'salary_component': d.salary_component})
- if component:
- struct_row.update(component[0])
+ additional_salaries.append(d)
- struct_row['deduct_full_tax_on_selected_payroll_date'] = d.deduct_full_tax_on_selected_payroll_date
- struct_row['is_additional_component'] = 1
-
- salary_components_details[d.salary_component] = struct_row
-
-
- if overwrites_components.count(d.salary_component) > 1:
- frappe.throw(_("Multiple Additional Salaries with overwrite property exist for Salary Component: {0} between {1} and {2}.".format(d.salary_component, start_date, end_date)), title=_("Error"))
- else:
- additional_salary_details.append({
- 'name': d.name,
- 'component': d.salary_component,
- 'amount': d.amount,
- 'type': d.type,
- 'overwrite': d.overwrite_salary_structure_amount,
- })
-
- existing_salary_components.append(d.salary_component)
-
- return salary_components_details, additional_salary_details
+ return additional_salaries
diff --git a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
index de26543..4d47f25 100644
--- a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
@@ -8,6 +8,7 @@
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_employee_salary_slip, setup_test
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
class TestAdditionalSalary(unittest.TestCase):
@@ -15,12 +16,19 @@
def setUp(self):
setup_test()
+ def tearDown(self):
+ for dt in ["Salary Slip", "Additional Salary", "Salary Structure Assignment", "Salary Structure"]:
+ frappe.db.sql("delete from `tab%s`" % dt)
+
def test_recurring_additional_salary(self):
+ amount = 0
+ salary_component = None
emp_id = make_employee("test_additional@salary.com")
frappe.db.set_value("Employee", emp_id, "relieving_date", add_days(nowdate(), 1800))
+ salary_structure = make_salary_structure("Test Salary Structure Additional Salary", "Monthly", employee=emp_id)
add_sal = get_additional_salary(emp_id)
-
- ss = make_employee_salary_slip("test_additional@salary.com", "Monthly")
+
+ ss = make_employee_salary_slip("test_additional@salary.com", "Monthly", salary_structure=salary_structure.name)
for earning in ss.earnings:
if earning.salary_component == "Recurring Salary Component":
amount = earning.amount
@@ -29,8 +37,6 @@
self.assertEqual(amount, add_sal.amount)
self.assertEqual(salary_component, add_sal.salary_component)
-
-
def get_additional_salary(emp_id):
create_salary_component("Recurring Salary Component")
add_sal = frappe.new_doc("Additional Salary")
@@ -40,6 +46,7 @@
add_sal.from_date = add_days(nowdate(), -50)
add_sal.to_date = add_days(nowdate(), 180)
add_sal.amount = 5000
+ add_sal.currency = erpnext.get_default_currency()
add_sal.save()
add_sal.submit()
diff --git a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.js b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.js
index f509df3..6756cd9 100644
--- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.js
+++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.js
@@ -3,7 +3,12 @@
frappe.ui.form.on('Employee Benefit Application', {
employee: function(frm) {
- frm.trigger('set_earning_component');
+ if (frm.doc.employee) {
+ frappe.run_serially([
+ () => frm.trigger('get_employee_currency'),
+ () => frm.trigger('set_earning_component')
+ ]);
+ }
var method, args;
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
method = "erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits_remaining";
@@ -38,9 +43,26 @@
});
},
+ get_employee_currency: function(frm) {
+ if (frm.doc.employee) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.refresh_fields();
+ }
+ }
+ });
+ }
+ },
+
payroll_period: function(frm) {
var method, args;
- if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
+ if (frm.doc.employee && frm.doc.date && frm.doc.payroll_period) {
method = "erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits_remaining";
args = {
employee: frm.doc.employee,
@@ -60,11 +82,14 @@
method: method,
args: args,
callback: function (data) {
- if(!data.exc){
- if(data.message){
+ if (!data.exc) {
+ if (data.message) {
frm.set_value("max_benefits", data.message);
+ } else {
+ frm.set_value("max_benefits", 0);
}
}
+ frm.refresh_fields();
}
});
};
@@ -82,14 +107,19 @@
var tbl = doc.employee_benefits || [];
var pro_rata_dispensed_amount = 0;
var total_amount = 0;
- for(var i = 0; i < tbl.length; i++){
- if(cint(tbl[i].amount) > 0) {
- total_amount += flt(tbl[i].amount);
- }
- if(tbl[i].pay_against_benefit_claim != 1){
- pro_rata_dispensed_amount += flt(tbl[i].amount);
+ if (doc.max_benefits === 0) {
+ doc.employee_benefits = [];
+ } else {
+ for (var i = 0; i < tbl.length; i++) {
+ if (cint(tbl[i].amount) > 0) {
+ total_amount += flt(tbl[i].amount);
+ }
+ if (tbl[i].pay_against_benefit_claim != 1) {
+ pro_rata_dispensed_amount += flt(tbl[i].amount);
+ }
}
}
+
doc.total_amount = total_amount;
doc.remaining_benefit = doc.max_benefits - total_amount;
doc.pro_rata_dispensed_amount = pro_rata_dispensed_amount;
diff --git a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.json b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.json
index b0c1bd6..4c45580 100644
--- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.json
+++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.json
@@ -10,17 +10,20 @@
"field_order": [
"employee",
"employee_name",
+ "currency",
"max_benefits",
"remaining_benefit",
"column_break_2",
"date",
"payroll_period",
"department",
+ "company",
"amended_from",
"section_break_4",
"employee_benefits",
"totals",
"total_amount",
+ "column_break",
"pro_rata_dispensed_amount"
],
"fields": [
@@ -43,12 +46,14 @@
"fieldname": "max_benefits",
"fieldtype": "Currency",
"label": "Max Benefits (Yearly)",
+ "options": "currency",
"read_only": 1
},
{
"fieldname": "remaining_benefit",
"fieldtype": "Currency",
"label": "Remaining Benefits (Yearly)",
+ "options": "currency",
"read_only": 1
},
{
@@ -108,18 +113,42 @@
"fieldname": "total_amount",
"fieldtype": "Currency",
"label": "Total Amount",
+ "options": "currency",
"read_only": 1
},
{
"fieldname": "pro_rata_dispensed_amount",
"fieldtype": "Currency",
"label": "Dispensed Amount (Pro-rated)",
+ "options": "currency",
"read_only": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.employee)",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break",
+ "fieldtype": "Column Break"
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 22:58:31.271922",
+ "modified": "2020-12-14 15:52:08.566418",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Benefit Application",
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 ef844fb..27df30a 100644
--- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
+++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
@@ -33,8 +33,8 @@
benefit_given = get_sal_slip_total_benefit_given(self.employee, payroll_period, component = benefit.earning_component)
benefit_claim_remining = benefit_claimed - benefit_given
if benefit_claimed > 0 and benefit_claim_remining > benefit.amount:
- frappe.throw(_("An amount of {0} already claimed for the component {1},\
- set the amount equal or greater than {2}").format(benefit_claimed, benefit.earning_component, benefit_claim_remining))
+ frappe.throw(_("An amount of {0} already claimed for the component {1}, set the amount equal or greater than {2}").format(
+ benefit_claimed, benefit.earning_component, benefit_claim_remining))
def validate_remaining_benefit_amount(self):
# check salary structure earnings have flexi component (sum of max_benefit_amount)
@@ -62,11 +62,11 @@
if pro_rata_amount == 0 and non_pro_rata_amount == 0:
frappe.throw(_("Please add the remaining benefits {0} to any of the existing component").format(self.remaining_benefit))
elif non_pro_rata_amount > 0 and non_pro_rata_amount < rounded(self.remaining_benefit):
- frappe.throw(_("You can claim only an amount of {0}, the rest amount {1} should be in the application \
- as pro-rata component").format(non_pro_rata_amount, self.remaining_benefit - non_pro_rata_amount))
+ frappe.throw(_("You can claim only an amount of {0}, the rest amount {1} should be in the application as pro-rata component").format(
+ non_pro_rata_amount, self.remaining_benefit - non_pro_rata_amount))
elif non_pro_rata_amount == 0:
- frappe.throw(_("Please add the remaining benefits {0} to the application as \
- pro-rata component").format(self.remaining_benefit))
+ frappe.throw(_("Please add the remaining benefits {0} to the application as pro-rata component").format(
+ self.remaining_benefit))
def validate_max_benefit_for_component(self):
if self.employee_benefits:
@@ -115,7 +115,7 @@
if max_benefits and max_benefits > 0:
have_depends_on_payment_days = False
per_day_amount_total = 0
- payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[0]
+ payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[1]
payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
# Get all salary slip flexi amount in the payroll period
@@ -239,4 +239,17 @@
""", salary_structure)
else:
frappe.throw(_("Salary Structure not found for employee {0} and date {1}")
- .format(filters['employee'], filters['date']))
\ No newline at end of file
+ .format(filters['employee'], filters['date']))
+
+@frappe.whitelist()
+def get_earning_components_max_benefits(employee, date, earning_component):
+ salary_structure = get_assigned_salary_structure(employee, date)
+ amount = frappe.db.sql("""
+ select amount
+ from `tabSalary Detail`
+ where parent = %s and is_flexible_benefit = 1
+ and salary_component = %s
+ order by name
+ """, salary_structure, earning_component)
+
+ return amount if amount else 0
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json b/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json
index fa6b4da..c93d356 100644
--- a/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json
+++ b/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json
@@ -33,6 +33,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Max Benefit Amount",
+ "options": "currency",
"read_only": 1
},
{
@@ -40,12 +41,13 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
+ "options": "currency",
"reqd": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-06-22 23:45:00.519134",
+ "modified": "2020-09-29 16:22:15.783854",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Benefit Application Detail",
diff --git a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.js b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.js
index 6db6cb8..ea9ccd5 100644
--- a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.js
+++ b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.js
@@ -12,5 +12,24 @@
},
employee: function(frm) {
frm.set_value("earning_component", null);
+ if (frm.doc.employee) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.set_df_property('currency', 'hidden', 0);
+ }
+ }
+ });
+ }
+ if (!frm.doc.earning_component) {
+ frm.doc.max_amount_eligible = null;
+ frm.doc.claimed_amount = null;
+ }
+ frm.refresh_fields();
}
});
diff --git a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.json b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.json
index ae4c218..da24aac 100644
--- a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.json
+++ b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.json
@@ -12,6 +12,8 @@
"department",
"column_break_3",
"claim_date",
+ "currency",
+ "company",
"benefit_type_and_amount",
"earning_component",
"max_amount_eligible",
@@ -76,6 +78,7 @@
"fieldname": "max_amount_eligible",
"fieldtype": "Currency",
"label": "Max Amount Eligible",
+ "options": "currency",
"read_only": 1
},
{
@@ -92,6 +95,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Claimed Amount",
+ "options": "currency",
"reqd": 1
},
{
@@ -119,11 +123,29 @@
"fieldname": "attachments",
"fieldtype": "Attach",
"label": "Attachments"
+ },
+ {
+ "default": "Company:company:default_currency",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Currency",
+ "options": "Currency",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 23:01:50.791676",
+ "modified": "2020-11-25 11:49:56.097352",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Benefit Claim",
diff --git a/erpnext/payroll/doctype/employee_incentive/employee_incentive.js b/erpnext/payroll/doctype/employee_incentive/employee_incentive.js
index db0f83a..b2809b1 100644
--- a/erpnext/payroll/doctype/employee_incentive/employee_incentive.js
+++ b/erpnext/payroll/doctype/employee_incentive/employee_incentive.js
@@ -10,13 +10,60 @@
}
};
});
+ frm.trigger('set_earning_component');
+ },
+ employee: function(frm) {
+ if (frm.doc.employee) {
+ frappe.run_serially([
+ () => frm.trigger('get_employee_currency'),
+ () => frm.trigger('set_company')
+ ]);
+ } else {
+ frm.set_value("company", null);
+ }
+ },
+
+ set_company: function(frm) {
+ frappe.call({
+ method: "frappe.client.get_value",
+ args: {
+ doctype: "Employee",
+ fieldname: "company",
+ filters: {
+ name: frm.doc.employee
+ }
+ },
+ callback: function(data) {
+ if (data.message) {
+ frm.set_value("company", data.message.company);
+ frm.trigger('set_earning_component');
+ }
+ }
+ });
+ },
+
+ set_earning_component: function(frm) {
+ if (!frm.doc.company) return;
frm.set_query("salary_component", function() {
return {
- filters: {
- "type": "Earning"
- }
+ filters: {type: "earning", company: frm.doc.company}
};
});
- }
+ },
+
+ get_employee_currency: function(frm) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.refresh_fields();
+ }
+ }
+ });
+ },
});
diff --git a/erpnext/payroll/doctype/employee_incentive/employee_incentive.json b/erpnext/payroll/doctype/employee_incentive/employee_incentive.json
index 204c9a4..e5b1052 100644
--- a/erpnext/payroll/doctype/employee_incentive/employee_incentive.json
+++ b/erpnext/payroll/doctype/employee_incentive/employee_incentive.json
@@ -7,10 +7,12 @@
"engine": "InnoDB",
"field_order": [
"employee",
- "incentive_amount",
"employee_name",
- "salary_component",
+ "company",
+ "currency",
+ "incentive_amount",
"column_break_5",
+ "salary_component",
"payroll_date",
"department",
"amended_from"
@@ -28,6 +30,7 @@
"fieldname": "incentive_amount",
"fieldtype": "Currency",
"label": "Incentive Amount",
+ "options": "currency",
"reqd": 1
},
{
@@ -70,11 +73,29 @@
"label": "Salary Component",
"options": "Salary Component",
"reqd": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.employee)",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 22:42:51.209630",
+ "modified": "2020-10-20 17:22:16.468042",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Incentive",
diff --git a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py
index 84a97f6..ead3db1 100644
--- a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py
+++ b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py
@@ -4,14 +4,23 @@
from __future__ import unicode_literals
import frappe
+from frappe import _
from frappe.model.document import Document
class EmployeeIncentive(Document):
+ def validate(self):
+ self.validate_salary_structure()
+
+ def validate_salary_structure(self):
+ if not frappe.db.exists('Salary Structure Assignment', {'employee': self.employee}):
+ frappe.throw(_("There is no Salary Structure assigned to {0}. First assign a Salary Stucture.").format(self.employee))
+
def on_submit(self):
company = frappe.db.get_value('Employee', self.employee, 'company')
additional_salary = frappe.new_doc('Additional Salary')
additional_salary.employee = self.employee
+ additional_salary.currency = self.currency
additional_salary.salary_component = self.salary_component
additional_salary.overwrite_salary_structure_amount = 0
additional_salary.amount = self.incentive_amount
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json b/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
index de7c348..83d4ae5 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
+++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
@@ -14,6 +14,7 @@
"column_break_2",
"payroll_period",
"company",
+ "currency",
"amended_from",
"section_break_8",
"declarations",
@@ -92,6 +93,7 @@
"fieldname": "total_declared_amount",
"fieldtype": "Currency",
"label": "Total Declared Amount",
+ "options": "currency",
"read_only": 1
},
{
@@ -102,12 +104,22 @@
"fieldname": "total_exemption_amount",
"fieldtype": "Currency",
"label": "Total Exemption Amount",
+ "options": "currency",
"read_only": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 22:49:43.829892",
+ "modified": "2020-10-20 16:42:24.493761",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Tax Exemption Declaration",
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 9549fd1..311f352 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
@@ -22,6 +22,7 @@
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
+ "currency": erpnext.get_default_currency(),
"declarations": [
dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
@@ -39,6 +40,7 @@
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
+ "currency": erpnext.get_default_currency(),
"declarations": [
dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
@@ -54,6 +56,7 @@
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
+ "currency": erpnext.get_default_currency(),
"declarations": [
dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
@@ -70,6 +73,7 @@
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
+ "currency": erpnext.get_default_currency(),
"declarations": [
dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
@@ -82,19 +86,21 @@
self.assertEqual(declaration.total_exemption_amount, 100000)
-def create_payroll_period():
- if not frappe.db.exists("Payroll Period", "_Test Payroll Period"):
+def create_payroll_period(**args):
+ args = frappe._dict(args)
+ name = args.name or "_Test Payroll Period"
+ if not frappe.db.exists("Payroll Period", name):
from datetime import date
payroll_period = frappe.get_doc(dict(
doctype = 'Payroll Period',
- name = "_Test Payroll Period",
- company = erpnext.get_default_company(),
- start_date = date(date.today().year, 1, 1),
- end_date = date(date.today().year, 12, 31)
+ name = name,
+ company = args.company or erpnext.get_default_company(),
+ start_date = args.start_date or date(date.today().year, 1, 1),
+ end_date = args.end_date or date(date.today().year, 12, 31)
)).insert()
return payroll_period
else:
- return frappe.get_doc("Payroll Period", "_Test Payroll Period")
+ return frappe.get_doc("Payroll Period", name)
def create_exemption_category():
if not frappe.db.exists("Employee Tax Exemption Category", "_Test Category"):
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json b/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
index 8c2f9aa..723a3df 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
+++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
@@ -35,6 +35,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Maximum Exempted Amount",
+ "options": "currency",
"read_only": 1,
"reqd": 1
},
@@ -43,12 +44,13 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Declared Amount",
+ "options": "currency",
"reqd": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-06-22 23:41:03.638739",
+ "modified": "2020-10-20 16:43:09.606265",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Tax Exemption Declaration Category",
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
index 715d755..497f35c 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
+++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
@@ -54,5 +54,9 @@
});
});
}
+ },
+
+ currency: function(frm) {
+ frm.refresh_fields();
}
});
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
index b62b5aa..53f18cb 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
+++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
@@ -11,6 +11,7 @@
"employee",
"employee_name",
"department",
+ "currency",
"column_break_2",
"submission_date",
"payroll_period",
@@ -97,6 +98,7 @@
"fieldname": "total_actual_amount",
"fieldtype": "Currency",
"label": "Total Actual Amount",
+ "options": "currency",
"read_only": 1
},
{
@@ -107,6 +109,7 @@
"fieldname": "exemption_amount",
"fieldtype": "Currency",
"label": "Total Exemption Amount",
+ "options": "currency",
"read_only": 1
},
{
@@ -126,11 +129,20 @@
"options": "Employee Tax Exemption Proof Submission",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 22:53:10.412321",
+ "modified": "2020-10-20 16:47:03.410020",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Tax Exemption Proof Submission",
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
index c1f5320..2fd8b94 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
+++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
@@ -34,6 +34,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Maximum Exemption Amount",
+ "options": "currency",
"read_only": 1,
"reqd": 1
},
@@ -48,12 +49,13 @@
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "Actual Amount"
+ "label": "Actual Amount",
+ "options": "currency"
}
],
"istable": 1,
"links": [],
- "modified": "2020-06-22 23:37:08.265600",
+ "modified": "2020-10-20 16:47:31.480870",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Tax Exemption Proof Submission Detail",
diff --git a/erpnext/config/__init__.py b/erpnext/payroll/doctype/gratuity/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/payroll/doctype/gratuity/__init__.py
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.js b/erpnext/payroll/doctype/gratuity/gratuity.js
new file mode 100644
index 0000000..565d2c4
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity/gratuity.js
@@ -0,0 +1,72 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Gratuity', {
+ setup: function (frm) {
+ frm.set_query('salary_component', function () {
+ return {
+ filters: {
+ type: "Earning"
+ }
+ };
+ });
+ frm.set_query("expense_account", function () {
+ return {
+ filters: {
+ "root_type": "Expense",
+ "is_group": 0,
+ "company": frm.doc.company
+ }
+ };
+ });
+
+ frm.set_query("payable_account", function () {
+ return {
+ filters: {
+ "root_type": "Liability",
+ "is_group": 0,
+ "company": frm.doc.company
+ }
+ };
+ });
+ },
+ refresh: function (frm) {
+ if (frm.doc.docstatus === 1 && frm.doc.pay_via_salary_slip === 0 && frm.doc.status === "Unpaid") {
+ frm.add_custom_button(__("Create Payment Entry"), function () {
+ return frappe.call({
+ method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry',
+ args: {
+ "dt": frm.doc.doctype,
+ "dn": frm.doc.name
+ },
+ callback: function (r) {
+ var doclist = frappe.model.sync(r.message);
+ frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+ }
+ });
+ });
+ }
+ },
+ employee: function (frm) {
+ frm.events.calculate_work_experience_and_amount(frm);
+ },
+ gratuity_rule: function (frm) {
+ frm.events.calculate_work_experience_and_amount(frm);
+ },
+ calculate_work_experience_and_amount: function (frm) {
+
+ if (frm.doc.employee && frm.doc.gratuity_rule) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.gratuity.gratuity.calculate_work_experience_and_amount",
+ args: {
+ employee: frm.doc.employee,
+ gratuity_rule: frm.doc.gratuity_rule
+ }
+ }).then((r) => {
+ frm.set_value("current_work_experience", r.message['current_work_experience']);
+ frm.set_value("amount", r.message['amount']);
+ });
+ }
+ }
+
+});
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.json b/erpnext/payroll/doctype/gratuity/gratuity.json
new file mode 100644
index 0000000..5cffd7e
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity/gratuity.json
@@ -0,0 +1,232 @@
+{
+ "actions": [],
+ "autoname": "HR-GRA-PAY-.#####",
+ "creation": "2020-08-05 20:52:13.024683",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "department",
+ "designation",
+ "column_break_3",
+ "posting_date",
+ "status",
+ "company",
+ "gratuity_rule",
+ "section_break_5",
+ "pay_via_salary_slip",
+ "payroll_date",
+ "salary_component",
+ "payable_account",
+ "expense_account",
+ "mode_of_payment",
+ "cost_center",
+ "column_break_15",
+ "current_work_experience",
+ "amount",
+ "paid_amount",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "employee.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "pay_via_salary_slip",
+ "fieldtype": "Check",
+ "label": "Pay via Salary Slip"
+ },
+ {
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "label": "Posting date",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval: doc.pay_via_salary_slip == 1",
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "label": "Salary Component",
+ "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 1",
+ "options": "Salary Component"
+ },
+ {
+ "default": "0",
+ "fieldname": "current_work_experience",
+ "fieldtype": "Int",
+ "label": "Current Work Experience",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Total Amount",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "options": "Draft\nUnpaid\nPaid",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "fieldname": "expense_account",
+ "fieldtype": "Link",
+ "label": "Expense Account",
+ "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "options": "Account"
+ },
+ {
+ "depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "options": "Mode of Payment"
+ },
+ {
+ "fieldname": "gratuity_rule",
+ "fieldtype": "Link",
+ "label": "Gratuity Rule",
+ "options": "Gratuity Rule",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "label": "Payment Configuration"
+ },
+ {
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "employee.designation",
+ "fieldname": "designation",
+ "fieldtype": "Data",
+ "label": "Designation",
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Gratuity",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval: doc.pay_via_salary_slip == 1",
+ "fieldname": "payroll_date",
+ "fieldtype": "Date",
+ "label": "Payroll Date",
+ "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 1"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.pay_via_salary_slip == 0",
+ "fieldname": "paid_amount",
+ "fieldtype": "Currency",
+ "label": "Paid Amount",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "fieldname": "payable_account",
+ "fieldtype": "Link",
+ "label": "Payable Account",
+ "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "options": "Account"
+ },
+ {
+ "depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
+ "options": "Cost Center"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-11-02 18:21:11.971488",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Gratuity",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "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": "HR User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py
new file mode 100644
index 0000000..1acd6e3
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity/gratuity.py
@@ -0,0 +1,249 @@
+# -*- 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 _, bold
+from frappe.utils import flt, get_datetime, get_link_to_form
+from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.controllers.accounts_controller import AccountsController
+from math import floor
+
+class Gratuity(AccountsController):
+ def validate(self):
+ data = calculate_work_experience_and_amount(self.employee, self.gratuity_rule)
+ self.current_work_experience = data["current_work_experience"]
+ self.amount = data["amount"]
+ if self.docstatus == 1:
+ self.status = "Unpaid"
+
+ def on_submit(self):
+ if self.pay_via_salary_slip:
+ self.create_additional_salary()
+ else:
+ self.create_gl_entries()
+
+ def on_cancel(self):
+ self.ignore_linked_doctypes = ['GL Entry']
+ self.create_gl_entries(cancel=True)
+
+ def create_gl_entries(self, cancel=False):
+ gl_entries = self.get_gl_entries()
+ make_gl_entries(gl_entries, cancel)
+
+ def get_gl_entries(self):
+ gl_entry = []
+ # payable entry
+ if self.amount:
+ gl_entry.append(
+ self.get_gl_dict({
+ "account": self.payable_account,
+ "credit": self.amount,
+ "credit_in_account_currency": self.amount,
+ "against": self.expense_account,
+ "party_type": "Employee",
+ "party": self.employee,
+ "against_voucher_type": self.doctype,
+ "against_voucher": self.name,
+ "cost_center": self.cost_center
+ }, item=self)
+ )
+
+ # expense entries
+ gl_entry.append(
+ self.get_gl_dict({
+ "account": self.expense_account,
+ "debit": self.amount,
+ "debit_in_account_currency": self.amount,
+ "against": self.payable_account,
+ "cost_center": self.cost_center
+ }, item=self)
+ )
+ else:
+ frappe.throw(_("Total Amount can not be zero"))
+
+ return gl_entry
+
+ def create_additional_salary(self):
+ if self.pay_via_salary_slip:
+ additional_salary = frappe.new_doc('Additional Salary')
+ additional_salary.employee = self.employee
+ additional_salary.salary_component = self.salary_component
+ additional_salary.overwrite_salary_structure_amount = 0
+ additional_salary.amount = self.amount
+ additional_salary.payroll_date = self.payroll_date
+ additional_salary.company = self.company
+ additional_salary.ref_doctype = self.doctype
+ additional_salary.ref_docname = self.name
+ additional_salary.submit()
+
+ def set_total_advance_paid(self):
+ paid_amount = frappe.db.sql("""
+ select ifnull(sum(debit_in_account_currency), 0) as paid_amount
+ from `tabGL Entry`
+ where against_voucher_type = 'Gratuity'
+ and against_voucher = %s
+ and party_type = 'Employee'
+ and party = %s
+ """, (self.name, self.employee), as_dict=1)[0].paid_amount
+
+ if flt(paid_amount) > self.amount:
+ frappe.throw(_("Row {0}# Paid Amount cannot be greater than Total amount"))
+
+
+ self.db_set("paid_amount", paid_amount)
+ if self.amount == self.paid_amount:
+ self.db_set("status", "Paid")
+
+
+@frappe.whitelist()
+def calculate_work_experience_and_amount(employee, gratuity_rule):
+ current_work_experience = calculate_work_experience(employee, gratuity_rule) or 0
+ gratuity_amount = calculate_gratuity_amount(employee, gratuity_rule, current_work_experience) or 0
+
+ return {'current_work_experience': current_work_experience, "amount": gratuity_amount}
+
+def calculate_work_experience(employee, gratuity_rule):
+
+ total_working_days_per_year, minimum_year_for_gratuity = frappe.db.get_value("Gratuity Rule", gratuity_rule, ["total_working_days_per_year", "minimum_year_for_gratuity"])
+
+ date_of_joining, relieving_date = frappe.db.get_value('Employee', employee, ['date_of_joining', 'relieving_date'])
+ if not relieving_date:
+ frappe.throw(_("Please set Relieving Date for employee: {0}").format(bold(get_link_to_form("Employee", employee))))
+
+ method = frappe.db.get_value("Gratuity Rule", gratuity_rule, "work_experience_calculation_function")
+ employee_total_workings_days = calculate_employee_total_workings_days(employee, date_of_joining, relieving_date)
+
+ current_work_experience = employee_total_workings_days/total_working_days_per_year or 1
+ current_work_experience = get_work_experience_using_method(method, current_work_experience, minimum_year_for_gratuity, employee)
+ return current_work_experience
+
+def calculate_employee_total_workings_days(employee, date_of_joining, relieving_date ):
+ employee_total_workings_days = (get_datetime(relieving_date) - get_datetime(date_of_joining)).days
+
+ payroll_based_on = frappe.db.get_value("Payroll Settings", None, "payroll_based_on") or "Leave"
+ if payroll_based_on == "Leave":
+ total_lwp = get_non_working_days(employee, relieving_date, "On Leave")
+ employee_total_workings_days -= total_lwp
+ elif payroll_based_on == "Attendance":
+ total_absents = get_non_working_days(employee, relieving_date, "Absent")
+ employee_total_workings_days -= total_absents
+
+ return employee_total_workings_days
+
+def get_work_experience_using_method(method, current_work_experience, minimum_year_for_gratuity, employee):
+ if method == "Round off Work Experience":
+ current_work_experience = round(current_work_experience)
+ else:
+ current_work_experience = floor(current_work_experience)
+
+ if current_work_experience < minimum_year_for_gratuity:
+ frappe.throw(_("Employee: {0} have to complete minimum {1} years for gratuity").format(bold(employee), minimum_year_for_gratuity))
+ return current_work_experience
+
+def get_non_working_days(employee, relieving_date, status):
+
+ filters={
+ "docstatus": 1,
+ "status": status,
+ "employee": employee,
+ "attendance_date": ("<=", get_datetime(relieving_date))
+ }
+
+ if status == "On Leave":
+ lwp_leave_types = frappe.get_list("Leave Type", filters = {"is_lwp":1})
+ lwp_leave_types = [leave_type.name for leave_type in lwp_leave_types]
+ filters["leave_type"] = ("IN", lwp_leave_types)
+
+
+ record = frappe.get_all("Attendance", filters=filters, fields = ["COUNT(name) as total_lwp"])
+ return record[0].total_lwp if len(record) else 0
+
+def calculate_gratuity_amount(employee, gratuity_rule, experience):
+ applicable_earnings_component = get_applicable_components(gratuity_rule)
+ total_applicable_components_amount = get_total_applicable_component_amount(employee, applicable_earnings_component, gratuity_rule)
+
+ calculate_gratuity_amount_based_on = frappe.db.get_value("Gratuity Rule", gratuity_rule, "calculate_gratuity_amount_based_on")
+ gratuity_amount = 0
+ slabs = get_gratuity_rule_slabs(gratuity_rule)
+ slab_found = False
+ year_left = experience
+
+ for slab in slabs:
+ if calculate_gratuity_amount_based_on == "Current Slab":
+ slab_found, gratuity_amount = calculate_amount_based_on_current_slab(slab.from_year, slab.to_year,
+ experience, total_applicable_components_amount, slab.fraction_of_applicable_earnings)
+ if slab_found:
+ break
+
+ elif calculate_gratuity_amount_based_on == "Sum of all previous slabs":
+ if slab.to_year == 0 and slab.from_year == 0:
+ gratuity_amount += year_left * total_applicable_components_amount * slab.fraction_of_applicable_earnings
+ slab_found = True
+ break
+
+ if experience > slab.to_year and experience > slab.from_year and slab.to_year !=0:
+ gratuity_amount += (slab.to_year - slab.from_year) * total_applicable_components_amount * slab.fraction_of_applicable_earnings
+ year_left -= (slab.to_year - slab.from_year)
+ slab_found = True
+ elif slab.from_year <= experience and (experience < slab.to_year or slab.to_year == 0):
+ gratuity_amount += year_left * total_applicable_components_amount * slab.fraction_of_applicable_earnings
+ slab_found = True
+
+ if not slab_found:
+ frappe.throw(_("No Suitable Slab found for Calculation of gratuity amount in Gratuity Rule: {0}").format(bold(gratuity_rule)))
+ return gratuity_amount
+
+def get_applicable_components(gratuity_rule):
+ applicable_earnings_component = frappe.get_all("Gratuity Applicable Component", filters= {'parent': gratuity_rule}, fields=["salary_component"])
+ if len(applicable_earnings_component) == 0:
+ frappe.throw(_("No Applicable Earnings Component found for Gratuity Rule: {0}").format(bold(get_link_to_form("Gratuity Rule",gratuity_rule))))
+ applicable_earnings_component = [component.salary_component for component in applicable_earnings_component]
+
+ return applicable_earnings_component
+
+def get_total_applicable_component_amount(employee, applicable_earnings_component, gratuity_rule):
+ sal_slip = get_last_salary_slip(employee)
+ if not sal_slip:
+ frappe.throw(_("No Salary Slip is found for Employee: {0}").format(bold(employee)))
+ component_and_amounts = frappe.get_list("Salary Detail",
+ filters={
+ "docstatus": 1,
+ 'parent': sal_slip,
+ "parentfield": "earnings",
+ 'salary_component': ('in', applicable_earnings_component)
+ },
+ fields=["amount"])
+ total_applicable_components_amount = 0
+ if not len(component_and_amounts):
+ frappe.throw(_("No Applicable Component is present in last month salary slip"))
+ for data in component_and_amounts:
+ total_applicable_components_amount += data.amount
+ return total_applicable_components_amount
+
+def calculate_amount_based_on_current_slab(from_year, to_year, experience, total_applicable_components_amount, fraction_of_applicable_earnings):
+ slab_found = False; gratuity_amount = 0
+ if experience >= from_year and (to_year == 0 or experience < to_year):
+ gratuity_amount = total_applicable_components_amount * experience * fraction_of_applicable_earnings
+ if fraction_of_applicable_earnings:
+ slab_found = True
+
+ return slab_found, gratuity_amount
+
+def get_gratuity_rule_slabs(gratuity_rule):
+ return frappe.get_all("Gratuity Rule Slab", filters= {'parent': gratuity_rule}, fields = ["*"], order_by="idx")
+
+def get_salary_structure(employee):
+ return frappe.get_list("Salary Structure Assignment", filters = {
+ "employee": employee, 'docstatus': 1
+ },
+ fields=["from_date", "salary_structure"],
+ order_by = "from_date desc")[0].salary_structure
+
+def get_last_salary_slip(employee):
+ return frappe.get_list("Salary Slip", filters = {
+ "employee": employee, 'docstatus': 1
+ },
+ order_by = "start_date desc")[0].name
+
diff --git a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
new file mode 100644
index 0000000..5b2489f
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
@@ -0,0 +1,20 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'reference_name',
+ 'non_standard_fieldnames': {
+ 'Additional Salary': 'ref_docname',
+ },
+ 'transactions': [
+ {
+ 'label': _('Payment'),
+ 'items': ['Payment Entry']
+ },
+ {
+ 'label': _('Additional Salary'),
+ 'items': ['Additional Salary']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/gratuity/test_gratuity.py b/erpnext/payroll/doctype/gratuity/test_gratuity.py
new file mode 100644
index 0000000..7daea2d
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity/test_gratuity.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_employee_salary_slip, make_earning_salary_component, \
+ make_deduction_salary_component
+from erpnext.payroll.doctype.gratuity.gratuity import get_last_salary_slip
+from erpnext.regional.united_arab_emirates.setup import create_gratuity_rule
+from erpnext.hr.doctype.expense_claim.test_expense_claim import get_payable_account
+from frappe.utils import getdate, add_days, get_datetime, flt
+
+test_dependencies = ["Salary Component", "Salary Slip", "Account"]
+class TestGratuity(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ make_earning_salary_component(setup=True, test_tax=True, company_list=['_Test Company'])
+ make_deduction_salary_component(setup=True, test_tax=True, company_list=['_Test Company'])
+
+ def setUp(self):
+ frappe.db.sql("DELETE FROM `tabGratuity`")
+ frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'")
+
+ def test_check_gratuity_amount_based_on_current_slab_and_additional_salary_creation(self):
+ employee, sal_slip = create_employee_and_get_last_salary_slip()
+
+ rule = get_gratuity_rule("Rule Under Unlimited Contract on termination (UAE)")
+
+ gratuity = create_gratuity(pay_via_salary_slip = 1, employee=employee, rule=rule.name)
+
+ #work experience calculation
+ date_of_joining, relieving_date = frappe.db.get_value('Employee', employee, ['date_of_joining', 'relieving_date'])
+ employee_total_workings_days = (get_datetime(relieving_date) - get_datetime(date_of_joining)).days
+
+ experience = employee_total_workings_days/rule.total_working_days_per_year
+ gratuity.reload()
+ from math import floor
+ self.assertEqual(floor(experience), gratuity.current_work_experience)
+
+ #amount Calculation
+ component_amount = frappe.get_list("Salary Detail",
+ filters={
+ "docstatus": 1,
+ 'parent': sal_slip,
+ "parentfield": "earnings",
+ 'salary_component': "Basic Salary"
+ },
+ fields=["amount"])
+
+ ''' 5 - 0 fraction is 1 '''
+
+ gratuity_amount = component_amount[0].amount * experience
+ gratuity.reload()
+
+ self.assertEqual(flt(gratuity_amount, 2), flt(gratuity.amount, 2))
+
+ #additional salary creation (Pay via salary slip)
+ self.assertTrue(frappe.db.exists("Additional Salary", {"ref_docname": gratuity.name}))
+
+ def test_check_gratuity_amount_based_on_all_previous_slabs(self):
+ employee, sal_slip = create_employee_and_get_last_salary_slip()
+ rule = get_gratuity_rule("Rule Under Limited Contract (UAE)")
+ set_mode_of_payment_account()
+
+ gratuity = create_gratuity(expense_account = 'Payment Account - _TC', mode_of_payment='Cash', employee=employee)
+
+ #work experience calculation
+ date_of_joining, relieving_date = frappe.db.get_value('Employee', employee, ['date_of_joining', 'relieving_date'])
+ employee_total_workings_days = (get_datetime(relieving_date) - get_datetime(date_of_joining)).days
+
+ experience = employee_total_workings_days/rule.total_working_days_per_year
+
+ gratuity.reload()
+
+ from math import floor
+
+ self.assertEqual(floor(experience), gratuity.current_work_experience)
+
+ #amount Calculation
+ component_amount = frappe.get_list("Salary Detail",
+ filters={
+ "docstatus": 1,
+ 'parent': sal_slip,
+ "parentfield": "earnings",
+ 'salary_component': "Basic Salary"
+ },
+ fields=["amount"])
+
+ ''' range | Fraction
+ 0-1 | 0
+ 1-5 | 0.7
+ 5-0 | 1
+ '''
+
+ gratuity_amount = ((0 * 1) + (4 * 0.7) + (1 * 1)) * component_amount[0].amount
+ gratuity.reload()
+
+ self.assertEqual(flt(gratuity_amount, 2), flt(gratuity.amount, 2))
+ self.assertEqual(gratuity.status, "Unpaid")
+
+ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+ pay_entry = get_payment_entry("Gratuity", gratuity.name)
+ pay_entry.reference_no = "123467"
+ pay_entry.reference_date = getdate()
+ pay_entry.save()
+ pay_entry.submit()
+ gratuity.reload()
+
+ self.assertEqual(gratuity.status, "Paid")
+ self.assertEqual(flt(gratuity.paid_amount,2), flt(gratuity.amount, 2))
+
+ def tearDown(self):
+ frappe.db.sql("DELETE FROM `tabGratuity`")
+ frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'")
+
+def get_gratuity_rule(name):
+ rule = frappe.db.exists("Gratuity Rule", name)
+ if not rule:
+ create_gratuity_rule()
+ rule = frappe.get_doc("Gratuity Rule", name)
+ rule.applicable_earnings_component = []
+ rule.append("applicable_earnings_component", {
+ "salary_component": "Basic Salary"
+ })
+ rule.save()
+ rule.reload()
+
+ return rule
+
+def create_gratuity(**args):
+ if args:
+ args = frappe._dict(args)
+ gratuity = frappe.new_doc("Gratuity")
+ gratuity.employee = args.employee
+ gratuity.posting_date = getdate()
+ gratuity.gratuity_rule = args.rule or "Rule Under Limited Contract (UAE)"
+ gratuity.pay_via_salary_slip = args.pay_via_salary_slip or 0
+ if gratuity.pay_via_salary_slip:
+ gratuity.payroll_date = getdate()
+ gratuity.salary_component = "Performance Bonus"
+ else:
+ gratuity.expense_account = args.expense_account or 'Payment Account - _TC'
+ gratuity.payable_account = args.payable_account or get_payable_account("_Test Company")
+ gratuity.mode_of_payment = args.mode_of_payment or 'Cash'
+
+ gratuity.save()
+ gratuity.submit()
+
+ return gratuity
+
+def set_mode_of_payment_account():
+ if not frappe.db.exists("Account", "Payment Account - _TC"):
+ mode_of_payment = create_account()
+
+ mode_of_payment = frappe.get_doc("Mode of Payment", "Cash")
+
+ mode_of_payment.accounts = []
+ mode_of_payment.append("accounts", {
+ "company": "_Test Company",
+ "default_account": "_Test Bank - _TC"
+ })
+ mode_of_payment.save()
+
+def create_account():
+ return frappe.get_doc({
+ "doctype": "Account",
+ "company": "_Test Company",
+ "account_name": "Payment Account",
+ "root_type": "Asset",
+ "report_type": "Balance Sheet",
+ "currency": "INR",
+ "parent_account": "Bank Accounts - _TC",
+ "account_type": "Bank",
+ }).insert(ignore_permissions=True)
+
+def create_employee_and_get_last_salary_slip():
+ employee = make_employee("test_employee@salary.com", company='_Test Company')
+ frappe.db.set_value("Employee", employee, "relieving_date", getdate())
+ frappe.db.set_value("Employee", employee, "date_of_joining", add_days(getdate(), - (6*365)))
+ if not frappe.db.exists("Salary Slip", {"employee":employee}):
+ salary_slip = make_employee_salary_slip("test_employee@salary.com", "Monthly")
+ salary_slip.submit()
+ salary_slip = salary_slip.name
+ else:
+ salary_slip = get_last_salary_slip(employee)
+
+ if not frappe.db.get_value("Employee", "test_employee@salary.com", "holiday_list"):
+ from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
+ make_holiday_list()
+ frappe.db.set_value("Company", '_Test Company', "default_holiday_list", "Salary Slip Test Holiday List")
+
+ return employee, salary_slip
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/payroll/doctype/gratuity_applicable_component/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/payroll/doctype/gratuity_applicable_component/__init__.py
diff --git a/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.json b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.json
new file mode 100644
index 0000000..eea0e85
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.json
@@ -0,0 +1,32 @@
+{
+ "actions": [],
+ "creation": "2020-08-05 19:00:28.097265",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "salary_component"
+ ],
+ "fields": [
+ {
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Salary Component ",
+ "options": "Salary Component",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-08-05 20:17:13.855035",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Gratuity Applicable Component",
+ "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/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py
new file mode 100644
index 0000000..23e4340
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class GratuityApplicableComponent(Document):
+ pass
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/payroll/doctype/gratuity_rule/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/payroll/doctype/gratuity_rule/__init__.py
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js
new file mode 100644
index 0000000..ee6c5df
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Gratuity Rule', {
+ // refresh: function(frm) {
+
+ // }
+});
+
+frappe.ui.form.on('Gratuity Rule Slab', {
+
+ /*
+ Slabs should be in order like
+
+ from | to | fraction
+ 0 | 4 | 0.5
+ 4 | 6 | 0.7
+
+ So, on row addition setting current_row.from = previous row.to.
+ On to_year insert we have to check that it is not less than from_year
+
+ Wrong order may lead to Wrong Calculation
+ */
+
+ gratuity_rule_slabs_add(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ let array_idx = row.idx - 1;
+ if (array_idx > 0) {
+ row.from_year = cur_frm.doc.gratuity_rule_slabs[array_idx - 1].to_year;
+ frm.refresh();
+ }
+ },
+
+ to_year(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ if (row.to_year <= row.from_year && row.to_year === 0) {
+ frappe.throw(__("To(Year) year can not be less than From(year) "));
+ }
+ }
+});
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.json b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.json
new file mode 100644
index 0000000..84cdcf5
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.json
@@ -0,0 +1,114 @@
+{
+ "actions": [],
+ "autoname": "Prompt",
+ "creation": "2020-08-05 19:00:36.103500",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "applicable_earnings_component",
+ "work_experience_calculation_function",
+ "total_working_days_per_year",
+ "column_break_3",
+ "disable",
+ "calculate_gratuity_amount_based_on",
+ "minimum_year_for_gratuity",
+ "gratuity_rules_section",
+ "gratuity_rule_slabs"
+ ],
+ "fields": [
+ {
+ "default": "0",
+ "fieldname": "disable",
+ "fieldtype": "Check",
+ "label": "Disable"
+ },
+ {
+ "fieldname": "calculate_gratuity_amount_based_on",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Calculate Gratuity Amount Based On",
+ "options": "Current Slab\nSum of all previous slabs",
+ "reqd": 1
+ },
+ {
+ "description": "Salary components should be part of the Salary Structure.",
+ "fieldname": "applicable_earnings_component",
+ "fieldtype": "Table MultiSelect",
+ "label": "Applicable Earnings Component",
+ "options": "Gratuity Applicable Component",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "gratuity_rules_section",
+ "fieldtype": "Section Break",
+ "label": "Gratuity Rules"
+ },
+ {
+ "description": "Leave <b>From</b> and <b>To</b> 0 for no upper and lower limit.",
+ "fieldname": "gratuity_rule_slabs",
+ "fieldtype": "Table",
+ "label": "Current Work Experience",
+ "options": "Gratuity Rule Slab",
+ "reqd": 1
+ },
+ {
+ "default": "Round off Work Experience",
+ "fieldname": "work_experience_calculation_function",
+ "fieldtype": "Select",
+ "label": "Work Experience Calculation method",
+ "options": "Round off Work Experience\nTake Exact Completed Years"
+ },
+ {
+ "default": "365",
+ "fieldname": "total_working_days_per_year",
+ "fieldtype": "Int",
+ "label": "Total working Days Per Year"
+ },
+ {
+ "fieldname": "minimum_year_for_gratuity",
+ "fieldtype": "Int",
+ "label": "Minimum Year for Gratuity"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-12-03 17:08:27.891535",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Gratuity Rule",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "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": "HR User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py
new file mode 100644
index 0000000..29a6ebe
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py
@@ -0,0 +1,33 @@
+# -*- 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 import _
+
+class GratuityRule(Document):
+
+ def validate(self):
+ for current_slab in self.gratuity_rule_slabs:
+ if (current_slab.from_year > current_slab.to_year) and current_slab.to_year != 0:
+ frappe(_("Row {0}: From (Year) can not be greater than To (Year)").format(current_slab.idx))
+
+ if current_slab.to_year == 0 and current_slab.from_year == 0 and len(self.gratuity_rule_slabs) > 1:
+ frappe.throw(_("You can not define multiple slabs if you have a slab with no lower and upper limits."))
+
+def get_gratuity_rule(name, slabs, **args):
+ args = frappe._dict(args)
+
+ rule = frappe.new_doc("Gratuity Rule")
+ rule.name = name
+ rule.calculate_gratuity_amount_based_on = args.calculate_gratuity_amount_based_on or "Current Slab"
+ rule.work_experience_calculation_method = args.work_experience_calculation_method or "Take Exact Completed Years"
+ rule.minimum_year_for_gratuity = 1
+
+
+ for slab in slabs:
+ slab = frappe._dict(slab)
+ rule.append("gratuity_rule_slabs", slab)
+ return rule
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
new file mode 100644
index 0000000..0d70163
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
@@ -0,0 +1,13 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'gratuity_rule',
+ 'transactions': [
+ {
+ 'label': _('Gratuity'),
+ 'items': ['Gratuity']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py
index 2ad7984..1f5dc4e 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestGratuityRule(unittest.TestCase):
pass
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/payroll/doctype/gratuity_rule_slab/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/payroll/doctype/gratuity_rule_slab/__init__.py
diff --git a/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.json b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.json
new file mode 100644
index 0000000..bc37b0f
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.json
@@ -0,0 +1,50 @@
+{
+ "actions": [],
+ "creation": "2020-08-05 19:12:49.423500",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "from_year",
+ "to_year",
+ "fraction_of_applicable_earnings"
+ ],
+ "fields": [
+ {
+ "fieldname": "fraction_of_applicable_earnings",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Fraction of Applicable Earnings ",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "from_year",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "From(Year)",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "to_year",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "To(Year)",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-08-17 14:09:56.781712",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Gratuity Rule Slab",
+ "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/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py
new file mode 100644
index 0000000..fa468e7
--- /dev/null
+++ b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class GratuityRuleSlab(Document):
+ pass
diff --git a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.js b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.js
index 73a54eb..7d780d3 100644
--- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.js
+++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.js
@@ -2,5 +2,7 @@
// For license information, please see license.txt
frappe.ui.form.on('Income Tax Slab', {
-
+ currency: function(frm) {
+ frm.refresh_fields();
+ }
});
diff --git a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.json b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.json
index 6337d5a..9fa261d 100644
--- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.json
+++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.json
@@ -9,8 +9,9 @@
"effective_from",
"company",
"column_break_3",
- "allow_tax_exemption",
+ "currency",
"standard_tax_exemption_amount",
+ "allow_tax_exemption",
"disabled",
"amended_from",
"taxable_salary_slabs_section",
@@ -70,7 +71,7 @@
"fieldname": "standard_tax_exemption_amount",
"fieldtype": "Currency",
"label": "Standard Tax Exemption Amount",
- "options": "Company:company:default_currency"
+ "options": "currency"
},
{
"fieldname": "company",
@@ -90,11 +91,20 @@
"fieldtype": "Table",
"label": "Other Taxes and Charges",
"options": "Income Tax Slab Other Charges"
+ },
+ {
+ "default": "Company:company:default_currency",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 20:27:13.425084",
+ "modified": "2020-10-19 13:54:24.728075",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Income Tax Slab",
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 253f023..81e3647 100644
--- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py
+++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py
@@ -3,8 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
+#import frappe
+import erpnext
from frappe.model.document import Document
class IncomeTaxSlab(Document):
- pass
+ def validate(self):
+ if self.company:
+ self.currency = erpnext.get_company_currency(self.company)
diff --git a/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json b/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json
index 7f21204..0dba338 100644
--- a/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json
+++ b/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json
@@ -45,7 +45,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Min Taxable Income",
- "options": "Company:company:default_currency"
+ "options": "currency"
},
{
"fieldname": "column_break_7",
@@ -57,12 +57,12 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Max Taxable Income",
- "options": "Company:company:default_currency"
+ "options": "currency"
}
],
"istable": 1,
"links": [],
- "modified": "2020-06-22 23:33:17.931912",
+ "modified": "2020-10-19 13:45:12.850090",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Income Tax Slab Other Charges",
diff --git a/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.json b/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.json
index bb68e18..09c7eb9 100644
--- a/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.json
+++ b/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.json
@@ -17,8 +17,7 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Employee",
- "options": "Employee",
- "read_only": 1
+ "options": "Employee"
},
{
"fetch_from": "employee.employee_name",
@@ -52,7 +51,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-06-22 23:25:13.779032",
+ "modified": "2020-12-17 15:43:29.542977",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll Employee Detail",
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
index 1abc869..395e56f 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
@@ -3,6 +3,8 @@
var in_progress = false;
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Payroll Entry', {
onload: function (frm) {
if (!frm.doc.posting_date) {
@@ -10,7 +12,13 @@
}
frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet);
- frm.set_query("department", function() {
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ frm.events.department_filters(frm);
+ frm.events.payroll_payable_account_filters(frm);
+ },
+
+ department_filters: function (frm) {
+ frm.set_query("department", function () {
return {
"filters": {
"company": frm.doc.company,
@@ -19,20 +27,32 @@
});
},
- refresh: function(frm) {
+ payroll_payable_account_filters: function (frm) {
+ frm.set_query("payroll_payable_account", function () {
+ return {
+ filters: {
+ "company": frm.doc.company,
+ "root_type": "Liability",
+ "is_group": 0,
+ }
+ };
+ });
+ },
+
+ refresh: function (frm) {
if (frm.doc.docstatus == 0) {
- if(!frm.is_new()) {
+ if (!frm.is_new()) {
frm.page.clear_primary_action();
frm.add_custom_button(__("Get Employees"),
- function() {
+ function () {
frm.events.get_employee_details(frm);
}
).toggleClass('btn-primary', !(frm.doc.employees || []).length);
}
- if ((frm.doc.employees || []).length) {
+ if ((frm.doc.employees || []).length && !frappe.model.has_workflow(frm.doctype)) {
frm.page.clear_primary_action();
frm.page.set_primary_action(__('Create Salary Slips'), () => {
- frm.save('Submit').then(()=>{
+ frm.save('Submit').then(() => {
frm.page.clear_primary_action();
frm.refresh();
frm.events.refresh(frm);
@@ -51,48 +71,48 @@
doc: frm.doc,
method: 'fill_employee_details',
}).then(r => {
- if (r.docs && r.docs[0].employees){
+ if (r.docs && r.docs[0].employees) {
frm.employees = r.docs[0].employees;
frm.dirty();
frm.save();
frm.refresh();
- if(r.docs[0].validate_attendance){
+ if (r.docs[0].validate_attendance) {
render_employee_attendance(frm, r.message);
}
}
- })
+ });
},
- create_salary_slips: function(frm) {
+ create_salary_slips: function (frm) {
frm.call({
doc: frm.doc,
method: "create_salary_slips",
- callback: function(r) {
+ callback: function () {
frm.refresh();
frm.toolbar.refresh();
}
- })
+ });
},
- add_context_buttons: function(frm) {
- if(frm.doc.salary_slips_submitted || (frm.doc.__onload && frm.doc.__onload.submitted_ss)) {
+ add_context_buttons: function (frm) {
+ if (frm.doc.salary_slips_submitted || (frm.doc.__onload && frm.doc.__onload.submitted_ss)) {
frm.events.add_bank_entry_button(frm);
- } else if(frm.doc.salary_slips_created) {
- frm.add_custom_button(__("Submit Salary Slip"), function() {
+ } else if (frm.doc.salary_slips_created) {
+ frm.add_custom_button(__("Submit Salary Slip"), function () {
submit_salary_slip(frm);
}).addClass("btn-primary");
}
},
- add_bank_entry_button: function(frm) {
+ add_bank_entry_button: function (frm) {
frappe.call({
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.payroll_entry_has_bank_entries',
args: {
'name': frm.doc.name
},
- callback: function(r) {
+ callback: function (r) {
if (r.message && !r.message.submitted) {
- frm.add_custom_button("Make Bank Entry", function() {
+ frm.add_custom_button("Make Bank Entry", function () {
make_bank_entry(frm);
}).addClass("btn-primary");
}
@@ -112,31 +132,76 @@
"company": frm.doc.company
}
};
- }),
- frm.set_query("cost_center", function () {
+ });
+ },
+
+ payroll_frequency: function (frm) {
+ frm.trigger("set_start_end_dates").then( ()=> {
+ frm.events.clear_employee_table(frm);
+ frm.events.get_employee_with_salary_slip_and_set_query(frm);
+ });
+ },
+
+ employee_filters: function (frm, emp_list) {
+ frm.set_query('employee', 'employees', () => {
return {
filters: {
- "is_group": 0,
- company: frm.doc.company
- }
- };
- }),
- frm.set_query("project", function () {
- return {
- filters: {
- company: frm.doc.company
+ name: ["not in", emp_list]
}
};
});
},
- payroll_frequency: function (frm) {
- frm.trigger("set_start_end_dates");
- frm.events.clear_employee_table(frm);
+ get_employee_with_salary_slip_and_set_query: function (frm) {
+ frappe.db.get_list('Salary Slip', {
+ filters: {
+ start_date: frm.doc.start_date,
+ end_date: frm.doc.end_date,
+ docstatus: 1,
+ },
+ fields: ['employee']
+ }).then((emp) => {
+ var emp_list = [];
+ emp.forEach((employee_data) => {
+ emp_list.push(Object.values(employee_data)[0]);
+ });
+ frm.events.employee_filters(frm, emp_list);
+ });
},
company: function (frm) {
frm.events.clear_employee_table(frm);
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
+ currency: function (frm) {
+ var company_currency;
+ if (!frm.doc.company) {
+ company_currency = erpnext.get_currency(frappe.defaults.get_default("Company"));
+ } else {
+ company_currency = erpnext.get_currency(frm.doc.company);
+ }
+ if (frm.doc.currency) {
+ if (company_currency != frm.doc.currency) {
+ frappe.call({
+ method: "erpnext.setup.utils.get_exchange_rate",
+ args: {
+ from_currency: frm.doc.currency,
+ to_currency: company_currency,
+ },
+ callback: function (r) {
+ frm.set_value("exchange_rate", flt(r.message));
+ frm.set_df_property('exchange_rate', 'hidden', 0);
+ frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency +
+ " = [?] " + company_currency);
+ }
+ });
+ } else {
+ frm.set_value("exchange_rate", 1.0);
+ frm.set_df_property('exchange_rate', 'hidden', 1);
+ frm.set_df_property("exchange_rate", "description", "");
+ }
+ }
},
department: function (frm) {
@@ -152,9 +217,9 @@
},
start_date: function (frm) {
- if(!in_progress && frm.doc.start_date){
+ if (!in_progress && frm.doc.start_date) {
frm.trigger("set_end_date");
- }else{
+ } else {
// reset flag
in_progress = false;
}
@@ -188,7 +253,7 @@
}
},
- set_end_date: function(frm){
+ set_end_date: function (frm) {
frappe.call({
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.get_end_date',
args: {
@@ -203,19 +268,19 @@
});
},
- validate_attendance: function(frm){
- if(frm.doc.validate_attendance && frm.doc.employees){
+ validate_attendance: function (frm) {
+ if (frm.doc.validate_attendance && frm.doc.employees) {
frappe.call({
method: 'validate_employee_attendance',
args: {},
- callback: function(r) {
+ callback: function (r) {
render_employee_attendance(frm, r.message);
},
doc: frm.doc,
freeze: true,
freeze_message: __('Validating Employee Attendance...')
});
- }else{
+ } else {
frm.fields_dict.attendance_detail_html.html("");
}
},
@@ -230,18 +295,20 @@
const submit_salary_slip = function (frm) {
frappe.confirm(__('This will submit Salary Slips and create accrual Journal Entry. Do you want to proceed?'),
- function() {
+ function () {
frappe.call({
method: 'submit_salary_slips',
args: {},
- callback: function() {frm.events.refresh(frm);},
+ callback: function () {
+ frm.events.refresh(frm);
+ },
doc: frm.doc,
freeze: true,
freeze_message: __('Submitting Salary Slips and creating Journal Entry...')
});
},
- function() {
- if(frappe.dom.freeze_count) {
+ function () {
+ if (frappe.dom.freeze_count) {
frappe.dom.unfreeze();
frm.events.refresh(frm);
}
@@ -255,9 +322,11 @@
return frappe.call({
doc: cur_frm.doc,
method: "make_payment_entry",
- callback: function() {
+ callback: function () {
frappe.set_route(
- 'List', 'Journal Entry', {"Journal Entry Account.reference_name": frm.doc.name}
+ 'List', 'Journal Entry', {
+ "Journal Entry Account.reference_name": frm.doc.name
+ }
);
},
freeze: true,
@@ -269,11 +338,18 @@
}
};
-
-let render_employee_attendance = function(frm, data) {
+let render_employee_attendance = function (frm, data) {
frm.fields_dict.attendance_detail_html.html(
frappe.render_template('employees_to_mark_attendance', {
data: data
})
);
-}
+};
+
+frappe.ui.form.on('Payroll Employee Detail', {
+ employee: function(frm) {
+ if (!frm.doc.payroll_frequency) {
+ frappe.throw(__("Please set a Payroll Frequency"));
+ }
+ }
+});
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.json b/erpnext/payroll/doctype/payroll_entry/payroll_entry.json
index 31a8996..0444134 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.json
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.json
@@ -11,8 +11,11 @@
"column_break0",
"posting_date",
"payroll_frequency",
- "column_break1",
"company",
+ "column_break1",
+ "currency",
+ "exchange_rate",
+ "payroll_payable_account",
"section_break_8",
"branch",
"department",
@@ -126,8 +129,7 @@
"fieldname": "employees",
"fieldtype": "Table",
"label": "Employee Details",
- "options": "Payroll Employee Detail",
- "read_only": 1
+ "options": "Payroll Employee Detail"
},
{
"fieldname": "section_break_13",
@@ -257,12 +259,37 @@
{
"fieldname": "column_break_33",
"fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "company",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Currency",
+ "options": "Currency",
+ "reqd": 1
+ },
+ {
+ "depends_on": "company",
+ "fieldname": "exchange_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "precision": "9",
+ "reqd": 1
+ },
+ {
+ "depends_on": "company",
+ "fieldname": "payroll_payable_account",
+ "fieldtype": "Link",
+ "label": "Payroll Payable Account",
+ "options": "Account",
+ "reqd": 1
}
],
"icon": "fa fa-cog",
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 20:06:06.953904",
+ "modified": "2020-12-17 15:13:17.766210",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll Entry",
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
index 30ea432..6bcd4e0 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
@@ -3,10 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+import frappe, erpnext
from frappe.model.document import Document
from dateutil.relativedelta import relativedelta
-from frappe.utils import cint, flt, nowdate, add_days, getdate, fmt_money, add_to_date, DATE_FORMAT, date_diff
+from frappe.utils import cint, flt, add_days, getdate, add_to_date, DATE_FORMAT, date_diff, comma_and
from frappe import _
from erpnext.accounts.utils import get_fiscal_year
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@@ -19,16 +19,29 @@
# check if salary slips were manually submitted
entries = frappe.db.count("Salary Slip", {'payroll_entry': self.name, 'docstatus': 1}, ['name'])
if cint(entries) == len(self.employees):
- self.set_onload("submitted_ss", True)
+ self.set_onload("submitted_ss", True)
+
+ def validate(self):
+ self.number_of_employees = len(self.employees)
def on_submit(self):
self.create_salary_slips()
def before_submit(self):
+ self.validate_employee_details()
if self.validate_attendance:
if self.validate_employee_attendance():
frappe.throw(_("Cannot Submit, Employees left to mark attendance"))
+ def validate_employee_details(self):
+ emp_with_sal_slip = []
+ for employee_details in self.employees:
+ if frappe.db.exists("Salary Slip", {"employee": employee_details.employee, "start_date": self.start_date, "end_date": self.end_date, "docstatus": 1}):
+ emp_with_sal_slip.append(employee_details.employee)
+
+ if len(emp_with_sal_slip):
+ frappe.throw(_("Salary Slip already exists for {0} ").format(comma_and(emp_with_sal_slip)))
+
def on_cancel(self):
frappe.delete_doc("Salary Slip", frappe.db.sql_list("""select name from `tabSalary Slip`
where payroll_entry=%s """, (self.name)))
@@ -51,13 +64,15 @@
where
docstatus = 1 and
is_active = 'Yes'
- and company = %(company)s and
+ and company = %(company)s
+ and currency = %(currency)s and
ifnull(salary_slip_based_on_timesheet,0) = %(salary_slip_based_on_timesheet)s
{condition}""".format(condition=condition),
- {"company": self.company, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet})
+ {"company": self.company, "currency": self.currency, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet})
if sal_struct:
cond += "and t2.salary_structure IN %(sal_struct)s "
+ cond += "and t2.payroll_payable_account = %(payroll_payable_account)s "
cond += "and %(from_date)s >= t2.from_date"
emp_list = frappe.db.sql("""
select
@@ -68,19 +83,40 @@
t1.name = t2.employee
and t2.docstatus = 1
%s order by t2.from_date desc
- """ % cond, {"sal_struct": tuple(sal_struct), "from_date": self.end_date}, as_dict=True)
+ """ % cond, {"sal_struct": tuple(sal_struct), "from_date": self.end_date, "payroll_payable_account": self.payroll_payable_account}, as_dict=True)
+
+ emp_list = self.remove_payrolled_employees(emp_list)
return emp_list
+ def remove_payrolled_employees(self, emp_list):
+ for employee_details in emp_list:
+ if frappe.db.exists("Salary Slip", {"employee": employee_details.employee, "start_date": self.start_date, "end_date": self.end_date, "docstatus": 1}):
+ emp_list.remove(employee_details)
+
+ return emp_list
+
def fill_employee_details(self):
self.set('employees', [])
employees = self.get_emp_list()
if not employees:
- frappe.throw(_("No employees for the mentioned criteria"))
+ error_msg = _("No employees found for the mentioned criteria:<br>Company: {0}<br> Currency: {1}<br>Payroll Payable Account: {2}").format(
+ frappe.bold(self.company), frappe.bold(self.currency), frappe.bold(self.payroll_payable_account))
+ if self.branch:
+ error_msg += "<br>" + _("Branch: {0}").format(frappe.bold(self.branch))
+ if self.department:
+ error_msg += "<br>" + _("Department: {0}").format(frappe.bold(self.department))
+ if self.designation:
+ error_msg += "<br>" + _("Designation: {0}").format(frappe.bold(self.designation))
+ if self.start_date:
+ error_msg += "<br>" + _("Start date: {0}").format(frappe.bold(self.start_date))
+ if self.end_date:
+ error_msg += "<br>" + _("End date: {0}").format(frappe.bold(self.end_date))
+ frappe.throw(error_msg, title=_("No employees found"))
for d in employees:
self.append('employees', d)
- self.number_of_employees = len(employees)
+ self.number_of_employees = len(self.employees)
if self.validate_attendance:
return self.validate_employee_attendance()
@@ -112,8 +148,8 @@
"""
self.check_permission('write')
self.created = 1
- emp_list = [d.employee for d in self.get_emp_list()]
- if emp_list:
+ employees = [emp.employee for emp in self.employees]
+ if employees:
args = frappe._dict({
"salary_slip_based_on_timesheet": self.salary_slip_based_on_timesheet,
"payroll_frequency": self.payroll_frequency,
@@ -123,12 +159,14 @@
"posting_date": self.posting_date,
"deduct_tax_for_unclaimed_employee_benefits": self.deduct_tax_for_unclaimed_employee_benefits,
"deduct_tax_for_unsubmitted_tax_exemption_proof": self.deduct_tax_for_unsubmitted_tax_exemption_proof,
- "payroll_entry": self.name
+ "payroll_entry": self.name,
+ "exchange_rate": self.exchange_rate,
+ "currency": self.currency
})
- if len(emp_list) > 30:
- frappe.enqueue(create_salary_slips_for_employees, timeout=600, employees=emp_list, args=args)
+ if len(employees) > 30:
+ frappe.enqueue(create_salary_slips_for_employees, timeout=600, employees=employees, args=args)
else:
- create_salary_slips_for_employees(emp_list, args, publish_progress=False)
+ create_salary_slips_for_employees(employees, args, publish_progress=False)
# since this method is called via frm.call this doc needs to be updated manually
self.reload()
@@ -160,10 +198,10 @@
def get_salary_component_account(self, salary_component):
account = frappe.db.get_value("Salary Component Account",
- {"parent": salary_component, "company": self.company}, "default_account")
+ {"parent": salary_component, "company": self.company}, "account")
if not account:
- frappe.throw(_("Please set default account in Salary Component {0}")
+ frappe.throw(_("Please set account in Salary Component {0}")
.format(salary_component))
return account
@@ -203,21 +241,11 @@
account_dict[(account, key[1])] = account_dict.get((account, key[1]), 0) + amount
return account_dict
- def get_default_payroll_payable_account(self):
- payroll_payable_account = frappe.get_cached_value('Company',
- {"company_name": self.company}, "default_payroll_payable_account")
-
- if not payroll_payable_account:
- frappe.throw(_("Please set Default Payroll Payable Account in Company {0}")
- .format(self.company))
-
- return payroll_payable_account
-
def make_accrual_jv_entry(self):
self.check_permission('write')
earnings = self.get_salary_component_total(component_type = "earnings") or {}
deductions = self.get_salary_component_total(component_type = "deductions") or {}
- default_payroll_payable_account = self.get_default_payroll_payable_account()
+ payroll_payable_account = self.payroll_payable_account
jv_name = ""
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
@@ -230,14 +258,19 @@
journal_entry.posting_date = self.posting_date
accounts = []
+ currencies = []
payable_amount = 0
+ multi_currency = 0
+ company_currency = erpnext.get_company_currency(self.company)
# Earnings
for acc_cc, amount in earnings.items():
+ exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
payable_amount += flt(amount, precision)
accounts.append({
"account": acc_cc[0],
- "debit_in_account_currency": flt(amount, precision),
+ "debit_in_account_currency": flt(amt, precision),
+ "exchange_rate": flt(exchange_rate),
"party_type": '',
"cost_center": acc_cc[1] or self.cost_center,
"project": self.project
@@ -245,25 +278,32 @@
# Deductions
for acc_cc, amount in deductions.items():
+ exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
payable_amount -= flt(amount, precision)
accounts.append({
"account": acc_cc[0],
- "credit_in_account_currency": flt(amount, precision),
+ "credit_in_account_currency": flt(amt, precision),
+ "exchange_rate": flt(exchange_rate),
"cost_center": acc_cc[1] or self.cost_center,
"party_type": '',
"project": self.project
})
# Payable amount
+ exchange_rate, payable_amt = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, payable_amount, company_currency, currencies)
accounts.append({
- "account": default_payroll_payable_account,
- "credit_in_account_currency": flt(payable_amount, precision),
+ "account": payroll_payable_account,
+ "credit_in_account_currency": flt(payable_amt, precision),
+ "exchange_rate": flt(exchange_rate),
"party_type": '',
"cost_center": self.cost_center
})
journal_entry.set("accounts", accounts)
- journal_entry.title = default_payroll_payable_account
+ if len(currencies) > 1:
+ multi_currency = 1
+ journal_entry.multi_currency = multi_currency
+ journal_entry.title = payroll_payable_account
journal_entry.save()
try:
@@ -271,10 +311,24 @@
jv_name = journal_entry.name
self.update_salary_slip_status(jv_name = jv_name)
except Exception as e:
- frappe.msgprint(e)
+ if type(e) in (str, list, tuple):
+ frappe.msgprint(e)
+ raise
return jv_name
+ def get_amount_and_exchange_rate_for_journal_entry(self, account, amount, company_currency, currencies):
+ conversion_rate = 1
+ exchange_rate = self.exchange_rate
+ account_currency = frappe.db.get_value('Account', account, 'account_currency')
+ if account_currency not in currencies:
+ currencies.append(account_currency)
+ if account_currency == company_currency:
+ conversion_rate = self.exchange_rate
+ exchange_rate = 1
+ amount = flt(amount) * flt(conversion_rate)
+ return exchange_rate, amount
+
def make_payment_entry(self):
self.check_permission('write')
@@ -303,31 +357,43 @@
self.create_journal_entry(salary_slip_total, "salary")
def create_journal_entry(self, je_payment_amount, user_remark):
- default_payroll_payable_account = self.get_default_payroll_payable_account()
+ payroll_payable_account = self.payroll_payable_account
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
+ accounts = []
+ currencies = []
+ multi_currency = 0
+ company_currency = erpnext.get_company_currency(self.company)
+
+ exchange_rate, amount = self.get_amount_and_exchange_rate_for_journal_entry(self.payment_account, je_payment_amount, company_currency, currencies)
+ accounts.append({
+ "account": self.payment_account,
+ "bank_account": self.bank_account,
+ "credit_in_account_currency": flt(amount, precision),
+ "exchange_rate": flt(exchange_rate),
+ })
+
+ exchange_rate, amount = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, je_payment_amount, company_currency, currencies)
+ accounts.append({
+ "account": payroll_payable_account,
+ "debit_in_account_currency": flt(amount, precision),
+ "exchange_rate": flt(exchange_rate),
+ "reference_type": self.doctype,
+ "reference_name": self.name
+ })
+
+ if len(currencies) > 1:
+ multi_currency = 1
+
journal_entry = frappe.new_doc('Journal Entry')
journal_entry.voucher_type = 'Bank Entry'
journal_entry.user_remark = _('Payment of {0} from {1} to {2}')\
.format(user_remark, self.start_date, self.end_date)
journal_entry.company = self.company
journal_entry.posting_date = self.posting_date
+ journal_entry.multi_currency = multi_currency
- payment_amount = flt(je_payment_amount, precision)
-
- journal_entry.set("accounts", [
- {
- "account": self.payment_account,
- "bank_account": self.bank_account,
- "credit_in_account_currency": payment_amount
- },
- {
- "account": default_payroll_payable_account,
- "debit_in_account_currency": payment_amount,
- "reference_type": self.doctype,
- "reference_name": self.name
- }
- ])
+ journal_entry.set("accounts", accounts)
journal_entry.save(ignore_permissions = True)
def update_salary_slip_status(self, jv_name = None):
@@ -344,9 +410,13 @@
employees_to_mark_attendance = []
days_in_payroll, days_holiday, days_attendance_marked = 0, 0, 0
for employee_detail in self.employees:
- days_holiday = self.get_count_holidays_of_employee(employee_detail.employee)
- days_attendance_marked = self.get_count_employee_attendance(employee_detail.employee)
- days_in_payroll = date_diff(self.end_date, self.start_date) + 1
+ employee_joining_date = frappe.db.get_value("Employee", employee_detail.employee, 'date_of_joining')
+ start_date = self.start_date
+ if employee_joining_date > getdate(self.start_date):
+ start_date = employee_joining_date
+ days_holiday = self.get_count_holidays_of_employee(employee_detail.employee, start_date)
+ days_attendance_marked = self.get_count_employee_attendance(employee_detail.employee, start_date)
+ days_in_payroll = date_diff(self.end_date, start_date) + 1
if days_in_payroll > days_holiday + days_attendance_marked:
employees_to_mark_attendance.append({
"employee": employee_detail.employee,
@@ -354,22 +424,25 @@
})
return employees_to_mark_attendance
- def get_count_holidays_of_employee(self, employee):
+ def get_count_holidays_of_employee(self, employee, start_date):
holiday_list = get_holiday_list_for_employee(employee)
holidays = 0
if holiday_list:
days = frappe.db.sql("""select count(*) from tabHoliday where
parent=%s and holiday_date between %s and %s""", (holiday_list,
- self.start_date, self.end_date))
+ start_date, self.end_date))
if days and days[0][0]:
holidays = days[0][0]
return holidays
- def get_count_employee_attendance(self, employee):
+ def get_count_employee_attendance(self, employee, start_date):
marked_days = 0
- attendances = frappe.db.sql("""select count(*) from tabAttendance where
- employee=%s and docstatus=1 and attendance_date between %s and %s""",
- (employee, self.start_date, self.end_date))
+ attendances = frappe.get_all("Attendance",
+ fields = ["count(*)"],
+ filters = {
+ "employee": employee,
+ "attendance_date": ('between', [start_date, self.end_date])
+ }, as_list=1)
if attendances and attendances[0][0]:
marked_days = attendances[0][0]
return marked_days
@@ -489,6 +562,21 @@
if publish_progress:
frappe.publish_progress(count*100/len(set(employees) - set(salary_slips_exists_for)),
title = _("Creating Salary Slips..."))
+ else:
+ salary_slip_name = frappe.db.sql(
+ '''SELECT
+ name
+ FROM `tabSalary Slip`
+ WHERE company=%s
+ AND start_date >= %s
+ AND end_date <= %s
+ AND employee = %s
+ ''', (args.company, args.start_date, args.end_date, emp), as_dict=True)
+
+ salary_slip_doc = frappe.get_doc('Salary Slip', salary_slip_name[0].name)
+ salary_slip_doc.exchange_rate = args.exchange_rate
+ salary_slip_doc.set_totals()
+ salary_slip_doc.db_update()
payroll_entry = frappe.get_doc("Payroll Entry", args.payroll_entry)
payroll_entry.db_set("salary_slips_created", 1)
diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
index b0f225d..84c3814 100644
--- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
@@ -10,9 +10,9 @@
from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates, get_end_date
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.payroll.doctype.salary_slip.test_salary_slip import get_salary_component_account, \
- make_earning_salary_component, make_deduction_salary_component, create_account
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
-from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry
+ make_earning_salary_component, make_deduction_salary_component, create_account, make_employee_salary_slip
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure, create_salary_structure_assignment
+from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry, create_loan_type, create_loan_accounts
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
class TestPayrollEntry(unittest.TestCase):
@@ -22,7 +22,7 @@
frappe.db.sql("delete from `tab%s`" % dt)
make_earning_salary_component(setup=True, company_list=["_Test Company"])
- make_deduction_salary_component(setup=True, company_list=["_Test Company"])
+ make_deduction_salary_component(setup=True, test_tax=False, company_list=["_Test Company"])
frappe.db.set_value("Payroll Settings", None, "email_salary_slip_to_employee", 0)
@@ -34,10 +34,47 @@
get_salary_component_account(data.name)
employee = frappe.db.get_value("Employee", {'company': company})
- make_salary_structure("_Test Salary Structure", "Monthly", employee, company=company)
+ company_doc = frappe.get_doc('Company', company)
+ make_salary_structure("_Test Salary Structure", "Monthly", employee, company=company, currency=company_doc.default_currency)
dates = get_start_end_dates('Monthly', nowdate())
if not frappe.db.get_value("Salary Slip", {"start_date": dates.start_date, "end_date": dates.end_date}):
- make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date)
+ make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date, payable_account=company_doc.default_payroll_payable_account,
+ currency=company_doc.default_currency)
+
+ def test_multi_currency_payroll_entry(self): # pylint: disable=no-self-use
+ company = erpnext.get_default_company()
+ employee = make_employee("test_muti_currency_employee@payroll.com", company=company)
+ for data in frappe.get_all('Salary Component', fields = ["name"]):
+ if not frappe.db.get_value('Salary Component Account',
+ {'parent': data.name, 'company': company}, 'name'):
+ get_salary_component_account(data.name)
+
+ company_doc = frappe.get_doc('Company', company)
+ salary_structure = make_salary_structure("_Test Multi Currency Salary Structure", "Monthly", company=company, currency='USD')
+ create_salary_structure_assignment(employee, salary_structure.name, company=company)
+ frappe.db.sql("""delete from `tabSalary Slip` where employee=%s""",(frappe.db.get_value("Employee", {"user_id": "test_muti_currency_employee@payroll.com"})))
+ salary_slip = get_salary_slip("test_muti_currency_employee@payroll.com", "Monthly", "_Test Multi Currency Salary Structure")
+ dates = get_start_end_dates('Monthly', nowdate())
+ payroll_entry = make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date,
+ payable_account=company_doc.default_payroll_payable_account, currency='USD', exchange_rate=70)
+ payroll_entry.make_payment_entry()
+
+ salary_slip.load_from_db()
+
+ payroll_je = salary_slip.journal_entry
+ payroll_je_doc = frappe.get_doc('Journal Entry', payroll_je)
+
+ self.assertEqual(salary_slip.base_gross_pay, payroll_je_doc.total_debit)
+ self.assertEqual(salary_slip.base_gross_pay, payroll_je_doc.total_credit)
+
+ payment_entry = frappe.db.sql('''
+ Select ifnull(sum(je.total_debit),0) as total_debit, ifnull(sum(je.total_credit),0) as total_credit from `tabJournal Entry` je, `tabJournal Entry Account` jea
+ Where je.name = jea.parent
+ And jea.reference_name = %s
+ ''', (payroll_entry.name), as_dict=1)
+
+ self.assertEqual(salary_slip.base_net_pay, payment_entry[0].total_debit)
+ self.assertEqual(salary_slip.base_net_pay, payment_entry[0].total_credit)
def test_payroll_entry_with_employee_cost_center(self): # pylint: disable=no-self-use
for data in frappe.get_all('Salary Component', fields = ["name"]):
@@ -52,24 +89,32 @@
"company": "_Test Company"
}).insert()
+ frappe.db.sql("""delete from `tabEmployee` where employee_name='test_employee1@example.com' """)
+ frappe.db.sql("""delete from `tabEmployee` where employee_name='test_employee2@example.com' """)
+ frappe.db.sql("""delete from `tabSalary Structure` where name='_Test Salary Structure 1' """)
+ frappe.db.sql("""delete from `tabSalary Structure` where name='_Test Salary Structure 2' """)
+
employee1 = make_employee("test_employee1@example.com", payroll_cost_center="_Test Cost Center - _TC",
department="cc - _TC", company="_Test Company")
employee2 = make_employee("test_employee2@example.com", payroll_cost_center="_Test Cost Center 2 - _TC",
department="cc - _TC", company="_Test Company")
- make_salary_structure("_Test Salary Structure 1", "Monthly", employee1, company="_Test Company")
- make_salary_structure("_Test Salary Structure 2", "Monthly", employee2, company="_Test Company")
-
if not frappe.db.exists("Account", "_Test Payroll Payable - _TC"):
- create_account(account_name="_Test Payroll Payable",
- company="_Test Company", parent_account="Current Liabilities - _TC")
- frappe.db.set_value("Company", "_Test Company", "default_payroll_payable_account",
- "_Test Payroll Payable - _TC")
+ create_account(account_name="_Test Payroll Payable",
+ company="_Test Company", parent_account="Current Liabilities - _TC")
+
+ if not frappe.db.get_value("Company", "_Test Company", "default_payroll_payable_account") or \
+ frappe.db.get_value("Company", "_Test Company", "default_payroll_payable_account") != "_Test Payroll Payable - _TC":
+ frappe.db.set_value("Company", "_Test Company", "default_payroll_payable_account",
+ "_Test Payroll Payable - _TC")
+ currency=frappe.db.get_value("Company", "_Test Company", "default_currency")
+ make_salary_structure("_Test Salary Structure 1", "Monthly", employee1, company="_Test Company", currency=currency, test_tax=False)
+ make_salary_structure("_Test Salary Structure 2", "Monthly", employee2, company="_Test Company", currency=currency, test_tax=False)
dates = get_start_end_dates('Monthly', nowdate())
if not frappe.db.get_value("Salary Slip", {"start_date": dates.start_date, "end_date": dates.end_date}):
- pe = make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date,
- department="cc - _TC", company="_Test Company", payment_account="Cash - _TC", cost_center="Main - _TC")
+ pe = make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date, payable_account="_Test Payroll Payable - _TC",
+ currency=frappe.db.get_value("Company", "_Test Company", "default_currency"), department="cc - _TC", company="_Test Company", payment_account="Cash - _TC", cost_center="Main - _TC")
je = frappe.db.get_value("Salary Slip", {"payroll_entry": pe.name}, "journal_entry")
je_entries = frappe.db.sql("""
select account, cost_center, debit, credit
@@ -121,20 +166,28 @@
employee_doc.save()
salary_structure = "Test Salary Structure for Loan"
- make_salary_structure(salary_structure, "Monthly", employee=employee_doc.name, company="_Test Company")
+ make_salary_structure(salary_structure, "Monthly", employee=employee_doc.name, company="_Test Company", currency=company_doc.default_currency)
+
+ if not frappe.db.exists("Loan Type", "Car Loan"):
+ create_loan_accounts()
+ create_loan_type("Car Loan", 500000, 8.4,
+ is_term_loan=1,
+ mode_of_payment='Cash',
+ payment_account='Payment Account - _TC',
+ loan_account='Loan Account - _TC',
+ interest_income_account='Interest Income Account - _TC',
+ penalty_income_account='Penalty Income Account - _TC')
loan = create_loan(applicant, "Car Loan", 280000, "Repay Over Number of Periods", 20, posting_date=add_months(nowdate(), -1))
loan.repay_from_salary = 1
loan.submit()
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1))
-
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
-
dates = get_start_end_dates('Monthly', nowdate())
- make_payroll_entry(company="_Test Company", start_date=dates.start_date,
- end_date=dates.end_date, branch=branch, cost_center="Main - _TC", payment_account="Cash - _TC")
+ make_payroll_entry(company="_Test Company", start_date=dates.start_date, payable_account=company_doc.default_payroll_payable_account,
+ currency=company_doc.default_currency, end_date=dates.end_date, branch=branch, cost_center="Main - _TC", payment_account="Cash - _TC")
name = frappe.db.get_value('Salary Slip',
{'posting_date': nowdate(), 'employee': applicant}, 'name')
@@ -165,6 +218,9 @@
payroll_entry.payroll_frequency = "Monthly"
payroll_entry.branch = args.branch or None
payroll_entry.department = args.department or None
+ payroll_entry.payroll_payable_account = args.payable_account
+ payroll_entry.currency = args.currency
+ payroll_entry.exchange_rate = args.exchange_rate or 1
if args.cost_center:
payroll_entry.cost_center = args.cost_center
@@ -212,3 +268,11 @@
}).insert()
return holiday_list_name
+
+def get_salary_slip(user, period, salary_structure):
+ salary_slip = make_employee_salary_slip(user, period, salary_structure)
+ salary_slip.exchange_rate = 70
+ salary_slip.calculate_net_pay()
+ salary_slip.db_update()
+
+ return salary_slip
diff --git a/erpnext/payroll/doctype/payroll_entry/test_set_salary_components.js b/erpnext/payroll/doctype/payroll_entry/test_set_salary_components.js
index 8ff5515..092cbd8 100644
--- a/erpnext/payroll/doctype/payroll_entry/test_set_salary_components.js
+++ b/erpnext/payroll/doctype/payroll_entry/test_set_salary_components.js
@@ -9,45 +9,45 @@
() => {
var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts");
row.company = 'For Testing';
- row.default_account = 'Salary - FT';
+ row.account = 'Salary - FT';
},
() => cur_frm.save(),
() => frappe.timeout(2),
- () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'),
+ () => assert.equal(cur_frm.doc.accounts[0].account, 'Salary - FT'),
() => frappe.set_route('Form', 'Salary Component', 'Basic'),
() => {
var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts");
row.company = 'For Testing';
- row.default_account = 'Salary - FT';
+ row.account = 'Salary - FT';
},
() => cur_frm.save(),
() => frappe.timeout(2),
- () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'),
+ () => assert.equal(cur_frm.doc.accounts[0].account, 'Salary - FT'),
() => frappe.set_route('Form', 'Salary Component', 'Income Tax'),
() => {
var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts");
row.company = 'For Testing';
- row.default_account = 'Salary - FT';
+ row.account = 'Salary - FT';
},
() => cur_frm.save(),
() => frappe.timeout(2),
- () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'),
+ () => assert.equal(cur_frm.doc.accounts[0].account, 'Salary - FT'),
() => frappe.set_route('Form', 'Salary Component', 'Arrear'),
() => {
var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts");
row.company = 'For Testing';
- row.default_account = 'Salary - FT';
+ row.account = 'Salary - FT';
},
() => cur_frm.save(),
() => frappe.timeout(2),
- () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'),
+ () => assert.equal(cur_frm.doc.accounts[0].account, 'Salary - FT'),
() => frappe.set_route('Form', 'Company', 'For Testing'),
() => cur_frm.set_value('default_payroll_payable_account', 'Payroll Payable - FT'),
diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period.py b/erpnext/payroll/doctype/payroll_period/payroll_period.py
index d7893d0..ef3a6cc 100644
--- a/erpnext/payroll/doctype/payroll_period/payroll_period.py
+++ b/erpnext/payroll/doctype/payroll_period/payroll_period.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import date_diff, getdate, formatdate, cint, month_diff, flt
+from frappe.utils import date_diff, getdate, formatdate, cint, month_diff, flt, add_months
from frappe.model.document import Document
from erpnext.hr.utils import get_holidays_for_employee
@@ -41,7 +41,7 @@
if overlap_doc:
msg = _("A {0} exists between {1} and {2} (").format(self.doctype,
formatdate(self.start_date), formatdate(self.end_date)) \
- + """ <b><a href="#Form/{0}/{1}">{1}</a></b>""".format(self.doctype, overlap_doc[0].name) \
+ + """ <b><a href="/app/Form/{0}/{1}">{1}</a></b>""".format(self.doctype, overlap_doc[0].name) \
+ _(") for {0}").format(self.company)
frappe.throw(msg)
@@ -88,6 +88,8 @@
period_start = joining_date
if relieving_date and getdate(relieving_date) < getdate(period_end):
period_end = relieving_date
+ if month_diff(period_end, start_date) > 1:
+ start_date = add_months(start_date, - (month_diff(period_end, start_date)+1))
total_sub_periods, remaining_sub_periods = 0.0, 0.0
diff --git a/erpnext/payroll/doctype/payroll_settings/payroll_settings.json b/erpnext/payroll/doctype/payroll_settings/payroll_settings.json
index c47caa1..54377e9 100644
--- a/erpnext/payroll/doctype/payroll_settings/payroll_settings.json
+++ b/erpnext/payroll/doctype/payroll_settings/payroll_settings.json
@@ -15,6 +15,7 @@
"daily_wages_fraction_for_half_day",
"email_salary_slip_to_employee",
"encrypt_salary_slips_in_emails",
+ "show_leave_balances_in_salary_slip",
"password_policy"
],
"fields": [
@@ -23,58 +24,44 @@
"fieldname": "payroll_based_on",
"fieldtype": "Select",
"label": "Calculate Payroll Working Days Based On",
- "options": "Leave\nAttendance",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Leave\nAttendance"
},
{
"fieldname": "max_working_hours_against_timesheet",
"fieldtype": "Float",
- "label": "Max working hours against Timesheet",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Max working hours against Timesheet"
},
{
"default": "0",
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
"fieldname": "include_holidays_in_total_working_days",
"fieldtype": "Check",
- "label": "Include holidays in Total no. of Working Days",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Include holidays in Total no. of Working Days"
},
{
"default": "0",
"description": "If checked, hides and disables Rounded Total field in Salary Slips",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
- "label": "Disable Rounded Total",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Disable Rounded Total"
},
{
"fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"default": "0.5",
"description": "The fraction of daily wages to be paid for half-day attendance",
"fieldname": "daily_wages_fraction_for_half_day",
"fieldtype": "Float",
- "label": "Fraction of Daily Salary for Half Day",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Fraction of Daily Salary for Half Day"
},
{
"default": "1",
"description": "Emails salary slip to employee based on preferred email selected in Employee",
"fieldname": "email_salary_slip_to_employee",
"fieldtype": "Check",
- "label": "Email Salary Slip to Employee",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Email Salary Slip to Employee"
},
{
"default": "0",
@@ -82,9 +69,7 @@
"description": "The salary slip emailed to the employee will be password protected, the password will be generated based on the password policy.",
"fieldname": "encrypt_salary_slips_in_emails",
"fieldtype": "Check",
- "label": "Encrypt Salary Slips in Emails",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Encrypt Salary Slips in Emails"
},
{
"depends_on": "eval: doc.encrypt_salary_slips_in_emails == 1",
@@ -92,24 +77,27 @@
"fieldname": "password_policy",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Password Policy",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Password Policy"
},
{
"depends_on": "eval:doc.payroll_based_on == 'Attendance'",
"fieldname": "consider_unmarked_attendance_as",
"fieldtype": "Select",
"label": "Consider Unmarked Attendance As",
- "options": "Present\nAbsent",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Present\nAbsent"
+ },
+ {
+ "default": "0",
+ "fieldname": "show_leave_balances_in_salary_slip",
+ "fieldtype": "Check",
+ "label": "Show Leave Balances in Salary Slip"
}
],
"icon": "fa fa-cog",
+ "index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-06-22 17:00:58.408030",
+ "modified": "2021-03-03 17:49:59.579723",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll Settings",
@@ -126,5 +114,6 @@
}
],
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/retention_bonus/retention_bonus.js b/erpnext/payroll/doctype/retention_bonus/retention_bonus.js
index 64e726d..f8bb40a 100644
--- a/erpnext/payroll/doctype/retention_bonus/retention_bonus.js
+++ b/erpnext/payroll/doctype/retention_bonus/retention_bonus.js
@@ -4,9 +4,13 @@
frappe.ui.form.on('Retention Bonus', {
setup: function(frm) {
frm.set_query("employee", function() {
+ if (!frm.doc.company) {
+ frappe.msgprint(__("Please Select Company First"));
+ }
return {
filters: {
- "status": "Active"
+ "status": "Active",
+ "company": frm.doc.company
}
};
});
@@ -18,5 +22,22 @@
}
};
});
+ },
+
+ employee: function(frm) {
+ if (frm.doc.employee) {
+ frappe.call({
+ method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
+ args: {
+ employee: frm.doc.employee,
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('currency', r.message);
+ frm.refresh_fields();
+ }
+ }
+ });
+ }
}
});
diff --git a/erpnext/payroll/doctype/retention_bonus/retention_bonus.json b/erpnext/payroll/doctype/retention_bonus/retention_bonus.json
index da884c2..6647230 100644
--- a/erpnext/payroll/doctype/retention_bonus/retention_bonus.json
+++ b/erpnext/payroll/doctype/retention_bonus/retention_bonus.json
@@ -17,7 +17,8 @@
"column_break_6",
"employee_name",
"department",
- "date_of_joining"
+ "date_of_joining",
+ "currency"
],
"fields": [
{
@@ -46,6 +47,7 @@
"fieldname": "bonus_amount",
"fieldtype": "Currency",
"label": "Bonus Amount",
+ "options": "currency",
"reqd": 1
},
{
@@ -89,11 +91,22 @@
"label": "Salary Component",
"options": "Salary Component",
"reqd": 1
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.employee)",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 22:42:05.251951",
+ "modified": "2020-10-20 17:27:47.003134",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Retention Bonus",
@@ -151,7 +164,6 @@
"share": 1
}
],
- "quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.js b/erpnext/payroll/doctype/salary_component/salary_component.js
index c455eb3..dbf7514 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.js
+++ b/erpnext/payroll/doctype/salary_component/salary_component.js
@@ -3,7 +3,7 @@
frappe.ui.form.on('Salary Component', {
setup: function(frm) {
- frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
+ frm.set_query("account", "accounts", function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
filters: {
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.json b/erpnext/payroll/doctype/salary_component/salary_component.json
index 225b048..c97e45c 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.json
+++ b/erpnext/payroll/doctype/salary_component/salary_component.json
@@ -217,7 +217,7 @@
"fieldname": "help",
"fieldtype": "HTML",
"label": "Help",
- "options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base < 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS > 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
+ "options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condition. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base < 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS > 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
},
{
"default": "0",
@@ -238,14 +238,13 @@
"depends_on": "eval:doc.type == \"Deduction\"",
"fieldname": "is_income_tax_component",
"fieldtype": "Check",
- "label": "Is Income Tax Component",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Is Income Tax Component"
}
],
"icon": "fa fa-flag",
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-06-22 15:39:20.826565",
+ "modified": "2020-10-07 20:38:33.795853",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Component",
diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json
index cc87cae..393f647 100644
--- a/erpnext/payroll/doctype/salary_detail/salary_detail.json
+++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json
@@ -9,6 +9,7 @@
"abbr",
"column_break_3",
"amount",
+ "year_to_date",
"section_break_5",
"additional_salary",
"statistical_component",
@@ -117,7 +118,7 @@
"depends_on": "eval:doc.is_flexible_benefit != 1",
"fieldname": "section_break_2",
"fieldtype": "Section Break",
- "label": "Condtion and formula"
+ "label": "Condition and formula"
},
{
"allow_on_submit": 1,
@@ -147,7 +148,7 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
- "options": "Company:company:default_currency"
+ "options": "currency"
},
{
"default": "0",
@@ -160,7 +161,7 @@
"fieldname": "default_amount",
"fieldtype": "Currency",
"label": "Default Amount",
- "options": "Company:company:default_currency",
+ "options": "currency",
"print_hide": 1
},
{
@@ -169,6 +170,7 @@
"hidden": 1,
"label": "Additional Amount",
"no_copy": 1,
+ "options": "currency",
"print_hide": 1,
"read_only": 1
},
@@ -177,6 +179,7 @@
"fieldname": "tax_on_flexible_benefit",
"fieldtype": "Currency",
"label": "Tax on flexible benefit",
+ "options": "currency",
"read_only": 1
},
{
@@ -184,6 +187,7 @@
"fieldname": "tax_on_additional_salary",
"fieldtype": "Currency",
"label": "Tax on additional salary",
+ "options": "currency",
"read_only": 1
},
{
@@ -206,38 +210,36 @@
"collapsible": 1,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
- "label": "Component properties and references ",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Component properties and references "
},
{
"fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "section_break_19",
- "fieldtype": "Section Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Section Break"
},
{
"fieldname": "column_break_18",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "column_break_24",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
+ },
+ {
+ "description": "Total salary booked against this component for this employee from the beginning of the year (payroll period or fiscal year) up to the current salary slip's end date.",
+ "fieldname": "year_to_date",
+ "fieldtype": "Currency",
+ "label": "Year To Date",
+ "options": "currency",
+ "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-07-01 12:13:41.956495",
+ "modified": "2021-01-14 13:39:15.847158",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Detail",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js
index 7b69dbe..d527839 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.js
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js
@@ -13,12 +13,12 @@
];
});
- frm.fields_dict["timesheets"].grid.get_field("time_sheet").get_query = function(){
+ frm.fields_dict["timesheets"].grid.get_field("time_sheet").get_query = function() {
return {
filters: {
employee: frm.doc.employee
}
- }
+ };
};
frm.set_query("salary_component", "earnings", function() {
@@ -26,7 +26,7 @@
filters: {
type: "earning"
}
- }
+ };
});
frm.set_query("salary_component", "deductions", function() {
@@ -34,18 +34,18 @@
filters: {
type: "deduction"
}
- }
+ };
});
frm.set_query("employee", function() {
- return{
+ return {
query: "erpnext.controllers.queries.employee_query"
- }
+ };
});
},
- start_date: function(frm){
- if(frm.doc.start_date){
+ start_date: function(frm) {
+ if (frm.doc.start_date) {
frm.trigger("set_end_date");
}
},
@@ -54,7 +54,7 @@
frm.events.get_emp_and_working_day_details(frm);
},
- set_end_date: function(frm){
+ set_end_date: function(frm) {
frappe.call({
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.get_end_date',
args: {
@@ -66,22 +66,95 @@
frm.set_value('end_date', r.message.end_date);
}
}
- })
+ });
},
company: function(frm) {
var company = locals[':Company'][frm.doc.company];
- if(!frm.doc.letter_head && company.default_letter_head) {
+ if (!frm.doc.letter_head && company.default_letter_head) {
frm.set_value('letter_head', company.default_letter_head);
}
},
+ currency: function(frm) {
+ frm.trigger("set_dynamic_labels");
+ },
+
+ set_dynamic_labels: function(frm) {
+ var company_currency = frm.doc.company? erpnext.get_currency(frm.doc.company): frappe.defaults.get_default("currency");
+ if (frm.doc.employee && frm.doc.currency) {
+ frappe.run_serially([
+ () => frm.events.set_exchange_rate(frm, company_currency),
+ () => frm.events.change_form_labels(frm, company_currency),
+ () => frm.events.change_grid_labels(frm),
+ () => frm.refresh_fields()
+ ]);
+ }
+ },
+
+ set_exchange_rate: function(frm, company_currency) {
+ if (frm.doc.currency) {
+ var from_currency = frm.doc.currency;
+ if (from_currency != company_currency) {
+ frm.events.hide_loan_section(frm);
+ frappe.call({
+ method: "erpnext.setup.utils.get_exchange_rate",
+ args: {
+ from_currency: from_currency,
+ to_currency: company_currency,
+ },
+ callback: function(r) {
+ frm.set_value("exchange_rate", flt(r.message));
+ frm.set_df_property("exchange_rate", "hidden", 0);
+ frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
+ + " = [?] " + company_currency);
+ }
+ });
+ } else {
+ frm.set_value("exchange_rate", 1.0);
+ frm.set_df_property("exchange_rate", "hidden", 1);
+ frm.set_df_property("exchange_rate", "description", "");
+ }
+ }
+ },
+
+ exchange_rate: function(frm) {
+ set_totals(frm);
+ },
+
+ hide_loan_section: function(frm) {
+ frm.set_df_property('section_break_43', 'hidden', 1);
+ },
+
+ change_form_labels: function(frm, company_currency) {
+ frm.set_currency_labels(["base_hour_rate", "base_gross_pay", "base_total_deduction",
+ "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date"],
+ company_currency);
+
+ frm.set_currency_labels(["hour_rate", "gross_pay", "total_deduction", "net_pay", "rounded_total", "total_in_words", "year_to_date", "month_to_date"],
+ frm.doc.currency);
+
+ // toggle fields
+ frm.toggle_display(["exchange_rate", "base_hour_rate", "base_gross_pay", "base_total_deduction",
+ "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date"],
+ frm.doc.currency != company_currency);
+ },
+
+ change_grid_labels: function(frm) {
+ let fields = ["amount", "year_to_date", "default_amount", "additional_amount", "tax_on_flexible_benefit",
+ "tax_on_additional_salary"];
+
+ frm.set_currency_labels(fields, frm.doc.currency, "earnings");
+ frm.set_currency_labels(fields, frm.doc.currency, "deductions");
+ },
+
refresh: function(frm) {
- frm.trigger("toggle_fields")
+ frm.trigger("toggle_fields");
var salary_detail_fields = ["formula", "abbr", "statistical_component", "variable_based_on_taxable_salary"];
- cur_frm.fields_dict['earnings'].grid.set_column_disp(salary_detail_fields,false);
- cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
+ frm.fields_dict['earnings'].grid.set_column_disp(salary_detail_fields, false);
+ frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields, false);
+ frm.trigger("set_dynamic_labels");
},
salary_slip_based_on_timesheet: function(frm) {
@@ -98,12 +171,12 @@
frm.events.get_emp_and_working_day_details(frm);
},
- leave_without_pay: function(frm){
+ leave_without_pay: function(frm) {
if (frm.doc.employee && frm.doc.start_date && frm.doc.end_date) {
return frappe.call({
method: 'process_salary_based_on_working_days',
doc: frm.doc,
- callback: function(r, rt) {
+ callback: function() {
frm.refresh();
}
});
@@ -118,51 +191,96 @@
},
get_emp_and_working_day_details: function(frm) {
- return frappe.call({
- method: 'get_emp_and_working_day_details',
- doc: frm.doc,
- callback: function(r, rt) {
- frm.refresh();
- if (r.message){
- frm.fields_dict.absent_days.set_description("Unmarked Days is treated as "+ r.message +". You can can change this in " + frappe.utils.get_form_link("Payroll Settings", "Payroll Settings", true));
+ if (frm.doc.employee) {
+ return frappe.call({
+ method: 'get_emp_and_working_day_details',
+ doc: frm.doc,
+ callback: function(r) {
+ if (r.message[1] !== "Leave" && r.message[0]) {
+ frm.fields_dict.absent_days.set_description(__("Unmarked Days is treated as {0}. You can can change this in {1}", [r.message, frappe.utils.get_form_link("Payroll Settings", "Payroll Settings", true)]));
+ }
+ frm.refresh();
}
- }
- });
+ });
+ }
}
});
frappe.ui.form.on('Salary Slip Timesheet', {
- time_sheet: function(frm, dt, dn) {
- total_work_hours(frm, dt, dn);
+ time_sheet: function(frm) {
+ set_totals(frm);
},
- timesheets_remove: function(frm, dt, dn) {
- total_work_hours(frm, dt, dn);
+ timesheets_remove: function(frm) {
+ set_totals(frm);
}
});
-// calculate total working hours, earnings based on hourly wages and totals
-var total_work_hours = function(frm, dt, dn) {
- var total_working_hours = 0.0;
- $.each(frm.doc["timesheets"] || [], function(i, timesheet) {
- total_working_hours += timesheet.working_hours;
- });
- frm.set_value('total_working_hours', total_working_hours);
+var set_totals = function(frm) {
+ if (frm.doc.docstatus === 0) {
+ if (frm.doc.earnings || frm.doc.deductions) {
+ frappe.call({
+ method: "set_totals",
+ doc: frm.doc,
+ callback: function() {
+ frm.refresh_fields();
+ }
+ });
+ }
+ }
+};
- var wages_amount = frm.doc.total_working_hours * frm.doc.hour_rate;
+frappe.ui.form.on('Salary Detail', {
+ amount: function(frm) {
+ set_totals(frm);
+ },
- frappe.db.get_value('Salary Structure', {'name': frm.doc.salary_structure}, 'salary_component', (r) => {
- var gross_pay = 0.0;
- $.each(frm.doc["earnings"], function(i, earning) {
- if (earning.salary_component == r.salary_component) {
- earning.amount = wages_amount;
- frm.refresh_fields('earnings');
- }
- gross_pay += earning.amount;
- });
- frm.set_value('gross_pay', gross_pay);
+ earnings_remove: function(frm) {
+ set_totals(frm);
+ },
- frm.doc.net_pay = flt(frm.doc.gross_pay) - flt(frm.doc.total_deduction);
- frm.doc.rounded_total = Math.round(frm.doc.net_pay);
- refresh_many(['net_pay', 'rounded_total']);
- });
-}
+ deductions_remove: function(frm) {
+ set_totals(frm);
+ },
+
+ salary_component: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ if (child.salary_component) {
+ frappe.call({
+ method: "frappe.client.get",
+ args: {
+ doctype: "Salary Component",
+ name: child.salary_component
+ },
+ callback: function(data) {
+ if (data.message) {
+ var result = data.message;
+ frappe.model.set_value(cdt, cdn, 'condition', result.condition);
+ frappe.model.set_value(cdt, cdn, 'amount_based_on_formula', result.amount_based_on_formula);
+ if (result.amount_based_on_formula === 1) {
+ frappe.model.set_value(cdt, cdn, 'formula', result.formula);
+ } else {
+ frappe.model.set_value(cdt, cdn, 'amount', result.amount);
+ }
+ frappe.model.set_value(cdt, cdn, 'statistical_component', result.statistical_component);
+ frappe.model.set_value(cdt, cdn, 'depends_on_payment_days', result.depends_on_payment_days);
+ frappe.model.set_value(cdt, cdn, 'do_not_include_in_total', result.do_not_include_in_total);
+ frappe.model.set_value(cdt, cdn, 'variable_based_on_taxable_salary', result.variable_based_on_taxable_salary);
+ frappe.model.set_value(cdt, cdn, 'is_tax_applicable', result.is_tax_applicable);
+ frappe.model.set_value(cdt, cdn, 'is_flexible_benefit', result.is_flexible_benefit);
+ refresh_field("earnings");
+ refresh_field("deductions");
+ }
+ }
+ });
+ }
+ },
+
+ amount_based_on_formula: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ if (child.amount_based_on_formula === 1) {
+ frappe.model.set_value(cdt, cdn, 'amount', null);
+ } else {
+ frappe.model.set_value(cdt, cdn, 'formula', null);
+ }
+ }
+});
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json
index 619c45f..6688368 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.json
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json
@@ -18,6 +18,8 @@
"journal_entry",
"payroll_entry",
"company",
+ "currency",
+ "exchange_rate",
"letter_head",
"section_break_10",
"start_date",
@@ -38,6 +40,7 @@
"column_break_20",
"total_working_hours",
"hour_rate",
+ "base_hour_rate",
"section_break_26",
"bank_name",
"bank_account_no",
@@ -52,8 +55,10 @@
"deductions",
"totals",
"gross_pay",
+ "base_gross_pay",
"column_break_25",
"total_deduction",
+ "base_total_deduction",
"loan_repayment",
"loans",
"section_break_43",
@@ -63,10 +68,21 @@
"total_loan_repayment",
"net_pay_info",
"net_pay",
+ "base_net_pay",
+ "year_to_date",
+ "base_year_to_date",
"column_break_53",
"rounded_total",
+ "base_rounded_total",
+ "month_to_date",
+ "base_month_to_date",
"section_break_55",
"total_in_words",
+ "column_break_69",
+ "base_total_in_words",
+ "leave_details_section",
+ "leave_details",
+ "section_break_75",
"amended_from"
],
"fields": [
@@ -205,9 +221,13 @@
{
"fieldname": "salary_structure",
"fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Salary Structure",
"options": "Salary Structure",
- "read_only": 1
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1
},
{
"depends_on": "eval:(!doc.salary_slip_based_on_timesheet)",
@@ -265,7 +285,7 @@
"fieldname": "hour_rate",
"fieldtype": "Currency",
"label": "Hour Rate",
- "options": "Company:company:default_currency",
+ "options": "currency",
"print_hide_if_no_value": 1
},
{
@@ -347,9 +367,7 @@
"fieldname": "gross_pay",
"fieldtype": "Currency",
"label": "Gross Pay",
- "oldfieldname": "gross_pay",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -357,15 +375,6 @@
"fieldtype": "Column Break"
},
{
- "fieldname": "total_deduction",
- "fieldtype": "Currency",
- "label": "Total Deduction",
- "oldfieldname": "total_deduction",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
"depends_on": "total_loan_repayment",
"fieldname": "loan_repayment",
"fieldtype": "Section Break",
@@ -379,6 +388,7 @@
"print_hide": 1
},
{
+ "depends_on": "eval:doc.docstatus != 0",
"fieldname": "section_break_43",
"fieldtype": "Section Break"
},
@@ -416,13 +426,10 @@
"label": "net pay info"
},
{
- "description": "Gross Pay - Total Deduction - Loan Repayment",
"fieldname": "net_pay",
"fieldtype": "Currency",
"label": "Net Pay",
- "oldfieldname": "net_pay",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -434,7 +441,7 @@
"fieldname": "rounded_total",
"fieldtype": "Currency",
"label": "Rounded Total",
- "options": "Company:company:default_currency",
+ "options": "currency",
"read_only": 1
},
{
@@ -442,15 +449,6 @@
"fieldtype": "Section Break"
},
{
- "description": "Net Pay (in words) will be visible once you save the Salary Slip.",
- "fieldname": "total_in_words",
- "fieldtype": "Data",
- "label": "Total in words",
- "oldfieldname": "net_pay_in_words",
- "oldfieldtype": "Data",
- "read_only": 1
- },
- {
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -500,13 +498,141 @@
{
"fieldname": "column_break_18",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
+ "fetch_from": "salary_structure.currency",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "total_deduction",
+ "fieldtype": "Currency",
+ "label": "Total Deduction",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_in_words",
+ "fieldtype": "Data",
+ "label": "Total in words",
+ "length": 240,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_75",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "base_hour_rate",
+ "fieldtype": "Currency",
+ "label": "Hour Rate (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide_if_no_value": 1
+ },
+ {
+ "fieldname": "base_gross_pay",
+ "fieldtype": "Currency",
+ "label": "Gross Pay (Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "default": "1.0",
+ "fieldname": "exchange_rate",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Exchange Rate",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "base_total_deduction",
+ "fieldtype": "Currency",
+ "label": "Total Deduction (Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_net_pay",
+ "fieldtype": "Currency",
+ "label": "Net Pay (Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "base_rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total (Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_total_in_words",
+ "fieldtype": "Data",
+ "label": "Total in words (Company Currency)",
+ "length": 240,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_69",
+ "fieldtype": "Column Break"
+ },
+ {
+ "description": "Total salary booked for this employee from the beginning of the year (payroll period or fiscal year) up to the current salary slip's end date.",
+ "fieldname": "year_to_date",
+ "fieldtype": "Currency",
+ "label": "Year To Date",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "description": "Total salary booked for this employee from the beginning of the month up to the current salary slip's end date.",
+ "fieldname": "month_to_date",
+ "fieldtype": "Currency",
+ "label": "Month To Date",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_year_to_date",
+ "fieldtype": "Currency",
+ "label": "Year To Date(Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_month_to_date",
+ "fieldtype": "Currency",
+ "label": "Month To Date(Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "leave_details_section",
+ "fieldtype": "Section Break",
+ "label": "Leave Details"
+ },
+ {
+ "fieldname": "leave_details",
+ "fieldtype": "Table",
+ "label": "Leave Details",
+ "options": "Salary Slip Leave",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 9,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-11 17:37:54.274384",
+ "modified": "2021-02-19 11:48:05.383945",
"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 4ccf564..a04a635 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -5,7 +5,7 @@
import frappe, erpnext
import datetime, math
-from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate
+from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate, get_first_day
from frappe.model.naming import make_autoname
from frappe import msgprint, _
@@ -13,11 +13,13 @@
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.utilities.transaction_base import TransactionBase
from frappe.utils.background_jobs import enqueue
-from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salary_component
+from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts, create_repayment_entry
+from erpnext.accounts.utils import get_fiscal_year
+from six import iteritems
class SalarySlip(TransactionBase):
def __init__(self, *args, **kwargs):
@@ -49,10 +51,10 @@
self.get_working_days_details(lwp = self.leave_without_pay)
self.calculate_net_pay()
-
- company_currency = erpnext.get_company_currency(self.company)
- total = self.net_pay if self.is_rounding_total_disabled() else self.rounded_total
- self.total_in_words = money_in_words(total, company_currency)
+ self.compute_year_to_date()
+ self.compute_month_to_date()
+ self.compute_component_wise_year_to_date()
+ self.add_leave_balances()
if frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet"):
max_working_hours = frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet")
@@ -60,6 +62,14 @@
frappe.msgprint(_("Total working hours should not be greater than max working hours {0}").
format(max_working_hours), alert=True)
+ def set_net_total_in_words(self):
+ doc_currency = self.currency
+ company_currency = erpnext.get_company_currency(self.company)
+ total = self.net_pay if self.is_rounding_total_disabled() else self.rounded_total
+ base_total = self.base_net_pay if self.is_rounding_total_disabled() else self.base_rounded_total
+ self.total_in_words = money_in_words(total, doc_currency)
+ self.base_total_in_words = money_in_words(base_total, company_currency)
+
def on_submit(self):
if self.net_pay < 0:
frappe.throw(_("Net Pay cannot be less than 0"))
@@ -70,9 +80,26 @@
if (frappe.db.get_single_value("Payroll Settings", "email_salary_slip_to_employee")) and not frappe.flags.via_payroll_entry:
self.email_salary_slip()
+ self.update_payment_status_for_gratuity()
+
+ def update_payment_status_for_gratuity(self):
+ add_salary = frappe.db.get_all("Additional Salary",
+ filters = {
+ "payroll_date": ("BETWEEN", [self.start_date, self.end_date]),
+ "employee": self.employee,
+ "ref_doctype": "Gratuity",
+ "docstatus": 1,
+ }, fields = ["ref_docname", "name"], limit=1)
+
+ if len(add_salary):
+ status = "Paid" if self.docstatus == 1 else "Unpaid"
+ if add_salary[0].name in [data.additional_salary for data in self.earnings]:
+ frappe.db.set_value("Gratuity", add_salary.ref_docname, "status", status)
+
def on_cancel(self):
self.set_status()
self.update_status()
+ self.update_payment_status_for_gratuity()
self.cancel_loan_repayment_entry()
def on_trash(self):
@@ -136,8 +163,8 @@
self.salary_slip_based_on_timesheet = self._salary_structure_doc.salary_slip_based_on_timesheet or 0
self.set_time_sheet()
self.pull_sal_struct()
- consider_unmarked_attendance_as = frappe.db.get_value("Payroll Settings", None, "consider_unmarked_attendance_as") or "Present"
- return consider_unmarked_attendance_as
+ ps = frappe.db.get_value("Payroll Settings", None, ["payroll_based_on","consider_unmarked_attendance_as"], as_dict=1)
+ return [ps.payroll_based_on, ps.consider_unmarked_attendance_as]
def set_time_sheet(self):
if self.salary_slip_based_on_timesheet:
@@ -182,6 +209,7 @@
if self.salary_slip_based_on_timesheet:
self.salary_structure = self._salary_structure_doc.name
self.hour_rate = self._salary_structure_doc.hour_rate
+ self.base_hour_rate = flt(self.hour_rate) * flt(self.exchange_rate)
self.total_working_hours = sum([d.working_hours or 0.0 for d in self.timesheets]) or 0.0
wages_amount = self.hour_rate * self.total_working_hours
@@ -210,10 +238,10 @@
frappe.throw(_("Please set Payroll based on in Payroll settings"))
if payroll_based_on == "Attendance":
- actual_lwp, absent = self.calculate_lwp_and_absent_days_based_on_attendance(holidays)
+ actual_lwp, absent = self.calculate_lwp_ppl_and_absent_days_based_on_attendance(holidays)
self.absent_days = absent
else:
- actual_lwp = self.calculate_lwp_based_on_leave_application(holidays, working_days)
+ actual_lwp = self.calculate_lwp_or_ppl_based_on_leave_application(holidays, working_days)
if not lwp:
lwp = actual_lwp
@@ -240,7 +268,6 @@
self.absent_days += unmarked_days #will be treated as absent
self.payment_days -= unmarked_days
if include_holidays_in_total_working_days:
- self.absent_days -= len(holidays)
for holiday in holidays:
if not frappe.db.exists("Attendance", {"employee": self.employee, "attendance_date": holiday, "docstatus": 1 }):
self.payment_days += 1
@@ -301,7 +328,7 @@
return holidays
- def calculate_lwp_based_on_leave_application(self, holidays, working_days):
+ def calculate_lwp_or_ppl_based_on_leave_application(self, holidays, working_days):
lwp = 0
holidays = "','".join(holidays)
daily_wages_fraction_for_half_day = \
@@ -312,10 +339,12 @@
leave = frappe.db.sql("""
SELECT t1.name,
CASE WHEN (t1.half_day_date = %(dt)s or t1.to_date = t1.from_date)
- THEN t1.half_day else 0 END
+ THEN t1.half_day else 0 END,
+ t2.is_ppl,
+ t2.fraction_of_daily_salary_per_leave
FROM `tabLeave Application` t1, `tabLeave Type` t2
WHERE t2.name = t1.leave_type
- AND t2.is_lwp = 1
+ AND (t2.is_lwp = 1 or t2.is_ppl = 1)
AND t1.docstatus = 1
AND t1.employee = %(employee)s
AND ifnull(t1.salary_slip, '') = ''
@@ -328,19 +357,35 @@
""".format(holidays), {"employee": self.employee, "dt": dt})
if leave:
+ equivalent_lwp_count = 0
is_half_day_leave = cint(leave[0][1])
- lwp += (1 - daily_wages_fraction_for_half_day) if is_half_day_leave else 1
+ is_partially_paid_leave = cint(leave[0][2])
+ fraction_of_daily_salary_per_leave = flt(leave[0][3])
+
+ equivalent_lwp_count = (1 - daily_wages_fraction_for_half_day) if is_half_day_leave else 1
+
+ if is_partially_paid_leave:
+ equivalent_lwp_count *= fraction_of_daily_salary_per_leave if fraction_of_daily_salary_per_leave else 1
+
+ lwp += equivalent_lwp_count
return lwp
- def calculate_lwp_and_absent_days_based_on_attendance(self, holidays):
+ def calculate_lwp_ppl_and_absent_days_based_on_attendance(self, holidays):
lwp = 0
absent = 0
daily_wages_fraction_for_half_day = \
flt(frappe.db.get_value("Payroll Settings", None, "daily_wages_fraction_for_half_day")) or 0.5
- lwp_leave_types = dict(frappe.get_all("Leave Type", {"is_lwp": 1}, ["name", "include_holiday"], as_list=1))
+ leave_types = frappe.get_all("Leave Type",
+ or_filters=[["is_ppl", "=", 1], ["is_lwp", "=", 1]],
+ fields =["name", "is_lwp", "is_ppl", "fraction_of_daily_salary_per_leave", "include_holiday"])
+
+ leave_type_map = {}
+ for leave_type in leave_types:
+ leave_type_map[leave_type.name] = leave_type
+
attendances = frappe.db.sql('''
SELECT attendance_date, status, leave_type
FROM `tabAttendance`
@@ -352,21 +397,30 @@
''', values=(self.employee, self.start_date, self.end_date), as_dict=1)
for d in attendances:
- if d.status in ('Half Day', 'On Leave') and d.leave_type and d.leave_type not in lwp_leave_types:
+ if d.status in ('Half Day', 'On Leave') and d.leave_type and d.leave_type not in leave_type_map.keys():
continue
if formatdate(d.attendance_date, "yyyy-mm-dd") in holidays:
if d.status == "Absent" or \
- (d.leave_type and d.leave_type in lwp_leave_types and not lwp_leave_types[d.leave_type]):
+ (d.leave_type and d.leave_type in leave_type_map.keys() and not leave_type_map[d.leave_type]['include_holiday']):
continue
+ if d.leave_type:
+ fraction_of_daily_salary_per_leave = leave_type_map[d.leave_type]["fraction_of_daily_salary_per_leave"]
+
if d.status == "Half Day":
- lwp += (1 - daily_wages_fraction_for_half_day)
- elif d.status == "On Leave" and d.leave_type in lwp_leave_types:
- lwp += 1
+ equivalent_lwp = (1 - daily_wages_fraction_for_half_day)
+
+ if d.leave_type in leave_type_map.keys() and leave_type_map[d.leave_type]["is_ppl"]:
+ equivalent_lwp *= fraction_of_daily_salary_per_leave if fraction_of_daily_salary_per_leave else 1
+ lwp += equivalent_lwp
+ elif d.status == "On Leave" and d.leave_type and d.leave_type in leave_type_map.keys():
+ equivalent_lwp = 1
+ if leave_type_map[d.leave_type]["is_ppl"]:
+ equivalent_lwp *= fraction_of_daily_salary_per_leave if fraction_of_daily_salary_per_leave else 1
+ lwp += equivalent_lwp
elif d.status == "Absent":
absent += 1
-
return lwp, absent
def add_earning_for_hourly_wages(self, doc, salary_component, amount):
@@ -390,16 +444,26 @@
def calculate_net_pay(self):
if self.salary_structure:
self.calculate_component_amounts("earnings")
- self.gross_pay = self.get_component_totals("earnings")
+ self.gross_pay = self.get_component_totals("earnings", depends_on_payment_days=1)
+ self.base_gross_pay = flt(flt(self.gross_pay) * flt(self.exchange_rate), self.precision('base_gross_pay'))
if self.salary_structure:
self.calculate_component_amounts("deductions")
- self.total_deduction = self.get_component_totals("deductions")
self.set_loan_repayment()
+ self.set_component_amounts_based_on_payment_days()
+ self.set_net_pay()
+ def set_net_pay(self):
+ self.total_deduction = self.get_component_totals("deductions")
+ self.base_total_deduction = flt(flt(self.total_deduction) * flt(self.exchange_rate), self.precision('base_total_deduction'))
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
self.rounded_total = rounded(self.net_pay)
+ self.base_net_pay = flt(flt(self.net_pay) * flt(self.exchange_rate), self.precision('base_net_pay'))
+ self.base_rounded_total = flt(rounded(self.base_net_pay), self.precision('base_net_pay'))
+ if self.hour_rate:
+ self.base_hour_rate = flt(flt(self.hour_rate) * flt(self.exchange_rate), self.precision('base_hour_rate'))
+ self.set_net_total_in_words()
def calculate_component_amounts(self, component_type):
if not getattr(self, '_salary_structure_doc', None):
@@ -414,8 +478,6 @@
else:
self.add_tax_components(payroll_period)
- self.set_component_amounts_based_on_payment_days(component_type)
-
def add_structure_components(self, component_type):
data = self.get_data_for_eval()
for struct_row in self._salary_structure_doc.get(component_type):
@@ -461,7 +523,8 @@
return amount
except NameError as err:
- frappe.throw(_("Name error: {0}").format(err))
+ frappe.throw(_("{0} <br> This error can be due to missing or deleted field.").format(err),
+ title=_("Name error"))
except SyntaxError as err:
frappe.throw(_("Syntax error in formula or condition: {0}").format(err))
except Exception as e:
@@ -495,15 +558,16 @@
self.update_component_row(frappe._dict(last_benefit.struct_row), amount, "earnings")
def add_additional_salary_components(self, component_type):
- salary_components_details, additional_salary_details = get_additional_salary_component(self.employee,
+ additional_salaries = get_additional_salaries(self.employee,
self.start_date, self.end_date, component_type)
- if salary_components_details and additional_salary_details:
- for additional_salary in additional_salary_details:
- additional_salary =frappe._dict(additional_salary)
- amount = additional_salary.amount
- overwrite = additional_salary.overwrite
- self.update_component_row(frappe._dict(salary_components_details[additional_salary.component]), amount,
- component_type, overwrite=overwrite, additional_salary=additional_salary.name)
+
+ for additional_salary in additional_salaries:
+ self.update_component_row(
+ get_salary_component_data(additional_salary.component),
+ additional_salary.amount,
+ component_type,
+ additional_salary
+ )
def add_tax_components(self, payroll_period):
# Calculate variable_based_on_taxable_salary after all components updated in salary slip
@@ -520,46 +584,59 @@
for d in tax_components:
tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period)
- tax_row = self.get_salary_slip_row(d)
+ tax_row = get_salary_component_data(d)
self.update_component_row(tax_row, tax_amount, "deductions")
- def update_component_row(self, struct_row, amount, key, overwrite=1, additional_salary = ''):
+ def update_component_row(self, component_data, amount, component_type, additional_salary=None):
component_row = None
- for d in self.get(key):
- if d.salary_component == struct_row.salary_component:
+ for d in self.get(component_type):
+ if d.salary_component != component_data.salary_component:
+ continue
+
+ if (
+ not d.additional_salary
+ and (not additional_salary or additional_salary.overwrite)
+ or additional_salary
+ and additional_salary.name == d.additional_salary
+ ):
component_row = d
- if not component_row or (struct_row.get("is_additional_component") and not overwrite):
- if amount:
- self.append(key, {
- 'amount': amount,
- 'default_amount': amount if not struct_row.get("is_additional_component") else 0,
- 'depends_on_payment_days' : struct_row.depends_on_payment_days,
- 'salary_component' : struct_row.salary_component,
- 'abbr' : struct_row.abbr,
- 'additional_salary': additional_salary,
- 'do_not_include_in_total' : struct_row.do_not_include_in_total,
- 'is_tax_applicable': struct_row.is_tax_applicable,
- 'is_flexible_benefit': struct_row.is_flexible_benefit,
- 'variable_based_on_taxable_salary': struct_row.variable_based_on_taxable_salary,
- 'deduct_full_tax_on_selected_payroll_date': struct_row.deduct_full_tax_on_selected_payroll_date,
- 'additional_amount': amount if struct_row.get("is_additional_component") else 0,
- 'exempted_from_income_tax': struct_row.exempted_from_income_tax
- })
+ break
+
+ if additional_salary and additional_salary.overwrite:
+ # Additional Salary with overwrite checked, remove default rows of same component
+ self.set(component_type, [
+ d for d in self.get(component_type)
+ if d.salary_component != component_data.salary_component
+ or d.additional_salary and additional_salary.name != d.additional_salary
+ or d == component_row
+ ])
+
+ if not component_row:
+ if not amount:
+ return
+
+ component_row = self.append(component_type)
+ for attr in (
+ 'depends_on_payment_days', 'salary_component', 'abbr'
+ 'do_not_include_in_total', 'is_tax_applicable',
+ 'is_flexible_benefit', 'variable_based_on_taxable_salary',
+ 'exempted_from_income_tax'
+ ):
+ component_row.set(attr, component_data.get(attr))
+
+ if additional_salary:
+ component_row.default_amount = 0
+ component_row.additional_amount = amount
+ 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
else:
- if struct_row.get("is_additional_component"):
- if overwrite:
- component_row.additional_amount = amount - component_row.get("default_amount", 0)
- component_row.additional_salary = additional_salary
- else:
- component_row.additional_amount = amount
+ component_row.default_amount = amount
+ component_row.additional_amount = 0
+ component_row.deduct_full_tax_on_selected_payroll_date = \
+ component_data.deduct_full_tax_on_selected_payroll_date
- if not overwrite and component_row.default_amount:
- amount += component_row.default_amount
- else:
- component_row.default_amount = amount
-
- component_row.amount = amount
- component_row.deduct_full_tax_on_selected_payroll_date = struct_row.deduct_full_tax_on_selected_payroll_date
+ component_row.amount = amount
def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period):
if not payroll_period:
@@ -772,7 +849,7 @@
cint(row.depends_on_payment_days) and cint(self.total_working_days) and
(not self.salary_slip_based_on_timesheet or
getdate(self.start_date) < joining_date or
- getdate(self.end_date) > relieving_date
+ (relieving_date and getdate(self.end_date) > relieving_date)
)):
additional_amount = flt((flt(row.additional_amount) * flt(self.payment_days)
/ cint(self.total_working_days)), row.precision("additional_amount"))
@@ -885,35 +962,29 @@
if condition:
return frappe.safe_eval(condition, self.whitelisted_globals, data)
except NameError as err:
- frappe.throw(_("Name error: {0}").format(err))
+ frappe.throw(_("{0} <br> This error can be due to missing or deleted field.").format(err),
+ title=_("Name error"))
except SyntaxError as err:
frappe.throw(_("Syntax error in condition: {0}").format(err))
except Exception as e:
frappe.throw(_("Error in formula or condition: {0}").format(e))
raise
- def get_salary_slip_row(self, salary_component):
- component = frappe.get_doc("Salary Component", salary_component)
- # Data for update_component_row
- struct_row = frappe._dict()
- struct_row['depends_on_payment_days'] = component.depends_on_payment_days
- struct_row['salary_component'] = component.name
- struct_row['abbr'] = component.salary_component_abbr
- struct_row['do_not_include_in_total'] = component.do_not_include_in_total
- struct_row['is_tax_applicable'] = component.is_tax_applicable
- struct_row['is_flexible_benefit'] = component.is_flexible_benefit
- struct_row['variable_based_on_taxable_salary'] = component.variable_based_on_taxable_salary
- return struct_row
+ def get_component_totals(self, component_type, depends_on_payment_days=0):
+ joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
+ ["date_of_joining", "relieving_date"])
- def get_component_totals(self, component_type):
total = 0.0
for d in self.get(component_type):
if not d.do_not_include_in_total:
- d.amount = flt(d.amount, d.precision("amount"))
- total += d.amount
+ if depends_on_payment_days:
+ amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0]
+ else:
+ amount = flt(d.amount, d.precision("amount"))
+ total += amount
return total
- def set_component_amounts_based_on_payment_days(self, component_type):
+ def set_component_amounts_based_on_payment_days(self):
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
["date_of_joining", "relieving_date"])
@@ -923,8 +994,9 @@
if not joining_date:
frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
- for d in self.get(component_type):
- d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0]
+ 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"))
def set_loan_repayment(self):
self.total_loan_repayment = 0
@@ -950,9 +1022,9 @@
amounts = calculate_amounts(payment.loan, self.posting_date, "Regular Payment")
total_amount = amounts['interest_amount'] + amounts['payable_principal_amount']
if payment.total_payment > total_amount:
- frappe.throw(_("""Row {0}: Paid amount {1} is greater than pending accrued amount {2}
- against loan {3}""").format(payment.idx, frappe.bold(payment.total_payment),
- frappe.bold(total_amount), frappe.bold(payment.loan)))
+ frappe.throw(_("""Row {0}: Paid amount {1} is greater than pending accrued amount {2} against loan {3}""")
+ .format(payment.idx, frappe.bold(payment.total_payment),
+ frappe.bold(total_amount), frappe.bold(payment.loan)))
self.total_interest_amount += payment.interest_amount
self.total_principal_amount += payment.principal_amount
@@ -960,7 +1032,6 @@
self.total_loan_repayment += payment.total_payment
def get_loan_details(self):
-
return frappe.get_all("Loan",
fields=["name", "interest_income_account", "loan_account", "loan_type"],
filters = {
@@ -1047,6 +1118,139 @@
self.get_working_days_details(lwp=self.leave_without_pay)
self.calculate_net_pay()
+ def set_totals(self):
+ self.gross_pay = 0.0
+ if self.salary_slip_based_on_timesheet == 1:
+ self.calculate_total_for_salary_slip_based_on_timesheet()
+ else:
+ self.total_deduction = 0.0
+ if hasattr(self, "earnings"):
+ for earning in self.earnings:
+ self.gross_pay += flt(earning.amount, earning.precision("amount"))
+ if hasattr(self, "deductions"):
+ for deduction in self.deductions:
+ self.total_deduction += flt(deduction.amount, deduction.precision("amount"))
+ self.net_pay = flt(self.gross_pay) - flt(self.total_deduction) - flt(self.total_loan_repayment)
+ self.set_base_totals()
+
+ def set_base_totals(self):
+ self.base_gross_pay = flt(self.gross_pay) * flt(self.exchange_rate)
+ self.base_total_deduction = flt(self.total_deduction) * flt(self.exchange_rate)
+ self.rounded_total = rounded(self.net_pay)
+ self.base_net_pay = flt(self.net_pay) * flt(self.exchange_rate)
+ self.base_rounded_total = rounded(self.base_net_pay)
+ self.set_net_total_in_words()
+
+ #calculate total working hours, earnings based on hourly wages and totals
+ def calculate_total_for_salary_slip_based_on_timesheet(self):
+ if self.timesheets:
+ self.total_working_hours = 0
+ for timesheet in self.timesheets:
+ if timesheet.working_hours:
+ self.total_working_hours += timesheet.working_hours
+
+ wages_amount = self.total_working_hours * self.hour_rate
+ self.base_hour_rate = flt(self.hour_rate) * flt(self.exchange_rate)
+ salary_component = frappe.db.get_value('Salary Structure', {'name': self.salary_structure}, 'salary_component')
+ if self.earnings:
+ for i, earning in enumerate(self.earnings):
+ if earning.salary_component == salary_component:
+ self.earnings[i].amount = wages_amount
+ self.gross_pay += self.earnings[i].amount
+ self.net_pay = flt(self.gross_pay) - flt(self.total_deduction)
+
+ def compute_year_to_date(self):
+ year_to_date = 0
+ period_start_date, period_end_date = self.get_year_to_date_period()
+
+ salary_slip_sum = frappe.get_list('Salary Slip',
+ fields = ['sum(net_pay) as sum'],
+ filters = {'employee_name' : self.employee_name,
+ 'start_date' : ['>=', period_start_date],
+ 'end_date' : ['<', period_end_date],
+ 'name': ['!=', self.name],
+ 'docstatus': 1
+ })
+
+ year_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0
+
+ year_to_date += self.net_pay
+ self.year_to_date = year_to_date
+
+ def compute_month_to_date(self):
+ month_to_date = 0
+ 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,
+ 'start_date' : ['>=', first_day_of_the_month],
+ 'end_date' : ['<', self.start_date],
+ 'name': ['!=', self.name],
+ 'docstatus': 1
+ })
+
+ month_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0
+
+ month_to_date += self.net_pay
+ self.month_to_date = month_to_date
+
+ def compute_component_wise_year_to_date(self):
+ period_start_date, period_end_date = self.get_year_to_date_period()
+
+ for key in ('earnings', 'deductions'):
+ for component in self.get(key):
+ year_to_date = 0
+ component_sum = frappe.db.sql("""
+ SELECT sum(detail.amount) as sum
+ FROM `tabSalary Detail` as detail
+ INNER JOIN `tabSalary Slip` as salary_slip
+ ON detail.parent = salary_slip.name
+ WHERE
+ salary_slip.employee_name = %(employee_name)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,
+ 'period_end_date': period_end_date, 'docname': self.name}
+ )
+
+ year_to_date = flt(component_sum[0][0]) if component_sum else 0.0
+ year_to_date += component.amount
+ component.year_to_date = year_to_date
+
+ def get_year_to_date_period(self):
+ payroll_period = get_payroll_period(self.start_date, self.end_date, self.company)
+
+ if payroll_period:
+ period_start_date = payroll_period.start_date
+ period_end_date = payroll_period.end_date
+ else:
+ # get dates based on fiscal year if no payroll period exists
+ fiscal_year = get_fiscal_year(date=self.start_date, company=self.company, as_dict=1)
+ period_start_date = fiscal_year.year_start_date
+ period_end_date = fiscal_year.year_end_date
+
+ return period_start_date, period_end_date
+
+ def add_leave_balances(self):
+ self.set('leave_details', [])
+
+ if frappe.db.get_single_value('Payroll Settings', 'show_leave_balances_in_salary_slip'):
+ 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']):
+ self.append('leave_details', {
+ 'leave_type': leave_type,
+ 'total_allocated_leaves': flt(leave_values.get('total_leaves')),
+ 'expired_leaves': flt(leave_values.get('expired_leaves')),
+ 'used_leaves': flt(leave_values.get('leaves_taken')),
+ 'pending_leaves': flt(leave_values.get('pending_leaves')),
+ 'available_leaves': flt(leave_values.get('remaining_leaves'))
+ })
+
def unlink_ref_doc_from_salary_slip(ref_no):
linked_ss = frappe.db.sql_list("""select name from `tabSalary Slip`
where journal_entry=%s and docstatus < 2""", (ref_no))
@@ -1058,3 +1262,19 @@
def generate_password_for_pdf(policy_template, employee):
employee = frappe.get_doc("Employee", employee)
return policy_template.format(**employee.as_dict())
+
+def get_salary_component_data(component):
+ return frappe.get_value(
+ "Salary Component",
+ component,
+ [
+ "name as salary_component",
+ "depends_on_payment_days",
+ "salary_component_abbr as abbr",
+ "do_not_include_in_total",
+ "is_tax_applicable",
+ "is_flexible_benefit",
+ "variable_based_on_taxable_salary",
+ ],
+ as_dict=1,
+ )
diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
index 37cd89a..7672695 100644
--- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
@@ -9,16 +9,19 @@
import random
from erpnext.accounts.utils import get_fiscal_year
from frappe.utils.make_random import get_random
-from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day
+from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day, cstr
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
+from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration \
import create_payroll_period, create_exemption_category
class TestSalarySlip(unittest.TestCase):
def setUp(self):
setup_test()
+
def tearDown(self):
frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 0)
frappe.set_user("Administrator")
@@ -31,7 +34,7 @@
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance")
frappe.db.set_value("Payroll Settings", None, "daily_wages_fraction_for_half_day", 0.75)
- emp_id = make_employee("test_for_attendance@salary.com")
+ emp_id = make_employee("test_payment_days_based_on_attendance@salary.com")
frappe.db.set_value("Employee", emp_id, {"relieving_date": None, "status": "Active"})
frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0)
@@ -53,7 +56,7 @@
mark_attendance(emp_id, add_days(first_sunday, 4), 'On Leave', leave_type='Casual Leave', ignore_validate=True) # invalid lwp
mark_attendance(emp_id, add_days(first_sunday, 7), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # invalid lwp
- ss = make_employee_salary_slip("test_for_attendance@salary.com", "Monthly")
+ ss = make_employee_salary_slip("test_payment_days_based_on_attendance@salary.com", "Monthly", "Test Payment Based On Attendence")
self.assertEqual(ss.leave_without_pay, 1.25)
self.assertEqual(ss.absent_days, 1)
@@ -76,7 +79,7 @@
# Payroll based on attendance
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
- emp_id = make_employee("test_for_attendance@salary.com")
+ emp_id = make_employee("test_payment_days_based_on_leave_application@salary.com")
frappe.db.set_value("Employee", emp_id, {"relieving_date": None, "status": "Active"})
frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0)
@@ -93,31 +96,40 @@
make_leave_application(emp_id, first_sunday, add_days(first_sunday, 3), "Leave Without Pay")
- ss = make_employee_salary_slip("test_for_attendance@salary.com", "Monthly")
+ leave_type_ppl = create_leave_type(leave_type_name="Test Partially Paid Leave", is_ppl = 1)
+ leave_type_ppl.save()
- self.assertEqual(ss.leave_without_pay, 3)
+ alloc = create_leave_allocation(
+ employee = emp_id, from_date = add_days(first_sunday, 4),
+ to_date = add_days(first_sunday, 10), new_leaves_allocated = 3,
+ leave_type = "Test Partially Paid Leave")
+ alloc.save()
+ alloc.submit()
+
+ #two day leave ppl with fraction_of_daily_salary_per_leave = 0.5 equivalent to single day lwp
+ make_leave_application(emp_id, add_days(first_sunday, 4), add_days(first_sunday, 5), "Test Partially Paid Leave")
+
+ ss = make_employee_salary_slip("test_payment_days_based_on_leave_application@salary.com", "Monthly", "Test Payment Based On Leave Application")
+
+
+ self.assertEqual(ss.leave_without_pay, 4)
days_in_month = no_of_days[0]
no_of_holidays = no_of_days[1]
- self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 3)
-
- #Gross pay calculation based on attendances
- gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
-
- self.assertEqual(flt(ss.gross_pay, 2), flt(gross_pay, 2))
+ self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 4)
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)
- make_employee("test_employee@salary.com")
+ make_employee("test_salary_slip_with_holidays_included@salary.com")
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ {"employee_name":"test_salary_slip_with_holidays_included@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
- ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
+ {"employee_name":"test_salary_slip_with_holidays_included@salary.com"}, "name"), "status", "Active")
+ ss = make_employee_salary_slip("test_salary_slip_with_holidays_included@salary.com", "Monthly", "Test Salary Slip With Holidays Included")
self.assertEqual(ss.total_working_days, no_of_days[0])
self.assertEqual(ss.payment_days, no_of_days[0])
@@ -128,12 +140,12 @@
def test_salary_slip_with_holidays_excluded(self):
no_of_days = self.get_no_of_days()
frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 0)
- make_employee("test_employee@salary.com")
+ make_employee("test_salary_slip_with_holidays_excluded@salary.com")
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ {"employee_name":"test_salary_slip_with_holidays_excluded@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
- ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
+ {"employee_name":"test_salary_slip_with_holidays_excluded@salary.com"}, "name"), "status", "Active")
+ ss = make_employee_salary_slip("test_salary_slip_with_holidays_excluded@salary.com", "Monthly", "Test Salary Slip With Holidays Excluded")
self.assertEqual(ss.total_working_days, no_of_days[0] - no_of_days[1])
self.assertEqual(ss.payment_days, no_of_days[0] - no_of_days[1])
@@ -148,7 +160,7 @@
frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1)
# set joinng date in the same month
- make_employee("test_employee@salary.com")
+ make_employee("test_payment_days@salary.com")
if getdate(nowdate()).day >= 15:
relieving_date = getdate(add_days(nowdate(),-10))
date_of_joining = getdate(add_days(nowdate(),-10))
@@ -163,39 +175,39 @@
relieving_date = getdate(nowdate())
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "date_of_joining", date_of_joining)
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "date_of_joining", date_of_joining)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Active")
- ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
+ ss = make_employee_salary_slip("test_payment_days@salary.com", "Monthly", "Test Payment Days")
self.assertEqual(ss.total_working_days, no_of_days[0])
self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1))
# set relieving date in the same month
frappe.db.set_value("Employee",frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60)))
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60)))
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", relieving_date)
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", relieving_date)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "status", "Left")
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Left")
ss.save()
self.assertEqual(ss.total_working_days, no_of_days[0])
self.assertEqual(ss.payment_days, getdate(relieving_date).day)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
+ {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Active")
def test_employee_salary_slip_read_permission(self):
- make_employee("test_employee@salary.com")
+ make_employee("test_employee_salary_slip_read_permission@salary.com")
- salary_slip_test_employee = make_employee_salary_slip("test_employee@salary.com", "Monthly")
- frappe.set_user("test_employee@salary.com")
+ salary_slip_test_employee = make_employee_salary_slip("test_employee_salary_slip_read_permission@salary.com", "Monthly", "Test Employee Salary Slip Read Permission")
+ frappe.set_user("test_employee_salary_slip_read_permission@salary.com")
self.assertTrue(salary_slip_test_employee.has_permission("read"))
def test_email_salary_slip(self):
@@ -203,8 +215,8 @@
frappe.db.set_value("Payroll Settings", None, "email_salary_slip_to_employee", 1)
- make_employee("test_employee@salary.com")
- ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
+ make_employee("test_email_salary_slip@salary.com")
+ ss = make_employee_salary_slip("test_email_salary_slip@salary.com", "Monthly", "Test Salary Slip Email")
ss.company = "_Test Company"
ss.save()
ss.submit()
@@ -215,8 +227,9 @@
def test_loan_repayment_salary_slip(self):
from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan, make_loan_disbursement_entry, create_loan_accounts
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
- applicant = make_employee("test_loanemployee@salary.com", company="_Test Company")
+ applicant = make_employee("test_loan_repayment_salary_slip@salary.com", company="_Test Company")
create_loan_accounts()
@@ -228,6 +241,12 @@
interest_income_account='Interest Income Account - _TC',
penalty_income_account='Penalty Income Account - _TC')
+ payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company")
+
+ make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR',
+ payroll_period=payroll_period)
+
+ frappe.db.sql("delete from tabLoan")
loan = create_loan(applicant, "Car Loan", 11000, "Repay Over Number of Periods", 20, posting_date=add_months(nowdate(), -1))
loan.repay_from_salary = 1
loan.submit()
@@ -236,7 +255,7 @@
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
- ss = make_employee_salary_slip("test_loanemployee@salary.com", "Monthly")
+ ss = make_employee_salary_slip("test_loan_repayment_salary_slip@salary.com", "Monthly", "Test Loan Repayment Salary Structure")
ss.submit()
self.assertEqual(ss.total_loan_repayment, 592)
@@ -249,7 +268,7 @@
for payroll_frequency in ["Monthly", "Bimonthly", "Fortnightly", "Weekly", "Daily"]:
make_employee(payroll_frequency + "_test_employee@salary.com")
- ss = make_employee_salary_slip(payroll_frequency + "_test_employee@salary.com", payroll_frequency)
+ ss = make_employee_salary_slip(payroll_frequency + "_test_employee@salary.com", payroll_frequency, payroll_frequency + "_Test Payroll Frequency")
if payroll_frequency == "Monthly":
self.assertEqual(ss.end_date, m['month_end_date'])
elif payroll_frequency == "Bimonthly":
@@ -264,6 +283,77 @@
elif payroll_frequency == "Daily":
self.assertEqual(ss.end_date, nowdate())
+ def test_multi_currency_salary_slip(self):
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
+ applicant = make_employee("test_multi_currency_salary_slip@salary.com", company="_Test Company")
+ frappe.db.sql("""delete from `tabSalary Structure` where name='Test Multi Currency Salary Slip'""")
+ salary_structure = make_salary_structure("Test Multi Currency Salary Slip", "Monthly", employee=applicant, company="_Test Company", currency='USD')
+ salary_slip = make_salary_slip(salary_structure.name, employee = applicant)
+ salary_slip.exchange_rate = 70
+ salary_slip.calculate_net_pay()
+
+ self.assertEqual(salary_slip.gross_pay, 78000)
+ self.assertEqual(salary_slip.base_gross_pay, 78000*70)
+
+ def test_year_to_date_computation(self):
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
+
+ applicant = make_employee("test_ytd@salary.com", company="_Test Company")
+
+ payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company")
+
+ create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01"),
+ company="_Test Company")
+
+ salary_structure = make_salary_structure("Monthly Salary Structure Test for Salary Slip YTD",
+ "Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period)
+
+ # clear salary slip for this employee
+ frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'")
+
+ create_salary_slips_for_payroll_period(applicant, salary_structure.name,
+ payroll_period, deduct_random=False)
+
+ salary_slips = frappe.get_all('Salary Slip', fields=['year_to_date', 'net_pay'], filters={'employee_name':
+ 'test_ytd@salary.com'}, order_by = 'posting_date')
+
+ year_to_date = 0
+ for slip in salary_slips:
+ year_to_date += flt(slip.net_pay)
+ self.assertEqual(slip.year_to_date, year_to_date)
+
+ def test_component_wise_year_to_date_computation(self):
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
+
+ applicant = make_employee("test_ytd@salary.com", company="_Test Company")
+
+ payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company")
+
+ create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01"),
+ company="_Test Company")
+
+ salary_structure = make_salary_structure("Monthly Salary Structure Test for Salary Slip YTD",
+ "Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period)
+
+ # clear salary slip for this employee
+ frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'")
+
+ create_salary_slips_for_payroll_period(applicant, salary_structure.name,
+ payroll_period, deduct_random=False, num=3)
+
+ salary_slips = frappe.get_all("Salary Slip", fields=["name"], filters={"employee_name":
+ "test_ytd@salary.com"}, order_by = "posting_date")
+
+ year_to_date = dict()
+ for slip in salary_slips:
+ doc = frappe.get_doc("Salary Slip", slip.name)
+ for entry in doc.get("earnings"):
+ if not year_to_date.get(entry.salary_component):
+ year_to_date[entry.salary_component] = 0
+
+ year_to_date[entry.salary_component] += entry.amount
+ self.assertEqual(year_to_date[entry.salary_component], entry.year_to_date)
+
def test_tax_for_payroll_period(self):
data = {}
# test the impact of tax exemption declaration, tax exemption proof submission
@@ -271,7 +361,6 @@
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
frappe.db.sql("""delete from `tabPayroll Period`""")
frappe.db.sql("""delete from `tabSalary Component`""")
- frappe.db.sql("""delete from `tabAdditional Salary`""")
payroll_period = create_payroll_period()
@@ -347,8 +436,7 @@
# create additional salary of 150000
frappe.db.sql("""delete from `tabSalary Slip` where employee=%s""", (employee))
- data["additional-1"] = create_additional_salary(employee, payroll_period, 50000)
- data["additional-2"] = create_additional_salary(employee, payroll_period, 100000)
+ data["additional-1"] = create_additional_salary(employee, payroll_period, 150000)
data["deducted_dates"] = create_salary_slips_for_payroll_period(employee,
salary_structure.name, payroll_period)
@@ -385,16 +473,18 @@
salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip"
employee = frappe.db.get_value("Employee", {"user_id": user})
- salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee)
- salary_slip = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})})
+ salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee=employee)
+ salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})})
- if not salary_slip:
+ if not salary_slip_name:
salary_slip = make_salary_slip(salary_structure_doc.name, employee = employee)
salary_slip.employee_name = frappe.get_value("Employee",
{"name":frappe.db.get_value("Employee", {"user_id": user})}, "employee_name")
salary_slip.payroll_frequency = payroll_frequency
salary_slip.posting_date = nowdate()
salary_slip.insert()
+ else:
+ salary_slip = frappe.get_doc('Salary Slip', salary_slip_name)
return salary_slip
@@ -435,7 +525,7 @@
sal_comp.append("accounts", {
"company": d,
- "default_account": create_account(account_name, d, parent_account)
+ "account": create_account(account_name, d, parent_account)
})
sal_comp.save()
@@ -527,14 +617,6 @@
"amount": 200,
"exempted_from_income_tax": 1
- },
- {
- "salary_component": 'TDS',
- "abbr":'T',
- "type": "Deduction",
- "depends_on_payment_days": 0,
- "variable_based_on_taxable_salary": 1,
- "round_to_the_nearest_integer": 1
}
]
if not test_tax:
@@ -545,6 +627,15 @@
"type": "Deduction",
"round_to_the_nearest_integer": 1
})
+ else:
+ data.append({
+ "salary_component": 'TDS',
+ "abbr":'T',
+ "type": "Deduction",
+ "depends_on_payment_days": 0,
+ "variable_based_on_taxable_salary": 1,
+ "round_to_the_nearest_integer": 1
+ })
if setup or test_tax:
make_salary_component(data, test_tax, company_list)
@@ -562,7 +653,8 @@
"doctype": "Employee Tax Exemption Declaration",
"employee": employee,
"payroll_period": payroll_period,
- "company": erpnext.get_default_company()
+ "company": erpnext.get_default_company(),
+ "currency": erpnext.get_default_currency()
})
declaration.append("declarations", {
"exemption_sub_category": "_Test Sub Category",
@@ -577,7 +669,8 @@
"doctype": "Employee Tax Exemption Proof Submission",
"employee": employee,
"payroll_period": payroll_period.name,
- "submission_date": submission_date
+ "submission_date": submission_date,
+ "currency": erpnext.get_default_currency()
})
proof_submission.append("tax_exemption_proofs", {
"exemption_sub_category": "_Test Sub Category",
@@ -594,13 +687,18 @@
"employee": employee,
"claimed_amount": amount,
"claim_date": claim_date,
- "earning_component": component
+ "earning_component": component,
+ "currency": erpnext.get_default_currency()
}).submit()
return claim_date
-def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False):
- if frappe.db.exists("Income Tax Slab", "Tax Slab: " + payroll_period.name):
- return
+def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False, currency=None,
+ company=None):
+ if not currency:
+ currency = erpnext.get_default_currency()
+
+ if company:
+ currency = erpnext.get_company_currency(company)
slabs = [
{
@@ -620,30 +718,38 @@
}
]
- income_tax_slab = frappe.new_doc("Income Tax Slab")
- income_tax_slab.name = "Tax Slab: " + payroll_period.name
- income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2)
+ income_tax_slab_name = frappe.db.get_value("Income Tax Slab", {"currency": currency})
+ if not income_tax_slab_name:
+ income_tax_slab = frappe.new_doc("Income Tax Slab")
+ income_tax_slab.name = "Tax Slab: " + payroll_period.name + " " + cstr(currency)
+ income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2)
+ income_tax_slab.company = company or ''
+ income_tax_slab.currency = currency
- if allow_tax_exemption:
- income_tax_slab.allow_tax_exemption = 1
- income_tax_slab.standard_tax_exemption_amount = 50000
+ if allow_tax_exemption:
+ income_tax_slab.allow_tax_exemption = 1
+ income_tax_slab.standard_tax_exemption_amount = 50000
- for item in slabs:
- income_tax_slab.append("slabs", item)
+ for item in slabs:
+ income_tax_slab.append("slabs", item)
- income_tax_slab.append("other_taxes_and_charges", {
- "description": "cess",
- "percent": 4
- })
+ income_tax_slab.append("other_taxes_and_charges", {
+ "description": "cess",
+ "percent": 4
+ })
- income_tax_slab.save()
- if not dont_submit:
- income_tax_slab.submit()
+ income_tax_slab.save()
+ if not dont_submit:
+ income_tax_slab.submit()
-def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True):
+ return income_tax_slab.name
+ else:
+ return income_tax_slab_name
+
+def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True, num=12):
deducted_dates = []
i = 0
- while i < 12:
+ while i < num:
slip = frappe.get_doc({"doctype": "Salary Slip", "employee": employee,
"salary_structure": salary_structure, "frequency": "Monthly"})
if i == 0:
@@ -673,7 +779,8 @@
"salary_component": "Performance Bonus",
"payroll_date": salary_date,
"amount": amount,
- "type": "Earning"
+ "type": "Earning",
+ "currency": erpnext.get_default_currency()
}).submit()
return salary_date
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/payroll/doctype/salary_slip_leave/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/payroll/doctype/salary_slip_leave/__init__.py
diff --git a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.json b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.json
new file mode 100644
index 0000000..7ac453b
--- /dev/null
+++ b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.json
@@ -0,0 +1,78 @@
+{
+ "actions": [],
+ "creation": "2021-02-19 11:45:18.173417",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "leave_type",
+ "total_allocated_leaves",
+ "expired_leaves",
+ "used_leaves",
+ "pending_leaves",
+ "available_leaves"
+ ],
+ "fields": [
+ {
+ "fieldname": "leave_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Leave Type",
+ "no_copy": 1,
+ "options": "Leave Type",
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_allocated_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Total Allocated Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "expired_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Expired Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "used_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Used Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "pending_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Pending Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "available_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Available Leave",
+ "no_copy": 1,
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-19 10:47:48.546724",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Salary Slip Leave",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
new file mode 100644
index 0000000..7a92bf1
--- /dev/null
+++ b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
@@ -0,0 +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 SalarySlipLeave(Document):
+ pass
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.js b/erpnext/payroll/doctype/salary_structure/salary_structure.js
index ad93a2f..6aa1387 100755
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.js
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.js
@@ -41,20 +41,6 @@
frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet)
- frm.set_query("salary_component", "earnings", function() {
- return {
- filters: {
- type: "earning"
- }
- }
- });
- frm.set_query("salary_component", "deductions", function() {
- return {
- filters: {
- type: "deduction"
- }
- }
- });
frm.set_query("payment_account", function () {
var account_types = ["Bank", "Cash"];
return {
@@ -65,9 +51,48 @@
}
};
});
+ frm.trigger('set_earning_deduction_component');
+ },
+
+ set_earning_deduction_component: function(frm) {
+ if(!frm.doc.company) return;
+ frm.set_query("salary_component", "earnings", function() {
+ return {
+ filters: {type: "earning", company: frm.doc.company}
+ };
+ });
+ frm.set_query("salary_component", "deductions", function() {
+ return {
+ filters: {type: "deduction", company: frm.doc.company}
+ };
+ });
+ },
+
+ company: function(frm) {
+ frm.trigger('set_earning_deduction_component');
+ },
+
+ currency: function(frm) {
+ calculate_totals(frm.doc);
+ frm.trigger("set_dynamic_labels")
+ frm.refresh()
+ },
+
+ set_dynamic_labels: function(frm) {
+ frm.set_currency_labels(["net_pay","hour_rate", "leave_encashment_amount_per_day", "max_benefits", "total_earning",
+ "total_deduction"], frm.doc.currency);
+
+ frm.set_currency_labels(["amount", "additional_amount", "tax_on_flexible_benefit", "tax_on_additional_salary"],
+ frm.doc.currency, "earnings");
+
+ frm.set_currency_labels(["amount", "additional_amount", "tax_on_flexible_benefit", "tax_on_additional_salary"],
+ frm.doc.currency, "deductions");
+
+ frm.refresh_fields();
},
refresh: function(frm) {
+ frm.trigger("set_dynamic_labels")
frm.trigger("toggle_fields");
frm.fields_dict['earnings'].grid.set_column_disp("default_amount", false);
frm.fields_dict['deductions'].grid.set_column_disp("default_amount", false);
@@ -93,6 +118,7 @@
fields_read_only.forEach(function(field) {
frappe.meta.get_docfield("Salary Detail", field, frm.doc.name).read_only = 1;
});
+ frm.trigger('set_earning_deduction_component');
},
assign_to_employees:function (frm) {
@@ -101,10 +127,12 @@
fields: [
{fieldname: "sec_break", fieldtype: "Section Break", label: __("Filter Employees By (Optional)")},
{fieldname: "company", fieldtype: "Link", options: "Company", label: __("Company"), default: frm.doc.company, read_only:1},
+ {fieldname: "currency", fieldtype: "Link", options: "Currency", label: __("Currency"), default: frm.doc.currency, read_only:1},
{fieldname: "grade", fieldtype: "Link", options: "Employee Grade", label: __("Employee Grade")},
{fieldname:'department', fieldtype:'Link', options: 'Department', label: __('Department')},
{fieldname:'designation', fieldtype:'Link', options: 'Designation', label: __('Designation')},
- {fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")},
+ {fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")},
+ {fieldname:"payroll_payable_account", fieldtype: "Link", options: "Account", filters: {"company": frm.doc.company, "root_type": "Liability", "is_group": 0, "account_currency": frm.doc.currency}, label: __("Payroll Payable Account")},
{fieldname:'base_variable', fieldtype:'Section Break'},
{fieldname:'from_date', fieldtype:'Date', label: __('From Date'), "reqd": 1},
{fieldname:'income_tax_slab', fieldtype:'Link', label: __('Income Tax Slab'), options: 'Income Tax Slab'},
@@ -114,6 +142,8 @@
],
primary_action: function() {
var data = d.get_values();
+ delete data.company
+ delete data.currency
frappe.call({
doc: frm.doc,
method: "assign_salary_structure",
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.json b/erpnext/payroll/doctype/salary_structure/salary_structure.json
index 5f94929..de56fc8 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.json
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.json
@@ -13,6 +13,7 @@
"column_break1",
"is_active",
"payroll_frequency",
+ "currency",
"is_default",
"time_sheet_earning_detail",
"salary_slip_based_on_timesheet",
@@ -26,9 +27,9 @@
"deductions",
"conditions_and_formula_variable_and_example",
"net_pay_detail",
- "column_break2",
"total_earning",
"total_deduction",
+ "column_break2",
"net_pay",
"account",
"mode_of_payment",
@@ -43,23 +44,17 @@
"label": "Company",
"options": "Company",
"remember_last_selected_value": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
- "options": "Letter Head",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Letter Head"
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -72,9 +67,7 @@
"oldfieldname": "is_active",
"oldfieldtype": "Select",
"options": "\nYes\nNo",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"default": "Monthly",
@@ -82,9 +75,7 @@
"fieldname": "payroll_frequency",
"fieldtype": "Select",
"label": "Payroll Frequency",
- "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily",
- "show_days": 1,
- "show_seconds": 1
+ "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily"
},
{
"default": "No",
@@ -95,62 +86,46 @@
"no_copy": 1,
"options": "Yes\nNo",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "time_sheet_earning_detail",
- "fieldtype": "Section Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Section Break"
},
{
"default": "0",
"fieldname": "salary_slip_based_on_timesheet",
"fieldtype": "Check",
- "label": "Salary Slip Based on Timesheet",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Salary Slip Based on Timesheet"
},
{
"fieldname": "column_break_17",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"description": "Salary Component for timesheet based payroll.",
"fieldname": "salary_component",
"fieldtype": "Link",
"label": "Salary Component",
- "options": "Salary Component",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Salary Component"
},
{
"fieldname": "hour_rate",
"fieldtype": "Currency",
"label": "Hour Rate",
- "options": "Company:company:default_currency",
- "show_days": 1,
- "show_seconds": 1
+ "options": "currency"
},
{
"fieldname": "leave_encashment_amount_per_day",
"fieldtype": "Currency",
"label": "Leave Encashment Amount Per Day",
- "options": "Company:company:default_currency",
- "show_days": 1,
- "show_seconds": 1
+ "options": "currency"
},
{
"fieldname": "max_benefits",
"fieldtype": "Currency",
"label": "Max Benefits (Amount)",
- "options": "Company:company:default_currency",
- "show_days": 1,
- "show_seconds": 1
+ "options": "currency"
},
{
"description": "Salary breakup based on Earning and Deduction.",
@@ -158,9 +133,7 @@
"fieldtype": "Section Break",
"oldfieldname": "earning_deduction",
"oldfieldtype": "Section Break",
- "precision": "2",
- "show_days": 1,
- "show_seconds": 1
+ "precision": "2"
},
{
"fieldname": "earnings",
@@ -168,9 +141,7 @@
"label": "Earnings",
"oldfieldname": "earning_details",
"oldfieldtype": "Table",
- "options": "Salary Detail",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Salary Detail"
},
{
"fieldname": "deductions",
@@ -178,22 +149,16 @@
"label": "Deductions",
"oldfieldname": "deduction_details",
"oldfieldtype": "Table",
- "options": "Salary Detail",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Salary Detail"
},
{
"fieldname": "net_pay_detail",
"fieldtype": "Section Break",
- "options": "Simple",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Simple"
},
{
"fieldname": "column_break2",
"fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -201,63 +166,45 @@
"fieldtype": "Currency",
"hidden": 1,
"label": "Total Earning",
- "oldfieldname": "total_earning",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "options": "currency",
+ "read_only": 1
},
{
"fieldname": "total_deduction",
"fieldtype": "Currency",
"hidden": 1,
"label": "Total Deduction",
- "oldfieldname": "total_deduction",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "options": "currency",
+ "read_only": 1
},
{
"fieldname": "net_pay",
"fieldtype": "Currency",
"hidden": 1,
"label": "Net Pay",
- "options": "Company:company:default_currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "options": "currency",
+ "read_only": 1
},
{
"fieldname": "account",
"fieldtype": "Section Break",
- "label": "Account",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Account"
},
{
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"label": "Mode of Payment",
- "options": "Mode of Payment",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Mode of Payment"
},
{
"fieldname": "column_break_28",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "payment_account",
"fieldtype": "Link",
"label": "Payment Account",
- "options": "Account",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Account"
},
{
"fieldname": "amended_from",
@@ -266,23 +213,26 @@
"no_copy": 1,
"options": "Salary Structure",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "conditions_and_formula_variable_and_example",
"fieldtype": "HTML",
- "label": "Conditions and Formula variable and example",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Conditions and Formula variable and example"
+ },
+ {
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "reqd": 1
}
],
"icon": "fa fa-file-text",
"idx": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 17:07:26.129355",
+ "modified": "2020-09-30 11:30:32.190798",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Structure",
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py
index ffc16d7..1712081 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py
@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe, erpnext
from frappe.utils import flt, cint, cstr
from frappe import _
@@ -88,24 +88,26 @@
return employees
@frappe.whitelist()
- def assign_salary_structure(self, company=None, grade=None, department=None, designation=None,employee=None,
- from_date=None, base=None, variable=None, income_tax_slab=None):
- employees = self.get_employees(company= company, grade= grade,department= department,designation= designation,name=employee)
+ def assign_salary_structure(self, grade=None, department=None, designation=None,employee=None,
+ payroll_payable_account=None, from_date=None, base=None, variable=None, income_tax_slab=None):
+ employees = self.get_employees(company= self.company, grade= grade,department= department,designation= designation,name=employee)
if employees:
if len(employees) > 20:
frappe.enqueue(assign_salary_structure_for_employees, timeout=600,
- employees=employees, salary_structure=self,from_date=from_date,
- base=base, variable=variable, income_tax_slab=income_tax_slab)
+ employees=employees, salary_structure=self,
+ payroll_payable_account=payroll_payable_account,
+ from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
else:
- assign_salary_structure_for_employees(employees, self, from_date=from_date,
- base=base, variable=variable, income_tax_slab=income_tax_slab)
+ assign_salary_structure_for_employees(employees, self,
+ payroll_payable_account=payroll_payable_account,
+ from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
else:
frappe.msgprint(_("No Employee Found"))
-def assign_salary_structure_for_employees(employees, salary_structure, from_date=None, base=None, variable=None, income_tax_slab=None):
+def assign_salary_structure_for_employees(employees, salary_structure, payroll_payable_account=None, from_date=None, base=None, variable=None, income_tax_slab=None):
salary_structures_assignments = []
existing_assignments_for = get_existing_assignments(employees, salary_structure, from_date)
count=0
@@ -115,7 +117,7 @@
count +=1
salary_structures_assignment = create_salary_structures_assignment(employee,
- salary_structure, from_date, base, variable, income_tax_slab)
+ salary_structure, payroll_payable_account, from_date, base, variable, income_tax_slab)
salary_structures_assignments.append(salary_structures_assignment)
frappe.publish_progress(count*100/len(set(employees) - set(existing_assignments_for)), title = _("Assigning Structures..."))
@@ -123,11 +125,22 @@
frappe.msgprint(_("Structures have been assigned successfully"))
-def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable, income_tax_slab=None):
+def create_salary_structures_assignment(employee, salary_structure, payroll_payable_account, from_date, base, variable, income_tax_slab=None):
+ if not payroll_payable_account:
+ payroll_payable_account = frappe.db.get_value('Company', salary_structure.company, 'default_payroll_payable_account')
+ if not payroll_payable_account:
+ frappe.throw(_('Please set "Default Payroll Payable Account" in Company Defaults'))
+ payroll_payable_account_currency = frappe.db.get_value('Account', payroll_payable_account, 'account_currency')
+ company_curency = erpnext.get_company_currency(salary_structure.company)
+ if payroll_payable_account_currency != salary_structure.currency and payroll_payable_account_currency != company_curency:
+ frappe.throw(_("Invalid Payroll Payable Account. The account currency must be {0} or {1}").format(salary_structure.currency, company_curency))
+
assignment = frappe.new_doc("Salary Structure Assignment")
assignment.employee = employee
assignment.salary_structure = salary_structure.name
assignment.company = salary_structure.company
+ assignment.currency = salary_structure.currency
+ assignment.payroll_payable_account = payroll_payable_account
assignment.from_date = from_date
assignment.base = base
assignment.variable = variable
@@ -170,7 +183,8 @@
"doctype": "Salary Slip",
"field_map": {
"total_earning": "gross_pay",
- "name": "salary_structure"
+ "name": "salary_structure",
+ "currency": "currency"
}
}
}, target_doc, postprocess, ignore_child_tables=True, ignore_permissions=ignore_permissions)
@@ -188,7 +202,8 @@
filters={'salary_structure': salary_structure, 'docstatus': 1}, fields=['employee'])
if not employees:
- frappe.throw(_("There's no Employee with Salary Structure: {0}. \
- Assign {1} to an Employee to preview Salary Slip").format(salary_structure, salary_structure))
+ frappe.throw(_("There's no Employee with Salary Structure: {0}. Assign {1} to an Employee to preview Salary Slip").format(
+ salary_structure, salary_structure))
return list(set([d.employee for d in employees]))
+
diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
index e04fda8..f2fb558 100644
--- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
@@ -94,7 +94,8 @@
self.assertFalse(("\n" in row.formula) or ("\n" in row.condition))
def test_salary_structures_assignment(self):
- salary_structure = make_salary_structure("Salary Structure Sample", "Monthly")
+ company_currency = erpnext.get_default_currency()
+ salary_structure = make_salary_structure("Salary Structure Sample", "Monthly", currency=company_currency)
employee = "test_assign_stucture@salary.com"
employee_doc_name = make_employee(employee)
# clear the already assigned stuctures
@@ -107,8 +108,13 @@
self.assertEqual(salary_structure_assignment.base, 5000)
self.assertEqual(salary_structure_assignment.variable, 200)
+ def test_multi_currency_salary_structure(self):
+ make_employee("test_muti_currency_employee@salary.com")
+ sal_struct = make_salary_structure("Salary Structure Multi Currency", "Monthly", currency='USD')
+ self.assertEqual(sal_struct.currency, 'USD')
+
def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None,
- test_tax=False, company=None):
+ test_tax=False, company=None, currency=erpnext.get_default_currency(), payroll_period=None):
if test_tax:
frappe.db.sql("""delete from `tabSalary Structure` where name=%s""",(salary_structure))
@@ -120,7 +126,8 @@
"earnings": make_earning_salary_component(test_tax=test_tax, company_list=["_Test Company"]),
"deductions": make_deduction_salary_component(test_tax=test_tax, company_list=["_Test Company"]),
"payroll_frequency": payroll_frequency,
- "payment_account": get_random("Account")
+ "payment_account": get_random("Account", filters={'account_currency': currency}),
+ "currency": currency
}
if other_details and isinstance(other_details, dict):
details.update(other_details)
@@ -134,16 +141,24 @@
if employee and not frappe.db.get_value("Salary Structure Assignment",
{'employee':employee, 'docstatus': 1}) and salary_structure_doc.docstatus==1:
- create_salary_structure_assignment(employee, salary_structure, company=company)
+ create_salary_structure_assignment(employee, salary_structure, company=company, currency=currency,
+ payroll_period=payroll_period)
return salary_structure_doc
-def create_salary_structure_assignment(employee, salary_structure, from_date=None, company=None):
+def create_salary_structure_assignment(employee, salary_structure, from_date=None, company=None, currency=erpnext.get_default_currency(),
+ payroll_period=None):
+
if frappe.db.exists("Salary Structure Assignment", {"employee": employee}):
frappe.db.sql("""delete from `tabSalary Structure Assignment` where employee=%s""",(employee))
- payroll_period = create_payroll_period()
- create_tax_slab(payroll_period, allow_tax_exemption=True)
+ if not payroll_period:
+ payroll_period = create_payroll_period()
+
+ income_tax_slab = frappe.db.get_value("Income Tax Slab", {"currency": currency})
+
+ if not income_tax_slab:
+ income_tax_slab = create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency)
salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
salary_structure_assignment.employee = employee
@@ -151,8 +166,15 @@
salary_structure_assignment.variable = 5000
salary_structure_assignment.from_date = from_date or add_days(nowdate(), -1)
salary_structure_assignment.salary_structure = salary_structure
+ salary_structure_assignment.currency = currency
+ salary_structure_assignment.payroll_payable_account = get_payable_account(company)
salary_structure_assignment.company = company or erpnext.get_default_company()
salary_structure_assignment.save(ignore_permissions=True)
- salary_structure_assignment.income_tax_slab = "Tax Slab: _Test Payroll Period"
+ salary_structure_assignment.income_tax_slab = income_tax_slab
salary_structure_assignment.submit()
return salary_structure_assignment
+
+def get_payable_account(company=None):
+ if not company:
+ company = erpnext.get_default_company()
+ return frappe.db.get_value("Company", company, "default_payroll_payable_account")
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js
index 818e853..6cd897e 100644
--- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js
+++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js
@@ -6,9 +6,6 @@
frm.set_query("employee", function() {
return {
query: "erpnext.controllers.queries.employee_query",
- filters: {
- company: frm.doc.company
- }
}
});
frm.set_query("salary_structure", function() {
@@ -26,11 +23,25 @@
filters: {
company: frm.doc.company,
docstatus: 1,
- disabled: 0
+ disabled: 0,
+ currency: frm.doc.currency
+ }
+ };
+ });
+
+ frm.set_query("payroll_payable_account", function() {
+ var company_currency = erpnext.get_currency(frm.doc.company);
+ return {
+ filters: {
+ "company": frm.doc.company,
+ "root_type": "Liability",
+ "is_group": 0,
+ "account_currency": ["in", [frm.doc.currency, company_currency]],
}
}
});
},
+
employee: function(frm) {
if(frm.doc.employee){
frappe.call({
@@ -52,5 +63,13 @@
else{
frm.set_value("company", null);
}
+ },
+
+ company: function(frm) {
+ if (frm.doc.company) {
+ frappe.db.get_value("Company", frm.doc.company, "default_payroll_payable_account", (r) => {
+ frm.set_value("payroll_payable_account", r.default_payroll_payable_account);
+ });
+ }
}
});
diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json
index c84e034..92bb347 100644
--- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json
+++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json
@@ -11,11 +11,13 @@
"employee_name",
"department",
"company",
+ "payroll_payable_account",
"column_break_6",
"designation",
"salary_structure",
"from_date",
"income_tax_slab",
+ "currency",
"section_break_7",
"base",
"column_break_9",
@@ -94,7 +96,7 @@
"fieldname": "base",
"fieldtype": "Currency",
"label": "Base",
- "options": "Company:company:default_currency"
+ "options": "currency"
},
{
"fieldname": "column_break_9",
@@ -104,7 +106,7 @@
"fieldname": "variable",
"fieldtype": "Currency",
"label": "Variable",
- "options": "Company:company:default_currency"
+ "options": "currency"
},
{
"fieldname": "amended_from",
@@ -116,15 +118,35 @@
"read_only": 1
},
{
+ "depends_on": "salary_structure",
"fieldname": "income_tax_slab",
"fieldtype": "Link",
"label": "Income Tax Slab",
"options": "Income Tax Slab"
+ },
+ {
+ "default": "Company:company:default_currency",
+ "depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
+ "fetch_from": "salary_structure.currency",
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "depends_on": "employee",
+ "fieldname": "payroll_payable_account",
+ "fieldtype": "Link",
+ "label": "Payroll Payable Account",
+ "options": "Account"
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-22 19:58:09.964692",
+ "modified": "2020-11-30 18:07:48.251311",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Structure Assignment",
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 668e0ec..a0c3013 100644
--- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
+++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
@@ -13,6 +13,8 @@
class SalaryStructureAssignment(Document):
def validate(self):
self.validate_dates()
+ self.validate_income_tax_slab()
+ self.set_payroll_payable_account()
def validate_dates(self):
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
@@ -31,6 +33,24 @@
frappe.throw(_("From Date {0} cannot be after employee's relieving Date {1}")
.format(self.from_date, relieving_date))
+ def validate_income_tax_slab(self):
+ if not self.income_tax_slab:
+ return
+
+ income_tax_slab_currency = frappe.db.get_value('Income Tax Slab', self.income_tax_slab, 'currency')
+ if self.currency != income_tax_slab_currency:
+ frappe.throw(_("Currency of selected Income Tax Slab should be {0} instead of {1}").format(self.currency, income_tax_slab_currency))
+
+ def set_payroll_payable_account(self):
+ if not self.payroll_payable_account:
+ payroll_payable_account = frappe.db.get_value('Company', self.company, 'default_payroll_payable_account')
+ if not payroll_payable_account:
+ payroll_payable_account = frappe.db.get_value(
+ "Account", {
+ "account_name": _("Payroll Payable"), "company": self.company, "account_currency": frappe.db.get_value(
+ "Company", self.company, "default_currency"), "is_group": 0})
+ self.payroll_payable_account = payroll_payable_account
+
def get_assigned_salary_structure(employee, on_date):
if not employee or not on_date:
return None
@@ -43,3 +63,10 @@
'on_date': on_date,
})
return salary_structure[0][0] if salary_structure else None
+
+@frappe.whitelist()
+def get_employee_currency(employee):
+ employee_currency = frappe.db.get_value('Salary Structure Assignment', {'employee': employee}, 'currency')
+ if not employee_currency:
+ frappe.throw(_("There is no Salary Structure assigned to {0}. First assign a Salary Stucture.").format(employee))
+ return employee_currency
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.json b/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.json
index 94eda4c..65d3824 100644
--- a/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.json
+++ b/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.json
@@ -19,13 +19,15 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "From Amount",
+ "options": "currency",
"reqd": 1
},
{
"fieldname": "to_amount",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "To Amount"
+ "label": "To Amount",
+ "options": "currency"
},
{
"default": "0",
@@ -53,7 +55,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-06-22 18:16:07.596493",
+ "modified": "2020-10-19 13:44:39.549337",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Taxable Salary Slab",
diff --git a/erpnext/config/__init__.py b/erpnext/payroll/print_format/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/payroll/print_format/__init__.py
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/payroll/print_format/salary_slip_with_year_to_date/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/payroll/print_format/salary_slip_with_year_to_date/__init__.py
diff --git a/erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json b/erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json
new file mode 100644
index 0000000..71ba37f
--- /dev/null
+++ b/erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json
@@ -0,0 +1,25 @@
+{
+ "absolute_value": 0,
+ "align_labels_right": 0,
+ "creation": "2021-01-14 09:56:42.393623",
+ "custom_format": 0,
+ "default_print_language": "en",
+ "disabled": 0,
+ "doc_type": "Salary Slip",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \" <h3 style=\\\"text-align: right;\\\"><span style=\\\"line-height: 1.42857;\\\">{{doc.name}}</span></h3>\\n<div>\\n <hr style=\\\"text-align: center;\\\">\\n</div> \"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"employee\", \"print_hide\": 0, \"label\": \"Employee\"}, {\"fieldname\": \"company\", \"print_hide\": 0, \"label\": \"Company\"}, {\"fieldname\": \"employee_name\", \"print_hide\": 0, \"label\": \"Employee Name\"}, {\"fieldname\": \"department\", \"print_hide\": 0, \"label\": \"Department\"}, {\"fieldname\": \"designation\", \"print_hide\": 0, \"label\": \"Designation\"}, {\"fieldname\": \"branch\", \"print_hide\": 0, \"label\": \"Branch\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"start_date\", \"print_hide\": 0, \"label\": \"Start Date\"}, {\"fieldname\": \"end_date\", \"print_hide\": 0, \"label\": \"End Date\"}, {\"fieldname\": \"total_working_days\", \"print_hide\": 0, \"label\": \"Working Days\"}, {\"fieldname\": \"leave_without_pay\", \"print_hide\": 0, \"label\": \"Leave Without Pay\"}, {\"fieldname\": \"payment_days\", \"print_hide\": 0, \"label\": \"Payment Days\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"earnings\", \"print_hide\": 0, \"label\": \"Earnings\", \"visible_columns\": [{\"fieldname\": \"salary_component\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"amount\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"year_to_date\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"deductions\", \"print_hide\": 0, \"label\": \"Deductions\", \"visible_columns\": [{\"fieldname\": \"salary_component\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"amount\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"year_to_date\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"depends_on_payment_days\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"gross_pay\", \"print_hide\": 0, \"label\": \"Gross Pay\"}, {\"fieldname\": \"total_deduction\", \"print_hide\": 0, \"label\": \"Total Deduction\"}, {\"fieldname\": \"net_pay\", \"print_hide\": 0, \"label\": \"Net Pay\"}, {\"fieldname\": \"rounded_total\", \"print_hide\": 0, \"label\": \"Rounded Total\"}, {\"fieldname\": \"total_in_words\", \"print_hide\": 0, \"label\": \"Total in words\"}, {\"fieldtype\": \"Section Break\", \"label\": \"net pay info\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"year_to_date\", \"print_hide\": 0, \"label\": \"Year To Date\"}, {\"fieldname\": \"month_to_date\", \"print_hide\": 0, \"label\": \"Month To Date\"}]",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2021-01-14 10:03:45.283725",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Salary Slip with Year to Date",
+ "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/payroll/report/bank_remittance/bank_remittance.py b/erpnext/payroll/report/bank_remittance/bank_remittance.py
index 4b052bf..500543c 100644
--- a/erpnext/payroll/report/bank_remittance/bank_remittance.py
+++ b/erpnext/payroll/report/bank_remittance/bank_remittance.py
@@ -47,33 +47,39 @@
"fieldtype": "Int",
"fieldname": "employee_account_no",
"width": 50
- },
- {
+ }
+ ]
+
+ if frappe.db.has_column('Employee', 'ifsc_code'):
+ columns.append({
"label": _("IFSC Code"),
"fieldtype": "Data",
"fieldname": "bank_code",
"width": 100
- },
- {
- "label": _("Currency"),
- "fieldtype": "Data",
- "fieldname": "currency",
- "width": 50
- },
- {
- "label": _("Net Salary Amount"),
- "fieldtype": "Currency",
- "options": "currency",
- "fieldname": "amount",
- "width": 100
- }
- ]
+ })
+
+ columns += [{
+ "label": _("Currency"),
+ "fieldtype": "Data",
+ "fieldname": "currency",
+ "width": 50
+ },
+ {
+ "label": _("Net Salary Amount"),
+ "fieldtype": "Currency",
+ "options": "currency",
+ "fieldname": "amount",
+ "width": 100
+ }]
+
data = []
accounts = get_bank_accounts()
payroll_entries = get_payroll_entries(accounts, filters)
salary_slips = get_salary_slips(payroll_entries)
- get_emp_bank_ifsc_code(salary_slips)
+
+ if frappe.db.has_column('Employee', 'ifsc_code'):
+ get_emp_bank_ifsc_code(salary_slips)
for salary in salary_slips:
if salary.bank_name and salary.bank_account_no and salary.debit_acc_no and salary.status in ["Submitted", "Paid"]:
diff --git a/erpnext/payroll/report/salary_register/salary_register.js b/erpnext/payroll/report/salary_register/salary_register.js
index 885e3d1..eb4acb9 100644
--- a/erpnext/payroll/report/salary_register/salary_register.js
+++ b/erpnext/payroll/report/salary_register/salary_register.js
@@ -8,34 +8,48 @@
"label": __("From"),
"fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.get_today(),-1),
- "reqd": 1
+ "reqd": 1,
+ "width": "100px"
},
{
"fieldname":"to_date",
"label": __("To"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
- "reqd": 1
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "options": "Currency",
+ "label": __("Currency"),
+ "default": erpnext.get_currency(frappe.defaults.get_default("Company")),
+ "width": "50px"
},
{
"fieldname":"employee",
"label": __("Employee"),
"fieldtype": "Link",
- "options": "Employee"
+ "options": "Employee",
+ "width": "100px"
},
{
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
- "default": frappe.defaults.get_user_default("Company")
+ "default": frappe.defaults.get_user_default("Company"),
+ "width": "100px",
+ "reqd": 1
},
{
"fieldname":"docstatus",
"label":__("Document Status"),
"fieldtype":"Select",
"options":["Draft", "Submitted", "Cancelled"],
- "default":"Submitted"
+ "default": "Submitted",
+ "width": "100px"
}
]
}
diff --git a/erpnext/payroll/report/salary_register/salary_register.py b/erpnext/payroll/report/salary_register/salary_register.py
index 8701085..a1b1a8c 100644
--- a/erpnext/payroll/report/salary_register/salary_register.py
+++ b/erpnext/payroll/report/salary_register/salary_register.py
@@ -2,18 +2,22 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe, erpnext
from frappe.utils import flt
from frappe import _
def execute(filters=None):
if not filters: filters = {}
- salary_slips = get_salary_slips(filters)
+ currency = None
+ if filters.get('currency'):
+ currency = filters.get('currency')
+ company_currency = erpnext.get_company_currency(filters.get("company"))
+ salary_slips = get_salary_slips(filters, company_currency)
if not salary_slips: return [], []
columns, earning_types, ded_types = get_columns(salary_slips)
- ss_earning_map = get_ss_earning_map(salary_slips)
- ss_ded_map = get_ss_ded_map(salary_slips)
+ ss_earning_map = get_ss_earning_map(salary_slips, currency, company_currency)
+ ss_ded_map = get_ss_ded_map(salary_slips,currency, company_currency)
doj_map = get_employee_doj_map()
data = []
@@ -21,24 +25,30 @@
row = [ss.name, ss.employee, ss.employee_name, doj_map.get(ss.employee), ss.branch, ss.department, ss.designation,
ss.company, ss.start_date, ss.end_date, ss.leave_without_pay, ss.payment_days]
- if not ss.branch == None:columns[3] = columns[3].replace('-1','120')
- if not ss.department == None: columns[4] = columns[4].replace('-1','120')
- if not ss.designation == None: columns[5] = columns[5].replace('-1','120')
- if not ss.leave_without_pay == None: columns[9] = columns[9].replace('-1','130')
+ if ss.branch is not None: columns[3] = columns[3].replace('-1','120')
+ if ss.department is not None: columns[4] = columns[4].replace('-1','120')
+ if ss.designation is not None: columns[5] = columns[5].replace('-1','120')
+ if ss.leave_without_pay is not None: columns[9] = columns[9].replace('-1','130')
for e in earning_types:
row.append(ss_earning_map.get(ss.name, {}).get(e))
- row += [ss.gross_pay]
+ if currency == company_currency:
+ row += [flt(ss.gross_pay) * flt(ss.exchange_rate)]
+ else:
+ row += [ss.gross_pay]
for d in ded_types:
row.append(ss_ded_map.get(ss.name, {}).get(d))
row.append(ss.total_loan_repayment)
- row += [ss.total_deduction, ss.net_pay]
-
+ if currency == company_currency:
+ row += [flt(ss.total_deduction) * flt(ss.exchange_rate), flt(ss.net_pay) * flt(ss.exchange_rate)]
+ else:
+ row += [ss.total_deduction, ss.net_pay]
+ row.append(currency or company_currency)
data.append(row)
return columns, data
@@ -46,10 +56,19 @@
def get_columns(salary_slips):
"""
columns = [
- _("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140",
- _("Date of Joining") + "::80", _("Branch") + ":Link/Branch:120", _("Department") + ":Link/Department:120",
- _("Designation") + ":Link/Designation:120", _("Company") + ":Link/Company:120", _("Start Date") + "::80",
- _("End Date") + "::80", _("Leave Without Pay") + ":Float:130", _("Payment Days") + ":Float:120"
+ _("Salary Slip ID") + ":Link/Salary Slip:150",
+ _("Employee") + ":Link/Employee:120",
+ _("Employee Name") + "::140",
+ _("Date of Joining") + "::80",
+ _("Branch") + ":Link/Branch:120",
+ _("Department") + ":Link/Department:120",
+ _("Designation") + ":Link/Designation:120",
+ _("Company") + ":Link/Company:120",
+ _("Start Date") + "::80",
+ _("End Date") + "::80",
+ _("Leave Without Pay") + ":Float:130",
+ _("Payment Days") + ":Float:120",
+ _("Currency") + ":Link/Currency:80"
]
"""
columns = [
@@ -73,15 +92,15 @@
return columns, salary_components[_("Earning")], salary_components[_("Deduction")]
-def get_salary_slips(filters):
+def get_salary_slips(filters, company_currency):
filters.update({"from_date": filters.get("from_date"), "to_date":filters.get("to_date")})
- conditions, filters = get_conditions(filters)
+ conditions, filters = get_conditions(filters, company_currency)
salary_slips = frappe.db.sql("""select * from `tabSalary Slip` where %s
order by employee""" % conditions, filters, as_dict=1)
return salary_slips or []
-def get_conditions(filters):
+def get_conditions(filters, company_currency):
conditions = ""
doc_status = {"Draft": 0, "Submitted": 1, "Cancelled": 2}
@@ -92,6 +111,8 @@
if filters.get("to_date"): conditions += " and end_date <= %(to_date)s"
if filters.get("company"): conditions += " and company = %(company)s"
if filters.get("employee"): conditions += " and employee = %(employee)s"
+ if filters.get("currency") and filters.get("currency") != company_currency:
+ conditions += " and currency = %(currency)s"
return conditions, filters
@@ -103,26 +124,32 @@
FROM `tabEmployee`
"""))
-def get_ss_earning_map(salary_slips):
- ss_earnings = frappe.db.sql("""select parent, salary_component, amount
- from `tabSalary Detail` where parent in (%s)""" %
+def get_ss_earning_map(salary_slips, currency, company_currency):
+ ss_earnings = frappe.db.sql("""select sd.parent, sd.salary_component, sd.amount, ss.exchange_rate, ss.name
+ from `tabSalary Detail` sd, `tabSalary Slip` ss where sd.parent=ss.name and sd.parent in (%s)""" %
(', '.join(['%s']*len(salary_slips))), tuple([d.name for d in salary_slips]), as_dict=1)
ss_earning_map = {}
for d in ss_earnings:
ss_earning_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, [])
- ss_earning_map[d.parent][d.salary_component] = flt(d.amount)
+ 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)
+ else:
+ ss_earning_map[d.parent][d.salary_component] = flt(d.amount)
return ss_earning_map
-def get_ss_ded_map(salary_slips):
- ss_deductions = frappe.db.sql("""select parent, salary_component, amount
- from `tabSalary Detail` where parent in (%s)""" %
+def get_ss_ded_map(salary_slips, currency, company_currency):
+ ss_deductions = frappe.db.sql("""select sd.parent, sd.salary_component, sd.amount, ss.exchange_rate, ss.name
+ from `tabSalary Detail` sd, `tabSalary Slip` ss where sd.parent=ss.name and sd.parent in (%s)""" %
(', '.join(['%s']*len(salary_slips))), tuple([d.name for d in salary_slips]), as_dict=1)
ss_ded_map = {}
for d in ss_deductions:
ss_ded_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, [])
- ss_ded_map[d.parent][d.salary_component] = flt(d.amount)
+ 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)
+ else:
+ 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
new file mode 100644
index 0000000..8149730
--- /dev/null
+++ b/erpnext/payroll/workspace/payroll/payroll.json
@@ -0,0 +1,333 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Outgoing Salary",
+ "label": "Outgoing Salary"
+ }
+ ],
+ "creation": "2020-05-27 19:54:23.405607",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "money-coins-1",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Payroll",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payroll",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Salary Component",
+ "link_to": "Salary Component",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Salary Structure",
+ "link_to": "Salary Structure",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Salary Structure Assignment",
+ "link_to": "Salary Structure Assignment",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payroll Entry",
+ "link_to": "Payroll Entry",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Salary Slip",
+ "link_to": "Salary Slip",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Taxation",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Payroll Period",
+ "link_to": "Payroll Period",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Income Tax Slab",
+ "link_to": "Income Tax Slab",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Other Income",
+ "link_to": "Employee Other Income",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Declaration",
+ "link_to": "Employee Tax Exemption Declaration",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Proof Submission",
+ "link_to": "Employee Tax Exemption Proof Submission",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Category",
+ "link_to": "Employee Tax Exemption Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Tax Exemption Sub Category",
+ "link_to": "Employee Tax Exemption Sub Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Compensations",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Additional Salary",
+ "link_to": "Additional Salary",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Retention Bonus",
+ "link_to": "Retention Bonus",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Incentive",
+ "link_to": "Employee Incentive",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Benefit Application",
+ "link_to": "Employee Benefit Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Benefit Claim",
+ "link_to": "Employee Benefit Claim",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Salary Slip",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Salary Register",
+ "link_to": "Salary Register",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Salary Slip",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Salary Payments Based On Payment Mode",
+ "link_to": "Salary Payments Based On Payment Mode",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Salary Slip",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Salary Payments via ECS",
+ "link_to": "Salary Payments via ECS",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Salary Slip",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Income Tax Deductions",
+ "link_to": "Income Tax Deductions",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Salary Slip",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Professional Tax Deductions",
+ "link_to": "Professional Tax Deductions",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Salary Slip",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Provident Fund Deductions",
+ "link_to": "Provident Fund Deductions",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Payroll Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Bank Remittance",
+ "link_to": "Bank Remittance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:37.205628",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Payroll",
+ "onboarding": "Payroll",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "label": "Salary Structure",
+ "link_to": "Salary Structure",
+ "type": "DocType"
+ },
+ {
+ "label": "Payroll Entry",
+ "link_to": "Payroll Entry",
+ "type": "DocType"
+ },
+ {
+ "color": "",
+ "format": "{} Pending",
+ "label": "Salary Slip",
+ "link_to": "Salary Slip",
+ "stats_filter": "{\"status\": \"Draft\"}",
+ "type": "DocType"
+ },
+ {
+ "label": "Income Tax Slab",
+ "link_to": "Income Tax Slab",
+ "type": "DocType"
+ },
+ {
+ "label": "Salary Register",
+ "link_to": "Salary Register",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Payroll",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/products_settings/products_settings.py b/erpnext/portal/doctype/products_settings/products_settings.py
index ae7dc68..9a70892 100644
--- a/erpnext/portal/doctype/products_settings/products_settings.py
+++ b/erpnext/portal/doctype/products_settings/products_settings.py
@@ -17,6 +17,7 @@
self.validate_field_filters()
self.validate_attribute_filters()
+ frappe.clear_document_cache("Product Settings", "Product Settings")
def validate_field_filters(self):
if not (self.enable_field_filters and self.filter_fields): return
diff --git a/erpnext/portal/product_configurator/test_product_configurator.py b/erpnext/portal/product_configurator/test_product_configurator.py
index 97042db..3521e7e 100644
--- a/erpnext/portal/product_configurator/test_product_configurator.py
+++ b/erpnext/portal/product_configurator/test_product_configurator.py
@@ -10,8 +10,38 @@
test_dependencies = ["Item"]
class TestProductConfigurator(unittest.TestCase):
- def setUp(self):
- self.create_variant_item()
+ @classmethod
+ def setUpClass(cls):
+ cls.create_variant_item()
+
+ @classmethod
+ def create_variant_item(cls):
+ if not frappe.db.exists('Item', '_Test Variant Item - 2XL'):
+ frappe.get_doc({
+ "description": "_Test Variant Item - 2XL",
+ "item_code": "_Test Variant Item - 2XL",
+ "item_name": "_Test Variant Item - 2XL",
+ "doctype": "Item",
+ "is_stock_item": 1,
+ "variant_of": "_Test Variant Item",
+ "item_group": "_Test Item Group",
+ "stock_uom": "_Test UOM",
+ "item_defaults": [{
+ "company": "_Test Company",
+ "default_warehouse": "_Test Warehouse - _TC",
+ "expense_account": "_Test Account Cost for Goods Sold - _TC",
+ "buying_cost_center": "_Test Cost Center - _TC",
+ "selling_cost_center": "_Test Cost Center - _TC",
+ "income_account": "Sales - _TC"
+ }],
+ "attributes": [
+ {
+ "attribute": "Test Size",
+ "attribute_value": "2XL"
+ }
+ ],
+ "show_variant_in_website": 1
+ }).insert()
def test_product_list(self):
template_items = frappe.get_all('Item', {'show_in_website': 1})
@@ -46,39 +76,6 @@
def test_get_products_for_website(self):
items = get_products_for_website(attribute_filters={
- 'Test Size': ['Medium']
+ 'Test Size': ['2XL']
})
self.assertEqual(len(items), 1)
-
-
- def create_variant_item(self):
- if not frappe.db.exists('Item', '_Test Variant Item 1'):
- frappe.get_doc({
- "description": "_Test Variant Item 12",
- "doctype": "Item",
- "is_stock_item": 1,
- "variant_of": "_Test Variant Item",
- "item_code": "_Test Variant Item 1",
- "item_group": "_Test Item Group",
- "item_name": "_Test Variant Item 1",
- "stock_uom": "_Test UOM",
- "item_defaults": [{
- "company": "_Test Company",
- "default_warehouse": "_Test Warehouse - _TC",
- "expense_account": "_Test Account Cost for Goods Sold - _TC",
- "buying_cost_center": "_Test Cost Center - _TC",
- "selling_cost_center": "_Test Cost Center - _TC",
- "income_account": "Sales - _TC"
- }],
- "attributes": [
- {
- "attribute": "Test Size",
- "attribute_value": "Medium"
- }
- ],
- "show_variant_in_website": 1
- }).insert()
-
-
- def tearDown(self):
- frappe.db.rollback()
\ No newline at end of file
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index 9ba4cdc..d77eb2c 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -1,6 +1,7 @@
import frappe
from frappe.utils import cint
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
+from erpnext.shopping_cart.product_info import get_product_info_for_website
def get_field_filter_data():
product_settings = get_product_settings()
@@ -297,7 +298,7 @@
def get_items(filters=None, search=None):
- start = frappe.form_dict.start or 0
+ start = frappe.form_dict.get('start', 0)
products_settings = get_product_settings()
page_length = products_settings.products_per_page
@@ -356,10 +357,10 @@
results = frappe.db.sql('''
SELECT
- `tabItem`.`name`, `tabItem`.`item_name`,
+ `tabItem`.`name`, `tabItem`.`item_name`, `tabItem`.`item_code`,
`tabItem`.`website_image`, `tabItem`.`image`,
`tabItem`.`web_long_description`, `tabItem`.`description`,
- `tabItem`.`route`
+ `tabItem`.`route`, `tabItem`.`item_group`
FROM
`tabItem`
{left_join}
@@ -384,6 +385,9 @@
for r in results:
r.description = r.web_long_description or r.description
r.image = r.website_image or r.image
+ product_info = get_product_info_for_website(r.item_code, skip_quotation_creation=True).get('product_info')
+ if product_info:
+ r.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
return results
diff --git a/erpnext/projects/desk_page/projects/projects.json b/erpnext/projects/desk_page/projects/projects.json
deleted file mode 100644
index e24cf30..0000000
--- a/erpnext/projects/desk_page/projects/projects.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Projects",
- "links": "[\n {\n \"description\": \"Project master.\",\n \"label\": \"Project\",\n \"name\": \"Project\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Project activity / task.\",\n \"label\": \"Task\",\n \"name\": \"Task\",\n \"onboard\": 1,\n \"route\": \"#List/Task\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Make project from a template.\",\n \"label\": \"Project Template\",\n \"name\": \"Project Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Define Project type.\",\n \"label\": \"Project Type\",\n \"name\": \"Project Type\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Project\"\n ],\n \"description\": \"Project Update.\",\n \"label\": \"Project Update\",\n \"name\": \"Project Update\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Time Tracking",
- "links": "[\n {\n \"description\": \"Timesheet for tasks.\",\n \"label\": \"Timesheet\",\n \"name\": \"Timesheet\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Types of activities for Time Logs\",\n \"label\": \"Activity Type\",\n \"name\": \"Activity Type\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Activity Type\"\n ],\n \"description\": \"Cost of various activities\",\n \"label\": \"Activity Cost\",\n \"name\": \"Activity Cost\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Timesheet\"\n ],\n \"doctype\": \"Timesheet\",\n \"is_query_report\": true,\n \"label\": \"Daily Timesheet Summary\",\n \"name\": \"Daily Timesheet Summary\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Project\"\n ],\n \"doctype\": \"Project\",\n \"is_query_report\": true,\n \"label\": \"Project wise Stock Tracking\",\n \"name\": \"Project wise Stock Tracking\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Project\"\n ],\n \"doctype\": \"Project\",\n \"is_query_report\": true,\n \"label\": \"Project Billing Summary\",\n \"name\": \"Project Billing Summary\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Project Summary",
- "label": "Open Projects"
- }
- ],
- "creation": "2020-03-02 15:46:04.874669",
- "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": "Projects",
- "modified": "2020-05-28 13:38:19.934937",
- "modified_by": "Administrator",
- "module": "Projects",
- "name": "Projects",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Assigned",
- "label": "Task",
- "link_to": "Task",
- "stats_filter": "{\n \"_assign\": [\"like\", '%' + frappe.session.user + '%'],\n \"status\": \"Open\"\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Open",
- "label": "Project",
- "link_to": "Project",
- "stats_filter": "{\n \"status\": \"Open\"\n}",
- "type": "DocType"
- },
- {
- "label": "Timesheet",
- "link_to": "Timesheet",
- "type": "DocType"
- },
- {
- "label": "Project Billing Summary",
- "link_to": "Project Billing Summary",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Project",
- "type": "Dashboard"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 3570a0f..077011a 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -75,24 +75,27 @@
frm.add_custom_button(__('Cancelled'), () => {
frm.events.set_status(frm, 'Cancelled');
}, __('Set Status'));
- }
- if (frappe.model.can_read("Task")) {
- frm.add_custom_button(__("Gantt Chart"), function () {
- frappe.route_options = {
- "project": frm.doc.name
- };
- frappe.set_route("List", "Task", "Gantt");
- });
- frm.add_custom_button(__("Kanban Board"), () => {
- frappe.call('erpnext.projects.doctype.project.project.create_kanban_board_if_not_exists', {
- project: frm.doc.project_name
- }).then(() => {
- frappe.set_route('List', 'Task', 'Kanban', frm.doc.project_name);
+ if (frappe.model.can_read("Task")) {
+ frm.add_custom_button(__("Gantt Chart"), function () {
+ frappe.route_options = {
+ "project": frm.doc.name
+ };
+ frappe.set_route("List", "Task", "Gantt");
});
- });
+
+ frm.add_custom_button(__("Kanban Board"), () => {
+ frappe.call('erpnext.projects.doctype.project.project.create_kanban_board_if_not_exists', {
+ project: frm.doc.project_name
+ }).then(() => {
+ frappe.set_route('List', 'Task', 'Kanban', frm.doc.project_name);
+ });
+ });
+ }
}
+
+
},
create_duplicate: function(frm) {
@@ -135,4 +138,4 @@
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
-}
\ No newline at end of file
+}
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index f3cecd9..3cdfcb2 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -2,12 +2,13 @@
"actions": [],
"allow_import": 1,
"allow_rename": 1,
- "autoname": "field:project_name",
+ "autoname": "naming_series:",
"creation": "2013-03-07 11:55:07",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
+ "naming_series",
"project_name",
"status",
"project_type",
@@ -440,13 +441,24 @@
"fieldtype": "Text",
"label": "Message",
"mandatory_depends_on": "collect_progress"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "PROJ-.####",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
}
],
"icon": "fa fa-puzzle-piece",
"idx": 29,
+ "index_web_pages_for_search": 1,
"links": [],
"max_attachments": 4,
- "modified": "2020-04-08 22:11:14.552615",
+ "modified": "2020-09-02 11:54:01.223620",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project",
@@ -488,5 +500,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"timeline_field": "customer",
+ "title_field": "project_name",
"track_seen": 1
}
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 5bbd29c..f9e1359 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -13,6 +13,7 @@
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_users_email
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
from frappe.model.document import Document
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
class Project(Document):
def get_feed(self):
@@ -26,7 +27,7 @@
self.update_costing()
- def before_print(self):
+ def before_print(self, settings=None):
self.onload()
@@ -54,17 +55,70 @@
self.project_type = template.project_type
# create tasks from template
+ project_tasks = []
+ tmp_task_details = []
for task in template.tasks:
- frappe.get_doc(dict(
- doctype = 'Task',
- subject = task.subject,
- project = self.name,
- status = 'Open',
- exp_start_date = add_days(self.expected_start_date, task.start),
- exp_end_date = add_days(self.expected_start_date, task.start + task.duration),
- description = task.description,
- task_weight = task.task_weight
- )).insert()
+ template_task_details = frappe.get_doc("Task", task.task)
+ tmp_task_details.append(template_task_details)
+ task = self.create_task_from_template(template_task_details)
+ project_tasks.append(task)
+ self.dependency_mapping(tmp_task_details, project_tasks)
+
+ def create_task_from_template(self, task_details):
+ return frappe.get_doc(dict(
+ doctype = 'Task',
+ subject = task_details.subject,
+ project = self.name,
+ status = 'Open',
+ exp_start_date = self.calculate_start_date(task_details),
+ exp_end_date = self.calculate_end_date(task_details),
+ description = task_details.description,
+ task_weight = task_details.task_weight,
+ type = task_details.type,
+ issue = task_details.issue,
+ is_group = task_details.is_group
+ )).insert()
+
+ def calculate_start_date(self, task_details):
+ self.start_date = add_days(self.expected_start_date, task_details.start)
+ self.start_date = self.update_if_holiday(self.start_date)
+ return self.start_date
+
+ def calculate_end_date(self, task_details):
+ self.end_date = add_days(self.start_date, task_details.duration)
+ return self.update_if_holiday(self.end_date)
+
+ def update_if_holiday(self, date):
+ holiday_list = self.holiday_list or get_holiday_list(self.company)
+ while is_holiday(holiday_list, date):
+ date = add_days(date, 1)
+ return date
+
+ def dependency_mapping(self, template_tasks, project_tasks):
+ for template_task in template_tasks:
+ project_task = list(filter(lambda x: x.subject == template_task.subject, project_tasks))[0]
+ project_task = frappe.get_doc("Task", project_task.name)
+ self.check_depends_on_value(template_task, project_task, project_tasks)
+ self.check_for_parent_tasks(template_task, project_task, project_tasks)
+
+ def check_depends_on_value(self, template_task, project_task, project_tasks):
+ if template_task.get("depends_on") and not project_task.get("depends_on"):
+ for child_task in template_task.get("depends_on"):
+ child_task_subject = frappe.db.get_value("Task", child_task.task, "subject")
+ corresponding_project_task = list(filter(lambda x: x.subject == child_task_subject, project_tasks))
+ if len(corresponding_project_task):
+ project_task.append("depends_on",{
+ "task": corresponding_project_task[0].name
+ })
+ project_task.save()
+
+ def check_for_parent_tasks(self, template_task, project_task, project_tasks):
+ if template_task.get("parent_task") and not project_task.get("parent_task"):
+ parent_task_subject = frappe.db.get_value("Task", template_task.get("parent_task"), "subject")
+ corresponding_project_task = list(filter(lambda x: x.subject == parent_task_subject, project_tasks))
+ if len(corresponding_project_task):
+ project_task.parent_task = corresponding_project_task[0].name
+ project_task.save()
def is_row_updated(self, row, existing_task_data, fields):
if self.get("__islocal") or not existing_task_data: return True
diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py
index 0c4f6f1..15a2873 100644
--- a/erpnext/projects/doctype/project/test_project.py
+++ b/erpnext/projects/doctype/project/test_project.py
@@ -7,60 +7,131 @@
test_records = frappe.get_test_records('Project')
test_ignore = ["Sales Order"]
-from erpnext.projects.doctype.project_template.test_project_template import get_project_template, make_project_template
-from erpnext.projects.doctype.project.project import set_project_status
-
-from frappe.utils import getdate
+from erpnext.projects.doctype.project_template.test_project_template import make_project_template
+from erpnext.projects.doctype.task.test_task import create_task
+from frappe.utils import getdate, nowdate, add_days
class TestProject(unittest.TestCase):
- def test_project_with_template(self):
- frappe.db.sql('delete from tabTask where project = "Test Project with Template"')
- frappe.delete_doc('Project', 'Test Project with Template')
+ def test_project_with_template_having_no_parent_and_depend_tasks(self):
+ project_name = "Test Project with Template - No Parent and Dependend Tasks"
+ frappe.db.sql(""" delete from tabTask where project = %s """, project_name)
+ frappe.delete_doc('Project', project_name)
- project = get_project('Test Project with Template')
+ task1 = task_exists("Test Template Task with No Parent and Dependency")
+ if not task1:
+ task1 = create_task(subject="Test Template Task with No Parent and Dependency", is_template=1, begin=5, duration=3)
- tasks = frappe.get_all('Task', '*', dict(project=project.name), order_by='creation asc')
+ template = make_project_template("Test Project Template - No Parent and Dependend Tasks", [task1])
+ project = get_project(project_name, template)
+ tasks = frappe.get_all('Task', ['subject','exp_end_date','depends_on_tasks'], dict(project=project.name), order_by='creation asc')
- task1 = tasks[0]
- self.assertEqual(task1.subject, 'Task 1')
- self.assertEqual(task1.description, 'Task 1 description')
- self.assertEqual(getdate(task1.exp_start_date), getdate('2019-01-01'))
- self.assertEqual(getdate(task1.exp_end_date), getdate('2019-01-04'))
+ self.assertEqual(tasks[0].subject, 'Test Template Task with No Parent and Dependency')
+ self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 5, 3))
+ self.assertEqual(len(tasks), 1)
- self.assertEqual(len(tasks), 4)
- task4 = tasks[3]
- self.assertEqual(task4.subject, 'Task 4')
- self.assertEqual(getdate(task4.exp_end_date), getdate('2019-01-06'))
+ def test_project_template_having_parent_child_tasks(self):
+ project_name = "Test Project with Template - Tasks with Parent-Child Relation"
+ frappe.db.sql(""" delete from tabTask where project = %s """, project_name)
+ frappe.delete_doc('Project', project_name)
-def get_project(name):
- template = get_project_template()
+ task1 = task_exists("Test Template Task Parent")
+ if not task1:
+ task1 = create_task(subject="Test Template Task Parent", is_group=1, is_template=1, begin=1, duration=4)
+
+ task2 = task_exists("Test Template Task Child 1")
+ if not task2:
+ task2 = create_task(subject="Test Template Task Child 1", parent_task=task1.name, is_template=1, begin=1, duration=3)
+
+ task3 = task_exists("Test Template Task Child 2")
+ if not task3:
+ task3 = create_task(subject="Test Template Task Child 2", parent_task=task1.name, is_template=1, begin=2, duration=3)
+
+ template = make_project_template("Test Project Template - Tasks with Parent-Child Relation", [task1, task2, task3])
+ project = get_project(project_name, template)
+ tasks = frappe.get_all('Task', ['subject','exp_end_date','depends_on_tasks', 'name', 'parent_task'], dict(project=project.name), order_by='creation asc')
+
+ self.assertEqual(tasks[0].subject, 'Test Template Task Parent')
+ self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 1, 4))
+
+ self.assertEqual(tasks[1].subject, 'Test Template Task Child 1')
+ self.assertEqual(getdate(tasks[1].exp_end_date), calculate_end_date(project, 1, 3))
+ self.assertEqual(tasks[1].parent_task, tasks[0].name)
+
+ self.assertEqual(tasks[2].subject, 'Test Template Task Child 2')
+ self.assertEqual(getdate(tasks[2].exp_end_date), calculate_end_date(project, 2, 3))
+ self.assertEqual(tasks[2].parent_task, tasks[0].name)
+
+ self.assertEqual(len(tasks), 3)
+
+ def test_project_template_having_dependent_tasks(self):
+ project_name = "Test Project with Template - Dependent Tasks"
+ frappe.db.sql(""" delete from tabTask where project = %s """, project_name)
+ frappe.delete_doc('Project', project_name)
+
+ task1 = task_exists("Test Template Task for Dependency")
+ if not task1:
+ task1 = create_task(subject="Test Template Task for Dependency", is_template=1, begin=3, duration=1)
+
+ task2 = task_exists("Test Template Task with Dependency")
+ if not task2:
+ task2 = create_task(subject="Test Template Task with Dependency", depends_on=task1.name, is_template=1, begin=2, duration=2)
+
+ template = make_project_template("Test Project with Template - Dependent Tasks", [task1, task2])
+ project = get_project(project_name, template)
+ tasks = frappe.get_all('Task', ['subject','exp_end_date','depends_on_tasks', 'name'], dict(project=project.name), order_by='creation asc')
+
+ self.assertEqual(tasks[1].subject, 'Test Template Task with Dependency')
+ self.assertEqual(getdate(tasks[1].exp_end_date), calculate_end_date(project, 2, 2))
+ self.assertTrue(tasks[1].depends_on_tasks.find(tasks[0].name) >= 0 )
+
+ self.assertEqual(tasks[0].subject, 'Test Template Task for Dependency')
+ self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 3, 1) )
+
+ self.assertEqual(len(tasks), 2)
+
+def get_project(name, template):
project = frappe.get_doc(dict(
doctype = 'Project',
project_name = name,
status = 'Open',
project_template = template.name,
- expected_start_date = '2019-01-01'
+ expected_start_date = nowdate(),
+ company="_Test Company"
)).insert()
return project
def make_project(args):
args = frappe._dict(args)
- if args.project_template_name:
- template = make_project_template(args.project_template_name)
- else:
- template = get_project_template()
+
+ if args.project_name and frappe.db.exists("Project", {"project_name": args.project_name}):
+ return frappe.get_doc("Project", {"project_name": args.project_name})
project = frappe.get_doc(dict(
doctype = 'Project',
project_name = args.project_name,
status = 'Open',
- project_template = template.name,
expected_start_date = args.start_date
))
- if not frappe.db.exists("Project", args.project_name):
- project.insert()
+ if args.project_template_name:
+ template = make_project_template(args.project_template_name)
+ project.project_template = template.name
- return project
\ No newline at end of file
+ project.insert()
+
+ return project
+
+def task_exists(subject):
+ result = frappe.db.get_list("Task", filters={"subject": subject},fields=["name"])
+ if not len(result):
+ return False
+ return frappe.get_doc("Task", result[0].name)
+
+def calculate_end_date(project, start, duration):
+ start = add_days(project.expected_start_date, start)
+ start = project.update_if_holiday(start)
+ end = add_days(start, duration)
+ end = project.update_if_holiday(end)
+ return getdate(end)
diff --git a/erpnext/projects/doctype/project_template/project_template.js b/erpnext/projects/doctype/project_template/project_template.js
index d7a876d..3d3c15c 100644
--- a/erpnext/projects/doctype/project_template/project_template.js
+++ b/erpnext/projects/doctype/project_template/project_template.js
@@ -5,4 +5,23 @@
// refresh: function(frm) {
// }
+ setup: function (frm) {
+ frm.set_query("task", "tasks", function () {
+ return {
+ filters: {
+ "is_template": 1
+ }
+ };
+ });
+ }
+});
+
+frappe.ui.form.on('Project Template Task', {
+ task: function (frm, cdt, cdn) {
+ var row = locals[cdt][cdn];
+ frappe.db.get_value("Task", row.task, "subject", (value) => {
+ row.subject = value.subject;
+ refresh_field("tasks");
+ });
+ }
});
diff --git a/erpnext/projects/doctype/project_template/project_template.py b/erpnext/projects/doctype/project_template/project_template.py
index ac78135..aace402 100644
--- a/erpnext/projects/doctype/project_template/project_template.py
+++ b/erpnext/projects/doctype/project_template/project_template.py
@@ -3,8 +3,28 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
+import frappe
from frappe.model.document import Document
+from frappe import _
+from frappe.utils import get_link_to_form
class ProjectTemplate(Document):
- pass
+
+ def validate(self):
+ self.validate_dependencies()
+
+ def validate_dependencies(self):
+ for task in self.tasks:
+ task_details = frappe.get_doc("Task", task.task)
+ if task_details.depends_on:
+ for dependency_task in task_details.depends_on:
+ if not self.check_dependent_task_presence(dependency_task.task):
+ task_details_format = get_link_to_form("Task",task_details.name)
+ dependency_task_format = get_link_to_form("Task", dependency_task.task)
+ frappe.throw(_("Task {0} depends on Task {1}. Please add Task {1} to the Tasks list.").format(frappe.bold(task_details_format), frappe.bold(dependency_task_format)))
+
+ def check_dependent_task_presence(self, task):
+ for task_details in self.tasks:
+ if task_details.task == task:
+ return True
+ return False
diff --git a/erpnext/projects/doctype/project_template/test_project_template.py b/erpnext/projects/doctype/project_template/test_project_template.py
index 2c5831a..95663cd 100644
--- a/erpnext/projects/doctype/project_template/test_project_template.py
+++ b/erpnext/projects/doctype/project_template/test_project_template.py
@@ -5,44 +5,25 @@
import frappe
import unittest
+from erpnext.projects.doctype.task.test_task import create_task
class TestProjectTemplate(unittest.TestCase):
pass
-def get_project_template():
- if not frappe.db.exists('Project Template', 'Test Project Template'):
- frappe.get_doc(dict(
- doctype = 'Project Template',
- name = 'Test Project Template',
- tasks = [
- dict(subject='Task 1', description='Task 1 description',
- start=0, duration=3),
- dict(subject='Task 2', description='Task 2 description',
- start=0, duration=2),
- dict(subject='Task 3', description='Task 3 description',
- start=2, duration=4),
- dict(subject='Task 4', description='Task 4 description',
- start=3, duration=2),
- ]
- )).insert()
-
- return frappe.get_doc('Project Template', 'Test Project Template')
-
def make_project_template(project_template_name, project_tasks=[]):
if not frappe.db.exists('Project Template', project_template_name):
- frappe.get_doc(dict(
- doctype = 'Project Template',
- name = project_template_name,
- tasks = project_tasks or [
- dict(subject='Task 1', description='Task 1 description',
- start=0, duration=3),
- dict(subject='Task 2', description='Task 2 description',
- start=0, duration=2),
- dict(subject='Task 3', description='Task 3 description',
- start=2, duration=4),
- dict(subject='Task 4', description='Task 4 description',
- start=3, duration=2),
+ project_tasks = project_tasks or [
+ create_task(subject="_Test Template Task 1", is_template=1, begin=0, duration=3),
+ create_task(subject="_Test Template Task 2", is_template=1, begin=0, duration=2),
]
- )).insert()
+ doc = frappe.get_doc(dict(
+ doctype = 'Project Template',
+ name = project_template_name
+ ))
+ for task in project_tasks:
+ doc.append("tasks",{
+ "task": task.name
+ })
+ doc.insert()
return frappe.get_doc('Project Template', project_template_name)
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project_template_task/project_template_task.json b/erpnext/projects/doctype/project_template_task/project_template_task.json
index 8644d89..16caaa2 100644
--- a/erpnext/projects/doctype/project_template_task/project_template_task.json
+++ b/erpnext/projects/doctype/project_template_task/project_template_task.json
@@ -1,203 +1,42 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
+ "actions": [],
"creation": "2019-02-18 17:24:41.830096",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "task",
+ "subject"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "columns": 2,
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Task",
+ "options": "Task",
+ "reqd": 1
+ },
+ {
+ "columns": 6,
+ "fetch_from": "task.subject",
"fieldname": "subject",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
+ "fieldtype": "Read Only",
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Subject",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "start",
- "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": "Begin On (Days)",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "duration",
- "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": "Duration (Days)",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "task_weight",
- "fieldtype": "Float",
- "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": "Task 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,
- "translatable": 0,
- "unique": 0
- },
- {
- "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": 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
+ "label": "Subject"
}
],
- "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-02-18 18:30:22.688966",
+ "links": [],
+ "modified": "2021-02-24 15:18:49.095071",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Template Task",
- "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
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index 8c6a9cf..002ddb2 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -49,7 +49,10 @@
},
callback: function (r) {
if (r.message.length > 0) {
- frappe.msgprint(__(`Cannot convert it to non-group. The following child Tasks exist: ${r.message.join(", ")}.`));
+ let message = __('Cannot convert Task to non-group because the following child Tasks exist: {0}.',
+ [r.message.join(", ")]
+ );
+ frappe.msgprint(message);
frm.reload_doc();
}
}
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index 27f1a71..160cc58 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -12,6 +12,7 @@
"issue",
"type",
"is_group",
+ "is_template",
"column_break0",
"status",
"priority",
@@ -22,9 +23,11 @@
"sb_timeline",
"exp_start_date",
"expected_time",
+ "start",
"column_break_11",
"exp_end_date",
"progress",
+ "duration",
"is_milestone",
"sb_details",
"description",
@@ -112,7 +115,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "Open\nWorking\nPending Review\nOverdue\nCompleted\nCancelled"
+ "options": "Open\nWorking\nPending Review\nOverdue\nTemplate\nCompleted\nCancelled"
},
{
"fieldname": "priority",
@@ -360,6 +363,24 @@
"label": "Completed By",
"no_copy": 1,
"options": "User"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_template",
+ "fieldtype": "Check",
+ "label": "Is Template"
+ },
+ {
+ "depends_on": "is_template",
+ "fieldname": "start",
+ "fieldtype": "Int",
+ "label": "Begin On (Days)"
+ },
+ {
+ "depends_on": "is_template",
+ "fieldname": "duration",
+ "fieldtype": "Int",
+ "label": "Duration (Days)"
}
],
"icon": "fa fa-check",
@@ -367,7 +388,7 @@
"is_tree": 1,
"links": [],
"max_attachments": 5,
- "modified": "2020-07-03 12:36:04.960457",
+ "modified": "2020-12-28 11:32:58.714991",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index fb84094..855ff5f 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -30,10 +30,12 @@
def validate(self):
self.validate_dates()
+ self.validate_parent_expected_end_date()
self.validate_parent_project_dates()
self.validate_progress()
self.validate_status()
self.update_depends_on()
+ self.validate_dependencies_for_template_task()
def validate_dates(self):
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
@@ -44,6 +46,12 @@
frappe.throw(_("{0} can not be greater than {1}").format(frappe.bold("Actual Start Date"), \
frappe.bold("Actual End Date")))
+ def validate_parent_expected_end_date(self):
+ if self.parent_task:
+ parent_exp_end_date = frappe.db.get_value("Task", self.parent_task, "exp_end_date")
+ if parent_exp_end_date and getdate(self.get("exp_end_date")) > getdate(parent_exp_end_date):
+ frappe.throw(_("Expected End Date should be less than or equal to parent task's Expected End Date {0}.").format(getdate(parent_exp_end_date)))
+
def validate_parent_project_dates(self):
if not self.project or frappe.flags.in_test:
return
@@ -55,6 +63,8 @@
validate_project_dates(getdate(expected_end_date), self, "act_start_date", "act_end_date", "Actual")
def validate_status(self):
+ if self.is_template and self.status != "Template":
+ self.status = "Template"
if self.status!=self.get_db_value("status") and self.status == "Completed":
for d in self.depends_on:
if frappe.db.get_value("Task", d.task, "status") not in ("Completed", "Cancelled"):
@@ -72,10 +82,28 @@
if self.status == 'Completed':
self.progress = 100
+ def validate_dependencies_for_template_task(self):
+ if self.is_template:
+ self.validate_parent_template_task()
+ self.validate_depends_on_tasks()
+
+ def validate_parent_template_task(self):
+ if self.parent_task:
+ if not frappe.db.get_value("Task", self.parent_task, "is_template"):
+ parent_task_format = """<a href="#Form/Task/{0}">{0}</a>""".format(self.parent_task)
+ frappe.throw(_("Parent Task {0} is not a Template Task").format(parent_task_format))
+
+ def validate_depends_on_tasks(self):
+ if self.depends_on:
+ for task in self.depends_on:
+ if not frappe.db.get_value("Task", task.task, "is_template"):
+ dependent_task_format = """<a href="#Form/Task/{0}">{0}</a>""".format(task.task)
+ frappe.throw(_("Dependent Task {0} is not a Template Task").format(dependent_task_format))
+
def update_depends_on(self):
depends_on_tasks = self.depends_on_tasks or ""
for d in self.depends_on:
- if d.task and not d.task in depends_on_tasks:
+ if d.task and d.task not in depends_on_tasks:
depends_on_tasks += d.task + ","
self.depends_on_tasks = depends_on_tasks
@@ -161,7 +189,7 @@
def populate_depends_on(self):
if self.parent_task:
parent = frappe.get_doc('Task', self.parent_task)
- if not self.name in [row.task for row in parent.depends_on]:
+ if self.name not in [row.task for row in parent.depends_on]:
parent.append("depends_on", {
"doctype": "Task Depends On",
"task": self.name,
@@ -196,17 +224,24 @@
@frappe.validate_and_sanitize_search_inputs
def get_project(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
- return frappe.db.sql(""" select name from `tabProject`
- where %(key)s like %(txt)s
- %(mcond)s
- order by name
- limit %(start)s, %(page_len)s""" % {
- 'key': searchfield,
- 'txt': frappe.db.escape('%' + txt + '%'),
- 'mcond':get_match_cond(doctype),
- 'start': start,
- 'page_len': page_len
- })
+ meta = frappe.get_meta(doctype)
+ searchfields = meta.get_search_fields()
+ search_columns = ", " + ", ".join(searchfields) if searchfields else ''
+ search_cond = " or " + " or ".join([field + " like %(txt)s" for field in searchfields])
+
+ return frappe.db.sql(""" select name {search_columns} from `tabProject`
+ where %(key)s like %(txt)s
+ %(mcond)s
+ {search_condition}
+ order by name
+ limit %(start)s, %(page_len)s""".format(search_columns = search_columns,
+ search_condition=search_cond), {
+ 'key': searchfield,
+ 'txt': '%' + txt + '%',
+ 'mcond':get_match_cond(doctype),
+ 'start': start,
+ 'page_len': page_len
+ })
@frappe.whitelist()
diff --git a/erpnext/projects/doctype/task/task_list.js b/erpnext/projects/doctype/task/task_list.js
index 941fe97..98d2bbc 100644
--- a/erpnext/projects/doctype/task/task_list.js
+++ b/erpnext/projects/doctype/task/task_list.js
@@ -20,13 +20,14 @@
"Pending Review": "orange",
"Working": "orange",
"Completed": "green",
- "Cancelled": "dark grey"
+ "Cancelled": "dark grey",
+ "Template": "blue"
}
return [__(doc.status), colors[doc.status], "status,=," + doc.status];
},
gantt_custom_popup_html: function(ganttobj, task) {
var html = `<h5><a style="text-decoration:underline"\
- href="#Form/Task/${ganttobj.id}""> ${ganttobj.name} </a></h5>`;
+ href="/app/task/${ganttobj.id}""> ${ganttobj.name} </a></h5>`;
if(task.project) html += `<p>Project: ${task.project}</p>`;
html += `<p>Progress: ${ganttobj.progress}</p>`;
diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py
index 47a28fd..0fad5e8 100644
--- a/erpnext/projects/doctype/task/test_task.py
+++ b/erpnext/projects/doctype/task/test_task.py
@@ -30,14 +30,16 @@
})
def test_reschedule_dependent_task(self):
+ project = frappe.get_value("Project", {"project_name": "_Test Project"})
+
task1 = create_task("_Test Task 1", nowdate(), add_days(nowdate(), 10))
task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name)
- task2.get("depends_on")[0].project = "_Test Project"
+ task2.get("depends_on")[0].project = project
task2.save()
task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name)
- task3.get("depends_on")[0].project = "_Test Project"
+ task3.get("depends_on")[0].project = project
task3.save()
task1.update({
@@ -97,14 +99,19 @@
self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
-def create_task(subject, start=None, end=None, depends_on=None, project=None, save=True):
+def create_task(subject, start=None, end=None, depends_on=None, project=None, parent_task=None, is_group=0, is_template=0, begin=0, duration=0, save=True):
if not frappe.db.exists("Task", subject):
task = frappe.new_doc('Task')
task.status = "Open"
task.subject = subject
task.exp_start_date = start or nowdate()
task.exp_end_date = end or nowdate()
- task.project = project or "_Test Project"
+ task.project = project or None if is_template else frappe.get_value("Project", {"project_name": "_Test Project"})
+ task.is_template = is_template
+ task.start = begin
+ task.duration = duration
+ task.is_group = is_group
+ task.parent_task = parent_task
if save:
task.save()
else:
@@ -116,5 +123,4 @@
})
if save:
task.save()
-
return task
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index a5ce44d..f7c764e 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -13,9 +13,18 @@
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.payroll.doctype.salary_structure.test_salary_structure \
import make_salary_structure, create_salary_structure_assignment
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
+ make_earning_salary_component,
+ make_deduction_salary_component
+)
from erpnext.hr.doctype.employee.test_employee import make_employee
class TestTimesheet(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ make_earning_salary_component(setup=True, company_list=['_Test Company'])
+ make_deduction_salary_component(setup=True, company_list=['_Test Company'])
+
def setUp(self):
for dt in ["Salary Slip", "Salary Structure", "Salary Structure Assignment", "Timesheet"]:
frappe.db.sql("delete from `tab%s`" % dt)
@@ -49,7 +58,7 @@
self.assertEqual(timesheet.total_billable_amount, 0)
def test_salary_slip_from_timesheet(self):
- emp = make_employee("test_employee_6@salary.com")
+ emp = make_employee("test_employee_6@salary.com", company="_Test Company")
salary_structure = make_salary_structure_for_timesheet(emp)
timesheet = make_timesheet(emp, simulate = True, billable=1)
@@ -89,10 +98,11 @@
def test_timesheet_billing_based_on_project(self):
emp = make_employee("test_employee_6@salary.com")
+ project = frappe.get_value("Project", {"project_name": "_Test Project"})
- timesheet = make_timesheet(emp, simulate=True, billable=1, project = '_Test Project', company='_Test Company')
+ timesheet = make_timesheet(emp, simulate=True, billable=1, project=project, company='_Test Company')
sales_invoice = create_sales_invoice(do_not_save=True)
- sales_invoice.project = '_Test Project'
+ sales_invoice.project = project
sales_invoice.submit()
ts = frappe.get_doc('Timesheet', timesheet.name)
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index 607c3fd..b123af5 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -133,6 +133,11 @@
frm: frm
});
},
+
+ parent_project: function(frm) {
+ set_project_in_timelog(frm);
+ },
+
});
frappe.ui.form.on("Timesheet Detail", {
@@ -162,7 +167,11 @@
frappe.model.set_value(cdt, cdn, "hours", hours);
},
- time_logs_add: function(frm) {
+ time_logs_add: function(frm, cdt, cdn) {
+ if(frm.doc.parent_project) {
+ frappe.model.set_value(cdt, cdn, 'project', frm.doc.parent_project);
+ }
+
var $trigger_again = $('.form-grid').find('.grid-row').find('.btn-open-row');
$trigger_again.on('click', () => {
$('.form-grid')
@@ -297,3 +306,11 @@
}
});
};
+
+function set_project_in_timelog(frm) {
+ if(frm.doc.parent_project) {
+ $.each(frm.doc.time_logs || [], function(i, item) {
+ frappe.model.set_value(item.doctype, item.name, "project", frm.doc.parent_project);
+ });
+ }
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json
index c29c11b..b286821 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.json
+++ b/erpnext/projects/doctype/timesheet/timesheet.json
@@ -1,1133 +1,352 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-02-28 17:57:33",
- "custom": 0,
- "description": "",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-02-28 17:57:33",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "title",
+ "naming_series",
+ "company",
+ "sales_invoice",
+ "column_break_3",
+ "salary_slip",
+ "status",
+ "parent_project",
+ "employee_detail",
+ "employee",
+ "employee_name",
+ "department",
+ "column_break_9",
+ "user",
+ "start_date",
+ "end_date",
+ "section_break_5",
+ "time_logs",
+ "working_hours",
+ "total_hours",
+ "billing_details",
+ "total_billable_hours",
+ "total_billed_hours",
+ "total_costing_amount",
+ "column_break_10",
+ "total_billable_amount",
+ "total_billed_amount",
+ "per_billed",
+ "section_break_18",
+ "note",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "{employee_name}",
- "fieldname": "title",
- "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": "Title",
- "length": 0,
- "no_copy": 1,
- "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
- },
+ "allow_on_submit": 1,
+ "default": "{employee_name}",
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1,
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "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": "Series",
- "length": 0,
- "no_copy": 0,
- "options": "TS-.YYYY.-",
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "TS-.YYYY.-",
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "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": 0,
- "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": 1,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fieldname": "sales_invoice",
- "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": "Sales Invoice",
- "length": 0,
- "no_copy": 1,
- "options": "Sales Invoice",
- "permlevel": 0,
- "print_hide": 1,
- "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": "sales_invoice",
+ "fieldtype": "Link",
+ "label": "Sales Invoice",
+ "no_copy": 1,
+ "options": "Sales Invoice",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "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,
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "salary_slip",
- "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": "Salary Slip",
- "length": 0,
- "no_copy": 1,
- "options": "Salary Slip",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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": "salary_slip",
+ "fieldtype": "Link",
+ "label": "Salary Slip",
+ "no_copy": 1,
+ "options": "Salary Slip",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "fieldname": "status",
- "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": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Draft\nSubmitted\nBilled\nPayslip\nCompleted\nCancelled",
- "permlevel": 0,
- "print_hide": 1,
- "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
- },
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Draft\nSubmitted\nBilled\nPayslip\nCompleted\nCancelled",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "",
- "columns": 0,
- "depends_on": "eval:!doc.work_order || doc.docstatus == 1",
- "fieldname": "employee_detail",
- "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": "Employee Detail",
- "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
- },
+ "depends_on": "eval:!doc.work_order || doc.docstatus == 1",
+ "fieldname": "employee_detail",
+ "fieldtype": "Section Break",
+ "label": "Employee Detail"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "",
- "fieldname": "employee",
- "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": 1,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "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": "employee",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "options": "Employee"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "employee",
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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
- },
+ "depends_on": "employee",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Employee Name",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "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": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 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_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": 1,
- "in_list_view": 0,
- "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": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "user",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "User",
+ "options": "User",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "start_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Start Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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": "start_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Start Date",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "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": "End Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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": "end_date",
+ "fieldtype": "Date",
+ "label": "End Date",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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_5",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "time_logs",
- "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": "Time Sheets",
- "length": 0,
- "no_copy": 0,
- "options": "Timesheet Detail",
- "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": 0
- },
+ "fieldname": "time_logs",
+ "fieldtype": "Table",
+ "label": "Time Sheets",
+ "options": "Timesheet Detail",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "working_hours",
- "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": "working_hours",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "description": "",
- "fieldname": "total_hours",
- "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": "Total Working Hours",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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_on_submit": 1,
+ "default": "0",
+ "fieldname": "total_hours",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Total Working Hours",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "billing_details",
- "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": "Billing Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 1,
- "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": "billing_details",
+ "fieldtype": "Section Break",
+ "label": "Billing Details",
+ "permlevel": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_billable_hours",
- "fieldtype": "Float",
- "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": "Total Billable Hours",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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_on_submit": 1,
+ "fieldname": "total_billable_hours",
+ "fieldtype": "Float",
+ "label": "Total Billable Hours",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_billed_hours",
- "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": "Total Billed Hours",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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_on_submit": 1,
+ "fieldname": "total_billed_hours",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Total Billed Hours",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_costing_amount",
- "fieldtype": "Currency",
- "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": "Total Costing Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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_on_submit": 1,
+ "fieldname": "total_costing_amount",
+ "fieldtype": "Currency",
+ "label": "Total Costing Amount",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_10",
- "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_10",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "depends_on": "",
- "description": "",
- "fieldname": "total_billable_amount",
- "fieldtype": "Currency",
- "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": "Total Billable Amount",
- "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_on_submit": 1,
+ "default": "0",
+ "fieldname": "total_billable_amount",
+ "fieldtype": "Currency",
+ "label": "Total Billable Amount",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_billed_amount",
- "fieldtype": "Currency",
- "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": "Total Billed Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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_on_submit": 1,
+ "fieldname": "total_billed_amount",
+ "fieldtype": "Currency",
+ "label": "Total Billed Amount",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "per_billed",
- "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": "% Amount Billed",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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_on_submit": 1,
+ "fieldname": "per_billed",
+ "fieldtype": "Percent",
+ "label": "% Amount Billed",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_18",
- "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_18",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "note",
- "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": "Note",
- "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": "note",
+ "fieldtype": "Text Editor",
+ "label": "Note"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Timesheet",
- "permlevel": 0,
- "print_hide": 1,
- "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": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Timesheet",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "parent_project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-clock-o",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-05 21:54:02.654690",
- "modified_by": "Administrator",
- "module": "Projects",
- "name": "Timesheet",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-clock-o",
+ "idx": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-01-08 20:51:14.590080",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Timesheet",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Projects User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Projects User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 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
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "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": "Employee",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
+ "create": 1,
+ "read": 1,
+ "role": "Employee",
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
+ "permlevel": 1,
+ "read": 1,
+ "role": "Accounts User",
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_order": "ASC",
- "title_field": "title",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "title_field": "title"
}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 9e807f7..ed02f79 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -204,14 +204,16 @@
ts_detail.billing_rate = 0.0
@frappe.whitelist()
-def get_projectwise_timesheet_data(project, parent=None):
- cond = ''
+def get_projectwise_timesheet_data(project, parent=None, from_time=None, to_time=None):
+ condition = ''
if parent:
- cond = "and parent = %(parent)s"
+ condition = "AND parent = %(parent)s"
+ if from_time and to_time:
+ condition += "AND from_time BETWEEN %(from_time)s AND %(to_time)s"
return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
from `tabTimesheet Detail` where parenttype = 'Timesheet' and docstatus=1 and project = %(project)s {0} and billable = 1
- and sales_invoice is null""".format(cond), {'project': project, 'parent': parent}, as_dict=1)
+ and sales_invoice is null""".format(condition), {'project': project, 'parent': parent, 'from_time': from_time, 'to_time': to_time}, as_dict=1)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
@@ -288,7 +290,7 @@
def make_salary_slip(source_name, target_doc=None):
target = frappe.new_doc("Salary Slip")
set_missing_values(source_name, target)
- target.run_method("get_emp_and_leave_details")
+ target.run_method("get_emp_and_working_day_details")
return target
diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py
index b808268..6c3c05f 100644
--- a/erpnext/projects/report/billing_summary.py
+++ b/erpnext/projects/report/billing_summary.py
@@ -136,6 +136,7 @@
return timesheet_details_map
def get_billable_and_total_duration(activity, start_time, end_time):
+ precision = frappe.get_precision("Timesheet Detail", "hours")
activity_duration = time_diff_in_hours(end_time, start_time)
billing_duration = 0.0
if activity.billable:
@@ -143,4 +144,4 @@
if activity_duration != activity.billing_hours:
billing_duration = activity_duration * activity.billing_hours / activity.hours
- return flt(activity_duration, 2), flt(billing_duration, 2)
\ No newline at end of file
+ return flt(activity_duration, precision), flt(billing_duration, precision)
\ No newline at end of file
diff --git a/erpnext/projects/workspace/projects/projects.json b/erpnext/projects/workspace/projects/projects.json
new file mode 100644
index 0000000..dbbd7e1
--- /dev/null
+++ b/erpnext/projects/workspace/projects/projects.json
@@ -0,0 +1,193 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Project Summary",
+ "label": "Open Projects"
+ }
+ ],
+ "creation": "2020-03-02 15:46:04.874669",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "project",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Projects",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Projects",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Project",
+ "link_to": "Project",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Task",
+ "link_to": "Task",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Project Template",
+ "link_to": "Project Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Project Type",
+ "link_to": "Project Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Project",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Project Update",
+ "link_to": "Project Update",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Time Tracking",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Timesheet",
+ "link_to": "Timesheet",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Activity Type",
+ "link_to": "Activity Type",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Activity Type",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Activity Cost",
+ "link_to": "Activity Cost",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Timesheet",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Daily Timesheet Summary",
+ "link_to": "Daily Timesheet Summary",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Project",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Project wise Stock Tracking",
+ "link_to": "Project wise Stock Tracking",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Project",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Project Billing Summary",
+ "link_to": "Project Billing Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:37.856224",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Projects",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Blue",
+ "format": "{} Assigned",
+ "label": "Task",
+ "link_to": "Task",
+ "stats_filter": "{\n \"_assign\": [\"like\", '%' + frappe.session.user + '%'],\n \"status\": \"Open\"\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Blue",
+ "format": "{} Open",
+ "label": "Project",
+ "link_to": "Project",
+ "stats_filter": "{\n \"status\": \"Open\"\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Timesheet",
+ "link_to": "Timesheet",
+ "type": "DocType"
+ },
+ {
+ "label": "Project Billing Summary",
+ "link_to": "Project Billing Summary",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Project",
+ "type": "Dashboard"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 2695502..7a3cb83 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -2,7 +2,8 @@
"css/erpnext.css": [
"public/less/erpnext.less",
"public/less/hub.less",
- "public/less/call_popup.less"
+ "public/scss/call_popup.scss",
+ "public/scss/point-of-sale.scss"
],
"css/marketplace.css": [
"public/less/hub.less"
@@ -12,7 +13,8 @@
"public/js/shopping_cart.js"
],
"css/erpnext-web.css": [
- "public/scss/website.scss"
+ "public/scss/website.scss",
+ "public/scss/shopping_cart.scss"
],
"js/marketplace.min.js": [
"public/js/hub/marketplace.js"
@@ -27,16 +29,6 @@
"public/js/payment/payments.js",
"public/js/controllers/taxes_and_totals.js",
"public/js/controllers/transaction.js",
- "public/js/pos/pos.html",
- "public/js/pos/pos_bill_item.html",
- "public/js/pos/pos_bill_item_new.html",
- "public/js/pos/pos_selected_item.html",
- "public/js/pos/pos_item.html",
- "public/js/pos/pos_tax_row.html",
- "public/js/pos/customer_toolbar.html",
- "public/js/pos/pos_invoice_list.html",
- "public/js/payment/pos_payment.html",
- "public/js/payment/payment_details.html",
"public/js/templates/item_selector.html",
"public/js/templates/employees_to_mark_attendance.html",
"public/js/utils/item_selector.js",
@@ -49,11 +41,30 @@
"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/utils/dimension_tree_filter.js",
+ "public/js/telephony.js",
+ "public/js/templates/call_link.html"
],
"js/item-dashboard.min.js": [
"stock/dashboard/item_dashboard.html",
"stock/dashboard/item_dashboard_list.html",
- "stock/dashboard/item_dashboard.js"
+ "stock/dashboard/item_dashboard.js",
+ "stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html",
+ "stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html"
+ ],
+ "js/point-of-sale.min.js": [
+ "selling/page/point_of_sale/pos_item_selector.js",
+ "selling/page/point_of_sale/pos_item_cart.js",
+ "selling/page/point_of_sale/pos_item_details.js",
+ "selling/page/point_of_sale/pos_number_pad.js",
+ "selling/page/point_of_sale/pos_payment.js",
+ "selling/page/point_of_sale/pos_past_order_list.js",
+ "selling/page/point_of_sale/pos_past_order_summary.js",
+ "selling/page/point_of_sale/pos_controller.js"
+ ],
+ "js/bank-reconciliation-tool.min.js": [
+ "public/js/bank_reconciliation_tool/data_table_manager.js",
+ "public/js/bank_reconciliation_tool/number_card.js",
+ "public/js/bank_reconciliation_tool/dialog_manager.js"
]
}
diff --git a/erpnext/public/css/pos.css b/erpnext/public/css/pos.css
deleted file mode 100644
index e80e3ed..0000000
--- a/erpnext/public/css/pos.css
+++ /dev/null
@@ -1,216 +0,0 @@
-[data-route="point-of-sale"] .layout-main-section { border: none; font-size: 12px; }
-[data-route="point-of-sale"] .layout-main-section-wrapper { margin-bottom: 0; }
-[data-route="point-of-sale"] .pos-items-wrapper { max-height: calc(100vh - 210px); }
-:root { --border-color: #d1d8dd; --text-color: #8d99a6; --primary: #5e64ff; }
-[data-route="point-of-sale"] .flex { display: flex; }
-[data-route="point-of-sale"] .grid { display: grid; }
-[data-route="point-of-sale"] .absolute { position: absolute; }
-[data-route="point-of-sale"] .relative { position: relative; }
-[data-route="point-of-sale"] .abs-center { top: 50%; left: 50%; transform: translate(-50%, -50%); }
-[data-route="point-of-sale"] .inline { display: inline; }
-[data-route="point-of-sale"] .float-right { float: right; }
-[data-route="point-of-sale"] .grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
-[data-route="point-of-sale"] .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
-[data-route="point-of-sale"] .grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
-[data-route="point-of-sale"] .grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
-[data-route="point-of-sale"] .grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
-[data-route="point-of-sale"] .grid-cols-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); }
-[data-route="point-of-sale"] .gap-2 { grid-gap: 0.5rem; gap: 0.5rem; }
-[data-route="point-of-sale"] .gap-4 { grid-gap: 1rem; gap: 1rem; }
-[data-route="point-of-sale"] .gap-6 { grid-gap: 1.25rem; gap: 1.25rem; }
-[data-route="point-of-sale"] .gap-8 { grid-gap: 1.5rem; gap: 1.5rem; }
-[data-route="point-of-sale"] .row-gap-2 { grid-row-gap: 0.5rem; row-gap: 0.5rem; }
-[data-route="point-of-sale"] .col-gap-4 { grid-column-gap: 1rem; column-gap: 1rem; }
-[data-route="point-of-sale"] .col-span-2 { grid-column: span 2 / span 2; }
-[data-route="point-of-sale"] .col-span-3 { grid-column: span 3 / span 3; }
-[data-route="point-of-sale"] .col-span-4 { grid-column: span 4 / span 4; }
-[data-route="point-of-sale"] .col-span-6 { grid-column: span 6 / span 6; }
-[data-route="point-of-sale"] .col-span-10 { grid-column: span 10 / span 10; }
-[data-route="point-of-sale"] .row-span-2 { grid-row: span 2 / span 2; }
-[data-route="point-of-sale"] .grid-auto-row { grid-auto-rows: 5.5rem; }
-[data-route="point-of-sale"] .d-none { display: none; }
-[data-route="point-of-sale"] .flex-wrap { flex-wrap: wrap; }
-[data-route="point-of-sale"] .flex-row { flex-direction: row; }
-[data-route="point-of-sale"] .flex-col { flex-direction: column; }
-[data-route="point-of-sale"] .flex-row-rev { flex-direction: row-reverse; }
-[data-route="point-of-sale"] .flex-col-rev { flex-direction: column-reverse; }
-[data-route="point-of-sale"] .flex-1 { flex: 1 1 0%; }
-[data-route="point-of-sale"] .items-center { align-items: center; }
-[data-route="point-of-sale"] .items-end { align-items: flex-end; }
-[data-route="point-of-sale"] .f-grow-1 { flex-grow: 1; }
-[data-route="point-of-sale"] .f-grow-2 { flex-grow: 2; }
-[data-route="point-of-sale"] .f-grow-3 { flex-grow: 3; }
-[data-route="point-of-sale"] .f-grow-4 { flex-grow: 4; }
-[data-route="point-of-sale"] .f-shrink-0 { flex-shrink: 0; }
-[data-route="point-of-sale"] .f-shrink-1 { flex-shrink: 1; }
-[data-route="point-of-sale"] .f-shrink-2 { flex-shrink: 2; }
-[data-route="point-of-sale"] .f-shrink-3 { flex-shrink: 3; }
-[data-route="point-of-sale"] .shadow { box-shadow: 0 0px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 2px 0 rgba(0, 0, 0, 0.06); }
-[data-route="point-of-sale"] .shadow-sm { box-shadow: 0 0.5px 3px 0 rgba(0, 0, 0, 0.125); }
-[data-route="point-of-sale"] .shadow-inner { box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.1); }
-[data-route="point-of-sale"] .rounded { border-radius: 0.3rem; }
-[data-route="point-of-sale"] .rounded-b { border-bottom-left-radius: 0.3rem; border-bottom-right-radius: 0.3rem; }
-[data-route="point-of-sale"] .p-8 { padding: 2rem; }
-[data-route="point-of-sale"] .p-16 { padding: 4rem; }
-[data-route="point-of-sale"] .p-32 { padding: 8rem; }
-[data-route="point-of-sale"] .p-6 { padding: 1.5rem; }
-[data-route="point-of-sale"] .p-4 { padding: 1rem; }
-[data-route="point-of-sale"] .p-3 { padding: 0.75rem; }
-[data-route="point-of-sale"] .p-2 { padding: 0.5rem; }
-[data-route="point-of-sale"] .m-8 { margin: 2rem; }
-[data-route="point-of-sale"] .p-1 { padding: 0.25rem; }
-[data-route="point-of-sale"] .pr-0 { padding-right: 0rem; }
-[data-route="point-of-sale"] .pl-0 { padding-left: 0rem; }
-[data-route="point-of-sale"] .pt-0 { padding-top: 0rem; }
-[data-route="point-of-sale"] .pb-0 { padding-bottom: 0rem; }
-[data-route="point-of-sale"] .mr-0 { margin-right: 0rem; }
-[data-route="point-of-sale"] .ml-0 { margin-left: 0rem; }
-[data-route="point-of-sale"] .mt-0 { margin-top: 0rem; }
-[data-route="point-of-sale"] .mb-0 { margin-bottom: 0rem; }
-[data-route="point-of-sale"] .pr-2 { padding-right: 0.5rem; }
-[data-route="point-of-sale"] .pl-2 { padding-left: 0.5rem; }
-[data-route="point-of-sale"] .pt-2 { padding-top: 0.5rem; }
-[data-route="point-of-sale"] .pb-2 { padding-bottom: 0.5rem; }
-[data-route="point-of-sale"] .pr-3 { padding-right: 0.75rem; }
-[data-route="point-of-sale"] .pl-3 { padding-left: 0.75rem; }
-[data-route="point-of-sale"] .pt-3 { padding-top: 0.75rem; }
-[data-route="point-of-sale"] .pb-3 { padding-bottom: 0.75rem; }
-[data-route="point-of-sale"] .pr-4 { padding-right: 1rem; }
-[data-route="point-of-sale"] .pl-4 { padding-left: 1rem; }
-[data-route="point-of-sale"] .pt-4 { padding-top: 1rem; }
-[data-route="point-of-sale"] .pb-4 { padding-bottom: 1rem; }
-[data-route="point-of-sale"] .mr-4 { margin-right: 1rem; }
-[data-route="point-of-sale"] .ml-4 { margin-left: 1rem; }
-[data-route="point-of-sale"] .mt-4 { margin-top: 1rem; }
-[data-route="point-of-sale"] .mb-4 { margin-bottom: 1rem; }
-[data-route="point-of-sale"] .mr-2 { margin-right: 0.5rem; }
-[data-route="point-of-sale"] .ml-2 { margin-left: 0.5rem; }
-[data-route="point-of-sale"] .mt-2 { margin-top: 0.5rem; }
-[data-route="point-of-sale"] .mb-2 { margin-bottom: 0.5rem; }
-[data-route="point-of-sale"] .mr-1 { margin-right: 0.25rem; }
-[data-route="point-of-sale"] .ml-1 { margin-left: 0.25rem; }
-[data-route="point-of-sale"] .mt-1 { margin-top: 0.25rem; }
-[data-route="point-of-sale"] .mb-1 { margin-bottom: 0.25rem; }
-[data-route="point-of-sale"] .mr-auto { margin-right: auto; }
-[data-route="point-of-sale"] .ml-auto { margin-left: auto; }
-[data-route="point-of-sale"] .mt-auto { margin-top: auto; }
-[data-route="point-of-sale"] .mb-auto { margin-bottom: auto; }
-[data-route="point-of-sale"] .pr-6 { padding-right: 1.5rem; }
-[data-route="point-of-sale"] .pl-6 { padding-left: 1.5rem; }
-[data-route="point-of-sale"] .pt-6 { padding-top: 1.5rem; }
-[data-route="point-of-sale"] .pb-6 { padding-bottom: 1.5rem; }
-[data-route="point-of-sale"] .mr-6 { margin-right: 1.5rem; }
-[data-route="point-of-sale"] .ml-6 { margin-left: 1.5rem; }
-[data-route="point-of-sale"] .mt-6 { margin-top: 1.5rem; }
-[data-route="point-of-sale"] .mb-6 { margin-bottom: 1.5rem; }
-[data-route="point-of-sale"] .mr-8 { margin-right: 2rem; }
-[data-route="point-of-sale"] .ml-8 { margin-left: 2rem; }
-[data-route="point-of-sale"] .mt-8 { margin-top: 2rem; }
-[data-route="point-of-sale"] .mb-8 { margin-bottom: 2rem; }
-[data-route="point-of-sale"] .pr-8 { padding-right: 2rem; }
-[data-route="point-of-sale"] .pl-8 { padding-left: 2rem; }
-[data-route="point-of-sale"] .pt-8 { padding-top: 2rem; }
-[data-route="point-of-sale"] .pb-8 { padding-bottom: 2rem; }
-[data-route="point-of-sale"] .pr-16 { padding-right: 4rem; }
-[data-route="point-of-sale"] .pl-16 { padding-left: 4rem; }
-[data-route="point-of-sale"] .pt-16 { padding-top: 4rem; }
-[data-route="point-of-sale"] .pb-16 { padding-bottom: 4rem; }
-[data-route="point-of-sale"] .w-full { width: 100%; }
-[data-route="point-of-sale"] .h-full { height: 100%; }
-[data-route="point-of-sale"] .w-quarter { width: 25%; }
-[data-route="point-of-sale"] .w-half { width: 50%; }
-[data-route="point-of-sale"] .w-66 { width: 66.66%; }
-[data-route="point-of-sale"] .w-33 { width: 33.33%; }
-[data-route="point-of-sale"] .w-60 { width: 60%; }
-[data-route="point-of-sale"] .w-40 { width: 40%; }
-[data-route="point-of-sale"] .w-fit { width: fit-content; }
-[data-route="point-of-sale"] .w-6 { width: 2rem; }
-[data-route="point-of-sale"] .h-6 { min-height: 2rem; height: 2rem; }
-[data-route="point-of-sale"] .w-8 { width: 2.5rem; }
-[data-route="point-of-sale"] .h-8 { min-height: 2.5rem; height: 2.5rem; }
-[data-route="point-of-sale"] .w-10 { width: 3rem; }
-[data-route="point-of-sale"] .h-10 { min-height:3rem; height: 3rem; }
-[data-route="point-of-sale"] .h-12 { min-height: 3.3rem; height: 3.3rem; }
-[data-route="point-of-sale"] .w-12 { width: 3.3rem; }
-[data-route="point-of-sale"] .h-14 { min-height: 4.2rem; height: 4.2rem; }
-[data-route="point-of-sale"] .h-16 { min-height: 4.6rem; height: 4.6rem; }
-[data-route="point-of-sale"] .h-18 { min-height: 5rem; height: 5rem; }
-[data-route="point-of-sale"] .w-18 { width: 5.4rem; }
-[data-route="point-of-sale"] .w-24 { width: 7.2rem; }
-[data-route="point-of-sale"] .w-26 { width: 8.4rem; }
-[data-route="point-of-sale"] .h-24 { min-height: 7.2rem; height: 7.2rem; }
-[data-route="point-of-sale"] .h-32 { min-height: 9.6rem; height: 9.6rem; }
-[data-route="point-of-sale"] .w-46 { width: 15rem; }
-[data-route="point-of-sale"] .h-46 { min-height:15rem; height: 15rem; }
-[data-route="point-of-sale"] .h-100 { height: 100vh; }
-[data-route="point-of-sale"] .mx-h-70 { max-height: 67rem; }
-[data-route="point-of-sale"] .border-grey-300 { border-color: #e2e8f0; }
-[data-route="point-of-sale"] .border-grey { border: 1px solid #d1d8dd; }
-[data-route="point-of-sale"] .border-white { border: 1px solid #fff; }
-[data-route="point-of-sale"] .border-b-grey { border-bottom: 1px solid #d1d8dd; }
-[data-route="point-of-sale"] .border-t-grey { border-top: 1px solid #d1d8dd; }
-[data-route="point-of-sale"] .border-r-grey { border-right: 1px solid #d1d8dd; }
-[data-route="point-of-sale"] .text-dark-grey { color: #5f5f5f; }
-[data-route="point-of-sale"] .text-grey { color: #8d99a6; }
-[data-route="point-of-sale"] .text-grey-100 { color: #d1d8dd; }
-[data-route="point-of-sale"] .text-grey-200 { color: #a0aec0; }
-[data-route="point-of-sale"] .bg-green-200 { background-color: #c6f6d5; }
-[data-route="point-of-sale"] .text-bold { font-weight: bold; }
-[data-route="point-of-sale"] .italic { font-style: italic; }
-[data-route="point-of-sale"] .font-weight-450 { font-weight: 450; }
-[data-route="point-of-sale"] .justify-around { justify-content: space-around; }
-[data-route="point-of-sale"] .justify-between { justify-content: space-between; }
-[data-route="point-of-sale"] .justify-center { justify-content: center; }
-[data-route="point-of-sale"] .justify-end { justify-content: flex-end; }
-[data-route="point-of-sale"] .bg-white { background-color: white; }
-[data-route="point-of-sale"] .bg-light-grey { background-color: #f0f4f7; }
-[data-route="point-of-sale"] .bg-grey-100 { background-color: #f7fafc; }
-[data-route="point-of-sale"] .bg-grey-200 { background-color: #edf2f7; }
-[data-route="point-of-sale"] .bg-grey { background-color: #f4f5f6; }
-[data-route="point-of-sale"] .text-center { text-align: center; }
-[data-route="point-of-sale"] .text-right { text-align: right; }
-[data-route="point-of-sale"] .text-sm { font-size: 1rem; }
-[data-route="point-of-sale"] .text-md-0 { font-size: 1.25rem; }
-[data-route="point-of-sale"] .text-md { font-size: 1.4rem; }
-[data-route="point-of-sale"] .text-lg { font-size: 1.6rem; }
-[data-route="point-of-sale"] .text-xl { font-size: 2.2rem; }
-[data-route="point-of-sale"] .text-2xl { font-size: 2.8rem; }
-[data-route="point-of-sale"] .text-2-5xl { font-size: 3rem; }
-[data-route="point-of-sale"] .text-3xl { font-size: 3.8rem; }
-[data-route="point-of-sale"] .text-6xl { font-size: 4.8rem; }
-[data-route="point-of-sale"] .line-through { text-decoration: line-through; }
-[data-route="point-of-sale"] .text-primary { color: #5e64ff; }
-[data-route="point-of-sale"] .text-white { color: #fff; }
-[data-route="point-of-sale"] .text-green-500 { color: #48bb78; }
-[data-route="point-of-sale"] .bg-primary { background-color: #5e64ff; }
-[data-route="point-of-sale"] .border-primary { border-color: #5e64ff; }
-[data-route="point-of-sale"] .text-danger { color: #e53e3e; }
-[data-route="point-of-sale"] .scroll-x { overflow-x: scroll;overflow-y: hidden; }
-[data-route="point-of-sale"] .scroll-y { overflow-y: scroll;overflow-x: hidden; }
-[data-route="point-of-sale"] .overflow-hidden { overflow: hidden; }
-[data-route="point-of-sale"] .whitespace-nowrap { white-space: nowrap; }
-[data-route="point-of-sale"] .sticky { position: sticky; top: -1px; }
-[data-route="point-of-sale"] .bg-white { background-color: #fff; }
-[data-route="point-of-sale"] .bg-selected { background-color: #fffdf4; }
-[data-route="point-of-sale"] .border-dashed { border-width:1px; border-style: dashed; }
-[data-route="point-of-sale"] .z-100 { z-index: 100; }
-
-[data-route="point-of-sale"] .frappe-control { margin: 0 !important; width: 100%; }
-[data-route="point-of-sale"] .form-control { font-size: 12px; }
-[data-route="point-of-sale"] .form-group { margin: 0 !important; }
-[data-route="point-of-sale"] .pointer { cursor: pointer; }
-[data-route="point-of-sale"] .no-select { user-select: none; }
-[data-route="point-of-sale"] .item-wrapper:hover { transform: scale(1.02, 1.02); }
-[data-route="point-of-sale"] .hover-underline:hover { text-decoration: underline; }
-[data-route="point-of-sale"] .item-wrapper { transition: scale 0.2s ease-in-out; }
-[data-route="point-of-sale"] .cart-items-section .cart-item-wrapper:not(:first-child) { border-top: none; }
-[data-route="point-of-sale"] .customer-transactions .invoice-wrapper:not(:first-child) { border-top: none; }
-
-[data-route="point-of-sale"] .payment-summary-wrapper:last-child { border-bottom: none; }
-[data-route="point-of-sale"] .item-summary-wrapper:last-child { border-bottom: none; }
-[data-route="point-of-sale"] .total-summary-wrapper:last-child { border-bottom: none; }
-[data-route="point-of-sale"] .invoices-container .invoice-wrapper:last-child { border-bottom: none; }
-[data-route="point-of-sale"] .summary-btns:last-child { margin-right: 0px; }
-[data-route="point-of-sale"] ::-webkit-scrollbar { width: 1px }
-
-[data-route="point-of-sale"] .indicator.grey::before { background-color: #8d99a6; }
\ No newline at end of file
diff --git a/erpnext/public/images/erp-icon.svg b/erpnext/public/images/erp-icon.svg
deleted file mode 100644
index 6bec40c..0000000
--- a/erpnext/public/images/erp-icon.svg
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="88px" height="88px" viewBox="0 0 88 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <!-- Generator: Sketch 44.1 (41455) - http://www.bohemiancoding.com/sketch -->
- <title>erpnext-logo</title>
- <desc>Created with Sketch.</desc>
- <defs></defs>
- <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g id="erpnext-logo" transform="translate(-2.000000, -2.000000)" fill-rule="nonzero">
- <g id="g1422-7-2" transform="translate(0.025630, 0.428785)" fill="#5E64FF">
- <g id="g1418-4-6" transform="translate(0.268998, 0.867736)">
- <g id="g1416-4-9" transform="translate(0.749997, 0.000000)">
- <path d="M14.1845844,0.703479866 L75.0387175,0.703479866 C82.3677094,0.703479866 88.2679029,6.60367875 88.2679029,13.9326374 L88.2679029,74.7868158 C88.2679029,82.1157744 82.3677094,88.0159833 75.0387175,88.0159833 L14.1845844,88.0159833 C6.85569246,88.0159833 0.955398949,82.1157744 0.955398949,74.7868158 L0.955398949,13.9326374 C0.955398949,6.60367875 6.85569246,0.703479866 14.1845844,0.703479866 L14.1845844,0.703479866 Z" id="path1414-3-4"></path>
- </g>
- </g>
- </g>
- <g id="g1444-6-7" transform="translate(27.708247, 23.320960)" fill="#FFFFFF">
- <path d="M4.06942472,0.507006595 C3.79457554,0.507006595 3.52673783,0.534925429 3.26792241,0.587619847 C3.00908052,0.640314265 2.75926093,0.717948309 2.52171801,0.818098395 C2.40292009,0.868173438 2.28745592,0.924056085 2.17495509,0.985013441 C1.94997987,1.10692286 1.73828674,1.24983755 1.54244215,1.41134187 C0.661062132,2.13811791 0.100674618,3.23899362 0.100674618,4.4757567 L0.100674618,4.71760174 L0.100674618,39.9531653 L0.100674618,40.1945182 C0.100674618,42.3932057 1.87073716,44.1632683 4.06942472,44.1632683 L31.8263867,44.1632683 C34.0250742,44.1632683 35.7951368,42.3932057 35.7951368,40.1945182 L35.7951368,39.9531653 C35.7951368,37.7544777 34.0250742,35.9844152 31.8263867,35.9844152 L8.28000399,35.9844152 L8.28000399,26.0992376 L25.7874571,26.0992376 C27.9861447,26.0992376 29.7562072,24.3291751 29.7562072,22.1304875 L29.7562072,21.8891611 C29.7562072,19.6904735 27.9861447,17.920411 25.7874571,17.920411 L8.28000399,17.920411 L8.28000399,8.68635184 L31.8263867,8.68635184 C34.0250742,8.68635184 35.7951368,6.9162893 35.7951368,4.71760174 L35.7951368,4.4757567 C35.7951368,2.27706914 34.0250742,0.507006595 31.8263867,0.507006595 L4.06942472,0.507006595 Z" id="rect1436-8-4"></path>
- </g>
- </g>
- </g>
-</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-12.svg b/erpnext/public/images/erpnext-12.svg
deleted file mode 100644
index fcc8e46..0000000
--- a/erpnext/public/images/erpnext-12.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="165px" height="88px" viewBox="0 0 165 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <!-- Generator: Sketch 44.1 (41455) - http://www.bohemiancoding.com/sketch -->
- <title>version-12</title>
- <desc>Created with Sketch.</desc>
- <defs></defs>
- <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g id="version-12" transform="translate(-2.000000, -2.000000)">
- <g id="erp-icon" fill-rule="nonzero">
- <g id="g1422-7-2" transform="translate(0.025630, 0.428785)" fill="#5E64FF">
- <g id="g1418-4-6" transform="translate(0.268998, 0.867736)">
- <g id="g1416-4-9" transform="translate(0.749997, 0.000000)">
- <path d="M14.1845844,0.703479866 L75.0387175,0.703479866 C82.3677094,0.703479866 88.2679029,6.60367875 88.2679029,13.9326374 L88.2679029,74.7868158 C88.2679029,82.1157744 82.3677094,88.0159833 75.0387175,88.0159833 L14.1845844,88.0159833 C6.85569246,88.0159833 0.955398949,82.1157744 0.955398949,74.7868158 L0.955398949,13.9326374 C0.955398949,6.60367875 6.85569246,0.703479866 14.1845844,0.703479866 L14.1845844,0.703479866 Z" id="path1414-3-4"></path>
- </g>
- </g>
- </g>
- <g id="g1444-6-7" transform="translate(27.708247, 23.320960)" fill="#FFFFFF">
- <path d="M4.06942472,0.507006595 C3.79457554,0.507006595 3.52673783,0.534925429 3.26792241,0.587619847 C3.00908052,0.640314265 2.75926093,0.717948309 2.52171801,0.818098395 C2.40292009,0.868173438 2.28745592,0.924056085 2.17495509,0.985013441 C1.94997987,1.10692286 1.73828674,1.24983755 1.54244215,1.41134187 C0.661062132,2.13811791 0.100674618,3.23899362 0.100674618,4.4757567 L0.100674618,4.71760174 L0.100674618,39.9531653 L0.100674618,40.1945182 C0.100674618,42.3932057 1.87073716,44.1632683 4.06942472,44.1632683 L31.8263867,44.1632683 C34.0250742,44.1632683 35.7951368,42.3932057 35.7951368,40.1945182 L35.7951368,39.9531653 C35.7951368,37.7544777 34.0250742,35.9844152 31.8263867,35.9844152 L8.28000399,35.9844152 L8.28000399,26.0992376 L25.7874571,26.0992376 C27.9861447,26.0992376 29.7562072,24.3291751 29.7562072,22.1304875 L29.7562072,21.8891611 C29.7562072,19.6904735 27.9861447,17.920411 25.7874571,17.920411 L8.28000399,17.920411 L8.28000399,8.68635184 L31.8263867,8.68635184 C34.0250742,8.68635184 35.7951368,6.9162893 35.7951368,4.71760174 L35.7951368,4.4757567 C35.7951368,2.27706914 34.0250742,0.507006595 31.8263867,0.507006595 L4.06942472,0.507006595 Z" id="rect1436-8-4"></path>
- </g>
- </g>
- <text id="12" font-family="SourceSansPro-Regular, Source Sans Pro" font-size="72" font-weight="normal" letter-spacing="-0.386831313" fill="#D1D8DD">
- <tspan x="99" y="71">12</tspan>
- </text>
- </g>
- </g>
-</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-favicon.svg b/erpnext/public/images/erpnext-favicon.svg
new file mode 100644
index 0000000..a3ac3bb
--- /dev/null
+++ b/erpnext/public/images/erpnext-favicon.svg
@@ -0,0 +1,5 @@
+<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 12C0 5.37258 5.37258 0 12 0H88C94.6274 0 100 5.37258 100 12V88C100 94.6274 94.6274 100 88 100H12C5.37258 100 0 94.6274 0 88V12Z" fill="#0089FF"/>
+<path d="M65.7097 32.9462H67.3871V24H33V32.9462H43.9032H65.7097Z" fill="white"/>
+<path d="M43.9032 66.2151V53.914H65.7097V44.9677H43.9032H33V75.1613H67.6667V66.2151H43.9032Z" fill="white"/>
+</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-footer.png b/erpnext/public/images/erpnext-footer.png
deleted file mode 100644
index ffff775..0000000
--- a/erpnext/public/images/erpnext-footer.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/erpnext-logo.png b/erpnext/public/images/erpnext-logo.png
index 115faaa..3090727 100644
--- a/erpnext/public/images/erpnext-logo.png
+++ b/erpnext/public/images/erpnext-logo.png
Binary files differ
diff --git a/erpnext/public/images/erpnext-logo.svg b/erpnext/public/images/erpnext-logo.svg
new file mode 100644
index 0000000..a3ac3bb
--- /dev/null
+++ b/erpnext/public/images/erpnext-logo.svg
@@ -0,0 +1,5 @@
+<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 12C0 5.37258 5.37258 0 12 0H88C94.6274 0 100 5.37258 100 12V88C100 94.6274 94.6274 100 88 100H12C5.37258 100 0 94.6274 0 88V12Z" fill="#0089FF"/>
+<path d="M65.7097 32.9462H67.3871V24H33V32.9462H43.9032H65.7097Z" fill="white"/>
+<path d="M43.9032 66.2151V53.914H65.7097V44.9677H43.9032H33V75.1613H67.6667V66.2151H43.9032Z" fill="white"/>
+</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/favicon.png b/erpnext/public/images/favicon.png
deleted file mode 100644
index b694885..0000000
--- a/erpnext/public/images/favicon.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/splash.png b/erpnext/public/images/splash.png
deleted file mode 100644
index 8e5d055..0000000
--- a/erpnext/public/images/splash.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/ui-states/cart-empty-state.png b/erpnext/public/images/ui-states/cart-empty-state.png
new file mode 100644
index 0000000..e1ead0e
--- /dev/null
+++ b/erpnext/public/images/ui-states/cart-empty-state.png
Binary files differ
diff --git a/erpnext/public/js/address.js b/erpnext/public/js/address.js
new file mode 100644
index 0000000..57f7163
--- /dev/null
+++ b/erpnext/public/js/address.js
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, Frappe Technologies and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Address", {
+ is_your_company_address: function(frm) {
+ frm.clear_table('links');
+ if(frm.doc.is_your_company_address) {
+ frm.add_child('links', {
+ link_doctype: 'Company',
+ link_name: frappe.defaults.get_user_default('Company')
+ });
+ frm.set_query('link_doctype', 'links', () => {
+ return {
+ filters: {
+ name: 'Company'
+ }
+ };
+ });
+ frm.refresh_field('links');
+ }
+ else {
+ frm.trigger('refresh');
+ }
+ }
+});
diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
new file mode 100644
index 0000000..5bb58fa
--- /dev/null
+++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
@@ -0,0 +1,220 @@
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager {
+ constructor(opts) {
+ Object.assign(this, opts);
+ this.dialog_manager = new erpnext.accounts.bank_reconciliation.DialogManager(
+ this.company,
+ this.bank_account
+ );
+ this.make_dt();
+ }
+
+ make_dt() {
+ var me = this;
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions",
+ args: {
+ bank_account: this.bank_account,
+ },
+ callback: function (response) {
+ me.format_data(response.message);
+ me.get_dt_columns();
+ me.get_datatable();
+ me.set_listeners();
+ },
+ });
+ }
+
+ get_dt_columns() {
+ this.columns = [
+ {
+ name: "Date",
+ editable: false,
+ width: 100,
+ },
+
+ {
+ name: "Party Type",
+ editable: false,
+ width: 95,
+ },
+ {
+ name: "Party",
+ editable: false,
+ width: 100,
+ },
+ {
+ name: "Description",
+ editable: false,
+ width: 350,
+ },
+ {
+ name: "Deposit",
+ editable: false,
+ width: 100,
+ format: (value) =>
+ "<span style='color:green;'>" +
+ format_currency(value, this.currency) +
+ "</span>",
+ },
+ {
+ name: "Withdrawal",
+ editable: false,
+ width: 100,
+ format: (value) =>
+ "<span style='color:red;'>" +
+ format_currency(value, this.currency) +
+ "</span>",
+ },
+ {
+ name: "Unallocated Amount",
+ editable: false,
+ width: 100,
+ format: (value) =>
+ "<span style='color:blue;'>" +
+ format_currency(value, this.currency) +
+ "</span>",
+ },
+ {
+ name: "Reference Number",
+ editable: false,
+ width: 140,
+ },
+ {
+ name: "Actions",
+ editable: false,
+ sortable: false,
+ focusable: false,
+ dropdown: false,
+ width: 80,
+ },
+ ];
+ }
+
+ format_data(transactions) {
+ this.transactions = [];
+ if (transactions[0]) {
+ this.currency = transactions[0]["currency"];
+ }
+ this.transaction_dt_map = {};
+ let length;
+ transactions.forEach((row) => {
+ length = this.transactions.push(this.format_row(row));
+ this.transaction_dt_map[row["name"]] = length - 1;
+ });
+ }
+
+ format_row(row) {
+ return [
+ row["date"],
+ row["party_type"],
+ row["party"],
+ row["description"],
+ row["deposit"],
+ row["withdrawal"],
+ row["unallocated_amount"],
+ row["reference_number"],
+ `
+ <Button class="btn btn-primary btn-xs center" data-name = ${row["name"]} >
+ Actions
+ </a>
+ `,
+ ];
+ }
+
+ get_datatable() {
+ const datatable_options = {
+ columns: this.columns,
+ data: this.transactions,
+ dynamicRowHeight: true,
+ checkboxColumn: false,
+ inlineFilters: true,
+ };
+ this.datatable = new frappe.DataTable(
+ this.$reconciliation_tool_dt.get(0),
+ datatable_options
+ );
+ $(`.${this.datatable.style.scopeClass} .dt-scrollable`).css(
+ "max-height",
+ "calc(100vh - 400px)"
+ );
+
+ if (this.transactions.length > 0) {
+ this.$reconciliation_tool_dt.show();
+ this.$no_bank_transactions.hide();
+ } else {
+ this.$reconciliation_tool_dt.hide();
+ this.$no_bank_transactions.show();
+ }
+ }
+
+ set_listeners() {
+ var me = this;
+ $(`.${this.datatable.style.scopeClass} .dt-scrollable`).on(
+ "click",
+ `.btn`,
+ function () {
+ me.dialog_manager.show_dialog(
+ $(this).attr("data-name"),
+ (bank_transaction) => me.update_dt_cards(bank_transaction)
+ );
+ return true;
+ }
+ );
+ }
+
+ update_dt_cards(bank_transaction) {
+ const transaction_index = this.transaction_dt_map[
+ bank_transaction.name
+ ];
+ if (bank_transaction.unallocated_amount > 0) {
+ this.transactions[transaction_index] = this.format_row(
+ bank_transaction
+ );
+ } else {
+ this.transactions.splice(transaction_index, 1);
+ }
+ this.datatable.refresh(this.transactions, this.columns);
+
+ if (this.transactions.length == 0) {
+ this.$reconciliation_tool_dt.hide();
+ this.$no_bank_transactions.show();
+ }
+
+ // this.make_dt();
+ this.get_cleared_balance().then(() => {
+ this.cards_manager.$cards[1].set_value(
+ format_currency(this.cleared_balance),
+ this.currency
+ );
+ this.cards_manager.$cards[2].set_value(
+ format_currency(
+ this.bank_statement_closing_balance - this.cleared_balance
+ ),
+ this.currency
+ );
+ this.cards_manager.$cards[2].set_value_color(
+ this.bank_statement_closing_balance - this.cleared_balance == 0
+ ? "text-success"
+ : "text-danger"
+ );
+ });
+ }
+
+ get_cleared_balance() {
+ if (this.bank_account && this.bank_statement_to_date) {
+ return frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
+ args: {
+ bank_account: this.bank_account,
+ till_date: this.bank_statement_to_date,
+ },
+ callback: (response) =>
+ (this.cleared_balance = response.message),
+ });
+ }
+ }
+};
diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
new file mode 100644
index 0000000..142fe79
--- /dev/null
+++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
@@ -0,0 +1,594 @@
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager {
+ constructor(company, bank_account) {
+ this.bank_account = bank_account;
+ this.company = company;
+ this.make_dialog();
+ }
+
+ show_dialog(bank_transaction_name, update_dt_cards) {
+ this.bank_transaction_name = bank_transaction_name;
+ this.update_dt_cards = update_dt_cards;
+ frappe.call({
+ method: "frappe.client.get_value",
+ args: {
+ doctype: "Bank Transaction",
+ filters: { name: this.bank_transaction_name },
+ fieldname: [
+ "date",
+ "deposit",
+ "withdrawal",
+ "currency",
+ "description",
+ "name",
+ "bank_account",
+ "company",
+ "reference_number",
+ "party_type",
+ "party",
+ "unallocated_amount",
+ "allocated_amount",
+ ],
+ },
+ callback: (r) => {
+ if (r.message) {
+ this.bank_transaction = r.message;
+ r.message.payment_entry = 1;
+ this.dialog.set_values(r.message);
+ this.dialog.show();
+ }
+ },
+ });
+ }
+
+ get_linked_vouchers(document_types) {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_linked_payments",
+ args: {
+ bank_transaction_name: this.bank_transaction_name,
+ document_types: document_types,
+ },
+
+ callback: (result) => {
+ const data = result.message;
+
+
+ if (data && data.length > 0) {
+ const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper;
+ proposals_wrapper.show();
+ this.dialog.fields_dict.no_matching_vouchers.$wrapper.hide();
+ this.data = [];
+ data.forEach((row) => {
+ const reference_date = row[5] ? row[5] : row[8];
+ this.data.push([
+ row[1],
+ row[2],
+ reference_date,
+ format_currency(row[3], row[9]),
+ row[6],
+ row[4],
+ ]);
+ });
+ this.get_dt_columns();
+ this.get_datatable(proposals_wrapper);
+ } else {
+ const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper;
+ proposals_wrapper.hide();
+ this.dialog.fields_dict.no_matching_vouchers.$wrapper.show();
+
+ }
+ this.dialog.show();
+ },
+ });
+ }
+
+ get_dt_columns() {
+ this.columns = [
+ {
+ name: "Document Type",
+ editable: false,
+ width: 125,
+ },
+ {
+ name: "Document Name",
+ editable: false,
+ width: 150,
+ },
+ {
+ name: "Reference Date",
+ editable: false,
+ width: 120,
+ },
+ {
+ name: "Amount",
+ editable: false,
+ width: 100,
+ },
+ {
+ name: "Party",
+ editable: false,
+ width: 120,
+ },
+
+ {
+ name: "Reference Number",
+ editable: false,
+ width: 140,
+ },
+ ];
+ }
+
+ get_datatable(proposals_wrapper) {
+ if (!this.datatable) {
+ const datatable_options = {
+ columns: this.columns,
+ data: this.data,
+ dynamicRowHeight: true,
+ checkboxColumn: true,
+ inlineFilters: true,
+ };
+ this.datatable = new frappe.DataTable(
+ proposals_wrapper.get(0),
+ datatable_options
+ );
+ } else {
+ this.datatable.refresh(this.data, this.columns);
+ this.datatable.rowmanager.checkMap = [];
+ }
+ }
+
+ make_dialog() {
+ const me = this;
+ me.selected_payment = null;
+
+ const fields = [
+ {
+ label: __("Action"),
+ fieldname: "action",
+ fieldtype: "Select",
+ options: `Match Against Voucher\nCreate Voucher\nUpdate Bank Transaction`,
+ default: "Match Against Voucher",
+ },
+ {
+ fieldname: "column_break_4",
+ fieldtype: "Column Break",
+ },
+ {
+ label: __("Document Type"),
+ fieldname: "document_type",
+ fieldtype: "Select",
+ options: `Payment Entry\nJournal Entry`,
+ default: "Payment Entry",
+ depends_on: "eval:doc.action=='Create Voucher'",
+ },
+ {
+ fieldtype: "Section Break",
+ fieldname: "section_break_1",
+ label: __("Filters"),
+ depends_on: "eval:doc.action=='Match Against Voucher'",
+ },
+ {
+ fieldtype: "Check",
+ label: "Payment Entry",
+ fieldname: "payment_entry",
+ onchange: () => this.update_options(),
+ },
+ {
+ fieldtype: "Check",
+ label: "Journal Entry",
+ fieldname: "journal_entry",
+ onchange: () => this.update_options(),
+ },
+ {
+ fieldname: "column_break_5",
+ fieldtype: "Column Break",
+ },
+ {
+ fieldtype: "Check",
+ label: "Sales Invoice",
+ fieldname: "sales_invoice",
+ onchange: () => this.update_options(),
+ },
+
+ {
+ fieldtype: "Check",
+ label: "Purchase Invoice",
+ fieldname: "purchase_invoice",
+ onchange: () => this.update_options(),
+ },
+ {
+ fieldname: "column_break_5",
+ fieldtype: "Column Break",
+ },
+ {
+ fieldtype: "Check",
+ label: "Expense Claim",
+ fieldname: "expense_claim",
+ onchange: () => this.update_options(),
+ },
+ {
+ fieldtype: "Check",
+ label: "Show Only Exact Amount",
+ fieldname: "exact_match",
+ onchange: () => this.update_options(),
+ },
+ {
+ fieldtype: "Section Break",
+ fieldname: "section_break_1",
+ label: __("Select Vouchers to Match"),
+ depends_on: "eval:doc.action=='Match Against Voucher'",
+ },
+ {
+ fieldtype: "HTML",
+ fieldname: "payment_proposals",
+ },
+ {
+ fieldtype: "HTML",
+ fieldname: "no_matching_vouchers",
+ options: "<div class='text-muted text-center'>No Matching Vouchers Found</div>"
+ },
+ {
+ fieldtype: "Section Break",
+ fieldname: "details",
+ label: "Details",
+ depends_on: "eval:doc.action!='Match Against Voucher'",
+ },
+ {
+ fieldname: "reference_number",
+ fieldtype: "Data",
+ label: "Reference Number",
+ mandatory_depends_on: "eval:doc.action=='Create Voucher'",
+ },
+ {
+ default: "Today",
+ fieldname: "posting_date",
+ fieldtype: "Date",
+ label: "Posting Date",
+ reqd: 1,
+ depends_on: "eval:doc.action=='Create Voucher'",
+ },
+ {
+ fieldname: "reference_date",
+ fieldtype: "Date",
+ label: "Cheque/Reference Date",
+ mandatory_depends_on: "eval:doc.action=='Create Voucher'",
+ depends_on: "eval:doc.action=='Create Voucher'",
+ reqd: 1,
+ },
+ {
+ fieldname: "mode_of_payment",
+ fieldtype: "Link",
+ label: "Mode of Payment",
+ options: "Mode of Payment",
+ depends_on: "eval:doc.action=='Create Voucher'",
+ },
+ {
+ fieldname: "edit_in_full_page",
+ fieldtype: "Button",
+ label: "Edit in Full Page",
+ click: () => {
+ this.edit_in_full_page();
+ },
+ depends_on:
+ "eval:doc.action=='Create Voucher'",
+ },
+ {
+ fieldname: "column_break_7",
+ fieldtype: "Column Break",
+ },
+ {
+ default: "Journal Entry Type",
+ fieldname: "journal_entry_type",
+ fieldtype: "Select",
+ label: "Journal Entry Type",
+ options:
+ "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nDeferred Revenue\nDeferred Expense",
+ depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'",
+ mandatory_depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'",
+ },
+ {
+ fieldname: "second_account",
+ fieldtype: "Link",
+ label: "Account",
+ options: "Account",
+ depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'",
+ mandatory_depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Journal Entry'",
+ get_query: () => {
+ return {
+ filters: {
+ is_group: 0,
+ company: this.company,
+ },
+ };
+ },
+ },
+ {
+ fieldname: "party_type",
+ fieldtype: "Link",
+ label: "Party Type",
+ options: "DocType",
+ mandatory_depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+ get_query: function () {
+ return {
+ filters: {
+ name: [
+ "in",
+ Object.keys(frappe.boot.party_account_types),
+ ],
+ },
+ };
+ },
+ },
+ {
+ fieldname: "party",
+ fieldtype: "Dynamic Link",
+ label: "Party",
+ options: "party_type",
+ mandatory_depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+ },
+ {
+ fieldname: "project",
+ fieldtype: "Link",
+ label: "Project",
+ options: "Project",
+ depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+ },
+ {
+ fieldname: "cost_center",
+ fieldtype: "Link",
+ label: "Cost Center",
+ options: "Cost Center",
+ depends_on:
+ "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+ },
+ {
+ fieldtype: "Section Break",
+ fieldname: "details_section",
+ label: "Transaction Details",
+ collapsible: 1,
+ },
+ {
+ fieldname: "deposit",
+ fieldtype: "Currency",
+ label: "Deposit",
+ read_only: 1,
+ },
+ {
+ fieldname: "withdrawal",
+ fieldtype: "Currency",
+ label: "Withdrawal",
+ read_only: 1,
+ },
+ {
+ fieldname: "description",
+ fieldtype: "Small Text",
+ label: "Description",
+ read_only: 1,
+ },
+ {
+ fieldname: "column_break_17",
+ fieldtype: "Column Break",
+ read_only: 1,
+ },
+ {
+ fieldname: "allocated_amount",
+ fieldtype: "Currency",
+ label: "Allocated Amount",
+ read_only: 1,
+ },
+
+ {
+ fieldname: "unallocated_amount",
+ fieldtype: "Currency",
+ label: "Unallocated Amount",
+ read_only: 1,
+ },
+ ];
+
+ me.dialog = new frappe.ui.Dialog({
+ title: __("Reconcile the Bank Transaction"),
+ fields: fields,
+ size: "large",
+ primary_action: (values) =>
+ this.reconciliation_dialog_primary_action(values),
+ });
+ }
+
+ get_selected_attributes() {
+ let selected_attributes = [];
+ this.dialog.$wrapper.find(".checkbox input").each((i, col) => {
+ if ($(col).is(":checked")) {
+ selected_attributes.push($(col).attr("data-fieldname"));
+ }
+ });
+
+ return selected_attributes;
+ }
+
+ update_options() {
+ let selected_attributes = this.get_selected_attributes();
+ this.get_linked_vouchers(selected_attributes);
+ }
+
+ reconciliation_dialog_primary_action(values) {
+ if (values.action == "Match Against Voucher") this.match(values);
+ if (
+ values.action == "Create Voucher" &&
+ values.document_type == "Payment Entry"
+ )
+ this.add_payment_entry(values);
+ if (
+ values.action == "Create Voucher" &&
+ values.document_type == "Journal Entry"
+ )
+ this.add_journal_entry(values);
+ else if (values.action == "Update Bank Transaction")
+ this.update_transaction(values);
+ }
+
+ match() {
+ var selected_map = this.datatable.rowmanager.checkMap;
+ let rows = [];
+ selected_map.forEach((val, index) => {
+ if (val == 1) rows.push(this.datatable.datamanager.rows[index]);
+ });
+ let vouchers = [];
+ rows.forEach((x) => {
+ vouchers.push({
+ payment_doctype: x[2].content,
+ payment_name: x[3].content,
+ amount: x[5].content,
+ });
+ });
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.reconcile_vouchers",
+ args: {
+ bank_transaction_name: this.bank_transaction.name,
+ vouchers: vouchers,
+ },
+ callback: (response) => {
+ const alert_string =
+ "Bank Transaction " +
+ this.bank_transaction.name +
+ " Matched";
+ frappe.show_alert(alert_string);
+ this.update_dt_cards(response.message);
+ this.dialog.hide();
+ },
+ });
+ }
+
+ add_payment_entry(values) {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts",
+ args: {
+ bank_transaction_name: this.bank_transaction.name,
+ reference_number: values.reference_number,
+ reference_date: values.reference_date,
+ party_type: values.party_type,
+ party: values.party,
+ posting_date: values.posting_date,
+ mode_of_payment: values.mode_of_payment,
+ project: values.project,
+ cost_center: values.cost_center,
+ },
+ callback: (response) => {
+ const alert_string =
+ "Bank Transaction " +
+ this.bank_transaction.name +
+ " added as Payment Entry";
+ frappe.show_alert(alert_string);
+ this.update_dt_cards(response.message);
+ this.dialog.hide();
+ },
+ });
+ }
+
+ add_journal_entry(values) {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts",
+ args: {
+ bank_transaction_name: this.bank_transaction.name,
+ reference_number: values.reference_number,
+ reference_date: values.reference_date,
+ party_type: values.party_type,
+ party: values.party,
+ posting_date: values.posting_date,
+ mode_of_payment: values.mode_of_payment,
+ entry_type: values.journal_entry_type,
+ second_account: values.second_account,
+ },
+ callback: (response) => {
+ const alert_string =
+ "Bank Transaction " +
+ this.bank_transaction.name +
+ " added as Journal Entry";
+ frappe.show_alert(alert_string);
+ this.update_dt_cards(response.message);
+ this.dialog.hide();
+ },
+ });
+ }
+
+ update_transaction(values) {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.update_bank_transaction",
+ args: {
+ bank_transaction_name: this.bank_transaction.name,
+ reference_number: values.reference_number,
+ party_type: values.party_type,
+ party: values.party,
+ },
+ callback: (response) => {
+ const alert_string =
+ "Bank Transaction " +
+ this.bank_transaction.name +
+ " updated";
+ frappe.show_alert(alert_string);
+ this.update_dt_cards(response.message);
+ this.dialog.hide();
+ },
+ });
+ }
+
+ edit_in_full_page() {
+ const values = this.dialog.get_values(true);
+ if (values.document_type == "Payment Entry") {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts",
+ args: {
+ bank_transaction_name: this.bank_transaction.name,
+ reference_number: values.reference_number,
+ reference_date: values.reference_date,
+ party_type: values.party_type,
+ party: values.party,
+ posting_date: values.posting_date,
+ mode_of_payment: values.mode_of_payment,
+ project: values.project,
+ cost_center: values.cost_center,
+ allow_edit: true
+ },
+ callback: (r) => {
+ const doc = frappe.model.sync(r.message);
+ frappe.set_route("Form", doc[0].doctype, doc[0].name);
+ },
+ });
+ } else {
+ frappe.call({
+ method:
+ "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts",
+ args: {
+ bank_transaction_name: this.bank_transaction.name,
+ reference_number: values.reference_number,
+ reference_date: values.reference_date,
+ party_type: values.party_type,
+ party: values.party,
+ posting_date: values.posting_date,
+ mode_of_payment: values.mode_of_payment,
+ entry_type: values.journal_entry_type,
+ second_account: values.second_account,
+ allow_edit: true
+ },
+ callback: (r) => {
+ var doc = frappe.model.sync(r.message);
+ frappe.set_route("Form", doc[0].doctype, doc[0].name);
+ },
+ });
+ }
+ }
+
+};
diff --git a/erpnext/public/js/bank_reconciliation_tool/number_card.js b/erpnext/public/js/bank_reconciliation_tool/number_card.js
new file mode 100644
index 0000000..e10d109
--- /dev/null
+++ b/erpnext/public/js/bank_reconciliation_tool/number_card.js
@@ -0,0 +1,75 @@
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+erpnext.accounts.bank_reconciliation.NumberCardManager = class NumberCardManager {
+ constructor(opts) {
+ Object.assign(this, opts);
+ this.make_cards();
+ }
+
+ make_cards() {
+ this.$reconciliation_tool_cards.empty();
+ this.$cards = [];
+ this.$summary = $(`<div class="report-summary"></div>`)
+ .hide()
+ .appendTo(this.$reconciliation_tool_cards);
+ var chart_data = [
+ {
+ value: this.bank_statement_closing_balance,
+ label: "Closing Balance as per Bank Statement",
+ datatype: "Currency",
+ currency: this.currency,
+ },
+ {
+ value: this.cleared_balance,
+ label: "Closing Balance as per ERP",
+ datatype: "Currency",
+ currency: this.currency,
+ },
+ {
+ value:
+ this.bank_statement_closing_balance - this.cleared_balance,
+ label: "Difference",
+ datatype: "Currency",
+ currency: this.currency,
+ },
+ ];
+
+ chart_data.forEach((summary) => {
+ let number_card = new erpnext.accounts.NumberCard(summary);
+ this.$cards.push(number_card);
+
+ number_card.$card.appendTo(this.$summary);
+ });
+ this.$cards[2].set_value_color(
+ this.bank_statement_closing_balance - this.cleared_balance == 0
+ ? "text-success"
+ : "text-danger"
+ );
+ this.$summary.css({"border-bottom": "0px", "margin-left": "0px", "margin-right": "0px"});
+ this.$summary.show();
+ }
+};
+
+erpnext.accounts.NumberCard = class NumberCard {
+ constructor(options) {
+ this.$card = frappe.utils.build_summary_item(options);
+ }
+
+ set_value(value) {
+ this.$card.find("div").text(value);
+ }
+
+ set_value_color(color) {
+ this.$card
+ .find("div")
+ .removeClass("text-danger text-success")
+ .addClass(`${color}`);
+ }
+
+ set_indicator(color) {
+ this.$card
+ .find("span")
+ .removeClass("indicator red green")
+ .addClass(`indicator ${color}`);
+ }
+};
diff --git a/erpnext/public/js/call_popup/call_popup.js b/erpnext/public/js/call_popup/call_popup.js
index 5e4d4a5..c954f12 100644
--- a/erpnext/public/js/call_popup/call_popup.js
+++ b/erpnext/public/js/call_popup/call_popup.js
@@ -7,103 +7,25 @@
}
make() {
+ frappe.utils.play_sound('incoming-call');
this.dialog = new frappe.ui.Dialog({
'static': true,
- 'minimizable': true,
- 'fields': [{
- 'fieldname': 'name',
- 'label': 'Name',
- 'default': this.get_caller_name() || __('Unknown Caller'),
- 'fieldtype': 'Data',
- 'read_only': 1
- }, {
- 'fieldtype': 'Button',
- 'label': __('Open Contact'),
- 'click': () => frappe.set_route('Form', 'Contact', this.call_log.contact),
- 'depends_on': () => this.call_log.contact
- }, {
- 'fieldtype': 'Button',
- 'label': __('Open Lead'),
- 'click': () => frappe.set_route('Form', 'Lead', this.call_log.lead),
- 'depends_on': () => this.call_log.lead
- }, {
- 'fieldtype': 'Button',
- 'label': __('Create New Contact'),
- 'click': () => frappe.new_doc('Contact', { 'mobile_no': this.caller_number }),
- 'depends_on': () => !this.get_caller_name()
- }, {
- 'fieldtype': 'Button',
- 'label': __('Create New Lead'),
- 'click': () => frappe.new_doc('Lead', { 'mobile_no': this.caller_number }),
- 'depends_on': () => !this.get_caller_name()
- }, {
- 'fieldtype': 'Column Break',
- }, {
- 'fieldname': 'number',
- 'label': 'Phone Number',
- 'fieldtype': 'Data',
- 'default': this.caller_number,
- 'read_only': 1
- }, {
- 'fielname': 'last_interaction',
- 'fieldtype': 'Section Break',
- 'label': __('Activity'),
- 'depends_on': () => this.get_caller_name()
- }, {
- 'fieldtype': 'Small Text',
- 'label': __('Last Issue'),
- 'fieldname': 'last_issue',
- 'read_only': true,
- 'depends_on': () => this.call_log.contact,
- 'default': `<i class="text-muted">${__('No issue has been raised by the caller.')}<i>`
- }, {
- 'fieldtype': 'Small Text',
- 'label': __('Last Communication'),
- 'fieldname': 'last_communication',
- 'read_only': true,
- 'default': `<i class="text-muted">${__('No communication found.')}<i>`
- }, {
- 'fieldtype': 'Section Break',
- }, {
- 'fieldtype': 'Small Text',
- 'label': __('Call Summary'),
- 'fieldname': 'call_summary',
- }, {
- 'fieldtype': 'Button',
- 'label': __('Save'),
- 'click': () => {
- const call_summary = this.dialog.get_value('call_summary');
- if (!call_summary) return;
- frappe.xcall('erpnext.communication.doctype.call_log.call_log.add_call_summary', {
- 'call_log': this.call_log.name,
- 'summary': call_summary,
- }).then(() => {
- this.close_modal();
- frappe.show_alert({
- message: `
- ${__('Call Summary Saved')}
- <br>
- <a
- class="text-small text-muted"
- href="#Form/Call Log/${this.call_log.name}">
- ${__('View call log')}
- </a>
- `,
- indicator: 'green'
- });
- });
- }
- }],
+ 'minimizable': true
});
- this.set_call_status();
this.dialog.get_close_btn().show();
- this.make_last_interaction_section();
- this.dialog.$body.addClass('call-popup');
- this.dialog.set_secondary_action(this.close_modal.bind(this));
- frappe.utils.play_sound('incoming-call');
+ this.setup_dialog();
+ this.set_call_status();
+ frappe.utils.bind_actions_with_object(this.dialog.$body, this);
+ this.dialog.$wrapper.addClass('call-popup');
+ this.dialog.get_close_btn().unbind('click').click(this.close_modal.bind(this));
this.dialog.show();
}
+ setup_dialog() {
+ this.setup_call_details();
+ this.dialog.$body.empty().append(this.caller_info);
+ }
+
set_indicator(color, blink=false) {
let classes = `indicator ${color} ${blink ? 'blink': ''}`;
this.dialog.header.find('.indicator').attr('class', classes);
@@ -117,13 +39,13 @@
this.set_indicator('blue', true);
} else if (call_status === 'In Progress') {
title = __('Call Connected');
+ this.set_indicator('green');
+ } else if (['No Answer', 'Missed'].includes(call_status)) {
this.set_indicator('yellow');
- } else if (call_status === 'Missed') {
- this.set_indicator('red');
title = __('Call Missed');
- } else if (['Completed', 'Disconnected'].includes(call_status)) {
+ } else if (['Completed', 'Busy', 'Failed'].includes(call_status)) {
this.set_indicator('red');
- title = __('Call Disconnected');
+ title = __('Call Ended');
} else {
this.set_indicator('blue');
title = call_status;
@@ -131,9 +53,9 @@
this.dialog.set_title(title);
}
- update_call_log(call_log) {
+ update_call_log(call_log, missed) {
this.call_log = call_log;
- this.set_call_status();
+ this.set_call_status(missed ? 'Missed': null);
}
close_modal() {
@@ -141,61 +63,149 @@
delete erpnext.call_popup;
}
- call_disconnected(call_log) {
+ call_ended(call_log, missed) {
frappe.utils.play_sound('call-disconnect');
- this.update_call_log(call_log);
+ this.update_call_log(call_log, missed);
setTimeout(() => {
if (!this.dialog.get_value('call_summary')) {
this.close_modal();
}
- }, 30000);
- }
-
- make_last_interaction_section() {
- frappe.xcall('erpnext.crm.doctype.utils.get_last_interaction', {
- 'contact': this.call_log.contact,
- 'lead': this.call_log.lead
- }).then(data => {
- const comm_field = this.dialog.get_field('last_communication');
- if (data.last_communication) {
- const comm = data.last_communication;
- comm_field.set_value(comm.content);
- }
-
- if (data.last_issue) {
- const issue = data.last_issue;
- const issue_field = this.dialog.get_field("last_issue");
- issue_field.set_value(issue.subject);
- issue_field.$wrapper.append(`
- <a class="text-medium" href="#List/Issue?customer=${issue.customer}">
- ${__('View all issues from {0}', [issue.customer])}
- </a>
- `);
- }
- });
+ }, 60000);
+ this.clear_listeners();
}
get_caller_name() {
+ const contact_link = this.get_contact_link();
+ return contact_link.link_title || contact_link.link_name;
+ }
+
+ get_contact_link() {
let log = this.call_log;
- return log.contact_name || log.lead_name;
+ let contact_link = log.links.find(d => d.link_doctype === 'Contact');
+ return contact_link || {};
}
setup_listener() {
- frappe.realtime.on(`call_${this.call_log.id}_disconnected`, call_log => {
- this.call_disconnected(call_log);
- // Remove call disconnect listener after the call is disconnected
- frappe.realtime.off(`call_${this.call_log.id}_disconnected`);
+ frappe.realtime.on(`call_${this.call_log.id}_ended`, call_log => {
+ this.call_ended(call_log);
});
+
+ frappe.realtime.on(`call_${this.call_log.id}_missed`, call_log => {
+ this.call_ended(call_log, true);
+ });
+ }
+
+ clear_listeners() {
+ frappe.realtime.off(`call_${this.call_log.id}_ended`);
+ frappe.realtime.off(`call_${this.call_log.id}_missed`);
+ }
+
+ setup_call_details() {
+ this.caller_info = $(`<div></div>`);
+ this.call_details = new frappe.ui.FieldGroup({
+ fields: [{
+ 'fieldname': 'name',
+ 'label': 'Name',
+ 'default': this.get_caller_name() || __('Unknown Caller'),
+ 'fieldtype': 'Data',
+ 'read_only': 1
+ }, {
+ 'fieldtype': 'Button',
+ 'label': __('Open Contact'),
+ 'click': () => frappe.set_route('Form', 'Contact', this.get_contact_link().link_name),
+ 'depends_on': () => this.get_caller_name()
+ }, {
+ 'fieldtype': 'Button',
+ 'label': __('Create New Contact'),
+ 'click': this.create_new_contact.bind(this),
+ 'depends_on': () => !this.get_caller_name()
+ }, {
+ 'fieldtype': 'Button',
+ 'label': __('Create New Customer'),
+ 'click': this.create_new_customer.bind(this),
+ 'depends_on': () => !this.get_caller_name()
+ }, {
+ 'fieldtype': 'Button',
+ 'label': __('Create New Lead'),
+ 'click': () => frappe.new_doc('Lead', { 'mobile_no': this.caller_number }),
+ 'depends_on': () => !this.get_caller_name()
+ }, {
+ 'fieldtype': 'Column Break',
+ }, {
+ 'fieldname': 'number',
+ 'label': 'Phone Number',
+ 'fieldtype': 'Data',
+ 'default': this.caller_number,
+ 'read_only': 1
+ }, {
+ 'fieldtype': 'Section Break',
+ 'hide_border': 1,
+ }, {
+ 'fieldtype': 'Small Text',
+ 'label': __('Call Summary'),
+ 'fieldname': 'call_summary',
+ }, {
+ 'fieldtype': 'Button',
+ 'label': __('Save'),
+ 'click': () => {
+ const call_summary = this.call_details.get_value('call_summary');
+ if (!call_summary) return;
+ frappe.xcall('erpnext.telephony.doctype.call_log.call_log.add_call_summary', {
+ 'call_log': this.call_log.name,
+ 'summary': call_summary,
+ }).then(() => {
+ this.close_modal();
+ frappe.show_alert({
+ message: `
+ ${__('Call Summary Saved')}
+ <br>
+ <a
+ class="text-small text-muted"
+ href="/app/call-log/${this.call_log.name}">
+ ${__('View call log')}
+ </a>
+ `,
+ indicator: 'green'
+ });
+ });
+ }
+ }],
+ body: this.caller_info
+ });
+ this.call_details.make();
+ }
+
+ is_known_caller() {
+ return Boolean(this.get_caller_name());
+ }
+
+ create_new_customer() {
+ // to avoid quick entry form
+ const new_customer = frappe.model.get_new_doc('Customer');
+ new_customer.mobile_no = this.caller_number;
+ frappe.set_route('Form', new_customer.doctype, new_customer.name);
+ }
+
+ create_new_contact() {
+ // TODO: fix new_doc, it should accept child table values
+ const new_contact = frappe.model.get_new_doc('Contact');
+ const phone_no = frappe.model.add_child(new_contact, 'Contact Phone', 'phone_nos');
+ phone_no.phone = this.caller_number;
+ phone_no.is_primary_mobile_no = 1;
+ frappe.set_route('Form', new_contact.doctype, new_contact.name);
}
}
$(document).on('app_ready', function () {
frappe.realtime.on('show_call_popup', call_log => {
- if (!erpnext.call_popup) {
- erpnext.call_popup = new CallPopup(call_log);
+ let call_popup = erpnext.call_popup;
+ if (call_popup && call_log.name === call_popup.call_log.name) {
+ call_popup.update_call_log(call_log);
+ call_popup.dialog.show();
} else {
- erpnext.call_popup.update_call_log(call_log);
- erpnext.call_popup.dialog.show();
+ erpnext.call_popup = new CallPopup(call_log);
}
});
});
+
+window.CallPopup = CallPopup;
diff --git a/erpnext/public/js/communication.js b/erpnext/public/js/communication.js
index 26e5ab8..7ce8b09 100644
--- a/erpnext/public/js/communication.js
+++ b/erpnext/public/js/communication.js
@@ -84,7 +84,7 @@
frm.reload_doc();
frappe.show_alert({
message: __("Opportunity {0} created",
- ['<a href="#Form/Opportunity/'+r.message+'">' + r.message + '</a>']),
+ ['<a href="/app/opportunity/'+r.message+'">' + r.message + '</a>']),
indicator: 'green'
});
}
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 6e97d81..649eb45 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -31,15 +31,6 @@
}
}
});
-
- frm.set_query("cost_center", "taxes", function(doc) {
- return {
- filters: {
- 'company': doc.company,
- "is_group": 0
- }
- }
- });
}
},
validate: function(frm) {
@@ -146,18 +137,18 @@
if(!d.charge_type && d.account_head){
frappe.msgprint(__("Please select Charge Type first"));
frappe.model.set_value(cdt, cdn, "account_head", "");
- } else if(d.account_head && d.charge_type!=="Actual") {
+ } else if (d.account_head) {
frappe.call({
type:"GET",
method: "erpnext.controllers.accounts_controller.get_tax_rate",
args: {"account_head":d.account_head},
callback: function(r) {
- frappe.model.set_value(cdt, cdn, "rate", r.message.tax_rate || 0);
+ if (d.charge_type!=="Actual") {
+ frappe.model.set_value(cdt, cdn, "rate", r.message.tax_rate || 0);
+ }
frappe.model.set_value(cdt, cdn, "description", r.message.account_name);
}
})
- } else if (d.charge_type == 'Actual' && d.account_head) {
- frappe.model.set_value(cdt, cdn, "description", d.account_head.split(' - ')[0]);
}
}
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cb76c87..67b12fb 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -141,29 +141,6 @@
this.apply_price_list();
},
- price_list_rate: function(doc, cdt, cdn) {
- var item = frappe.get_doc(cdt, cdn);
-
- frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
-
- let item_rate = item.price_list_rate;
- if (doc.doctype == "Purchase Order" && item.blanket_order_rate) {
- item_rate = item.blanket_order_rate;
- }
-
- if (item.discount_percentage) {
- item.discount_amount = flt(item_rate) * flt(item.discount_percentage) / 100;
- }
-
- if (item.discount_amount) {
- item.rate = flt((item.price_list_rate) - (item.discount_amount), precision('rate', item));
- } else {
- item.rate = item_rate;
- }
-
- this.calculate_taxes_and_totals();
- },
-
discount_percentage: function(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
item.discount_amount = 0.0;
@@ -189,8 +166,12 @@
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._super(doc, cdt, cdn);
+ },
+ batch_no: function(doc, cdt, cdn) {
this._super(doc, cdt, cdn);
},
@@ -218,8 +199,7 @@
var is_negative_qty = false;
for(var i = 0; i<fieldnames.length; i++) {
if(item[fieldnames[i]] < 0){
- frappe.msgprint(__("Row #{0}: {1} can not be negative for item {2}",
- [item.idx,__(frappe.meta.get_label(cdt, fieldnames[i], cdn)), item.item_code]));
+ frappe.msgprint(__("Row #{0}: {1} can not be negative for item {2}", [item.idx,__(frappe.meta.get_label(cdt, fieldnames[i], cdn)), item.item_code]));
is_negative_qty = true;
break;
}
@@ -276,7 +256,7 @@
var me = this;
this.frm.add_custom_button(__("Product Bundle"), function() {
erpnext.buying.get_items_from_product_bundle(me.frm);
- }, __("Get items from"));
+ }, __("Get Items From"));
},
shipping_address: function(){
@@ -294,69 +274,6 @@
this.get_terms();
},
- link_to_mrs: function() {
- var my_items = [];
- for (var i in cur_frm.doc.items) {
- if(!cur_frm.doc.items[i].material_request){
- my_items.push(cur_frm.doc.items[i].item_code);
- }
- }
- frappe.call({
- method: "erpnext.buying.utils.get_linked_material_requests",
- args:{
- items: my_items
- },
- callback: function(r) {
- if(!r.message || r.message.length == 0) {
- frappe.throw(__("No pending Material Requests found to link for the given items."))
- }
- else {
- var i = 0;
- var item_length = cur_frm.doc.items.length;
- while (i < item_length) {
- var qty = cur_frm.doc.items[i].qty;
- (r.message[0] || []).forEach(function(d) {
- if (d.qty > 0 && qty > 0 && cur_frm.doc.items[i].item_code == d.item_code && !cur_frm.doc.items[i].material_request_item)
- {
- cur_frm.doc.items[i].material_request = d.mr_name;
- cur_frm.doc.items[i].material_request_item = d.mr_item;
- var my_qty = Math.min(qty, d.qty);
- qty = qty - my_qty;
- d.qty = d.qty - my_qty;
- cur_frm.doc.items[i].stock_qty = my_qty*cur_frm.doc.items[i].conversion_factor;
- cur_frm.doc.items[i].qty = my_qty;
-
- frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
- if (qty > 0)
- {
- frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
- var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
- item_length++;
-
- for (var key in cur_frm.doc.items[i])
- {
- newrow[key] = cur_frm.doc.items[i][key];
- }
-
- newrow.idx = item_length;
- newrow["stock_qty"] = newrow.conversion_factor*qty;
- newrow["qty"] = qty;
-
- newrow["material_request"] = "";
- newrow["material_request_item"] = "";
-
- }
- }
- });
- i++;
- }
- refresh_field("items");
- //cur_frm.save();
- }
- }
- });
- },
-
update_auto_repeat_reference: function(doc) {
if (doc.auto_repeat) {
frappe.call({
@@ -422,6 +339,62 @@
cur_frm.add_fetch('project', 'cost_center', 'cost_center');
+erpnext.buying.link_to_mrs = function(frm) {
+ frappe.call({
+ method: "erpnext.buying.utils.get_linked_material_requests",
+ args:{
+ items: frm.doc.items.map((item) => item.item_code)
+ },
+ callback: function(r) {
+ if (!r.message || r.message.length == 0) {
+ frappe.throw({
+ message: __("No pending Material Requests found to link for the given items."),
+ title: __("Note")
+ });
+ }
+
+ var item_length = frm.doc.items.length;
+ for (let item of frm.doc.items) {
+ var qty = item.qty;
+ (r.message[0] || []).forEach(function(d) {
+ if (d.qty > 0 && qty > 0 && item.item_code == d.item_code && !item.material_request_item)
+ {
+ item.material_request = d.mr_name;
+ item.material_request_item = d.mr_item;
+ var my_qty = Math.min(qty, d.qty);
+ qty = qty - my_qty;
+ d.qty = d.qty - my_qty;
+ item.stock_qty = my_qty*item.conversion_factor;
+ item.qty = my_qty;
+
+ frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + item.idx + ")");
+ if (qty > 0)
+ {
+ frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
+ var newrow = frappe.model.add_child(frm.doc, item.doctype, "items");
+ item_length++;
+
+ for (var key in item)
+ {
+ newrow[key] = item[key];
+ }
+
+ newrow.idx = item_length;
+ newrow["stock_qty"] = newrow.conversion_factor*qty;
+ newrow["qty"] = qty;
+
+ newrow["material_request"] = "";
+ newrow["material_request_item"] = "";
+
+ }
+ }
+ });
+ }
+ refresh_field("items");
+ }
+ });
+}
+
erpnext.buying.get_default_bom = function(frm) {
$.each(frm.doc["items"] || [], function(i, d) {
if (d.item_code && d.bom === "") {
@@ -523,4 +496,4 @@
});
dialog.show();
-}
+}
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index be30086..3a3ee38 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -2,10 +2,13 @@
// License: GNU General Public License v3. See license.txt
erpnext.taxes_and_totals = erpnext.payments.extend({
- setup: function() {},
+ setup: function() {
+ this.fetch_round_off_accounts();
+ },
- apply_pricing_rule_on_item: function(item){
+ apply_pricing_rule_on_item: function(item) {
let effective_item_rate = item.price_list_rate;
+ let item_rate = item.rate;
if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) {
effective_item_rate = item.blanket_order_rate;
}
@@ -17,15 +20,18 @@
}
item.base_rate_with_margin = flt(item.rate_with_margin) * flt(this.frm.doc.conversion_rate);
- item.rate = flt(item.rate_with_margin , precision("rate", item));
+ item_rate = flt(item.rate_with_margin , precision("rate", item));
if(item.discount_percentage){
item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100;
}
if (item.discount_amount) {
- item.rate = flt((item.rate_with_margin) - (item.discount_amount), precision('rate', item));
+ item_rate = flt((item.rate_with_margin) - (item.discount_amount), precision('rate', item));
+ item.discount_percentage = 100 * flt(item.discount_amount) / flt(item.rate_with_margin);
}
+
+ frappe.model.set_value(item.doctype, item.name, "rate", item_rate);
},
calculate_taxes_and_totals: function(update_paid_amount) {
@@ -88,11 +94,8 @@
if(this.frm.doc.currency == company_currency) {
this.frm.set_value("conversion_rate", 1);
} else {
- const err_message = __('{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}', [
- conversion_rate_label,
- this.frm.doc.currency,
- company_currency
- ]);
+ const subs = [conversion_rate_label, this.frm.doc.currency, company_currency];
+ const err_message = __('{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}', subs);
frappe.throw(err_message);
}
}
@@ -151,6 +154,24 @@
});
},
+ fetch_round_off_accounts: function() {
+ let me = this;
+ frappe.flags.round_off_applicable_accounts = [];
+
+ if (me.frm.doc.company) {
+ return frappe.call({
+ "method": "erpnext.controllers.taxes_and_totals.get_round_off_applicable_accounts",
+ "args": {
+ "company": me.frm.doc.company,
+ "account_list": frappe.flags.round_off_applicable_accounts
+ },
+ callback: function(r) {
+ frappe.flags.round_off_applicable_accounts.push(...r.message);
+ }
+ });
+ }
+ },
+
determine_exclusive_rate: function() {
var me = this;
@@ -371,11 +392,21 @@
} else if (tax.charge_type == "On Item Quantity") {
current_tax_amount = tax_rate * item.qty;
}
+
+ current_tax_amount = this.get_final_tax_amount(tax, current_tax_amount);
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
return current_tax_amount;
},
+ get_final_tax_amount: function(tax, current_tax_amount) {
+ if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
+ current_tax_amount = Math.round(current_tax_amount);
+ }
+
+ return current_tax_amount;
+ },
+
set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item
let tax_detail = tax.item_wise_tax_detail;
@@ -609,6 +640,15 @@
this.calculate_outstanding_amount(update_paid_amount);
},
+ is_internal_invoice: function() {
+ if (['Sales Invoice', 'Purchase Invoice'].includes(this.frm.doc.doctype)) {
+ if (this.frm.doc.company === this.frm.doc.represents_company) {
+ return true;
+ }
+ }
+ return false;
+ },
+
calculate_outstanding_amount: function(update_paid_amount) {
// NOTE:
// paid_amount and write_off_amount is only for POS/Loyalty Point Redemption Invoice
@@ -617,7 +657,7 @@
this.calculate_paid_amount();
}
- if(this.frm.doc.is_return || this.frm.doc.docstatus > 0) return;
+ if (this.frm.doc.is_return || (this.frm.doc.docstatus > 0) || this.is_internal_invoice()) return;
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount"]);
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 3391179..32d371d 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1,6 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+frappe.provide('erpnext.accounts.dimensions');
+
erpnext.TransactionController = erpnext.taxes_and_totals.extend({
setup: function() {
this._super();
@@ -38,7 +40,7 @@
cur_frm.cscript.set_gross_profit(item);
cur_frm.cscript.calculate_taxes_and_totals();
-
+ cur_frm.cscript.calculate_stock_uom_rate(frm, cdt, cdn);
});
@@ -103,9 +105,19 @@
frappe.ui.form.on(this.frm.doctype + " Item", {
items_add: function(frm, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
- if(!item.warehouse && frm.doc.set_warehouse) {
+ if (!item.warehouse && frm.doc.set_warehouse) {
item.warehouse = frm.doc.set_warehouse;
}
+
+ if (!item.target_warehouse && frm.doc.set_target_warehouse) {
+ item.target_warehouse = frm.doc.set_target_warehouse;
+ }
+
+ if (!item.from_warehouse && frm.doc.set_from_warehouse) {
+ item.from_warehouse = frm.doc.set_from_warehouse;
+ }
+
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(frm, cdt, cdn, 'items');
}
});
@@ -159,16 +171,6 @@
};
});
}
- if (this.frm.fields_dict["items"].grid.get_field("cost_center")) {
- this.frm.set_query("cost_center", "items", function(doc) {
- return {
- filters: {
- "company": doc.company,
- "is_group": 0
- }
- };
- });
- }
if (this.frm.fields_dict["items"].grid.get_field("expense_account")) {
this.frm.set_query("expense_account", "items", function(doc) {
@@ -209,6 +211,17 @@
});
}
+ if (this.frm.fields_dict.taxes_and_charges) {
+ this.frm.set_query("taxes_and_charges", function() {
+ return {
+ filters: [
+ ['company', '=', me.frm.doc.company],
+ ['docstatus', '!=', 2]
+ ]
+ };
+ });
+ }
+
},
onload: function() {
var me = this;
@@ -222,6 +235,8 @@
}
};
+ this.frm.trigger('set_default_internal_warehouse');
+
return frappe.run_serially([
() => set_value('currency', currency),
() => set_value('price_list_currency', currency),
@@ -352,9 +367,15 @@
let show_description = function(idx, exist = null) {
if (exist) {
- scan_barcode_field.set_new_description(__('Row #{0}: Qty increased by 1', [idx]));
+ frappe.show_alert({
+ message: __('Row #{0}: Qty increased by 1', [idx]),
+ indicator: 'green'
+ });
} else {
- scan_barcode_field.set_new_description(__('Row #{0}: Item added', [idx]));
+ frappe.show_alert({
+ message: __('Row #{0}: Item added', [idx]),
+ indicator: 'green'
+ });
}
}
@@ -365,7 +386,10 @@
}).then(r => {
const data = r && r.message;
if (!data || Object.keys(data).length === 0) {
- scan_barcode_field.set_new_description(__('Cannot find Item with this barcode'));
+ frappe.show_alert({
+ message: __('Cannot find Item with this Barcode'),
+ indicator: 'red'
+ });
return;
}
@@ -388,7 +412,7 @@
show_description(row_to_modify.idx, row_to_modify.item_code);
- this.frm.from_barcode = true;
+ 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
@@ -426,9 +450,10 @@
method: "erpnext.controllers.accounts_controller.get_default_taxes_and_charges",
args: {
"master_doctype": taxes_and_charges_field.options,
- "tax_template": me.frm.doc.taxes_and_charges,
+ "tax_template": me.frm.doc.taxes_and_charges || "",
"company": me.frm.doc.company
},
+ debounce: 2000,
callback: function(r) {
if(!r.exc && r.message) {
frappe.run_serially([
@@ -472,7 +497,7 @@
d.item_code = "";
}
- this.frm.from_barcode = true;
+ this.frm.from_barcode = this.frm.from_barcode ? this.frm.from_barcode + 1 : 1;
this.item_code(doc, cdt, cdn);
},
@@ -489,11 +514,12 @@
show_batch_dialog = 1;
}
// clear barcode if setting item (else barcode will take priority)
- if(!this.frm.from_barcode) {
+ if (this.frm.from_barcode == 0) {
item.barcode = null;
}
+ this.frm.from_barcode = this.frm.from_barcode - 1 >= 0 ? this.frm.from_barcode - 1 : 0;
- this.frm.from_barcode = false;
+
if(item.item_code || item.barcode || item.serial_no) {
if(!this.validate_company_and_party()) {
this.frm.fields_dict["items"].grid.grid_rows[item.idx - 1].remove();
@@ -522,6 +548,7 @@
company: me.frm.doc.company,
order_type: me.frm.doc.order_type,
is_pos: cint(me.frm.doc.is_pos),
+ is_return: cint(me.frm.doc.is_return),
is_subcontracted: me.frm.doc.is_subcontracted,
transaction_date: me.frm.doc.transaction_date || me.frm.doc.posting_date,
ignore_pricing_rule: me.frm.doc.ignore_pricing_rule,
@@ -550,7 +577,7 @@
var d = locals[cdt][cdn];
me.add_taxes_from_item_tax_template(d.item_tax_rate);
if (d.free_item_data) {
- me.apply_product_discount(d.free_item_data);
+ me.apply_product_discount(d);
}
},
() => {
@@ -573,12 +600,22 @@
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
.then((r) => {
if (r.message &&
- (r.message.has_batch_no || r.message.has_serial_no)) {
+ (r.message.has_batch_no || r.message.has_serial_no)) {
frappe.flags.hide_serial_batch_dialog = false;
}
});
},
() => {
+ // check if batch serial selector is disabled or not
+ if (show_batch_dialog && !frappe.flags.hide_serial_batch_dialog)
+ return frappe.db.get_single_value('Stock Settings', 'disable_serial_no_and_batch_selector')
+ .then((value) => {
+ if (value) {
+ frappe.flags.hide_serial_batch_dialog = true;
+ }
+ });
+ },
+ () => {
if(show_batch_dialog && !frappe.flags.hide_serial_batch_dialog) {
var d = locals[cdt][cdn];
$.each(r.message, function(k, v) {
@@ -612,6 +649,40 @@
}
},
+ price_list_rate: function(doc, cdt, cdn) {
+ var item = frappe.get_doc(cdt, cdn);
+ frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
+
+ // check if child doctype is Sales Order Item/Qutation Item and calculate the rate
+ if (in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Purchase Receipt Item"]), cdt)
+ this.apply_pricing_rule_on_item(item);
+ else
+ item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0),
+ precision("rate", item));
+
+ this.calculate_taxes_and_totals();
+ },
+
+ margin_rate_or_amount: function(doc, cdt, cdn) {
+ // calculated the revised total margin and rate on margin rate changes
+ let item = frappe.get_doc(cdt, cdn);
+ this.apply_pricing_rule_on_item(item);
+ this.calculate_taxes_and_totals();
+ cur_frm.refresh_fields();
+ },
+
+ margin_type: function(doc, cdt, cdn) {
+ // calculate the revised total margin and rate on margin type changes
+ let item = frappe.get_doc(cdt, cdn);
+ if (!item.margin_type) {
+ frappe.model.set_value(cdt, cdn, "margin_rate_or_amount", 0);
+ } else {
+ this.apply_pricing_rule_on_item(item, doc, cdt, cdn);
+ this.calculate_taxes_and_totals();
+ cur_frm.refresh_fields();
+ }
+ },
+
get_incoming_rate: function(item, posting_date, posting_time, voucher_type, company) {
let item_args = {
@@ -632,7 +703,7 @@
args: item_args
},
callback: function(r) {
- frappe.model.set_value(item.doctype, item.name, 'rate', r.message);
+ frappe.model.set_value(item.doctype, item.name, 'rate', r.message * item.conversion_factor);
}
});
},
@@ -651,7 +722,7 @@
let child = frappe.model.add_child(me.frm.doc, "taxes");
child.charge_type = "On Net Total";
child.account_head = tax;
- child.rate = rate;
+ child.rate = 0;
}
});
}
@@ -667,21 +738,15 @@
}
else {
var valid_serial_nos = [];
-
+ var serialnos = [];
// Replacing all occurences of comma with carriage return
- var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
-
- serial_nos = serial_nos.trim().split('\n');
-
- // Trim each string and push unique string to new list
- for (var x=0; x<=serial_nos.length - 1; x++) {
- if (serial_nos[x].trim() != "" && valid_serial_nos.indexOf(serial_nos[x].trim()) == -1) {
- valid_serial_nos.push(serial_nos[x].trim());
+ item.serial_no = item.serial_no.replace(/,/g, '\n');
+ serialnos = item.serial_no.split("\n");
+ for (var i = 0; i < serialnos.length; i++) {
+ if (serialnos[i] != "") {
+ valid_serial_nos.push(serialnos[i]);
}
}
-
- // Add the new list to the serial no. field in grid with each in new line
- item.serial_no = valid_serial_nos.join('\n');
item.conversion_factor = item.conversion_factor || 1;
refresh_field("serial_no", item.name, item.parentfield);
@@ -698,6 +763,31 @@
this.calculate_taxes_and_totals(false);
},
+ update_stock: function() {
+ this.frm.trigger('set_default_internal_warehouse');
+ },
+
+ set_default_internal_warehouse: function() {
+ let me = this;
+ if ((this.frm.doc.doctype === 'Sales Invoice' && me.frm.doc.update_stock)
+ || this.frm.doc.doctype == 'Delivery Note') {
+ if (this.frm.doc.is_internal_customer && this.frm.doc.company === this.frm.doc.represents_company) {
+ frappe.db.get_value('Company', this.frm.doc.company, 'default_in_transit_warehouse', function(value) {
+ me.frm.set_value('set_target_warehouse', value.default_in_transit_warehouse);
+ });
+ }
+ }
+
+ if ((this.frm.doc.doctype === 'Purchase Invoice' && me.frm.doc.update_stock)
+ || this.frm.doc.doctype == 'Purchase Receipt') {
+ if (this.frm.doc.is_internal_supplier && this.frm.doc.company === this.frm.doc.represents_company) {
+ frappe.db.get_value('Company', this.frm.doc.company, 'default_in_transit_warehouse', function(value) {
+ me.frm.set_value('set_from_warehouse', value.default_in_transit_warehouse);
+ });
+ }
+ }
+ },
+
company: function() {
var me = this;
var set_pricing = function() {
@@ -784,7 +874,7 @@
in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) {
erpnext.utils.get_shipping_address(this.frm, function(){
set_party_account(set_pricing);
- })
+ });
// Get default company billing address in Purchase Invoice, Order and Receipt
frappe.call({
@@ -968,7 +1058,7 @@
},
set_margin_amount_based_on_currency: function(exchange_rate) {
- if (in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]), this.frm.doc.doctype) {
+ if (in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "Purchase Invoice", "Purchase Order", "Purchase Receipt"]), this.frm.doc.doctype) {
var me = this;
$.each(this.frm.doc.items || [], function(i, d) {
if(d.margin_type == "Amount") {
@@ -1049,18 +1139,18 @@
if(item.item_code && item.uom) {
return this.frm.call({
method: "erpnext.stock.get_item_details.get_conversion_factor",
- child: item,
args: {
item_code: item.item_code,
uom: item.uom
},
callback: function(r) {
if(!r.exc) {
- me.conversion_factor(me.frm.doc, cdt, cdn);
+ frappe.model.set_value(cdt, cdn, 'conversion_factor', r.message.conversion_factor);
}
}
});
}
+ me.calculate_stock_uom_rate(doc, cdt, cdn);
},
conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
@@ -1081,9 +1171,15 @@
frappe.meta.has_field(doc.doctype, "price_list_currency")) {
this.apply_price_list(item, true);
}
+ this.calculate_stock_uom_rate(doc, cdt, cdn);
}
},
+ batch_no: function(doc, cdt, cdn) {
+ let item = frappe.get_doc(cdt, cdn);
+ this.apply_price_list(item, true);
+ },
+
toggle_conversion_factor: function(item) {
// toggle read only property for conversion factor field if the uom and stock uom are same
if(this.frm.get_field('items').grid.fields_map.conversion_factor) {
@@ -1096,9 +1192,15 @@
qty: function(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
this.conversion_factor(doc, cdt, cdn, true);
+ this.calculate_stock_uom_rate(doc, cdt, cdn);
this.apply_pricing_rule(item, true);
},
+ calculate_stock_uom_rate: function(doc, cdt, cdn) {
+ let item = frappe.get_doc(cdt, cdn);
+ item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
+ refresh_field("stock_uom_rate", item.name, item.parentfield);
+ },
service_stop_date: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
@@ -1206,10 +1308,10 @@
change_grid_labels: function(company_currency) {
var me = this;
- this.frm.set_currency_labels(["base_rate", "base_net_rate", "base_price_list_rate", "base_amount", "base_net_amount"],
+ this.frm.set_currency_labels(["base_rate", "base_net_rate", "base_price_list_rate", "base_amount", "base_net_amount", "base_rate_with_margin"],
company_currency, "items");
- this.frm.set_currency_labels(["rate", "net_rate", "price_list_rate", "amount", "net_amount"],
+ this.frm.set_currency_labels(["rate", "net_rate", "price_list_rate", "amount", "net_amount", "stock_uom_rate", "rate_with_margin"],
this.frm.doc.currency, "items");
if(this.frm.fields_dict["operations"]) {
@@ -1247,7 +1349,7 @@
// toggle columns
var item_grid = this.frm.fields_dict["items"].grid;
- $.each(["base_rate", "base_price_list_rate", "base_amount"], function(i, fname) {
+ $.each(["base_rate", "base_price_list_rate", "base_amount", "base_rate_with_margin"], function(i, fname) {
if(frappe.meta.get_docfield(item_grid.doctype, fname))
item_grid.set_column_disp(fname, me.frm.doc.currency != company_currency);
});
@@ -1388,12 +1490,13 @@
"pricing_rules": d.pricing_rules,
"warehouse": d.warehouse,
"serial_no": d.serial_no,
+ "batch_no": d.batch_no,
"price_list_rate": d.price_list_rate,
"conversion_factor": d.conversion_factor || 1.0
});
// if doctype is Quotation Item / Sales Order Iten then add Margin Type and rate in item_list
- if (in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item"]), d.doctype){
+ if (in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Purchase Receipt Item"]), d.doctype) {
item_list[0]["margin_type"] = d.margin_type;
item_list[0]["margin_rate_or_amount"] = d.margin_rate_or_amount;
}
@@ -1424,7 +1527,10 @@
if(k=="price_list_rate") {
if(flt(v) != flt(d.price_list_rate)) price_list_rate_changed = true;
}
- frappe.model.set_value(d.doctype, d.name, k, v);
+
+ if (k !== 'free_item_data') {
+ frappe.model.set_value(d.doctype, d.name, k, v);
+ }
}
}
@@ -1436,7 +1542,7 @@
}
if (d.free_item_data) {
- me.apply_product_discount(d.free_item_data);
+ me.apply_product_discount(d);
}
if (d.apply_rule_on_other_items) {
@@ -1470,20 +1576,31 @@
}
},
- apply_product_discount: function(free_item_data) {
- const items = this.frm.doc.items.filter(d => (d.item_code == free_item_data.item_code
- && d.is_free_item)) || [];
+ apply_product_discount: function(args) {
+ const items = this.frm.doc.items.filter(d => (d.is_free_item)) || [];
- if (!items.length) {
- let row_to_modify = frappe.model.add_child(this.frm.doc,
- this.frm.doc.doctype + ' Item', 'items');
+ const exist_items = items.map(row => (row.item_code, row.pricing_rules));
- for (let key in free_item_data) {
- row_to_modify[key] = free_item_data[key];
+ args.free_item_data.forEach(pr_row => {
+ let row_to_modify = {};
+ if (!items || !in_list(exist_items, (pr_row.item_code, pr_row.pricing_rules))) {
+
+ row_to_modify = frappe.model.add_child(this.frm.doc,
+ this.frm.doc.doctype + ' Item', 'items');
+
+ } else if(items) {
+ row_to_modify = items.filter(d => (d.item_code === pr_row.item_code
+ && d.pricing_rules === pr_row.pricing_rules))[0];
}
- } if (items && items.length && free_item_data) {
- items[0].qty = free_item_data.qty
- }
+
+ for (let key in pr_row) {
+ row_to_modify[key] = pr_row[key];
+ }
+ });
+
+ // free_item_data is a temporary variable
+ args.free_item_data = '';
+ refresh_field('items');
},
apply_price_list: function(item, reset_plc_conversion) {
@@ -1810,7 +1927,6 @@
frappe.throw(__("Please enter Item Code to get batch no"));
} else if (doc.doctype == "Purchase Receipt" ||
(doc.doctype == "Purchase Invoice" && doc.update_stock)) {
-
return {
filters: {'item': item.item_code}
}
@@ -1836,9 +1952,8 @@
set_query_for_item_tax_template: function(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if(!item.item_code) {
- frappe.throw(__("Please enter Item Code to get item taxes"));
+ return doc.company ? {filters: {company: doc.company}} : {};
} else {
-
let filters = {
'item_code': item.item_code,
'valid_from': ["<=", doc.transaction_date || doc.bill_date || doc.posting_date],
@@ -1946,6 +2061,14 @@
this.autofill_warehouse(this.frm.doc.items, "warehouse", this.frm.doc.set_warehouse);
},
+ set_target_warehouse: function() {
+ this.autofill_warehouse(this.frm.doc.items, "target_warehouse", this.frm.doc.set_target_warehouse);
+ },
+
+ set_from_warehouse: function() {
+ this.autofill_warehouse(this.frm.doc.items, "from_warehouse", this.frm.doc.set_from_warehouse);
+ },
+
autofill_warehouse : function (child_table, warehouse_field, warehouse) {
if (warehouse && child_table && child_table.length) {
let doctype = child_table[0].doctype;
@@ -2010,3 +2133,35 @@
}, show_dialog);
});
}
+
+erpnext.apply_putaway_rule = (frm, purpose=null) => {
+ if (!frm.doc.company) {
+ frappe.throw({message: __("Please select a Company first."), title: __("Mandatory")});
+ }
+ if (!frm.doc.items.length) return;
+
+ frappe.call({
+ method: "erpnext.stock.doctype.putaway_rule.putaway_rule.apply_putaway_rule",
+ args: {
+ doctype: frm.doctype,
+ items: frm.doc.items,
+ company: frm.doc.company,
+ sync: true,
+ purpose: purpose
+ },
+ callback: (result) => {
+ if (!result.exc && result.message) {
+ frm.clear_table("items");
+
+ let items = result.message;
+ items.forEach((row) => {
+ delete row["name"]; // dont overwrite name from server side
+ let child = frm.add_child("items");
+ Object.assign(child, row);
+ frm.script_manager.trigger("qty", child.doctype, child.name);
+ });
+ frm.get_field("items").grid.refresh();
+ }
+ }
+ });
+};
diff --git a/erpnext/public/js/education/assessment_result_tool.html b/erpnext/public/js/education/assessment_result_tool.html
index 9fc17f7..b591010 100644
--- a/erpnext/public/js/education/assessment_result_tool.html
+++ b/erpnext/public/js/education/assessment_result_tool.html
@@ -19,7 +19,7 @@
</thead>
<tbody>
{% for s in students %}
- <tr
+ <tr
{% if(s.assessment_details && s.docstatus && s.docstatus == 1) { %} class="text-muted" {% } %}
data-student="{{s.student}}">
@@ -29,7 +29,7 @@
<td>
<span data-student="{{s.student}}" data-criteria="{{c.assessment_criteria}}" class="student-result-grade badge" >
{% if(s.assessment_details) { %}
- {{s.assessment_details[c.assessment_criteria][1]}}
+ {{s.assessment_details[c.assessment_criteria][1]}}
{% } %}
</span>
<input type="number" class="student-result-data" style="width:70%; float:right;"
@@ -61,7 +61,7 @@
{% } %}
</span>
<span data-student="{{s.student}}" class="total-result-link" style="width: 10%; display:{% if(!s.assessment_details) { %}None{% } %}; float:right;">
- <a class="btn-open no-decoration" title="Open Link" href="#Form/Assessment Result/{% if(s.assessment_details) { %}{{s.name}}{% } %}">
+ <a class="btn-open no-decoration" title="Open Link" href="/app/Form/Assessment Result/{% if(s.assessment_details) { %}{{s.name}}{% } %}">
<i class="octicon octicon-arrow-right"></i>
</a>
</span>
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 459c01b..b2f7afe 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -57,18 +57,22 @@
});
});
- report.page.add_inner_button(__("Balance Sheet"), function() {
+ const views_menu = report.page.add_custom_button_group(__('Financial Statements'));
+
+ report.page.add_custom_menu_item(views_menu, __("Balance Sheet"), function() {
var filters = report.get_values();
frappe.set_route('query-report', 'Balance Sheet', {company: filters.company});
- }, __('Financial Statements'));
- report.page.add_inner_button(__("Profit and Loss"), function() {
+ });
+
+ report.page.add_custom_menu_item(views_menu, __("Profit and Loss"), function() {
var filters = report.get_values();
frappe.set_route('query-report', 'Profit and Loss Statement', {company: filters.company});
- }, __('Financial Statements'));
- report.page.add_inner_button(__("Cash Flow Statement"), function() {
+ });
+
+ report.page.add_custom_menu_item(views_menu, __("Cash Flow Statement"), function() {
var filters = report.get_values();
frappe.set_route('query-report', 'Cash Flow', {company: filters.company});
- }, __('Financial Statements'));
+ });
}
};
diff --git a/erpnext/public/js/help_links.js b/erpnext/public/js/help_links.js
index 66ff464..e789923 100644
--- a/erpnext/public/js/help_links.js
+++ b/erpnext/public/js/help_links.js
@@ -1,526 +1,1051 @@
-frappe.provide('frappe.help.help_links');
+frappe.provide("frappe.help.help_links");
-const docsUrl = 'https://erpnext.com/docs/';
+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' },
-]
+frappe.help.help_links["Form/Rename Tool"] = [
+ {
+ label: "Bulk Rename",
+ url: docsUrl + "user/manual/en/setting-up/data/bulk-rename",
+ },
+];
//Setup
-frappe.help.help_links['List/User'] = [
- { label: 'New User', url: docsUrl + 'user/manual/en/setting-up/users-and-permissions/adding-users' },
- { label: 'Rename User', url: docsUrl + 'user/manual/en/setting-up/articles/rename-user' },
-]
+frappe.help.help_links["List/User"] = [
+ {
+ label: "New User",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/users-and-permissions/adding-users",
+ },
+ {
+ label: "Rename User",
+ url: docsUrl + "user/manual/en/setting-up/articles/rename-user",
+ },
+];
-frappe.help.help_links['permission-manager'] = [
- { label: 'Role Permissions Manager', url: docsUrl + 'user/manual/en/setting-up/users-and-permissions/role-based-permissions' },
- { label: 'Managing Perm Level in Permissions Manager', url: docsUrl + 'user/manual/en/setting-up/articles/managing-perm-level' },
- { label: 'User Permissions', url: docsUrl + 'user/manual/en/setting-up/users-and-permissions/user-permissions' },
- { label: 'Sharing', url: docsUrl + 'user/manual/en/setting-up/users-and-permissions/sharing' },
- { label: 'Password', url: docsUrl + 'user/manual/en/setting-up/articles/change-password' },
-]
+frappe.help.help_links["permission-manager"] = [
+ {
+ label: "Role Permissions Manager",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/users-and-permissions/role-based-permissions",
+ },
+ {
+ label: "Managing Perm Level in Permissions Manager",
+ url: docsUrl + "user/manual/en/setting-up/articles/managing-perm-level",
+ },
+ {
+ label: "User Permissions",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/users-and-permissions/user-permissions",
+ },
+ {
+ label: "Sharing",
+ url:
+ docsUrl + "user/manual/en/setting-up/users-and-permissions/sharing",
+ },
+ {
+ label: "Password",
+ url: docsUrl + "user/manual/en/setting-up/articles/change-password",
+ },
+];
-frappe.help.help_links['Form/System Settings'] = [
- { label: 'Naming Series', url: docsUrl + 'user/manual/en/setting-up/settings/system-settings' },
-]
+frappe.help.help_links["Form/System Settings"] = [
+ {
+ label: "Naming Series",
+ url: docsUrl + "user/manual/en/setting-up/settings/system-settings",
+ },
+];
-frappe.help.help_links['data-import-tool'] = [
- { label: 'Importing and Exporting Data', url: docsUrl + 'user/manual/en/setting-up/data/data-import-tool' },
- { 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["data-import-tool"] = [
+ {
+ label: "Importing and Exporting Data",
+ url: docsUrl + "user/manual/en/setting-up/data/data-import-tool",
+ },
+ {
+ 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['module_setup'] = [
- { label: 'Role Permissions Manager', url: docsUrl + 'user/manual/en/setting-up/users-and-permissions/role-based-permissions' },
-]
+frappe.help.help_links["module_setup"] = [
+ {
+ label: "Role Permissions Manager",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/users-and-permissions/role-based-permissions",
+ },
+];
-frappe.help.help_links['Form/Naming Series'] = [
- { label: 'Naming Series', url: docsUrl + 'user/manual/en/setting-up/settings/naming-series' },
- { label: 'Setting the Current Value for Naming Series', url: docsUrl + 'user/manual/en/setting-up/articles/naming-series-current-value' },
-]
+frappe.help.help_links["Form/Naming Series"] = [
+ {
+ label: "Naming Series",
+ url: docsUrl + "user/manual/en/setting-up/settings/naming-series",
+ },
+ {
+ label: "Setting the Current Value for Naming Series",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/articles/naming-series-current-value",
+ },
+];
-frappe.help.help_links['Form/Global Defaults'] = [
- { label: 'Global Settings', url: docsUrl + 'user/manual/en/setting-up/settings/global-defaults' },
-]
+frappe.help.help_links["Form/Global Defaults"] = [
+ {
+ label: "Global Settings",
+ url: docsUrl + "user/manual/en/setting-up/settings/global-defaults",
+ },
+];
-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",
+ },
+];
-frappe.help.help_links['List/Print Heading'] = [
- { label: 'Print Heading', url: docsUrl + 'user/manual/en/setting-up/print/print-headings' },
-]
+frappe.help.help_links["List/Print Heading"] = [
+ {
+ label: "Print Heading",
+ url: docsUrl + "user/manual/en/setting-up/print/print-headings",
+ },
+];
-frappe.help.help_links['List/Letter Head'] = [
- { label: 'Letter Head', url: docsUrl + 'user/manual/en/setting-up/print/letter-head' },
-]
+frappe.help.help_links["List/Letter Head"] = [
+ {
+ label: "Letter Head",
+ url: docsUrl + "user/manual/en/setting-up/print/letter-head",
+ },
+];
-frappe.help.help_links['List/Address Template'] = [
- { label: 'Address Template', url: docsUrl + 'user/manual/en/setting-up/print/address-template' },
-]
+frappe.help.help_links["List/Address Template"] = [
+ {
+ label: "Address Template",
+ url: docsUrl + "user/manual/en/setting-up/print/address-template",
+ },
+];
-frappe.help.help_links['List/Terms and Conditions'] = [
- { label: 'Terms and Conditions', url: docsUrl + 'user/manual/en/setting-up/print/terms-and-conditions' },
-]
+frappe.help.help_links["List/Terms and Conditions"] = [
+ {
+ label: "Terms and Conditions",
+ url: docsUrl + "user/manual/en/setting-up/print/terms-and-conditions",
+ },
+];
-frappe.help.help_links['List/Cheque Print Template'] = [
- { label: 'Cheque Print Template', url: docsUrl + 'user/manual/en/setting-up/print/cheque-print-template' },
-]
+frappe.help.help_links["List/Cheque Print Template"] = [
+ {
+ label: "Cheque Print Template",
+ url: docsUrl + "user/manual/en/setting-up/print/cheque-print-template",
+ },
+];
-frappe.help.help_links['List/Email Account'] = [
- { label: 'Email Account', url: docsUrl + 'user/manual/en/setting-up/email/email-account' },
-]
+frappe.help.help_links["List/Email Account"] = [
+ {
+ label: "Email Account",
+ url: docsUrl + "user/manual/en/setting-up/email/email-account",
+ },
+];
-frappe.help.help_links['List/Notification'] = [
- { label: 'Notification', url: docsUrl + 'user/manual/en/setting-up/email/notifications' },
-]
+frappe.help.help_links["List/Notification"] = [
+ {
+ label: "Notification",
+ url: docsUrl + "user/manual/en/setting-up/email/notifications",
+ },
+];
-frappe.help.help_links['Form/Notification'] = [
- { label: 'Notification', url: docsUrl + 'user/manual/en/setting-up/email/notifications' },
-]
+frappe.help.help_links["Form/Notification"] = [
+ {
+ label: "Notification",
+ url: docsUrl + "user/manual/en/setting-up/email/notifications",
+ },
+];
-frappe.help.help_links['List/Email Digest'] = [
- { label: 'Email Digest', url: docsUrl + 'user/manual/en/setting-up/email/email-digest' },
-]
+frappe.help.help_links["List/Email Digest"] = [
+ {
+ label: "Email Digest",
+ url: docsUrl + "user/manual/en/setting-up/email/email-digest",
+ },
+];
-frappe.help.help_links['List/Auto Email Report'] = [
- { label: 'Auto Email Reports', url: docsUrl + 'user/manual/en/setting-up/email/email-reports' },
-]
+frappe.help.help_links["List/Auto Email Report"] = [
+ {
+ label: "Auto Email Reports",
+ url: docsUrl + "user/manual/en/setting-up/email/email-reports",
+ },
+];
-frappe.help.help_links['Form/Print Settings'] = [
- { label: 'Print Settings', url: docsUrl + 'user/manual/en/setting-up/print/print-settings' },
-]
+frappe.help.help_links["Form/Print Settings"] = [
+ {
+ label: "Print Settings",
+ url: docsUrl + "user/manual/en/setting-up/print/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["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' },
-]
+frappe.help.help_links["List/Print Heading"] = [
+ {
+ label: "Print Heading",
+ url: docsUrl + "user/manual/en/setting-up/print/print-headings",
+ },
+];
//setup-integrations
-frappe.help.help_links['Form/PayPal Settings'] = [
- { label: 'PayPal Settings', url: docsUrl + 'user/manual/en/setting-up/integrations/paypal-integration' },
-]
+frappe.help.help_links["Form/PayPal Settings"] = [
+ {
+ label: "PayPal Settings",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/integrations/paypal-integration",
+ },
+];
-frappe.help.help_links['Form/Razorpay Settings'] = [
- { label: 'Razorpay Settings', url: docsUrl + 'user/manual/en/setting-up/integrations/razorpay-integration' },
-]
+frappe.help.help_links["Form/Razorpay Settings"] = [
+ {
+ label: "Razorpay Settings",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/integrations/razorpay-integration",
+ },
+];
-frappe.help.help_links['Form/Dropbox Settings'] = [
- { label: 'Dropbox Settings', url: docsUrl + 'user/manual/en/setting-up/integrations/dropbox-backup' },
-]
+frappe.help.help_links["Form/Dropbox Settings"] = [
+ {
+ label: "Dropbox Settings",
+ url: docsUrl + "user/manual/en/setting-up/integrations/dropbox-backup",
+ },
+];
-frappe.help.help_links['Form/LDAP Settings'] = [
- { label: 'LDAP Settings', url: docsUrl + 'user/manual/en/setting-up/integrations/ldap-integration' },
-]
+frappe.help.help_links["Form/LDAP Settings"] = [
+ {
+ label: "LDAP Settings",
+ url:
+ docsUrl + "user/manual/en/setting-up/integrations/ldap-integration",
+ },
+];
-frappe.help.help_links['Form/Stripe Settings'] = [
- { label: 'Stripe Settings', url: docsUrl + 'user/manual/en/setting-up/integrations/stripe-integration' },
-]
+frappe.help.help_links["Form/Stripe Settings"] = [
+ {
+ label: "Stripe Settings",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/integrations/stripe-integration",
+ },
+];
//Sales
-frappe.help.help_links['Form/Quotation'] = [
- { label: 'Quotation', url: docsUrl + 'user/manual/en/selling/quotation' },
- { label: 'Applying Discount', url: docsUrl + 'user/manual/en/selling/articles/applying-discount' },
- { label: 'Sales Person', url: docsUrl + 'user/manual/en/selling/articles/sales-persons-in-the-sales-transactions' },
- { label: 'Applying Margin', url: docsUrl + 'user/manual/en/selling/articles/adding-margin' },
-]
+frappe.help.help_links["Form/Quotation"] = [
+ { label: "Quotation", url: docsUrl + "user/manual/en/selling/quotation" },
+ {
+ label: "Applying Discount",
+ url: docsUrl + "user/manual/en/selling/articles/applying-discount",
+ },
+ {
+ label: "Sales Person",
+ url:
+ docsUrl +
+ "user/manual/en/selling/articles/sales-persons-in-the-sales-transactions",
+ },
+ {
+ label: "Applying Margin",
+ url: docsUrl + "user/manual/en/selling/articles/adding-margin",
+ },
+];
-frappe.help.help_links['List/Customer'] = [
- { label: 'Customer', url: docsUrl + 'user/manual/en/CRM/customer' },
- { label: 'Credit Limit', url: docsUrl + 'user/manual/en/accounts/credit-limit' },
-]
+frappe.help.help_links["List/Customer"] = [
+ { label: "Customer", url: docsUrl + "user/manual/en/CRM/customer" },
+ {
+ label: "Credit Limit",
+ url: docsUrl + "user/manual/en/accounts/credit-limit",
+ },
+];
-frappe.help.help_links['Form/Customer'] = [
- { label: 'Customer', url: docsUrl + 'user/manual/en/CRM/customer' },
- { label: 'Credit Limit', url: docsUrl + 'user/manual/en/accounts/credit-limit' },
-]
+frappe.help.help_links["Form/Customer"] = [
+ { label: "Customer", url: docsUrl + "user/manual/en/CRM/customer" },
+ {
+ label: "Credit Limit",
+ url: docsUrl + "user/manual/en/accounts/credit-limit",
+ },
+];
-frappe.help.help_links['List/Sales Taxes and Charges Template'] = [
- { label: 'Setting Up Taxes', url: docsUrl + 'user/manual/en/setting-up/setting-up-taxes' },
-]
+frappe.help.help_links["List/Sales Taxes and Charges Template"] = [
+ {
+ label: "Setting Up Taxes",
+ url: docsUrl + "user/manual/en/setting-up/setting-up-taxes",
+ },
+];
-frappe.help.help_links['Form/Sales Taxes and Charges Template'] = [
- { label: 'Setting Up Taxes', url: docsUrl + 'user/manual/en/setting-up/setting-up-taxes' },
-]
+frappe.help.help_links["Form/Sales Taxes and Charges Template"] = [
+ {
+ label: "Setting Up Taxes",
+ url: docsUrl + "user/manual/en/setting-up/setting-up-taxes",
+ },
+];
-frappe.help.help_links['List/Sales Order'] = [
- { label: 'Sales Order', url: docsUrl + 'user/manual/en/selling/sales-order' },
- { label: 'Recurring Sales Order', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
- { label: 'Applying Discount', url: docsUrl + 'user/manual/en/selling/articles/applying-discount' },
-]
+frappe.help.help_links["List/Sales Order"] = [
+ {
+ label: "Sales Order",
+ url: docsUrl + "user/manual/en/selling/sales-order",
+ },
+ {
+ label: "Recurring Sales Order",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+ {
+ label: "Applying Discount",
+ url: docsUrl + "user/manual/en/selling/articles/applying-discount",
+ },
+];
-frappe.help.help_links['Form/Sales Order'] = [
- { label: 'Sales Order', url: docsUrl + 'user/manual/en/selling/sales-order' },
- { label: 'Recurring Sales Order', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
- { label: 'Applying Discount', url: docsUrl + 'user/manual/en/selling/articles/applying-discount' },
- { label: 'Drop Shipping', url: docsUrl + 'user/manual/en/selling/articles/drop-shipping' },
- { label: 'Sales Person', url: docsUrl + 'user/manual/en/selling/articles/sales-persons-in-the-sales-transactions' },
- { label: 'Close Sales Order', url: docsUrl + 'user/manual/en/selling/articles/close-sales-order' },
- { label: 'Applying Margin', url: docsUrl + 'user/manual/en/selling/articles/adding-margin' },
-]
+frappe.help.help_links["Form/Sales Order"] = [
+ {
+ label: "Sales Order",
+ url: docsUrl + "user/manual/en/selling/sales-order",
+ },
+ {
+ label: "Recurring Sales Order",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+ {
+ label: "Applying Discount",
+ url: docsUrl + "user/manual/en/selling/articles/applying-discount",
+ },
+ {
+ label: "Drop Shipping",
+ url: docsUrl + "user/manual/en/selling/articles/drop-shipping",
+ },
+ {
+ label: "Sales Person",
+ url:
+ docsUrl +
+ "user/manual/en/selling/articles/sales-persons-in-the-sales-transactions",
+ },
+ {
+ label: "Close Sales Order",
+ url: docsUrl + "user/manual/en/selling/articles/close-sales-order",
+ },
+ {
+ label: "Applying Margin",
+ url: docsUrl + "user/manual/en/selling/articles/adding-margin",
+ },
+];
-frappe.help.help_links['Form/Product Bundle'] = [
- { label: 'Product Bundle', url: docsUrl + 'user/manual/en/selling/setup/product-bundle' },
-]
+frappe.help.help_links["Form/Product Bundle"] = [
+ {
+ label: "Product Bundle",
+ url: docsUrl + "user/manual/en/selling/setup/product-bundle",
+ },
+];
-frappe.help.help_links['Form/Selling Settings'] = [
- { label: 'Selling Settings', url: docsUrl + 'user/manual/en/selling/setup/selling-settings' },
-]
+frappe.help.help_links["Form/Selling Settings"] = [
+ {
+ label: "Selling Settings",
+ url: docsUrl + "user/manual/en/selling/setup/selling-settings",
+ },
+];
//Buying
-frappe.help.help_links['List/Supplier'] = [
- { label: 'Supplier', url: docsUrl + 'user/manual/en/buying/supplier' },
-]
+frappe.help.help_links["List/Supplier"] = [
+ { label: "Supplier", url: docsUrl + "user/manual/en/buying/supplier" },
+];
-frappe.help.help_links['Form/Supplier'] = [
- { label: 'Supplier', url: docsUrl + 'user/manual/en/buying/supplier' },
-]
+frappe.help.help_links["Form/Supplier"] = [
+ { label: "Supplier", url: docsUrl + "user/manual/en/buying/supplier" },
+];
-frappe.help.help_links['Form/Request for Quotation'] = [
- { label: 'Request for Quotation', url: docsUrl + 'user/manual/en/buying/request-for-quotation' },
- { label: 'RFQ Video', url: docsUrl + 'user/videos/learn/request-for-quotation.html' },
-]
+frappe.help.help_links["Form/Request for Quotation"] = [
+ {
+ label: "Request for Quotation",
+ url: docsUrl + "user/manual/en/buying/request-for-quotation",
+ },
+ {
+ label: "RFQ Video",
+ url: docsUrl + "user/videos/learn/request-for-quotation.html",
+ },
+];
-frappe.help.help_links['Form/Supplier Quotation'] = [
- { label: 'Supplier Quotation', url: docsUrl + 'user/manual/en/buying/supplier-quotation' },
-]
+frappe.help.help_links["Form/Supplier Quotation"] = [
+ {
+ label: "Supplier Quotation",
+ url: docsUrl + "user/manual/en/buying/supplier-quotation",
+ },
+];
-frappe.help.help_links['Form/Buying Settings'] = [
- { label: 'Buying Settings', url: docsUrl + 'user/manual/en/buying/setup/buying-settings' },
-]
+frappe.help.help_links["Form/Buying Settings"] = [
+ {
+ label: "Buying Settings",
+ url: docsUrl + "user/manual/en/buying/setup/buying-settings",
+ },
+];
-frappe.help.help_links['List/Purchase Order'] = [
- { label: 'Purchase Order', url: docsUrl + 'user/manual/en/buying/purchase-order' },
- { label: 'Recurring Purchase Order', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
-]
+frappe.help.help_links["List/Purchase Order"] = [
+ {
+ label: "Purchase Order",
+ url: docsUrl + "user/manual/en/buying/purchase-order",
+ },
+ {
+ label: "Recurring Purchase Order",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+];
-frappe.help.help_links['Form/Purchase Order'] = [
- { label: 'Purchase Order', url: docsUrl + 'user/manual/en/buying/purchase-order' },
- { label: 'Item UoM', url: docsUrl + 'user/manual/en/buying/articles/purchasing-in-different-unit' },
- { label: 'Supplier Item Code', url: docsUrl + 'user/manual/en/buying/articles/maintaining-suppliers-part-no-in-item' },
- { label: 'Recurring Purchase Order', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
- { label: 'Subcontracting', url: docsUrl + 'user/manual/en/manufacturing/subcontracting' },
-]
+frappe.help.help_links["Form/Purchase Order"] = [
+ {
+ label: "Purchase Order",
+ url: docsUrl + "user/manual/en/buying/purchase-order",
+ },
+ {
+ label: "Item UoM",
+ url:
+ docsUrl +
+ "user/manual/en/buying/articles/purchasing-in-different-unit",
+ },
+ {
+ label: "Supplier Item Code",
+ url:
+ docsUrl +
+ "user/manual/en/buying/articles/maintaining-suppliers-part-no-in-item",
+ },
+ {
+ label: "Recurring Purchase Order",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+ {
+ label: "Subcontracting",
+ url: docsUrl + "user/manual/en/manufacturing/subcontracting",
+ },
+];
-frappe.help.help_links['List/Purchase Taxes and Charges Template'] = [
- { label: 'Setting Up Taxes', url: docsUrl + 'user/manual/en/setting-up/setting-up-taxes' },
-]
+frappe.help.help_links["List/Purchase Taxes and Charges Template"] = [
+ {
+ label: "Setting Up Taxes",
+ url: docsUrl + "user/manual/en/setting-up/setting-up-taxes",
+ },
+];
-frappe.help.help_links['List/POS Profile'] = [
- { label: 'POS Profile', url: docsUrl + 'user/manual/en/setting-up/pos-setting' },
-]
+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' },
-]
+frappe.help.help_links["List/Price List"] = [
+ {
+ label: "Price List",
+ url: docsUrl + "user/manual/en/setting-up/price-lists",
+ },
+];
-frappe.help.help_links['List/Authorization Rule'] = [
- { label: 'Authorization Rule', url: docsUrl + 'user/manual/en/setting-up/authorization-rule' },
-]
+frappe.help.help_links["List/Authorization Rule"] = [
+ {
+ label: "Authorization Rule",
+ url: docsUrl + "user/manual/en/setting-up/authorization-rule",
+ },
+];
-frappe.help.help_links['Form/SMS Settings'] = [
- { label: 'SMS Settings', url: docsUrl + 'user/manual/en/setting-up/sms-setting' },
-]
+frappe.help.help_links["Form/SMS Settings"] = [
+ {
+ label: "SMS Settings",
+ url: docsUrl + "user/manual/en/setting-up/sms-setting",
+ },
+];
-frappe.help.help_links['List/Stock Reconciliation'] = [
- { label: 'Stock Reconciliation', url: docsUrl + 'user/manual/en/setting-up/stock-reconciliation-for-non-serialized-item' },
-]
+frappe.help.help_links["List/Stock Reconciliation"] = [
+ {
+ label: "Stock Reconciliation",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/stock-reconciliation-for-non-serialized-item",
+ },
+];
-frappe.help.help_links['Tree/Territory'] = [
- { label: 'Territory', url: docsUrl + 'user/manual/en/setting-up/territory' },
-]
+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' },
-]
+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",
+ },
+];
-frappe.help.help_links['List/Workflow'] = [
- { label: 'Workflow', url: docsUrl + 'user/manual/en/setting-up/workflows' },
-]
+frappe.help.help_links["List/Workflow"] = [
+ { label: "Workflow", url: docsUrl + "user/manual/en/setting-up/workflows" },
+];
-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: docsUrl + 'user/manual/en/setting-up/articles/delete-a-company-and-all-related-transactions' },
-]
+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:
+ docsUrl +
+ "user/manual/en/setting-up/articles/delete-a-company-and-all-related-transactions",
+ },
+];
//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["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', url: docsUrl + 'user/manual/en/accounts/chart-of-accounts' },
- { label: 'Managing Tree Mastes', url: docsUrl + 'user/manual/en/setting-up/articles/managing-tree-structure-masters' },
-]
+frappe.help.help_links["Tree/Account"] = [
+ {
+ label: "Chart of Accounts",
+ url: docsUrl + "user/manual/en/accounts/chart-of-accounts",
+ },
+ {
+ label: "Managing Tree Mastes",
+ url:
+ docsUrl +
+ "user/manual/en/setting-up/articles/managing-tree-structure-masters",
+ },
+];
-frappe.help.help_links['Form/Sales Invoice'] = [
- { label: 'Sales Invoice', url: docsUrl + 'user/manual/en/accounts/sales-invoice' },
- { label: 'Accounts Opening Balance', url: docsUrl + 'user/manual/en/accounts/opening-accounts' },
- { label: 'Sales Return', url: docsUrl + 'user/manual/en/stock/sales-return' },
- { label: 'Recurring Sales Invoice', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
-]
+frappe.help.help_links["Form/Sales Invoice"] = [
+ {
+ label: "Sales Invoice",
+ url: docsUrl + "user/manual/en/accounts/sales-invoice",
+ },
+ {
+ label: "Accounts Opening Balance",
+ url: docsUrl + "user/manual/en/accounts/opening-accounts",
+ },
+ {
+ label: "Sales Return",
+ url: docsUrl + "user/manual/en/stock/sales-return",
+ },
+ {
+ label: "Recurring Sales Invoice",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+];
-frappe.help.help_links['List/Sales Invoice'] = [
- { label: 'Sales Invoice', url: docsUrl + 'user/manual/en/accounts/sales-invoice' },
- { label: 'Accounts Opening Balance', url: docsUrl + 'user/manual/en/accounts/opening-accounts' },
- { label: 'Sales Return', url: docsUrl + 'user/manual/en/stock/sales-return' },
- { label: 'Recurring Sales Invoice', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
-]
+frappe.help.help_links["List/Sales Invoice"] = [
+ {
+ label: "Sales Invoice",
+ url: docsUrl + "user/manual/en/accounts/sales-invoice",
+ },
+ {
+ label: "Accounts Opening Balance",
+ url: docsUrl + "user/manual/en/accounts/opening-accounts",
+ },
+ {
+ label: "Sales Return",
+ url: docsUrl + "user/manual/en/stock/sales-return",
+ },
+ {
+ label: "Recurring Sales Invoice",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+];
-frappe.help.help_links['pos'] = [
- { label: 'Point of Sale Invoice', url: docsUrl + 'user/manual/en/accounts/point-of-sale-pos-invoice' },
-]
+frappe.help.help_links["pos"] = [
+ {
+ label: "Point of Sale Invoice",
+ url: docsUrl + "user/manual/en/accounts/point-of-sale-pos-invoice",
+ },
+];
-frappe.help.help_links['List/POS Profile'] = [
- { label: 'Point of Sale Profile', url: docsUrl + 'user/manual/en/setting-up/pos-setting' },
-]
+frappe.help.help_links["List/POS Profile"] = [
+ {
+ label: "Point of Sale Profile",
+ url: docsUrl + "user/manual/en/setting-up/pos-setting",
+ },
+];
-frappe.help.help_links['List/Purchase Invoice'] = [
- { label: 'Purchase Invoice', url: docsUrl + 'user/manual/en/accounts/purchase-invoice' },
- { label: 'Accounts Opening Balance', url: docsUrl + 'user/manual/en/accounts/opening-accounts' },
- { label: 'Recurring Purchase Invoice', url: docsUrl + 'user/manual/en/accounts/recurring-orders-and-invoices' },
-]
+frappe.help.help_links["List/Purchase Invoice"] = [
+ {
+ label: "Purchase Invoice",
+ url: docsUrl + "user/manual/en/accounts/purchase-invoice",
+ },
+ {
+ label: "Accounts Opening Balance",
+ url: docsUrl + "user/manual/en/accounts/opening-accounts",
+ },
+ {
+ label: "Recurring Purchase Invoice",
+ url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
+ },
+];
-frappe.help.help_links['List/Journal Entry'] = [
- { label: 'Journal Entry', url: docsUrl + 'user/manual/en/accounts/journal-entry' },
- { label: 'Advance Payment Entry', url: docsUrl + 'user/manual/en/accounts/advance-payment-entry' },
- { label: 'Accounts Opening Balance', url: docsUrl + 'user/manual/en/accounts/opening-accounts' },
-]
+frappe.help.help_links["List/Journal Entry"] = [
+ {
+ label: "Journal Entry",
+ url: docsUrl + "user/manual/en/accounts/journal-entry",
+ },
+ {
+ label: "Advance Payment Entry",
+ url: docsUrl + "user/manual/en/accounts/advance-payment-entry",
+ },
+ {
+ label: "Accounts Opening Balance",
+ url: docsUrl + "user/manual/en/accounts/opening-accounts",
+ },
+];
-frappe.help.help_links['List/Payment Entry'] = [
- { label: 'Payment Entry', url: docsUrl + 'user/manual/en/accounts/payment-entry' },
-]
+frappe.help.help_links["List/Payment Entry"] = [
+ {
+ label: "Payment Entry",
+ url: docsUrl + "user/manual/en/accounts/payment-entry",
+ },
+];
-frappe.help.help_links['List/Payment Request'] = [
- { label: 'Payment Request', url: docsUrl + 'user/manual/en/accounts/payment-request' },
-]
+frappe.help.help_links["List/Payment Request"] = [
+ {
+ label: "Payment Request",
+ url: docsUrl + "user/manual/en/accounts/payment-request",
+ },
+];
-frappe.help.help_links['List/Asset'] = [
- { label: 'Managing Fixed Assets', url: docsUrl + 'user/manual/en/accounts/managing-fixed-assets' },
-]
+frappe.help.help_links["List/Asset"] = [
+ {
+ label: "Managing Fixed Assets",
+ url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+ },
+];
-frappe.help.help_links['List/Asset Category'] = [
- { label: 'Asset Category', url: docsUrl + 'user/manual/en/accounts/managing-fixed-assets' },
-]
+frappe.help.help_links["List/Asset Category"] = [
+ {
+ label: "Asset Category",
+ url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+ },
+];
-frappe.help.help_links['Tree/Cost Center'] = [
- { label: 'Budgeting', url: docsUrl + 'user/manual/en/accounts/budgeting' },
-]
+frappe.help.help_links["Tree/Cost Center"] = [
+ { label: "Budgeting", url: docsUrl + "user/manual/en/accounts/budgeting" },
+];
-frappe.help.help_links['List/Item'] = [
- { label: 'Item', url: docsUrl + 'user/manual/en/stock/item' },
- { label: 'Item Price', url: docsUrl + 'user/manual/en/stock/item/item-price' },
- { label: 'Barcode', url: docsUrl + 'user/manual/en/stock/articles/track-items-using-barcode' },
- { label: 'Item Wise Taxation', url: docsUrl + 'user/manual/en/accounts/item-wise-taxation' },
- { label: 'Managing Fixed Assets', url: docsUrl + 'user/manual/en/accounts/managing-fixed-assets' },
- { label: 'Item Codification', url: docsUrl + 'user/manual/en/stock/item/item-codification' },
- { label: 'Item Variants', url: docsUrl + 'user/manual/en/stock/item/item-variants' },
- { label: 'Item Valuation', url: docsUrl + 'user/manual/en/stock/item/item-valuation-fifo-and-moving-average' },
-]
+frappe.help.help_links["List/Item"] = [
+ { label: "Item", url: docsUrl + "user/manual/en/stock/item" },
+ {
+ label: "Item Price",
+ url: docsUrl + "user/manual/en/stock/item/item-price",
+ },
+ {
+ label: "Barcode",
+ url:
+ docsUrl + "user/manual/en/stock/articles/track-items-using-barcode",
+ },
+ {
+ label: "Item Wise Taxation",
+ url: docsUrl + "user/manual/en/accounts/item-wise-taxation",
+ },
+ {
+ label: "Managing Fixed Assets",
+ url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+ },
+ {
+ label: "Item Codification",
+ url: docsUrl + "user/manual/en/stock/item/item-codification",
+ },
+ {
+ label: "Item Variants",
+ url: docsUrl + "user/manual/en/stock/item/item-variants",
+ },
+ {
+ label: "Item Valuation",
+ url:
+ docsUrl +
+ "user/manual/en/stock/item/item-valuation-fifo-and-moving-average",
+ },
+];
-frappe.help.help_links['Form/Item'] = [
- { label: 'Item', url: docsUrl + 'user/manual/en/stock/item' },
- { label: 'Item Price', url: docsUrl + 'user/manual/en/stock/item/item-price' },
- { label: 'Barcode', url: docsUrl + 'user/manual/en/stock/articles/track-items-using-barcode' },
- { label: 'Item Wise Taxation', url: docsUrl + 'user/manual/en/accounts/item-wise-taxation' },
- { label: 'Managing Fixed Assets', url: docsUrl + 'user/manual/en/accounts/managing-fixed-assets' },
- { label: 'Item Codification', url: docsUrl + 'user/manual/en/stock/item/item-codification' },
- { label: 'Item Variants', url: docsUrl + 'user/manual/en/stock/item/item-variants' },
- { label: 'Item Valuation', url: docsUrl + 'user/manual/en/stock/item/item-valuation-fifo-and-moving-average' },
-]
+frappe.help.help_links["Form/Item"] = [
+ { label: "Item", url: docsUrl + "user/manual/en/stock/item" },
+ {
+ label: "Item Price",
+ url: docsUrl + "user/manual/en/stock/item/item-price",
+ },
+ {
+ label: "Barcode",
+ url:
+ docsUrl + "user/manual/en/stock/articles/track-items-using-barcode",
+ },
+ {
+ label: "Item Wise Taxation",
+ url: docsUrl + "user/manual/en/accounts/item-wise-taxation",
+ },
+ {
+ label: "Managing Fixed Assets",
+ url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+ },
+ {
+ label: "Item Codification",
+ url: docsUrl + "user/manual/en/stock/item/item-codification",
+ },
+ {
+ label: "Item Variants",
+ url: docsUrl + "user/manual/en/stock/item/item-variants",
+ },
+ {
+ label: "Item Valuation",
+ url:
+ docsUrl +
+ "user/manual/en/stock/item/item-valuation-fifo-and-moving-average",
+ },
+];
-frappe.help.help_links['List/Purchase Receipt'] = [
- { label: 'Purchase Receipt', url: docsUrl + 'user/manual/en/stock/purchase-receipt' },
- { label: 'Barcode', url: docsUrl + 'user/manual/en/stock/articles/track-items-using-barcode' },
-]
+frappe.help.help_links["List/Purchase Receipt"] = [
+ {
+ label: "Purchase Receipt",
+ url: docsUrl + "user/manual/en/stock/purchase-receipt",
+ },
+ {
+ label: "Barcode",
+ url:
+ docsUrl + "user/manual/en/stock/articles/track-items-using-barcode",
+ },
+];
-frappe.help.help_links['List/Delivery Note'] = [
- { label: 'Delivery Note', url: docsUrl + 'user/manual/en/stock/delivery-note' },
- { label: 'Barcode', url: docsUrl + 'user/manual/en/stock/articles/track-items-using-barcode' },
- { label: 'Sales Return', url: docsUrl + 'user/manual/en/stock/sales-return' },
-]
+frappe.help.help_links["List/Delivery Note"] = [
+ {
+ label: "Delivery Note",
+ url: docsUrl + "user/manual/en/stock/delivery-note",
+ },
+ {
+ label: "Barcode",
+ url:
+ docsUrl + "user/manual/en/stock/articles/track-items-using-barcode",
+ },
+ {
+ label: "Sales Return",
+ url: docsUrl + "user/manual/en/stock/sales-return",
+ },
+];
-frappe.help.help_links['Form/Delivery Note'] = [
- { label: 'Delivery Note', url: docsUrl + 'user/manual/en/stock/delivery-note' },
- { label: 'Sales Return', url: docsUrl + 'user/manual/en/stock/sales-return' },
- { label: 'Barcode', url: docsUrl + 'user/manual/en/stock/articles/track-items-using-barcode' },
- { label: 'Subcontracting', url: docsUrl + 'user/manual/en/manufacturing/subcontracting' },
-]
+frappe.help.help_links["Form/Delivery Note"] = [
+ {
+ label: "Delivery Note",
+ url: docsUrl + "user/manual/en/stock/delivery-note",
+ },
+ {
+ label: "Sales Return",
+ url: docsUrl + "user/manual/en/stock/sales-return",
+ },
+ {
+ label: "Barcode",
+ 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'] = [
- { label: 'Installation Note', url: docsUrl + 'user/manual/en/stock/installation-note' },
-]
+frappe.help.help_links["List/Installation Note"] = [
+ {
+ label: "Installation Note",
+ url: docsUrl + "user/manual/en/stock/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['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' },
-]
+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', url: docsUrl + 'user/manual/en/stock/material-request' },
- { label: 'Auto-creation of Material Request', url: docsUrl + 'user/manual/en/stock/articles/auto-creation-of-material-request' },
-]
+frappe.help.help_links["List/Material Request"] = [
+ {
+ label: "Material Request",
+ url: docsUrl + "user/manual/en/stock/material-request",
+ },
+ {
+ label: "Auto-creation of Material Request",
+ url:
+ docsUrl +
+ "user/manual/en/stock/articles/auto-creation-of-material-request",
+ },
+];
-frappe.help.help_links['Form/Material Request'] = [
- { label: 'Material Request', url: docsUrl + 'user/manual/en/stock/material-request' },
- { label: 'Auto-creation of Material Request', url: docsUrl + 'user/manual/en/stock/articles/auto-creation-of-material-request' },
-]
+frappe.help.help_links["Form/Material Request"] = [
+ {
+ label: "Material Request",
+ url: docsUrl + "user/manual/en/stock/material-request",
+ },
+ {
+ label: "Auto-creation of Material Request",
+ url:
+ docsUrl +
+ "user/manual/en/stock/articles/auto-creation-of-material-request",
+ },
+];
-frappe.help.help_links['Form/Stock Entry'] = [
- { label: 'Stock Entry', url: docsUrl + 'user/manual/en/stock/stock-entry' },
- { label: 'Stock Entry Types', url: docsUrl + 'user/manual/en/stock/articles/stock-entry-purpose' },
- { label: 'Repack Entry', url: docsUrl + 'user/manual/en/stock/articles/repack-entry' },
- { label: 'Opening Stock', url: docsUrl + 'user/manual/en/stock/opening-stock' },
- { label: 'Subcontracting', url: docsUrl + 'user/manual/en/manufacturing/subcontracting' },
-]
+frappe.help.help_links["Form/Stock Entry"] = [
+ { label: "Stock Entry", url: docsUrl + "user/manual/en/stock/stock-entry" },
+ {
+ label: "Stock Entry Types",
+ url: docsUrl + "user/manual/en/stock/articles/stock-entry-purpose",
+ },
+ {
+ label: "Repack Entry",
+ url: docsUrl + "user/manual/en/stock/articles/repack-entry",
+ },
+ {
+ label: "Opening Stock",
+ url: docsUrl + "user/manual/en/stock/opening-stock",
+ },
+ {
+ label: "Subcontracting",
+ url: docsUrl + "user/manual/en/manufacturing/subcontracting",
+ },
+];
-frappe.help.help_links['List/Stock Entry'] = [
- { label: 'Stock Entry', url: docsUrl + 'user/manual/en/stock/stock-entry' },
-]
+frappe.help.help_links["List/Stock Entry"] = [
+ { label: "Stock Entry", url: docsUrl + "user/manual/en/stock/stock-entry" },
+];
-frappe.help.help_links['Tree/Warehouse'] = [
- { label: 'Warehouse', url: docsUrl + 'user/manual/en/stock/warehouse' },
-]
+frappe.help.help_links["Tree/Warehouse"] = [
+ { label: "Warehouse", url: docsUrl + "user/manual/en/stock/warehouse" },
+];
-frappe.help.help_links['List/Serial No'] = [
- { label: 'Serial No', url: docsUrl + 'user/manual/en/stock/serial-no' },
-]
+frappe.help.help_links["List/Serial No"] = [
+ { label: "Serial No", url: docsUrl + "user/manual/en/stock/serial-no" },
+];
-frappe.help.help_links['Form/Serial No'] = [
- { label: 'Serial No', url: docsUrl + 'user/manual/en/stock/serial-no' },
-]
+frappe.help.help_links["Form/Serial No"] = [
+ { label: "Serial No", url: docsUrl + "user/manual/en/stock/serial-no" },
+];
-frappe.help.help_links['Form/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" },
+];
-frappe.help.help_links['Form/Packing Slip'] = [
- { label: 'Packing Slip', url: docsUrl + 'user/manual/en/stock/tools/packing-slip' },
-]
+frappe.help.help_links["Form/Packing Slip"] = [
+ {
+ label: "Packing Slip",
+ url: docsUrl + "user/manual/en/stock/tools/packing-slip",
+ },
+];
-frappe.help.help_links['Form/Quality Inspection'] = [
- { label: 'Quality Inspection', url: docsUrl + 'user/manual/en/stock/tools/quality-inspection' },
-]
+frappe.help.help_links["Form/Quality Inspection"] = [
+ {
+ label: "Quality Inspection",
+ url: docsUrl + "user/manual/en/stock/tools/quality-inspection",
+ },
+];
-frappe.help.help_links['Form/Landed Cost Voucher'] = [
- { label: 'Landed Cost Voucher', url: docsUrl + 'user/manual/en/stock/tools/landed-cost-voucher' },
-]
+frappe.help.help_links["Form/Landed Cost Voucher"] = [
+ {
+ label: "Landed Cost Voucher",
+ url: docsUrl + "user/manual/en/stock/tools/landed-cost-voucher",
+ },
+];
-frappe.help.help_links['Tree/Item Group'] = [
- { label: 'Item Group', url: docsUrl + 'user/manual/en/stock/setup/item-group' },
-]
+frappe.help.help_links["Tree/Item Group"] = [
+ {
+ label: "Item Group",
+ url: docsUrl + "user/manual/en/stock/setup/item-group",
+ },
+];
-frappe.help.help_links['Form/Item Attribute'] = [
- { label: 'Item Attribute', url: docsUrl + 'user/manual/en/stock/setup/item-attribute' },
-]
+frappe.help.help_links["Form/Item Attribute"] = [
+ {
+ label: "Item Attribute",
+ url: docsUrl + "user/manual/en/stock/setup/item-attribute",
+ },
+];
-frappe.help.help_links['Form/UOM'] = [
- { label: 'Fractions in UOM', url: docsUrl + 'user/manual/en/stock/articles/managing-fractions-in-uom' },
-]
+frappe.help.help_links["Form/UOM"] = [
+ {
+ label: "Fractions in UOM",
+ url:
+ docsUrl + "user/manual/en/stock/articles/managing-fractions-in-uom",
+ },
+];
-frappe.help.help_links['Form/Stock Reconciliation'] = [
- { label: 'Opening Stock Entry', url: docsUrl + 'user/manual/en/stock/opening-stock' },
-]
+frappe.help.help_links["Form/Stock Reconciliation"] = [
+ {
+ label: "Opening Stock Entry",
+ url: docsUrl + "user/manual/en/stock/opening-stock",
+ },
+];
//CRM
-frappe.help.help_links['Form/Lead'] = [
- { label: 'Lead', url: docsUrl + 'user/manual/en/CRM/lead' },
-]
+frappe.help.help_links["Form/Lead"] = [
+ { label: "Lead", url: docsUrl + "user/manual/en/CRM/lead" },
+];
-frappe.help.help_links['Form/Opportunity'] = [
- { label: 'Opportunity', url: docsUrl + 'user/manual/en/CRM/opportunity' },
-]
+frappe.help.help_links["Form/Opportunity"] = [
+ { label: "Opportunity", url: docsUrl + "user/manual/en/CRM/opportunity" },
+];
-frappe.help.help_links['Form/Address'] = [
- { label: 'Address', url: docsUrl + 'user/manual/en/CRM/address' },
-]
+frappe.help.help_links["Form/Address"] = [
+ { label: "Address", url: docsUrl + "user/manual/en/CRM/address" },
+];
-frappe.help.help_links['Form/Contact'] = [
- { label: 'Contact', url: docsUrl + 'user/manual/en/CRM/contact' },
-]
+frappe.help.help_links["Form/Contact"] = [
+ { label: "Contact", url: docsUrl + "user/manual/en/CRM/contact" },
+];
-frappe.help.help_links['Form/Newsletter'] = [
- { label: 'Newsletter', url: docsUrl + 'user/manual/en/CRM/newsletter' },
-]
+frappe.help.help_links["Form/Newsletter"] = [
+ { label: "Newsletter", url: docsUrl + "user/manual/en/CRM/newsletter" },
+];
-frappe.help.help_links['Form/Campaign'] = [
- { label: 'Campaign', url: docsUrl + 'user/manual/en/CRM/setup/campaign' },
-]
+frappe.help.help_links["Form/Campaign"] = [
+ { label: "Campaign", url: docsUrl + "user/manual/en/CRM/setup/campaign" },
+];
-frappe.help.help_links['Tree/Sales Person'] = [
- { label: 'Sales Person', url: docsUrl + 'user/manual/en/CRM/setup/sales-person' },
-]
+frappe.help.help_links["Tree/Sales Person"] = [
+ {
+ label: "Sales Person",
+ url: docsUrl + "user/manual/en/CRM/setup/sales-person",
+ },
+];
-frappe.help.help_links['Form/Sales Person'] = [
- { label: 'Sales Person Target', url: docsUrl + 'user/manual/en/selling/setup/sales-person-target-allocation' },
-]
+frappe.help.help_links["Form/Sales Person"] = [
+ {
+ label: "Sales Person Target",
+ url:
+ docsUrl +
+ "user/manual/en/selling/setup/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 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",
+ },
+];
-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",
+ },
+];
//Manufacturing
-frappe.help.help_links['Form/BOM'] = [
- { label: 'Bill of Material', url: docsUrl + 'user/manual/en/manufacturing/bill-of-materials' },
- { label: 'Nested BOM Structure', url: docsUrl + 'user/manual/en/manufacturing/articles/nested-bom-structure' },
-]
+frappe.help.help_links["Form/BOM"] = [
+ {
+ label: "Bill of Material",
+ url: docsUrl + "user/manual/en/manufacturing/bill-of-materials",
+ },
+ {
+ label: "Nested BOM Structure",
+ url:
+ docsUrl +
+ "user/manual/en/manufacturing/articles/nested-bom-structure",
+ },
+];
-frappe.help.help_links['Form/Work Order'] = [
- { label: 'Work Order', url: docsUrl + 'user/manual/en/manufacturing/work-order' },
-]
+frappe.help.help_links["Form/Work Order"] = [
+ {
+ label: "Work Order",
+ url: docsUrl + "user/manual/en/manufacturing/work-order",
+ },
+];
-frappe.help.help_links['Form/Workstation'] = [
- { label: 'Workstation', url: docsUrl + 'user/manual/en/manufacturing/workstation' },
-]
+frappe.help.help_links["Form/Workstation"] = [
+ {
+ label: "Workstation",
+ url: docsUrl + "user/manual/en/manufacturing/workstation",
+ },
+];
-frappe.help.help_links['Form/Operation'] = [
- { label: 'Operation', url: docsUrl + 'user/manual/en/manufacturing/operation' },
-]
+frappe.help.help_links["Form/Operation"] = [
+ {
+ label: "Operation",
+ url: docsUrl + "user/manual/en/manufacturing/operation",
+ },
+];
-frappe.help.help_links['Form/BOM Update Tool'] = [
- { label: 'BOM Update Tool', url: docsUrl + 'user/manual/en/manufacturing/tools/bom-update-tool' },
-]
+frappe.help.help_links["Form/BOM Update Tool"] = [
+ {
+ label: "BOM Update Tool",
+ url: docsUrl + "user/manual/en/manufacturing/tools/bom-update-tool",
+ },
+];
//Customize
-frappe.help.help_links['Form/Customize Form'] = [
- { label: 'Custom Field', url: docsUrl + 'user/manual/en/customize-erpnext/custom-field' },
- { label: 'Customize Field', url: docsUrl + 'user/manual/en/customize-erpnext/customize-form' },
-]
+frappe.help.help_links["Form/Customize Form"] = [
+ {
+ label: "Custom Field",
+ url: docsUrl + "user/manual/en/customize-erpnext/custom-field",
+ },
+ {
+ label: "Customize Field",
+ url: docsUrl + "user/manual/en/customize-erpnext/customize-form",
+ },
+];
-frappe.help.help_links['Form/Custom Field'] = [
- { label: 'Custom Field', url: docsUrl + 'user/manual/en/customize-erpnext/custom-field' },
-]
+frappe.help.help_links["Form/Custom Field"] = [
+ {
+ label: "Custom Field",
+ url: docsUrl + "user/manual/en/customize-erpnext/custom-field",
+ },
+];
-frappe.help.help_links['Form/Custom Field'] = [
- { label: 'Custom Field', url: docsUrl + 'user/manual/en/customize-erpnext/custom-field' },
-]
+frappe.help.help_links["Form/Custom Field"] = [
+ {
+ label: "Custom Field",
+ url: docsUrl + "user/manual/en/customize-erpnext/custom-field",
+ },
+];
diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue
index 057fe8b..16d0601 100644
--- a/erpnext/public/js/hub/pages/Category.vue
+++ b/erpnext/public/js/hub/pages/Category.vue
@@ -32,7 +32,7 @@
item_id_fieldname: 'name',
// Constants
- empty_state_message: __(`No items in this category yet.`),
+ empty_state_message: __('No items in this category yet.'),
search_value: '',
diff --git a/erpnext/public/js/hub/pages/FeaturedItems.vue b/erpnext/public/js/hub/pages/FeaturedItems.vue
index ab9990a..63ae7e9 100644
--- a/erpnext/public/js/hub/pages/FeaturedItems.vue
+++ b/erpnext/public/js/hub/pages/FeaturedItems.vue
@@ -33,10 +33,8 @@
// Constants
page_title: __('Your Featured Items'),
- empty_state_message: __(`No featured items yet. Got to your
- <a href="#marketplace/published-items">
- Published Items</a>
- and feature upto 8 items that you want to highlight to your customers.`)
+ empty_state_message: __('No featured items yet. Got to your {0} and feature up to eight items that you want to highlight to your customers.',
+ [`<a href="#marketplace/published-items">${__("Published Items")}</a>`])
};
},
created() {
@@ -71,9 +69,9 @@
const item_name = this.items.filter(item => item.hub_item_name === hub_item_name);
- alert = frappe.show_alert(__(`<span>${item_name} removed.
- <a href="#" data-action="undo-remove"><b>Undo</b></a></span>`),
- grace_period/1000,
+ alert_message = __('{0} removed. {1}', [item_name,
+ `<a href="#" data-action="undo-remove"><b>${__('Undo')}</b></a>`]);
+ alert = frappe.show_alert(alert_message, grace_period / 1000,
{
'undo-remove': undo_remove.bind(this)
}
diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue
index 51ade42..93002a7 100644
--- a/erpnext/public/js/hub/pages/Item.vue
+++ b/erpnext/public/js/hub/pages/Item.vue
@@ -113,12 +113,12 @@
let stats = __('No views yet');
if (this.item.view_count) {
- const views_message = __(`${this.item.view_count} Views`);
+ const views_message = __('{0} Views', [this.item.view_count]);
const rating_html = get_rating_html(this.item.average_rating);
const rating_count =
this.item.no_of_ratings > 0
- ? `${this.item.no_of_ratings} reviews`
+ ? __('{0} reviews', [this.item.no_of_ratings])
: __('No reviews yet');
stats = [views_message, rating_html, rating_count];
@@ -310,7 +310,7 @@
return this.get_item_details();
})
.then(() => {
- frappe.show_alert(__(`${this.item.item_name} Updated`));
+ frappe.show_alert(__('{0} Updated', [this.item.item_name]));
});
},
@@ -337,7 +337,7 @@
},
unpublish_item() {
- frappe.confirm(__(`Unpublish {0}?`, [this.item.item_name]), () => {
+ frappe.confirm(__('Unpublish {0}?', [this.item.item_name]), () => {
frappe
.call('erpnext.hub_node.api.unpublish_item', {
item_code: this.item.item_code,
diff --git a/erpnext/public/js/hub/pages/NotFound.vue b/erpnext/public/js/hub/pages/NotFound.vue
index 246d31b..8901b97 100644
--- a/erpnext/public/js/hub/pages/NotFound.vue
+++ b/erpnext/public/js/hub/pages/NotFound.vue
@@ -27,7 +27,7 @@
},
// Constants
- empty_state_message: __(`Sorry! I could not find what you were looking for.`)
+ empty_state_message: __('Sorry! We could not find what you were looking for.')
};
},
}
diff --git a/erpnext/public/js/hub/pages/Publish.vue b/erpnext/public/js/hub/pages/Publish.vue
index 735f2b9..96fa0aa 100644
--- a/erpnext/public/js/hub/pages/Publish.vue
+++ b/erpnext/public/js/hub/pages/Publish.vue
@@ -75,14 +75,11 @@
// TODO: multiline translations don't work
page_title: __('Publish Items'),
search_placeholder: __('Search Items ...'),
- empty_state_message: __(`No Items selected yet. Browse and click on items below to publish.`),
- valid_items_instruction: __(`Only items with an image and description can be published. Please update them if an item in your inventory does not appear.`),
+ empty_state_message: __('No Items selected yet. Browse and click on items below to publish.'),
+ valid_items_instruction: __('Only items with an image and description can be published. Please update them if an item in your inventory does not appear.'),
last_sync_message: (hub.settings.last_sync_datetime)
- ? __(`Last sync was
- <a href="#marketplace/profile">
- ${comment_when(hub.settings.last_sync_datetime)}</a>.
- <a href="#marketplace/published-items">
- See your Published Items</a>.`)
+ ? __('Last sync was {0}.', [`<a href="#marketplace/profile">${comment_when(hub.settings.last_sync_datetime)}</a>`]) +
+ ` <a href="#marketplace/published-items">${__('See your Published Items.')}</a>`
: ''
};
},
@@ -147,11 +144,9 @@
},
add_last_sync_message() {
- this.last_sync_message = __(`Last sync was
- <a href="#marketplace/profile">
- ${comment_when(hub.settings.last_sync_datetime)}</a>.
- <a href="#marketplace/published-items">
- See your Published Items</a>.`);
+ this.last_sync_message = __('Last sync was {0}.',
+ [`<a href="#marketplace/profile">${comment_when(hub.settings.last_sync_datetime)}</a>`]
+ ) + `<a href="#marketplace/published-items">${__('See your Published Items')}</a>.`;
},
clear_last_sync_message() {
diff --git a/erpnext/public/js/hub/pages/SavedItems.vue b/erpnext/public/js/hub/pages/SavedItems.vue
index c29675a..7007ddc 100644
--- a/erpnext/public/js/hub/pages/SavedItems.vue
+++ b/erpnext/public/js/hub/pages/SavedItems.vue
@@ -29,7 +29,7 @@
// Constants
page_title: __('Saved Items'),
- empty_state_message: __(`You haven't saved any items yet.`)
+ empty_state_message: __('You have not saved any items yet.')
};
},
created() {
@@ -64,8 +64,13 @@
const item_name = this.items.filter(item => item.hub_item_name === hub_item_name);
- alert = frappe.show_alert(__(`<span>${item_name} removed.
- <a href="#" data-action="undo-remove"><b>Undo</b></a></span>`),
+ alert = frappe.show_alert(`
+ <span>
+ ${__('{0} removed.', [item_name], 'A specific Item has been removed.')}
+ <a href="#" data-action="undo-remove">
+ <b>${__('Undo', None, 'Undo removal of item.')}</b>
+ </a>
+ </span>`,
grace_period/1000,
{
'undo-remove': undo_remove.bind(this)
diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue
index 1032842..c10841e 100644
--- a/erpnext/public/js/hub/pages/Search.vue
+++ b/erpnext/public/js/hub/pages/Search.vue
@@ -42,7 +42,10 @@
computed: {
page_title() {
return this.items.length
- ? __(`Results for "${this.search_value}" ${this.category !== 'All'? `in category ${this.category}` : ''}`)
+ ? __('Results for "{0}" {1}', [
+ this.search_value,
+ this.category !== 'All' ? __('in category {0}', [this.category]) : ''
+ ])
: __('No Items found.');
}
},
diff --git a/erpnext/public/js/hub/pages/Seller.vue b/erpnext/public/js/hub/pages/Seller.vue
index e339eaa..c0903c6 100644
--- a/erpnext/public/js/hub/pages/Seller.vue
+++ b/erpnext/public/js/hub/pages/Seller.vue
@@ -136,7 +136,7 @@
this.init = false;
this.profile = data.profile;
this.items = data.items;
- this.item_container_heading = data.is_featured_item? "Features Items":"Popular Items";
+ this.item_container_heading = data.is_featured_item ? __('Featured Items') : __('Popular Items');
this.hub_seller = this.items[0].hub_seller;
this.recent_seller_reviews = data.recent_seller_reviews;
this.seller_product_view_stats = data.seller_product_view_stats;
@@ -147,7 +147,7 @@
this.country = __(profile.country);
this.site_name = __(profile.site_name);
- this.joined_when = __(`Joined ${comment_when(profile.creation)}`);
+ this.joined_when = __('Joined {0}', [comment_when(profile.creation)]);
this.image = profile.logo;
this.sections = [
diff --git a/erpnext/public/js/payment/payment_details.html b/erpnext/public/js/payment/payment_details.html
deleted file mode 100644
index 3e63944..0000000
--- a/erpnext/public/js/payment/payment_details.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<div class="row pos-payment-row" type="{{type}}" idx={{idx}}>
- <div class="col-xs-6" style="padding:20px">{{mode_of_payment}}</div>
- <div class="col-xs-6">
- <div class="input-group">
- <input disabled class="form-control text-right amount" idx="{{idx}}" type="text" value="{%= format_currency(amount, currency) %}">
- <span class="input-group-btn">
- <button type="button" class="btn btn-default clr" idx="{{idx}}" style="border:1px solid #d1d8dd">C</button>
- </span>
- </div>
- </div>
-</div>
\ No newline at end of file
diff --git a/erpnext/public/js/payment/pos_payment.html b/erpnext/public/js/payment/pos_payment.html
deleted file mode 100644
index cb6971b..0000000
--- a/erpnext/public/js/payment/pos_payment.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<div class="pos_payment row">
- <div class="row" style="padding: 0px 30px;">
- <h3>{{ __("Total Amount") }}: <span class="label label-default" style="font-size:20px;padding:5px">{%= format_currency(grand_total, currency) %}</span></h3>
- </div>
- <div class="row amount-row">
- <div class="col-xs-6 col-sm-3 text-center">
- <p class="amount-label"> {{ __("Paid") }} <h3 class="paid_amount">{%= format_currency(paid_amount, currency) %}</h3></p>
- </div>
- <div class="col-xs-6 col-sm-3 text-center">
- <p class="amount-label"> {{ __("Outstanding") }} <h3 class="outstanding_amount">{%= format_currency(outstanding_amount, currency) %} </h3></p>
- </div>
- <div class="col-xs-6 col-sm-3 text-center">
- <p class="amount-label"> {{ __("Change") }} <input class="form-control text-right change_amount bold" type="text" idx="change_amount" value="{{format_number(change_amount, null, 2)}}">
- </p>
- </div>
- <div class="col-xs-6 col-sm-3 text-center">
- <p class="amount-label"> {{ __("Write off") }} <input class="form-control text-right write_off_amount bold" type="text" idx="write_off_amount" value="{{format_number(write_off_amount, null, 2)}}">
- </p>
- </div>
- </div>
- <hr>
- <div class="row">
- <div class="col-sm-6 ">
- <div class ="row multimode-payments" style = "margin-right:10px">
- </div>
- </div>
- <div class="col-sm-6 payment-toolbar">
- {% for(var i=0; i<3; i++) { %}
- <div class="row">
- {% for(var j=i*3; j<(i+1)*3; j++) { %}
- <button type="button" class="btn btn-default pos-keyboard-key">{{j+1}}</button>
- {% } %}
- </div>
- {% } %}
- <div class="row">
- <button type="button" class="btn btn-default delete-btn">{{ __("Del") }}</button>
- <button type="button" class="btn btn-default pos-keyboard-key">0</button>
- <button type="button" class="btn btn-default pos-keyboard-key">.</button>
- </div>
- </div>
- </div>
-</div>
diff --git a/erpnext/public/js/pos/clusterize.js b/erpnext/public/js/pos/clusterize.js
deleted file mode 100644
index 075c9ca..0000000
--- a/erpnext/public/js/pos/clusterize.js
+++ /dev/null
@@ -1,330 +0,0 @@
-/* eslint-disable */
-/*! Clusterize.js - v0.17.6 - 2017-03-05
-* http://NeXTs.github.com/Clusterize.js/
-* Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
-
-;(function(name, definition) {
- if (typeof module != 'undefined') module.exports = definition();
- else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
- else this[name] = definition();
-}('Clusterize', function() {
- "use strict"
-
- // detect ie9 and lower
- // https://gist.github.com/padolsey/527683#comment-786682
- var ie = (function(){
- for( var v = 3,
- el = document.createElement('b'),
- all = el.all || [];
- el.innerHTML = '<!--[if gt IE ' + (++v) + ']><i><![endif]-->',
- all[0];
- ){}
- return v > 4 ? v : document.documentMode;
- }()),
- is_mac = navigator.platform.toLowerCase().indexOf('mac') + 1;
- var Clusterize = function(data) {
- if( ! (this instanceof Clusterize))
- return new Clusterize(data);
- var self = this;
-
- var defaults = {
- rows_in_block: 50,
- blocks_in_cluster: 4,
- tag: null,
- show_no_data_row: true,
- no_data_class: 'clusterize-no-data',
- no_data_text: 'No data',
- keep_parity: true,
- callbacks: {}
- }
-
- // public parameters
- self.options = {};
- var options = ['rows_in_block', 'blocks_in_cluster', 'show_no_data_row', 'no_data_class', 'no_data_text', 'keep_parity', 'tag', 'callbacks'];
- for(var i = 0, option; option = options[i]; i++) {
- self.options[option] = typeof data[option] != 'undefined' && data[option] != null
- ? data[option]
- : defaults[option];
- }
-
- var elems = ['scroll', 'content'];
- for(var i = 0, elem; elem = elems[i]; i++) {
- self[elem + '_elem'] = data[elem + 'Id']
- ? document.getElementById(data[elem + 'Id'])
- : data[elem + 'Elem'];
- if( ! self[elem + '_elem'])
- throw new Error("Error! Could not find " + elem + " element");
- }
-
- // tabindex forces the browser to keep focus on the scrolling list, fixes #11
- if( ! self.content_elem.hasAttribute('tabindex'))
- self.content_elem.setAttribute('tabindex', 0);
-
- // private parameters
- var rows = isArray(data.rows)
- ? data.rows
- : self.fetchMarkup(),
- cache = {},
- scroll_top = self.scroll_elem.scrollTop;
-
- // append initial data
- self.insertToDOM(rows, cache);
-
- // restore the scroll position
- self.scroll_elem.scrollTop = scroll_top;
-
- // adding scroll handler
- var last_cluster = false,
- scroll_debounce = 0,
- pointer_events_set = false,
- scrollEv = function() {
- // fixes scrolling issue on Mac #3
- if (is_mac) {
- if( ! pointer_events_set) self.content_elem.style.pointerEvents = 'none';
- pointer_events_set = true;
- clearTimeout(scroll_debounce);
- scroll_debounce = setTimeout(function () {
- self.content_elem.style.pointerEvents = 'auto';
- pointer_events_set = false;
- }, 50);
- }
- if (last_cluster != (last_cluster = self.getClusterNum()))
- self.insertToDOM(rows, cache);
- if (self.options.callbacks.scrollingProgress)
- self.options.callbacks.scrollingProgress(self.getScrollProgress());
- },
- resize_debounce = 0,
- resizeEv = function() {
- clearTimeout(resize_debounce);
- resize_debounce = setTimeout(self.refresh, 100);
- }
- on('scroll', self.scroll_elem, scrollEv);
- on('resize', window, resizeEv);
-
- // public methods
- self.destroy = function(clean) {
- off('scroll', self.scroll_elem, scrollEv);
- off('resize', window, resizeEv);
- self.html((clean ? self.generateEmptyRow() : rows).join(''));
- }
- self.refresh = function(force) {
- if(self.getRowsHeight(rows) || force) self.update(rows);
- }
- self.update = function(new_rows) {
- rows = isArray(new_rows)
- ? new_rows
- : [];
- var scroll_top = self.scroll_elem.scrollTop;
- // fixes #39
- if(rows.length * self.options.item_height < scroll_top) {
- self.scroll_elem.scrollTop = 0;
- last_cluster = 0;
- }
- self.insertToDOM(rows, cache);
- self.scroll_elem.scrollTop = scroll_top;
- }
- self.clear = function() {
- self.update([]);
- }
- self.getRowsAmount = function() {
- return rows.length;
- }
- self.getScrollProgress = function() {
- return this.options.scroll_top / (rows.length * this.options.item_height) * 100 || 0;
- }
-
- var add = function(where, _new_rows) {
- var new_rows = isArray(_new_rows)
- ? _new_rows
- : [];
- if( ! new_rows.length) return;
- rows = where == 'append'
- ? rows.concat(new_rows)
- : new_rows.concat(rows);
- self.insertToDOM(rows, cache);
- }
- self.append = function(rows) {
- add('append', rows);
- }
- self.prepend = function(rows) {
- add('prepend', rows);
- }
- }
-
- Clusterize.prototype = {
- constructor: Clusterize,
- // fetch existing markup
- fetchMarkup: function() {
- var rows = [], rows_nodes = this.getChildNodes(this.content_elem);
- while (rows_nodes.length) {
- rows.push(rows_nodes.shift().outerHTML);
- }
- return rows;
- },
- // get tag name, content tag name, tag height, calc cluster height
- exploreEnvironment: function(rows, cache) {
- var opts = this.options;
- opts.content_tag = this.content_elem.tagName.toLowerCase();
- if( ! rows.length) return;
- if(ie && ie <= 9 && ! opts.tag) opts.tag = rows[0].match(/<([^>\s/]*)/)[1].toLowerCase();
- if(this.content_elem.children.length <= 1) cache.data = this.html(rows[0] + rows[0] + rows[0]);
- if( ! opts.tag) opts.tag = this.content_elem.children[0].tagName.toLowerCase();
- this.getRowsHeight(rows);
- },
- getRowsHeight: function(rows) {
- var opts = this.options,
- prev_item_height = opts.item_height;
- opts.cluster_height = 0;
- if( ! rows.length) return;
- var nodes = this.content_elem.children;
- var node = nodes[Math.floor(nodes.length / 2)];
- opts.item_height = node.offsetHeight;
- // consider table's border-spacing
- if(opts.tag == 'tr' && getStyle('borderCollapse', this.content_elem) != 'collapse')
- opts.item_height += parseInt(getStyle('borderSpacing', this.content_elem), 10) || 0;
- // consider margins (and margins collapsing)
- if(opts.tag != 'tr') {
- var marginTop = parseInt(getStyle('marginTop', node), 10) || 0;
- var marginBottom = parseInt(getStyle('marginBottom', node), 10) || 0;
- opts.item_height += Math.max(marginTop, marginBottom);
- }
- opts.block_height = opts.item_height * opts.rows_in_block;
- opts.rows_in_cluster = opts.blocks_in_cluster * opts.rows_in_block;
- opts.cluster_height = opts.blocks_in_cluster * opts.block_height;
- return prev_item_height != opts.item_height;
- },
- // get current cluster number
- getClusterNum: function () {
- this.options.scroll_top = this.scroll_elem.scrollTop;
- return Math.floor(this.options.scroll_top / (this.options.cluster_height - this.options.block_height)) || 0;
- },
- // generate empty row if no data provided
- generateEmptyRow: function() {
- var opts = this.options;
- if( ! opts.tag || ! opts.show_no_data_row) return [];
- var empty_row = document.createElement(opts.tag),
- no_data_content = document.createTextNode(opts.no_data_text), td;
- empty_row.className = opts.no_data_class;
- if(opts.tag == 'tr') {
- td = document.createElement('td');
- // fixes #53
- td.colSpan = 100;
- td.appendChild(no_data_content);
- }
- empty_row.appendChild(td || no_data_content);
- return [empty_row.outerHTML];
- },
- // generate cluster for current scroll position
- generate: function (rows, cluster_num) {
- var opts = this.options,
- rows_len = rows.length;
- if (rows_len < opts.rows_in_block) {
- return {
- top_offset: 0,
- bottom_offset: 0,
- rows_above: 0,
- rows: rows_len ? rows : this.generateEmptyRow()
- }
- }
- var items_start = Math.max((opts.rows_in_cluster - opts.rows_in_block) * cluster_num, 0),
- items_end = items_start + opts.rows_in_cluster,
- top_offset = Math.max(items_start * opts.item_height, 0),
- bottom_offset = Math.max((rows_len - items_end) * opts.item_height, 0),
- this_cluster_rows = [],
- rows_above = items_start;
- if(top_offset < 1) {
- rows_above++;
- }
- for (var i = items_start; i < items_end; i++) {
- rows[i] && this_cluster_rows.push(rows[i]);
- }
- return {
- top_offset: top_offset,
- bottom_offset: bottom_offset,
- rows_above: rows_above,
- rows: this_cluster_rows
- }
- },
- renderExtraTag: function(class_name, height) {
- var tag = document.createElement(this.options.tag),
- clusterize_prefix = 'clusterize-';
- tag.className = [clusterize_prefix + 'extra-row', clusterize_prefix + class_name].join(' ');
- height && (tag.style.height = height + 'px');
- return tag.outerHTML;
- },
- // if necessary verify data changed and insert to DOM
- insertToDOM: function(rows, cache) {
- // explore row's height
- if( ! this.options.cluster_height) {
- this.exploreEnvironment(rows, cache);
- }
- var data = this.generate(rows, this.getClusterNum()),
- this_cluster_rows = data.rows.join(''),
- this_cluster_content_changed = this.checkChanges('data', this_cluster_rows, cache),
- top_offset_changed = this.checkChanges('top', data.top_offset, cache),
- only_bottom_offset_changed = this.checkChanges('bottom', data.bottom_offset, cache),
- callbacks = this.options.callbacks,
- layout = [];
-
- if(this_cluster_content_changed || top_offset_changed) {
- if(data.top_offset) {
- this.options.keep_parity && layout.push(this.renderExtraTag('keep-parity'));
- layout.push(this.renderExtraTag('top-space', data.top_offset));
- }
- layout.push(this_cluster_rows);
- data.bottom_offset && layout.push(this.renderExtraTag('bottom-space', data.bottom_offset));
- callbacks.clusterWillChange && callbacks.clusterWillChange();
- this.html(layout.join(''));
- this.options.content_tag == 'ol' && this.content_elem.setAttribute('start', data.rows_above);
- callbacks.clusterChanged && callbacks.clusterChanged();
- } else if(only_bottom_offset_changed) {
- this.content_elem.lastChild.style.height = data.bottom_offset + 'px';
- }
- },
- // unfortunately ie <= 9 does not allow to use innerHTML for table elements, so make a workaround
- html: function(data) {
- var content_elem = this.content_elem;
- if(ie && ie <= 9 && this.options.tag == 'tr') {
- var div = document.createElement('div'), last;
- div.innerHTML = '<table><tbody>' + data + '</tbody></table>';
- while((last = content_elem.lastChild)) {
- content_elem.removeChild(last);
- }
- var rows_nodes = this.getChildNodes(div.firstChild.firstChild);
- while (rows_nodes.length) {
- content_elem.appendChild(rows_nodes.shift());
- }
- } else {
- content_elem.innerHTML = data;
- }
- },
- getChildNodes: function(tag) {
- var child_nodes = tag.children, nodes = [];
- for (var i = 0, ii = child_nodes.length; i < ii; i++) {
- nodes.push(child_nodes[i]);
- }
- return nodes;
- },
- checkChanges: function(type, value, cache) {
- var changed = value != cache[type];
- cache[type] = value;
- return changed;
- }
- }
-
- // support functions
- function on(evt, element, fnc) {
- return element.addEventListener ? element.addEventListener(evt, fnc, false) : element.attachEvent("on" + evt, fnc);
- }
- function off(evt, element, fnc) {
- return element.removeEventListener ? element.removeEventListener(evt, fnc, false) : element.detachEvent("on" + evt, fnc);
- }
- function isArray(arr) {
- return Object.prototype.toString.call(arr) === '[object Array]';
- }
- function getStyle(prop, elem) {
- return window.getComputedStyle ? window.getComputedStyle(elem)[prop] : elem.currentStyle[prop];
- }
-
- return Clusterize;
-}));
\ No newline at end of file
diff --git a/erpnext/public/js/pos/customer_toolbar.html b/erpnext/public/js/pos/customer_toolbar.html
deleted file mode 100644
index 3ba5ccb..0000000
--- a/erpnext/public/js/pos/customer_toolbar.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<div class="pos-bill-toolbar col-xs-9" style="display: flex; width: 70%;">
- <div class="party-area" style="flex: 1;">
- <span class="edit-customer-btn text-muted" style="display: inline;">
- <a class="btn-open no-decoration" title="Edit Customer">
- <i class="octicon octicon-pencil"></i>
- </a>
- </span>
- </div>
- <button class="btn btn-default list-customers-btn" style="margin-left: 12px">
- <i class="octicon octicon-organization"></i>
- </button>
- </button> {% if (allow_delete) { %}
- <button class="btn btn-default btn-danger" style="margin: 0 5px 0 5px">
- <i class="octicon octicon-trashcan"></i>
- </button> {% } %}
-</div>
\ No newline at end of file
diff --git a/erpnext/public/js/pos/pos.html b/erpnext/public/js/pos/pos.html
deleted file mode 100644
index 89e2940..0000000
--- a/erpnext/public/js/pos/pos.html
+++ /dev/null
@@ -1,136 +0,0 @@
-<div class="pos">
- <div class="row">
- <div class="col-sm-5 pos-bill-wrapper">
- <div class="col-sm-12"><h6 class="form-section-heading uppercase">{{ __("Item Cart") }}</h6></div>
- <div class="pos-bill">
- <div class="item-cart">
- <div class="pos-list-row pos-bill-header text-muted h6">
- <span class="cell subject">
- <!--<input class="list-select-all" type="checkbox" title="{%= __("Select All") %}">-->
- {{ __("Item Name")}}
- </span>
- <span class="cell text-right">{{ __("Quantity") }}</span>
- <span class="cell text-right">{{ __("Discount") }}</span>
- <span class="cell text-right">{{ __("Rate") }}</span>
- </div>
- <div class="item-cart-items">
- <div class="no-items-message text-extra-muted">
- <span class="text-center">
- <i class="fa fa-2x fa-shopping-cart"></i>
- <p>{{ __("Tap items to add them here") }}</p>
- </span>
- </div>
- <div class="items">
- </div>
- </div>
- </div>
- </div>
- <div class="totals-area">
- <div class="pos-list-row net-total-area">
- <div class="cell"></div>
- <div class="cell text-right">{%= __("Net Total") %}</div>
- <div class="cell price-cell bold net-total text-right"></div>
- </div>
- <div class="pos-list-row tax-area">
- <div class="cell"></div>
- <div class="cell text-right">{%= __("Taxes") %}</div>
- <div class="cell price-cell text-right tax-table">
- </div>
- </div>
- {% if(allow_user_to_edit_discount) { %}
- <div class="pos-list-row discount-amount-area">
- <div class="cell"></div>
- <div class="cell text-right">{%= __("Discount") %}</div>
- <div class="cell price-cell discount-field-col">
- <div class="input-group input-group-sm">
- <span class="input-group-addon">%</span>
- <input type="text" class="form-control discount-percentage text-right">
- </div>
- <div class="input-group input-group-sm">
- <span class="input-group-addon">{%= get_currency_symbol(currency) %}</span>
- <input type="text" class="form-control discount-amount text-right" placeholder="{%= 0.00 %}">
- </div>
- </div>
- </div>
- {% } %}
- <div class="pos-list-row grand-total-area collapse-btn" style="border-bottom:1px solid #d1d8dd;">
- <div class="cell">
- <a class="">
- <i class="octicon octicon-chevron-down"></i>
- </a>
- </div>
- <div class="cell text-right bold">{%= __("Grand Total") %}</div>
- <div class="cell price-cell grand-total text-right lead"></div>
- </div>
- <div class="pos-list-row qty-total-area collapse-btn" style="border-bottom:1px solid #d1d8dd;">
- <div class="cell">
- <a class="">
- <i class="octicon octicon-chevron-down"></i>
- </a>
- </div>
- <div class="cell text-right bold">{%= __("Qty Total") %}</div>
- <div class="cell price-cell qty-total text-right lead"></div>
- </div>
- </div>
- <div class="row" style="margin-top: 30px">
- <div class="col-sm-6 selected-item">
-
- </div>
- <div class="col-xs-6 numeric_keypad hidden-xs" style="display:none">
- {% var chartData = ["Qty", "Disc", "Price"] %} {% for(var i=0; i
- <3; i++) { %} <div class="row text-right">
- {% for(var j=i*3; j
- <(i+1)*3; j++) { %} <button type="button" class="btn btn-default numeric-keypad" val="{{j+1}}">{{j+1}}</button>
- {% } %}
- <button type="button" {% if((!allow_user_to_edit_rate && __(chartData[i]) == __("Price")) || (!allow_user_to_edit_discount && __(chartData[i]) == __("Disc"))) { %} disabled {% } %} id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
- </div>
- {% } %}
- <div class="row text-right">
- <button type="button" class="btn btn-default numeric-keypad numeric-del">{{ __("Del") }}</button>
- <button type="button" class="btn btn-default numeric-keypad" val="0">0</button>
- <button type="button" class="btn btn-default numeric-keypad" val=".">.</button>
- <button type="button" class="btn btn-primary numeric-keypad pos-pay">{{ __("Pay") }}</button>
- </div>
- </div>
- </div>
- </div>
- <div class="col-sm-5 list-customers">
- <div class="col-sm-12"><h6 class="form-section-heading uppercase">{{ __("Customers in Queue") }}</h6></div>
- <div class="pos-list-row pos-bill-header">
- <div class="cell subject"><input class="list-select-all" type="checkbox">{{ __("Customer") }}</div>
- <div class="cell text-left">{{ __("Status") }}</div>
- <div class="cell text-right">{{ __("Amount") }}</div>
- <div class="cell text-right">{{ __("Grand Total") }}</div>
- </div>
- <div class="list-customers-table border-left border-right border-bottom">
- <div class="no-items-message text-extra-muted">
- <span class="text-center">
- <i class="fa fa-2x fa-user"></i>
- <p>{{ __("No Customers yet!") }}</p>
- </span>
- </div>
- </div>
- </div>
- <div class="col-sm-7 pos-items-section">
- <div class="col-sm-12"><h6 class="form-section-heading uppercase">{{ __("Stock Items") }}</h6></div>
- <div class="row pos-item-area">
-
- </div>
- <span id="customer-results" style="color:#68a;"></span>
- <div class="item-list-area">
- <div class="pos-list-row pos-bill-header text-muted h6">
- <div class="cell subject search-item-group">
- <div class="dropdown">
- <a class="text-muted dropdown-toggle" data-toggle="dropdown"><span class="dropdown-text">{{ __("All Item Groups") }}</span><i class="caret"></i></a>
- <ul class="dropdown-menu">
- </ul>
- </div>
- </div>
- <div class="cell search-item"></div>
- </div>
- <div class="app-listing item-list image-view-container">
-
- </div>
- </div>
- </div>
-</div>
diff --git a/erpnext/public/js/pos/pos_bill_item.html b/erpnext/public/js/pos/pos_bill_item.html
deleted file mode 100644
index 21868a6..0000000
--- a/erpnext/public/js/pos/pos_bill_item.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<div class="row pos-bill-row pos-bill-item" data-item-code="{%= item_code %}">
- <div class="col-xs-4"><h6>{%= item_code || "" %}{%= __(item_name) || "" %}</h6></div>
- <div class="col-xs-3">
- <div class="row pos-qty-row">
- <div class="col-xs-2 text-center pos-qty-btn" data-action="decrease-qty"><i class="fa fa-minus text-muted" style="font-size:12px"></i></div>
- <div class="col-xs-8">
- <div>
- <input type="tel" value="{%= qty %}" class="form-control pos-item-qty text-right">
- </div>
- {% if(actual_qty != null) { %}
- <div style="margin-top: 5px;" class="text-muted small text-right">
- {%= __("In Stock: ") %} <span>{%= actual_qty || 0.0 %}</span>
- </div>
- {% } %}
- </div>
- <div class="col-xs-2 text-center pos-qty-btn" data-action="increase-qty"><i class="fa fa-plus text-muted" style="font-size:12px"></i></div>
- </div>
- </div>
- <div class="col-xs-2 text-right">
- <div class="row input-sm">
- <input type="tel" value="{%= discount_percentage %}" class="form-control text-right pos-item-disc">
- </div>
- </div>
- <div class="col-xs-3 text-right">
- <div class="text-muted" style="margin-top: 5px;">
- {% if(enabled) { %}
- <input type="tel" value="{%= rate %}" class="form-control input-sm pos-item-price text-right">
- {% } else { %}
- <h6>{%= format_currency(rate) %}</h6>
- {% } %}
- </div>
- <p><h6>{%= amount %}</h6></p>
- </div>
-</div>
diff --git a/erpnext/public/js/pos/pos_bill_item_new.html b/erpnext/public/js/pos/pos_bill_item_new.html
deleted file mode 100644
index cb626ce..0000000
--- a/erpnext/public/js/pos/pos_bill_item_new.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<div class="pos-list-row pos-bill-item {{ selected_class }}" data-item-code="{{ item_code }}">
- <div class="cell subject">
- <!--<input class="list-row-checkbox" type="checkbox" data-name="{{item_code}}">-->
- <a class="grey list-id" title="{{ item_name }}">{{ strip_html(__(item_name)) || item_code }}</a>
- </div>
- <div class="cell text-right">{%= qty %}</div>
- <div class="cell text-right">{%= discount_percentage %}</div>
- <div class="cell text-right">{%= format_currency(rate) %}</div>
-</div>
diff --git a/erpnext/public/js/pos/pos_invoice_list.html b/erpnext/public/js/pos/pos_invoice_list.html
deleted file mode 100644
index 13aa520..0000000
--- a/erpnext/public/js/pos/pos_invoice_list.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<div class="pos-list-row" invoice-name = "{{name}}">
- <div class="list-column cell subject" invoice-name = "{{name}}">
- <input class="list-delete text-left" type="checkbox" style = "margin-right:5px">
- <a class="grey list-id text-left customer-row" title="{{ customer }}">{%= customer %}</a>
- </div>
- <div class="list-column cell text-left customer-row"><span class="indicator {{data.indicator}}">{{ data.status }}</span></div>
- <div class="list-column cell text-right customer-row">{%= paid_amount %}</div>
- <div class="list-column cell text-right customer-row">{%= grand_total %}</div>
-</div>
diff --git a/erpnext/public/js/pos/pos_item.html b/erpnext/public/js/pos/pos_item.html
deleted file mode 100755
index 52f3cf6..0000000
--- a/erpnext/public/js/pos/pos_item.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<div class="pos-item-wrapper image-view-item" data-item-code="{{item_code}}">
- <div class="image-view-header doclist-row">
- <div class="list-value">
- <a class="grey list-id" data-name="{{item_code}}" title="{{ item_name || item_code}}">{{item_name || item_code}}<br>({{ __(item_stock) }})</a>
- </div>
- </div>
- <div class="image-view-body">
- <a data-item-code="{{ item_code }}"
- title="{{ item_name || item_code }}"
- >
- <div class="image-field"
- style="
- {% if (!item_image) { %}
- background-color: #fafbfc;
- {% } %}
- border: 0px;"
- >
- {% if (!item_image) { %}
- <span class="placeholder-text">
- {%= frappe.get_abbr(item_name || item_code) %}
- </span>
- {% } %}
- {% if (item_image) { %}
- <img src="{{ item_image }}" alt="{{item_name || item_code}}">
- {% } %}
- </div>
- <span class="price-info">
- {{item_price}} / {{item_uom}}
- </span>
- </a>
- </div>
-</div>
\ No newline at end of file
diff --git a/erpnext/public/js/pos/pos_selected_item.html b/erpnext/public/js/pos/pos_selected_item.html
deleted file mode 100644
index 03c7341..0000000
--- a/erpnext/public/js/pos/pos_selected_item.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<div class="pos-selected-item-action" data-item-code="{%= item_code %}" data-idx="{%= idx %}">
- <div class="pos-list-row">
- <div class="cell">{{ __("Quantity") }}:</div>
- <input type="tel" class="form-control cell pos-item-qty" value="{%= qty %}"/>
- </div>
- <div class="pos-list-row">
- <div class="cell">{{ __("Price List Rate") }}:</div>
- <input type="tel" class="form-control cell" disabled value="{%= price_list_rate %}"/>
- </div>
- <div class="pos-list-row">
- <div class="cell">{{ __("Discount") }}: %</div>
- <input type="tel" class="form-control cell pos-item-disc" {% if !allow_user_to_edit_discount %} disabled {% endif %} value="{%= discount_percentage %}">
- </div>
- <div class="pos-list-row">
- <div class="cell">{{ __("Price") }}:</div>
- <input type="tel" class="form-control cell pos-item-price" {% if !allow_user_to_edit_rate %} disabled {% endif %} value="{%= rate %}"/>
- </div>
- <div class="pos-list-row">
- <div class="cell">{{ __("Amount") }}:</div>
- <input type="tel" class="form-control cell pos-amount" disabled value="{%= amount %}"/>
- </div>
-</div>
\ No newline at end of file
diff --git a/erpnext/public/js/pos/pos_tax_row.html b/erpnext/public/js/pos/pos_tax_row.html
deleted file mode 100644
index 3752a89..0000000
--- a/erpnext/public/js/pos/pos_tax_row.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<div class="pos-list-row" style="padding-right: 0;">
- <div class="cell">{%= description %}</div>
- <div class="cell text-right bold">{%= tax_amount %}</div>
-</div>
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index 560a561..b635adc 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -115,7 +115,26 @@
["Warehouse", "is_group", "=",0]
]
- }
+ };
+ },
+
+ get_filtered_dimensions: function(doc, child_fields, dimension, company) {
+ let account = '';
+
+ child_fields.forEach((field) => {
+ if (!account) {
+ account = doc[field];
+ }
+ });
+
+ return {
+ query: "erpnext.controllers.queries.get_filtered_dimensions",
+ filters: {
+ 'dimension': dimension,
+ 'account': account,
+ 'company': company
+ }
+ };
}
});
diff --git a/erpnext/public/js/salary_slip_deductions_report_filters.js b/erpnext/public/js/salary_slip_deductions_report_filters.js
index 2b30e65..1ca3660 100644
--- a/erpnext/public/js/salary_slip_deductions_report_filters.js
+++ b/erpnext/public/js/salary_slip_deductions_report_filters.js
@@ -45,7 +45,7 @@
},
{
fieldname: "branch",
- label: __("Barnch"),
+ label: __("Branch"),
fieldtype: "Link",
options: "Branch",
}
@@ -63,4 +63,4 @@
}
});
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 9beba6a..ef03b01 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -127,11 +127,9 @@
options: "", fieldtype: 'Select'
},
{ fieldname: 'view_coa', label: __('View Chart of Accounts'), fieldtype: 'Button' },
-
- { fieldtype: "Section Break", label: __('Financial Year') },
- { fieldname: 'fy_start_date', label: __('Start Date'), fieldtype: 'Date', reqd: 1 },
- { fieldtype: "Column Break" },
- { fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1 },
+ { fieldname: 'fy_start_date', label: __('Financial Year Begins On'), fieldtype: 'Date', reqd: 1 },
+ // end date should be hidden (auto calculated)
+ { fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1, hidden: 1 },
],
onload: function (slide) {
@@ -161,7 +159,10 @@
if(r.message){
exist = r.message;
me.get_field("bank_account").set_value("");
- frappe.msgprint(__(`Account ${me.values.bank_account} already exists, enter a different name for your bank account`));
+ let message = __('Account {0} already exists. Please enter a different name for your bank account.',
+ [me.values.bank_account]
+ );
+ frappe.msgprint(message);
}
}
});
@@ -309,7 +310,6 @@
"Hong Kong": ["04-01", "03-31"],
"India": ["04-01", "03-31"],
"Iran": ["06-23", "06-22"],
- "Italy": ["07-01", "06-30"],
"Myanmar": ["04-01", "03-31"],
"New Zealand": ["04-01", "03-31"],
"Pakistan": ["07-01", "06-30"],
diff --git a/erpnext/public/js/telephony.js b/erpnext/public/js/telephony.js
new file mode 100644
index 0000000..9548d6c
--- /dev/null
+++ b/erpnext/public/js/telephony.js
@@ -0,0 +1,33 @@
+frappe.ui.form.ControlData = frappe.ui.form.ControlData.extend( {
+ make_input() {
+ this._super();
+ if (this.df.options == 'Phone') {
+ this.setup_phone();
+ }
+ if (this.frm && this.frm.fields_dict) {
+ Object.values(this.frm.fields_dict).forEach(function(field) {
+ if (field.df.read_only === 1 && field.df.options === 'Phone'
+ && field.disp_area.style[0] != 'display' && !field.has_icon) {
+ field.setup_phone();
+ field.has_icon = true;
+ }
+ });
+ }
+ },
+ setup_phone() {
+ if (frappe.phone_call.handler) {
+ let control = this.df.read_only ? '.control-value' : '.control-input';
+ this.$wrapper.find(control)
+ .append(`
+ <span class="phone-btn">
+ <a class="btn-open no-decoration" title="${__('Make a call')}">
+ ${frappe.utils.icon('call')}
+ </span>
+ `)
+ .find('.phone-btn')
+ .click(() => {
+ frappe.phone_call.handler(this.get_value(), this.frm);
+ });
+ }
+ }
+});
diff --git a/erpnext/public/js/templates/call_link.html b/erpnext/public/js/templates/call_link.html
new file mode 100644
index 0000000..071078c
--- /dev/null
+++ b/erpnext/public/js/templates/call_link.html
@@ -0,0 +1,42 @@
+<div class="call-detail-wrapper">
+ <div class="head flex justify-between">
+ <div>
+ <span class="bold"> {{ type }} Call</span>
+ {% if (duration) %}
+ <span class="text-muted"> • {{ frappe.format(duration, { fieldtype: "Duration" }) }}</span>
+ {% endif %}
+ <span class="text-muted"> • {{ comment_when(creation) }}</span>
+ </div>
+ <span>
+ <a class="action-btn" href="/app/call-log/{{ name }}" title="{{ __("Open Call Log") }}">
+ <svg class="icon icon-sm">
+ <use href="#icon-link-url" class="like-icon"></use>
+ </svg>
+ </a>
+ </span>
+ </div>
+
+
+ <div class="body pt-3">
+ {% if (type === "Incoming") { %}
+ <span> Incoming call from {{ from }}, received by {{ to }}</span>
+ {% } else { %}
+ <span> Outgoing Call made by {{ from }} to {{ to }}</span>
+ {% } %}
+ <div class="summary pt-3">
+ {% if (summary) { %}
+ <i>{{ summary }}</i>
+ {% } else { %}
+ <i class="text-muted">{{ __("No Summary") }}</i>
+ {% } %}
+ </div>
+ {% if (recording_url) { %}
+ <div class="margin-top">
+ <audio
+ controls
+ src="{{ recording_url }}">
+ </audio>
+ </div>
+ {% } %}
+ </div>
+</div>
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 9ed5009..e5b50d8 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -194,15 +194,21 @@
add_dimensions: function(report_name, index) {
let filters = frappe.query_reports[report_name].filters;
- erpnext.dimension_filters.forEach((dimension) => {
- let found = filters.some(el => el.fieldname === dimension['fieldname']);
+ frappe.call({
+ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimensions",
+ callback: function(r) {
+ let accounting_dimensions = r.message[0];
+ accounting_dimensions.forEach((dimension) => {
+ let found = filters.some(el => el.fieldname === dimension['fieldname']);
- if (!found) {
- filters.splice(index, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
+ if (!found) {
+ filters.splice(index, 0, {
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
+ });
+ }
});
}
});
@@ -452,6 +458,9 @@
const frm = opts.frm;
const cannot_add_row = (typeof opts.cannot_add_row === 'undefined') ? true : opts.cannot_add_row;
const child_docname = (typeof opts.cannot_add_row === 'undefined') ? "items" : opts.child_docname;
+ const child_meta = frappe.get_meta(`${frm.doc.doctype} Item`);
+ const get_precision = (fieldname) => child_meta.fields.find(f => f.fieldname == fieldname).precision;
+
this.data = [];
const fields = [{
fieldtype:'Data',
@@ -499,14 +508,17 @@
default: 0,
read_only: 0,
in_list_view: 1,
- label: __('Qty')
+ label: __('Qty'),
+ precision: get_precision("qty")
}, {
fieldtype:'Currency',
fieldname:"rate",
+ options: "currency",
default: 0,
read_only: 0,
in_list_view: 1,
- label: __('Rate')
+ label: __('Rate'),
+ precision: get_precision("rate")
}];
if (frm.doc.doctype == 'Sales Order' || frm.doc.doctype == 'Purchase Order' ) {
@@ -521,7 +533,8 @@
fieldtype: 'Float',
fieldname: "conversion_factor",
in_list_view: 1,
- label: __("Conversion Factor")
+ label: __("Conversion Factor"),
+ precision: get_precision('conversion_factor')
})
}
@@ -533,7 +546,7 @@
fieldtype: "Table",
label: "Items",
cannot_add_rows: cannot_add_row,
- in_place_edit: true,
+ in_place_edit: false,
reqd: 1,
data: this.data,
get_data: () => {
@@ -582,21 +595,7 @@
}
erpnext.utils.map_current_doc = function(opts) {
- let query_args = {};
- if (opts.get_query_filters) {
- query_args.filters = opts.get_query_filters;
- }
-
- if (opts.get_query_method) {
- query_args.query = opts.get_query_method;
- }
-
- if (query_args.filters || query_args.query) {
- opts.get_query = () => {
- return query_args;
- }
- }
- var _map = function() {
+ function _map() {
if($.isArray(cur_frm.doc.items) && cur_frm.doc.items.length > 0) {
// remove first item row if empty
if(!cur_frm.doc.items[0].item_code) {
@@ -670,8 +669,22 @@
}
});
}
- if(opts.source_doctype) {
- var d = new frappe.ui.form.MultiSelectDialog({
+
+ let query_args = {};
+ if (opts.get_query_filters) {
+ query_args.filters = opts.get_query_filters;
+ }
+
+ if (opts.get_query_method) {
+ query_args.query = opts.get_query_method;
+ }
+
+ if (query_args.filters || query_args.query) {
+ opts.get_query = () => query_args;
+ }
+
+ if (opts.source_doctype) {
+ const d = new frappe.ui.form.MultiSelectDialog({
doctype: opts.source_doctype,
target: opts.target,
date_field: opts.date_field || undefined,
@@ -690,16 +703,24 @@
_map();
},
});
- } else if(opts.source_name) {
+
+ return d;
+ }
+
+ if (opts.source_name) {
opts.source_name = [opts.source_name];
_map();
}
}
frappe.form.link_formatters['Item'] = function(value, doc) {
- if(doc && doc.item_name && doc.item_name !== value) {
- return value? value + ': ' + doc.item_name: doc.item_name;
+ if (doc && value && doc.item_name && doc.item_name !== value) {
+ return value + ': ' + doc.item_name;
+ } else if (!value && doc.doctype && doc.item_name) {
+ // format blank value in child table
+ return doc.item_name;
} else {
+ // if value is blank in report view or item code and name are the same, return as is
return value;
}
}
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index b6720c0..96e1817 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -1,54 +1,83 @@
-frappe.provide('frappe.ui.form');
+frappe.provide('erpnext.accounts');
-let default_dimensions = {};
+erpnext.accounts.dimensions = {
+ setup_dimension_filters(frm, doctype) {
+ this.accounting_dimensions = [];
+ this.default_dimensions = {};
+ this.fetch_custom_dimensions(frm, doctype);
+ },
-let doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
- "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program",
- "Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool",
- "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"];
+ fetch_custom_dimensions(frm, doctype) {
+ let me = this;
+ frappe.call({
+ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimensions",
+ args: {
+ 'with_cost_center_and_project': true
+ },
+ callback: function(r) {
+ me.accounting_dimensions = r.message[0];
+ me.default_dimensions = r.message[1];
+ me.setup_filters(frm, doctype);
+ }
+ });
+ },
-let child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
- "Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction",
- "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"];
-
-frappe.call({
- method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
- callback: function(r) {
- erpnext.dimension_filters = r.message[0];
- default_dimensions = r.message[1];
- }
-});
-
-doctypes_with_dimensions.forEach((doctype) => {
- frappe.ui.form.on(doctype, {
- onload: function(frm) {
- erpnext.dimension_filters.forEach((dimension) => {
+ setup_filters(frm, doctype) {
+ if (this.accounting_dimensions) {
+ this.accounting_dimensions.forEach((dimension) => {
frappe.model.with_doctype(dimension['document_type'], () => {
- if(frappe.meta.has_field(dimension['document_type'], 'is_group')) {
- frm.set_query(dimension['fieldname'], {
- "is_group": 0
- });
- }
+ let parent_fields = [];
+ frappe.meta.get_docfields(doctype).forEach((df) => {
+ if (df.fieldtype === 'Link' && df.options === 'Account') {
+ parent_fields.push(df.fieldname);
+ } else if (df.fieldtype === 'Table') {
+ this.setup_child_filters(frm, df.options, df.fieldname, dimension['fieldname']);
+ }
+
+ if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
+ this.setup_account_filters(frm, dimension['fieldname'], parent_fields);
+ }
+ });
});
});
- },
+ }
+ },
- company: function(frm) {
- if(frm.doc.company && (Object.keys(default_dimensions || {}).length > 0)
- && default_dimensions[frm.doc.company]) {
- frm.trigger('update_dimension');
- }
- },
+ setup_child_filters(frm, doctype, parentfield, dimension) {
+ let fields = [];
- update_dimension: function(frm) {
- erpnext.dimension_filters.forEach((dimension) => {
- if(frm.is_new()) {
- if(frm.doc.company && Object.keys(default_dimensions || {}).length > 0
- && default_dimensions[frm.doc.company]) {
+ if (frappe.meta.has_field(doctype, dimension)) {
+ frappe.model.with_doctype(doctype, () => {
+ frappe.meta.get_docfields(doctype).forEach((df) => {
+ if (df.fieldtype === 'Link' && df.options === 'Account') {
+ fields.push(df.fieldname);
+ }
+ });
- let default_dimension = default_dimensions[frm.doc.company][dimension['fieldname']];
+ frm.set_query(dimension, parentfield, function(doc, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ return erpnext.queries.get_filtered_dimensions(row, fields, dimension, doc.company);
+ });
+ });
+ }
+ },
- if(default_dimension) {
+ setup_account_filters(frm, dimension, fields) {
+ frm.set_query(dimension, function(doc) {
+ return erpnext.queries.get_filtered_dimensions(doc, fields, dimension, doc.company);
+ });
+ },
+
+ update_dimension(frm, doctype) {
+ if (this.accounting_dimensions) {
+ this.accounting_dimensions.forEach((dimension) => {
+ if (frm.is_new()) {
+ if (frm.doc.company && Object.keys(this.default_dimensions || {}).length > 0
+ && this.default_dimensions[frm.doc.company]) {
+
+ let default_dimension = this.default_dimensions[frm.doc.company][dimension['fieldname']];
+
+ if (default_dimension) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
frm.set_value(dimension['fieldname'], default_dimension);
}
@@ -61,23 +90,14 @@
}
});
}
- });
-});
+ },
-child_docs.forEach((doctype) => {
- frappe.ui.form.on(doctype, {
- items_add: function(frm, cdt, cdn) {
- erpnext.dimension_filters.forEach((dimension) => {
- var row = frappe.get_doc(cdt, cdn);
- frm.script_manager.copy_from_first_row("items", row, [dimension['fieldname']]);
- });
- },
-
- accounts_add: function(frm, cdt, cdn) {
- erpnext.dimension_filters.forEach((dimension) => {
- var row = frappe.get_doc(cdt, cdn);
- frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
+ copy_dimension_from_first_row(frm, cdt, cdn, fieldname) {
+ if (frappe.meta.has_field(frm.doctype, fieldname) && this.accounting_dimensions) {
+ this.accounting_dimensions.forEach((dimension) => {
+ let row = frappe.get_doc(cdt, cdn);
+ frm.script_manager.copy_from_first_row(fieldname, row, [dimension['fieldname']]);
});
}
- });
-});
\ No newline at end of file
+ }
+};
\ No newline at end of file
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 44e75ae..808dd5a 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -276,8 +276,14 @@
erpnext.utils.get_shipping_address = function(frm, callback){
if (frm.doc.company) {
+ if (!(frm.doc.inter_com_order_reference || frm.doc.internal_invoice_reference ||
+ frm.doc.internal_order_reference)) {
+ if (callback) {
+ return callback();
+ }
+ }
frappe.call({
- method: "frappe.contacts.doctype.address.address.get_shipping_address",
+ method: "erpnext.accounts.custom.address.get_shipping_address",
args: {
company: frm.doc.company,
address: frm.doc.shipping_address
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index d9f6e1d..d49a813 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -75,7 +75,7 @@
fieldtype:'Float',
read_only: me.has_batch && !me.has_serial_no,
label: __(me.has_batch && !me.has_serial_no ? 'Total Qty' : 'Qty'),
- default: 0
+ default: flt(me.item.stock_qty),
},
{
fieldname: 'auto_fetch_button',
@@ -91,7 +91,8 @@
qty: qty,
item_code: me.item_code,
warehouse: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '',
- batch_no: me.item.batch_no || null
+ batch_no: me.item.batch_no || null,
+ posting_date: me.frm.doc.posting_date || me.frm.doc.transaction_date
}
});
@@ -100,11 +101,12 @@
let records_length = auto_fetched_serial_numbers.length;
if (!records_length) {
const warehouse = me.dialog.fields_dict.warehouse.get_value().bold();
- frappe.msgprint(__(`Serial numbers unavailable for Item ${me.item.item_code.bold()}
- under warehouse ${warehouse}. Please try changing warehouse.`));
+ frappe.msgprint(
+ __('Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.', [me.item.item_code.bold(), warehouse])
+ );
}
if (records_length < qty) {
- frappe.msgprint(__(`Fetched only ${records_length} available serial numbers.`));
+ frappe.msgprint(__('Fetched only {0} available serial numbers.', [records_length]));
}
let serial_no_list_field = this.dialog.fields_dict.serial_no;
numbers = auto_fetched_serial_numbers.join('\n');
@@ -138,6 +140,7 @@
() => me.update_batch_serial_no_items(),
() => {
refresh_field("items");
+ refresh_field("packed_items");
if (me.callback) {
return me.callback(me.item);
}
@@ -152,7 +155,7 @@
if (this.item.serial_no) {
this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
}
-
+
if (this.has_batch && !this.has_serial_no && d.batch_no) {
this.frm.doc.items.forEach(data => {
if(data.item_code == d.item_code) {
@@ -189,15 +192,12 @@
}
if(this.has_batch && !this.has_serial_no) {
if(values.batches.length === 0 || !values.batches) {
- frappe.throw(__("Please select batches for batched item "
- + values.item_code));
- return false;
+ frappe.throw(__("Please select batches for batched item {0}", [values.item_code]));
}
values.batches.map((batch, i) => {
if(!batch.selected_qty || batch.selected_qty === 0 ) {
if (!this.show_dialog) {
- frappe.throw(__("Please select quantity on row " + (i+1)));
- return false;
+ frappe.throw(__("Please select quantity on row {0}", [i+1]));
}
}
});
@@ -206,9 +206,7 @@
} else {
let serial_nos = values.serial_no || '';
if (!serial_nos || !serial_nos.replace(/\s/g, '').length) {
- frappe.throw(__("Please enter serial numbers for serialized item "
- + values.item_code));
- return false;
+ frappe.throw(__("Please enter serial numbers for serialized item {0}", [values.item_code]));
}
return true;
}
@@ -234,7 +232,7 @@
this.map_row_values(row, batch, 'batch_no',
'selected_qty', this.values.warehouse);
});
- }
+ }
},
update_serial_no_item() {
@@ -253,7 +251,7 @@
filters: { 'name': ["in", selected_serial_nos]},
fields: ["batch_no", "name"]
}).then((data) => {
- // data = [{batch_no: 'batch-1', name: "SR-001"},
+ // data = [{batch_no: 'batch-1', name: "SR-001"},
// {batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}]
const batch_serial_map = data.reduce((acc, d) => {
if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
@@ -301,6 +299,8 @@
} else {
row.warehouse = values.warehouse || warehouse;
}
+
+ this.frm.dirty();
},
update_total_qty: function() {
@@ -355,8 +355,7 @@
});
if (selected_batches.includes(val)) {
this.set_value("");
- frappe.throw(__(`Batch ${val} already selected.`));
- return;
+ frappe.throw(__('Batch {0} already selected.', [val]));
}
if (me.warehouse_details.name) {
@@ -375,8 +374,7 @@
} else {
this.set_value("");
- frappe.throw(__(`Please select a warehouse to get available
- quantities`));
+ frappe.throw(__('Please select a warehouse to get available quantities'));
}
// e.stopImmediatePropagation();
}
@@ -411,8 +409,7 @@
parseFloat(available_qty) < parseFloat(selected_qty)) {
this.set_value('0');
- frappe.throw(__(`For transfer from source, selected quantity cannot be
- greater than available quantity`));
+ frappe.throw(__('For transfer from source, selected quantity cannot be greater than available quantity'));
} else {
this.grid.refresh();
}
@@ -451,20 +448,12 @@
frappe.call({
method: "erpnext.stock.doctype.serial_no.serial_no.get_pos_reserved_serial_nos",
args: {
- item_code: me.item_code,
- warehouse: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : ''
+ filters: {
+ item_code: me.item_code,
+ warehouse: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '',
+ }
}
}).then((data) => {
- if (!data.message[1].length) {
- this.showing_reserved_serial_nos_error = true;
- const warehouse = me.dialog.fields_dict.warehouse.get_value().bold();
- const d = frappe.msgprint(__(`Serial numbers unavailable for Item ${me.item.item_code.bold()}
- under warehouse ${warehouse}. Please try changing warehouse.`));
- d.get_close_btn().on('click', () => {
- this.showing_reserved_serial_nos_error = false;
- d.hide();
- });
- }
serial_no_filters['name'] = ["not in", data.message[0]]
})
}
diff --git a/erpnext/public/less/call_popup.less b/erpnext/public/less/call_popup.less
deleted file mode 100644
index 32e85ce..0000000
--- a/erpnext/public/less/call_popup.less
+++ /dev/null
@@ -1,9 +0,0 @@
-.call-popup {
- a:hover {
- text-decoration: underline;
- }
- .for-description {
- max-height: 250px;
- overflow: scroll;
- }
-}
\ No newline at end of file
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less
index 8685837..4076ebe 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/less/erpnext.less
@@ -39,8 +39,9 @@
.dashboard-list-item {
background-color: inherit;
- padding: 5px 0px;
- border-bottom: 1px solid @border-color;
+ border-bottom: 1px solid var(--border-color);
+ font-size: var(--text-md);
+ color: var(--text-color);
}
#page-stock-balance .dashboard-list-item {
@@ -446,20 +447,6 @@
}
-// Leaderboard
-
-.leaderboard {
- .result {
- border-top: 1px solid #d1d8dd;
- }
- .list-item {
- padding-left: 45px;
- }
- .list-item_content {
- padding-right: 45px;
- }
-}
-
// Healthcare
.exercise-card {
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
index 8cb7a9c..29deada 100644
--- a/erpnext/public/less/hub.less
+++ b/erpnext/public/less/hub.less
@@ -32,7 +32,12 @@
}
.hub-image-loading, .hub-image-broken {
- .img-background();
+ content: " ";
+ position: absolute;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ background-color: var(--bg-light-gray);
display: flex;
align-items: center;
justify-content: center;
diff --git a/erpnext/public/scss/call_popup.scss b/erpnext/public/scss/call_popup.scss
new file mode 100644
index 0000000..95e3182
--- /dev/null
+++ b/erpnext/public/scss/call_popup.scss
@@ -0,0 +1,21 @@
+.call-popup {
+ a:hover {
+ text-decoration: underline;
+ }
+ .for-description {
+ max-height: 250px;
+ overflow: scroll;
+ }
+}
+
+audio {
+ height: 40px;
+ width: 100%;
+ max-width: 500px;
+ background-color: var(--control-bg);
+ border-radius: var(--border-radius-sm);
+ &-webkit-media-controls-panel {
+ background: var(--control-bg);
+ }
+ outline: none;
+}
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
new file mode 100644
index 0000000..0bb8e68
--- /dev/null
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -0,0 +1,1110 @@
+.point-of-sale-app {
+ display: grid;
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ gap: var(--margin-md);
+
+ section {
+ min-height: 45rem;
+ height: calc(100vh - 200px);
+ max-height: calc(100vh - 200px);
+ }
+
+ .frappe-control {
+ margin: 0 !important;
+ width: 100%;
+ }
+
+ .form-group {
+ margin-bottom: 0px !important;
+ }
+
+ .pointer-no-select {
+ cursor: pointer;
+ user-select: none;
+ }
+
+ .nowrap {
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .image {
+ height: 100% !important;
+ object-fit: cover;
+ }
+
+ .abbr {
+ background-color: var(--gray-50);
+ font-size: var(--text-3xl);
+ }
+
+ .label {
+ display: flex;
+ align-items: center;
+ font-weight: 700;
+ font-size: var(--text-lg);
+ }
+
+ .pos-card {
+ background-color: var(--fg-color);
+ box-shadow: var(--shadow-base);
+ border-radius: var(--border-radius-md);
+ }
+
+ .seperator {
+ margin-left: var(--margin-sm);
+ margin-right: var(--margin-sm);
+ border-bottom: 1px solid var(--gray-300);
+ }
+
+ .primary-action {
+ @extend .pointer-no-select;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--padding-sm);
+ margin-top: var(--margin-sm);
+ border-radius: var(--border-radius-md);
+ font-size: var(--text-lg);
+ font-weight: 700;
+ }
+
+ .highlighted-numpad-btn {
+ box-shadow: inset 0 0px 4px 0px rgba(0, 0, 0, 0.15) !important;
+ font-weight: 700;
+ background-color: var(--gray-50);
+ }
+
+ > .items-selector {
+ @extend .pos-card;
+ grid-column: span 6 / span 6;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+
+ > .filter-section {
+ display: grid;
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ background-color: var(--fg-color);
+ padding: var(--padding-lg);
+ padding-bottom: var(--padding-sm);
+ align-items: center;
+
+ > .label {
+ @extend .label;
+ grid-column: span 4 / span 4;
+ padding-bottom: var(--padding-xs);
+ }
+
+ > .search-field {
+ grid-column: span 5 / span 5;
+ display: flex;
+ align-items: center;
+ margin: 0px var(--margin-sm);
+ }
+
+ > .item-group-field {
+ grid-column: span 3 / span 3;
+ display: flex;
+ align-items: center;
+ }
+ }
+
+ > .items-container {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: var(--margin-lg);
+ padding: var(--padding-lg);
+ padding-top: var(--padding-xs);
+ overflow-y: scroll;
+ overflow-x: hidden;
+
+ &:after {
+ content: "";
+ display: block;
+ height: 1px;
+ }
+
+ > .item-wrapper {
+ @extend .pointer-no-select;
+ border-radius: var(--border-radius-md);
+ box-shadow: var(--shadow-base);
+
+ &:hover {
+ transform: scale(1.02, 1.02);
+ }
+
+ .item-display {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: var(--border-radius-md);
+ margin: var(--margin-sm);
+ margin-bottom: 0px;
+ min-height: 8rem;
+ height: 8rem;
+ color: var(--gray-500);
+
+ > img {
+ @extend .image;
+ }
+ }
+
+ > .item-detail {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ min-height: 3.5rem;
+ height: 3.5rem;
+ padding-left: var(--padding-sm);
+ padding-right: var(--padding-sm);
+
+ > .item-name {
+ @extend .nowrap;
+ display: flex;
+ align-items: center;
+ font-size: var(--text-md);
+ }
+
+ > .item-rate {
+ font-weight: 700;
+ }
+ }
+
+ }
+ }
+ }
+
+ > .customer-cart-container {
+ grid-column: span 4 / span 4;
+ display: flex;
+ flex-direction: column;
+
+ > .customer-section {
+ @extend .pos-card;
+ display: flex;
+ flex-direction: column;
+ padding: var(--padding-md) var(--padding-lg);
+ overflow: visible;
+
+ > .customer-field {
+ display: flex;
+ align-items: center;
+ padding-top: var(--padding-xs);
+ }
+
+ > .customer-details {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--fg-color);
+
+ > .header {
+ display: flex;
+ margin-bottom: var(--margin-md);
+ justify-content: space-between;
+ padding-top: var(--padding-md);
+
+ > .label {
+ @extend .label;
+ }
+
+ > .close-details-btn {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ }
+ }
+
+ > .customer-display {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+
+ > .customer-image {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 3rem;
+ height: 3rem;
+ border-radius: 50%;
+ color: var(--gray-500);
+ margin-right: var(--margin-md);
+
+ > img {
+ @extend .image;
+ border-radius: 50%;
+ }
+ }
+
+ > .customer-abbr {
+ @extend .abbr;
+ font-size: var(--text-2xl);
+ }
+
+ > .customer-name-desc {
+ @extend .nowrap;
+ display: flex;
+ flex-direction: column;
+ margin-right: auto;
+
+ >.customer-name {
+ font-weight: 700;
+ font-size: var(--text-lg);
+ }
+
+ >.customer-desc {
+ color: var(--gray-600);
+ font-weight: 500;
+ font-size: var(--text-sm);
+ }
+ }
+
+ > .reset-customer-btn {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ }
+
+ }
+
+ > .customer-fields-container {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ margin-top: var(--margin-md);
+ column-gap: var(--padding-sm);
+ row-gap: var(--padding-xs);
+ }
+
+ > .transactions-label {
+ @extend .label;
+ margin-top: var(--margin-md);
+ margin-bottom: var(--margin-sm);
+ }
+ }
+
+ > .customer-transactions {
+ height: 100%;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ margin-right: -12px;
+ padding-right: 12px;
+ margin-left: -10px;
+
+ > .no-transactions-placeholder {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--gray-50);
+ border-radius: var(--border-radius-md);
+ }
+ }
+ }
+
+ > .cart-container {
+ @extend .pos-card;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-top: var(--margin-md);
+ position: relative;
+ height: 100%;
+
+ > .abs-cart-container {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ padding: var(--padding-lg);
+ width: 100%;
+ height: 100%;
+
+ > .cart-label {
+ @extend .label;
+ padding-bottom: var(--padding-md);
+ }
+
+ > .cart-header {
+ display: flex;
+ width: 100%;
+ font-size: var(--text-md);
+ padding-bottom: var(--padding-md);
+
+ > .name-header {
+ flex: 1 1 0%;
+ }
+
+ > .qty-header {
+ margin-right: var(--margin-lg);
+ text-align: center;
+ }
+
+ > .rate-amount-header {
+ text-align: right;
+ margin-right: var(--margin-sm);
+ }
+ }
+
+ .no-item-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--gray-50);
+ border-radius: var(--border-radius-md);
+ font-size: var(--text-md);
+ font-weight: 500;
+ width: 100%;
+ height: 100%;
+ }
+
+ > .cart-items-section {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 0%;
+ overflow-y: scroll;
+
+ > .cart-item-wrapper {
+ @extend .pointer-no-select;
+ display: flex;
+ align-items: center;
+ padding: var(--padding-sm);
+ border-radius: var(--border-radius-md);
+
+ &:hover {
+ background-color: var(--gray-50);
+ }
+
+ > .item-image {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ border-radius: var(--border-radius-md);
+ color: var(--gray-500);
+ margin-right: var(--margin-md);
+
+ > img {
+ @extend .image;
+ }
+ }
+
+ > .item-abbr {
+ @extend .abbr;
+ font-size: var(--text-lg);
+ }
+
+
+ > .item-name-desc {
+ @extend .nowrap;
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 0%;
+ flex-shrink: 1;
+
+ > .item-name {
+ font-weight: 700;
+ }
+
+ > .item-desc {
+ font-size: var(--text-sm);
+ color: var(--gray-600);
+ font-weight: 500;
+ }
+ }
+
+ > .item-qty-rate {
+ display: flex;
+ flex-shrink: 0;
+ text-align: right;
+ margin-left: var(--margin-md);
+
+ > .item-qty {
+ display: flex;
+ align-items: center;
+ margin-right: var(--margin-lg);
+ font-weight: 700;
+ }
+
+ > .item-rate-amount {
+ display: flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ text-align: right;
+
+ > .item-rate {
+ font-weight: 700;
+ }
+
+ > .item-amount {
+ font-size: var(--text-md);
+ font-weight: 600;
+ }
+ }
+ }
+
+ }
+ }
+
+ > .cart-totals-section {
+ display: flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ width: 100%;
+ margin-top: var(--margin-md);
+
+ > .add-discount-wrapper {
+ @extend .pointer-no-select;
+ display: none;
+ align-items: center;
+ border-radius: var(--border-radius-md);
+ border: 1px dashed var(--gray-500);
+ padding: var(--padding-sm) var(--padding-md);
+ margin-bottom: var(--margin-sm);
+
+ > .add-discount-field {
+ width: 100%;
+ }
+
+ .discount-icon {
+ margin-right: var(--margin-sm);
+ }
+
+ .edit-discount-btn {
+ display: flex;
+ align-items: center;
+ font-weight: 500;
+ color: var(--dark-green-500);
+ }
+ }
+
+ > .net-total-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: var(--padding-sm) 0px;
+ font-weight: 500;
+ font-size: var(--text-md);
+ }
+
+ > .taxes-container {
+ display: none;
+ flex-direction: column;
+ font-weight: 500;
+ font-size: var(--text-md);
+
+ > .tax-row {
+ display: flex;
+ justify-content: space-between;
+ line-height: var(--text-3xl);
+ }
+ }
+
+ > .grand-total-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: var(--padding-sm) 0px;
+ font-weight: 700;
+ font-size: var(--text-lg);
+ }
+
+ > .checkout-btn {
+ @extend .primary-action;
+ background-color: var(--blue-200);
+ color: white;
+ }
+
+ > .edit-cart-btn {
+ @extend .primary-action;
+ display: none;
+ background-color: var(--gray-300);
+ font-weight: 500;
+ transition: all 0.15s ease-in-out;
+
+ &:hover {
+ background-color: var(--gray-600);
+ color: white;
+ font-weight: 700;
+ }
+ }
+ }
+
+ > .numpad-section {
+ display: none;
+ flex-direction: column;
+ flex-shrink: 0;
+ margin-top: var(--margin-sm);
+ padding: var(--padding-sm);
+ padding-bottom: 0px;
+ width: 100%;
+
+ > .numpad-totals {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: var(--margin-md);
+ font-size: var(--text-md);
+ font-weight: 700;
+ }
+
+ > .numpad-container {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: var(--margin-md);
+ margin-bottom: var(--margin-md);
+
+ > .numpad-btn {
+ @extend .pointer-no-select;
+ border-radius: var(--border-radius-md);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--padding-md);
+ box-shadow: var(--shadow-sm);
+ }
+
+ > .col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ > .remove-btn {
+ font-weight: 700;
+ color: var(--red-500);
+ }
+ }
+
+ > .checkout-btn {
+ @extend .primary-action;
+ margin: 0px;
+ margin-bottom: var(--margin-sm);
+ background-color: var(--blue-200);
+ color: white;
+ }
+ }
+ }
+ }
+ }
+
+ .invoice-wrapper {
+ @extend .pointer-no-select;
+ display: flex;
+ justify-content: space-between;
+ border-radius: var(--border-radius-md);
+ padding: var(--padding-sm);
+
+ &:hover {
+ background-color: var(--gray-50);
+ }
+
+ > .invoice-name-date {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+
+ > .invoice-name {
+ @extend .nowrap;
+ font-size: var(--text-md);
+ font-weight: 700;
+ }
+
+ > .invoice-date {
+ @extend .nowrap;
+ font-size: var(--text-sm);
+ display: flex;
+ align-items: center;
+ }
+ }
+
+ > .invoice-total-status {
+ display: flex;
+ flex-direction: column;
+ font-weight: 500;
+ font-size: var(--text-sm);
+ margin-left: var(--margin-md);
+
+ > .invoice-total {
+ margin-bottom: var(--margin-xs);
+ font-size: var(--text-base);
+ font-weight: 700;
+ text-align: right;
+ }
+
+ > .invoice-status {
+ display: flex;
+ align-items: center;
+ justify-content: right;
+ }
+ }
+ }
+
+ > .item-details-container {
+ @extend .pos-card;
+ grid-column: span 4 / span 4;
+ display: none;
+ flex-direction: column;
+ padding: var(--padding-lg);
+ padding-top: var(--padding-md);
+
+ > .item-details-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: var(--margin-md);
+
+ > .close-btn {
+ @extend .pointer-no-select;
+ }
+ }
+
+ > .item-display {
+ display: flex;
+
+ > .item-name-desc-price {
+ flex: 1 1 0%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ margin-right: var(--margin-md);
+
+ > .item-name {
+ font-size: var(--text-3xl);
+ font-weight: 600;
+ }
+
+ > .item-desc {
+ font-size: var(--text-md);
+ font-weight: 500;
+ }
+
+ > .item-price {
+ font-size: var(--text-3xl);
+ font-weight: 700;
+ }
+ }
+
+ > .item-image {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 11rem;
+ height: 11rem;
+ border-radius: var(--border-radius-md);
+ margin-left: var(--margin-md);
+ color: var(--gray-500);
+
+ > img {
+ @extend .image;
+ }
+
+ > .item-abbr {
+ @extend .abbr;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: var(--border-radius-md);
+ font-size: var(--text-3xl);
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ > .discount-section {
+ display: flex;
+ align-items: center;
+ margin-bottom: var(--margin-sm);
+
+ > .item-rate {
+ font-weight: 500;
+ margin-right: var(--margin-sm);
+ text-decoration: line-through;
+ }
+
+ > .item-discount {
+ padding: 3px var(--padding-sm);
+ border-radius: var(--border-radius-sm);
+ background-color: var(--green-100);
+ color: var(--dark-green-500);
+ font-size: var(--text-sm);
+ font-weight: 700;
+ }
+ }
+
+ > .form-container {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ column-gap: var(--padding-md);
+
+ > .auto-fetch-btn {
+ @extend .pointer-no-select;
+ margin: var(--margin-xs);
+ }
+ }
+ }
+
+ > .payment-container {
+ @extend .pos-card;
+ grid-column: span 6 / span 6;
+ display: none;
+ flex-direction: column;
+ padding: var(--padding-lg);
+
+ .border-primary {
+ border: 1px solid var(--blue-500);
+ }
+
+ .submit-order-btn {
+ @extend .primary-action;
+ background-color: var(--blue-500);
+ color: white;
+ }
+
+ .section-label {
+ @extend .label;
+ @extend .pointer-no-select;
+ margin-bottom: var(--margin-md);
+ }
+
+ > .payment-modes {
+ display: flex;
+ padding-bottom: var(--padding-sm);
+ margin-bottom: var(--margin-xs);
+ overflow-x: scroll;
+ overflow-y: hidden;
+
+ > .payment-mode-wrapper {
+ min-width: 40%;
+ padding: var(--padding-xs);
+
+ > .mode-of-payment {
+ @extend .pos-card;
+ @extend .pointer-no-select;
+ padding: var(--padding-md) var(--padding-lg);
+
+ > .pay-amount {
+ display: inline;
+ float: right;
+ font-weight: 700;
+ }
+
+ > .mode-of-payment-control {
+ display: none;
+ align-items: center;
+ margin-top: var(--margin-sm);
+ margin-bottom: var(--margin-xs);
+ }
+
+ > .loyalty-amount-name {
+ display: none;
+ float: right;
+ font-weight: 700;
+ }
+
+ > .cash-shortcuts {
+ display: none;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: var(--margin-sm);
+ font-size: var(--text-sm);
+ text-align: center;
+
+ > .shortcut {
+ @extend .pointer-no-select;
+ border-radius: var(--border-radius-sm);
+ background-color: var(--gray-100);
+ font-weight: 500;
+ padding: var(--padding-xs) var(--padding-sm);
+ transition: all 0.15s ease-in-out;
+
+ &:hover {
+ background-color: var(--gray-300);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ > .fields-numpad-container {
+ display: flex;
+ flex: 1;
+
+ > .fields-section {
+ flex: 1;
+ }
+
+ > .number-pad {
+ flex: 1;
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-end;
+
+ .numpad-container {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: var(--margin-md);
+ margin-bottom: var(--margin-md);
+
+ > .numpad-btn {
+ @extend .pointer-no-select;
+ border-radius: var(--border-radius-md);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--padding-md);
+ box-shadow: var(--shadow-sm);
+ }
+ }
+ }
+ }
+
+ > .totals-section {
+ display: flex;
+ margin-top: auto;
+ margin-bottom: var(--margin-sm);
+ justify-content: center;
+ flex-direction: column;
+
+ > .totals {
+ display: flex;
+ background-color: var(--gray-100);
+ justify-content: center;
+ padding: var(--padding-md);
+ border-radius: var(--border-radius-md);
+
+ > .col {
+ flex-grow: 1;
+ text-align: center;
+
+ > .total-label {
+ font-size: var(--text-md);
+ font-weight: 500;
+ color: var(--gray-600);
+ }
+
+ > .value {
+ font-size: var(--text-2xl);
+ font-weight: 700;
+ }
+ }
+
+ > .seperator-y {
+ margin-left: var(--margin-sm);
+ margin-right: var(--margin-sm);
+ border-right: 1px solid var(--gray-300);
+ }
+ }
+
+ > .number-pad {
+ display: none;
+ }
+ }
+ }
+
+ > .past-order-list {
+ @extend .pos-card;
+ grid-column: span 4 / span 4;
+ display: none;
+ flex-direction: column;
+ overflow: hidden;
+
+ > .filter-section {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--fg-color);
+ padding: var(--padding-lg);
+
+ > .search-field {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ margin-top: var(--margin-md);
+ margin-bottom: var(--margin-xs);
+ }
+
+ > .status-field {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ }
+ }
+
+ > .invoices-container {
+ padding: var(--padding-lg);
+ padding-top: 0px;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ }
+ }
+
+ > .past-order-summary {
+ display: none;
+ grid-column: span 6 / span 6;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ > .no-summary-placeholder {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ background-color: var(--gray-50);
+ font-weight: 500;
+ border-radius: var(--border-radius-md);
+ }
+
+ > .invoice-summary-wrapper {
+ @extend .pos-card;
+ display: none;
+ position: relative;
+ width: 31rem;
+ height: 100%;
+
+ > .abs-container {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+ padding: var(--padding-lg);
+
+ > .upper-section {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ margin-bottom: var(--margin-md);
+
+ > .left-section {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: flex-end;
+ padding-right: var(--padding-sm);
+
+ > .customer-name {
+ font-size: var(--text-2xl);
+ font-weight: 700;
+ }
+
+ > .customer-email {
+ font-size: var(--text-md);
+ font-weight: 500;
+ color: var(--gray-600);
+ }
+
+ > .cashier {
+ font-size: var(--text-md);
+ font-weight: 500;
+ color: var(--gray-600);
+ margin-top: auto;
+ }
+ }
+
+ > .right-section {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ justify-content: space-between;
+
+ > .paid-amount {
+ font-size: var(--text-2xl);
+ font-weight: 700;
+ }
+
+ > .invoice-name {
+ font-size: var(--text-md);
+ font-weight: 500;
+ color: var(--gray-600);
+ margin-bottom: var(--margin-sm);
+ }
+ }
+ }
+
+ > .summary-container {
+ display: flex;
+ flex-direction: column;
+ border-radius: var(--border-radius-md);
+ background-color: var(--gray-50);
+ margin: var(--margin-md) 0px;
+
+ > .summary-row-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: var(--padding-sm) var(--padding-md);
+ }
+
+ > .taxes-wrapper {
+ display: flex;
+ flex-direction: column;
+ padding: 0px var(--padding-md);
+
+ > .tax-row {
+ display: flex;
+ justify-content: space-between;
+ font-size: var(--text-md);
+ line-height: var(--text-3xl);
+ }
+ }
+
+ > .item-row-wrapper {
+ display: flex;
+ align-items: center;
+ padding: var(--padding-sm) var(--padding-md);
+
+ > .item-name {
+ @extend .nowrap;
+ font-weight: 500;
+ margin-right: var(--margin-md);
+ }
+
+ > .item-qty {
+ font-weight: 500;
+ margin-left: auto;
+ }
+
+ > .item-rate-disc {
+ display: flex;
+ text-align: right;
+ margin-left: var(--margin-md);
+ justify-content: flex-end;
+
+ > .item-disc {
+ color: var(--dark-green-500);
+ }
+
+ > .item-rate {
+ font-weight: 500;
+ margin-left: var(--margin-md);
+ }
+ }
+ }
+
+ > .grand-total {
+ font-weight: 700;
+ }
+
+ > .payments {
+ font-weight: 700;
+ }
+ }
+
+
+ > .summary-btns {
+ display: flex;
+ justify-content: space-between;
+
+ > .summary-btn {
+ flex: 1;
+ margin: 0px var(--margin-xs);
+ }
+
+ > .new-btn {
+ background-color: var(--blue-500);
+ color:white;
+ font-weight: 500;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
new file mode 100644
index 0000000..159a8a4
--- /dev/null
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -0,0 +1,494 @@
+@import "frappe/public/scss/desk/variables";
+@import "frappe/public/scss/common/mixins";
+
+body.product-page {
+ background: var(--gray-50);
+}
+
+
+.item-breadcrumbs {
+ .breadcrumb-container {
+ ol.breadcrumb {
+ background-color: var(--gray-50) !important;
+ }
+
+ a {
+ color: var(--gray-900);
+ }
+ }
+}
+
+.carousel-control {
+ height: 42px;
+ width: 42px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: white;
+ box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.08), 0px 1px 2px 1px rgba(0, 0, 0, 0.06);
+ border-radius: 100px;
+}
+
+.carousel-control-prev,
+.carousel-control-next {
+ opacity: 1;
+}
+
+.carousel-body {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.carousel-content {
+ max-width: 400px;
+}
+
+.card {
+ border: none;
+}
+
+.product-category-section {
+ .card:hover {
+ box-shadow: 0px 16px 45px 6px rgba(0, 0, 0, 0.08), 0px 8px 10px -10px rgba(0, 0, 0, 0.04);
+ }
+
+ .card-grid {
+ display: grid;
+ grid-gap: 15px;
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
+ }
+}
+
+.item-card-group-section {
+ .card {
+ height: 360px;
+ align-items: center;
+ justify-content: center;
+
+ &:hover {
+ box-shadow: 0px 16px 60px rgba(0, 0, 0, 0.08), 0px 8px 30px -20px rgba(0, 0, 0, 0.04);
+ transition: box-shadow 400ms;
+ }
+ }
+
+ // .card-body {
+ // text-align: center;
+ // }
+
+ // .featured-item {
+ // .card-body {
+ // text-align: left;
+ // }
+ // }
+ .card-img-container {
+ height: 210px;
+ width: 100%;
+ }
+
+ .card-img {
+ max-height: 210px;
+ object-fit: contain;
+ margin-top: 1.25rem;
+ }
+
+ .no-image {
+ @include flex(flex, center, center, null);
+ height: 200px;
+ margin: 0 auto;
+ margin-top: var(--margin-xl);
+ background: var(--gray-100);
+ width: 80%;
+ border-radius: var(--border-radius);
+ font-size: 2rem;
+ color: var(--gray-500);
+ }
+
+ .product-title {
+ font-size: 14px;
+ color: var(--gray-800);
+ font-weight: 500;
+ }
+
+ .product-description {
+ font-size: 12px;
+ color: var(--text-color);
+ margin: 20px 0;
+ display: -webkit-box;
+ -webkit-line-clamp: 6;
+ -webkit-box-orient: vertical;
+
+ p {
+ margin-bottom: 0.5rem;
+ }
+ }
+
+ .product-category {
+ font-size: 13px;
+ color: var(--text-muted);
+ margin: var(--margin-sm) 0;
+ }
+
+ .product-price {
+ font-size: 18px;
+ font-weight: 600;
+ color: var(--text-color);
+ margin: var(--margin-sm) 0;
+ }
+
+ .item-card {
+ padding: var(--padding-sm);
+ }
+}
+
+[data-doctype="Item Group"],
+#page-all-products {
+ .page-header {
+ font-size: 20px;
+ font-weight: 700;
+ color: var(--text-color);
+ }
+
+ .filters-section {
+ .title-section {
+ border-bottom: 1px solid var(--table-border-color);
+ }
+
+ .filter-title {
+ font-weight: 500;
+ }
+
+ .clear-filters {
+ font-size: 13px;
+ }
+
+ .filter-label {
+ font-size: 11px;
+ font-weight: 600;
+ color: var(--gray-700);
+ text-transform: uppercase;
+ }
+
+ .filter-block {
+ border-bottom: 1px solid var(--table-border-color);
+ }
+
+ .checkbox {
+ .label-area {
+ font-size: 13px;
+ color: var(--gray-800);
+ }
+ }
+ }
+}
+
+.product-container {
+ @include card($padding: var(--padding-md));
+ min-height: 70vh;
+
+ .product-details {
+ max-width: 40%;
+ margin-left: -30px;
+
+ .btn-add-to-cart {
+ font-size: var(--text-base);
+ }
+ }
+
+ .product-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: var(--text-color);
+ }
+
+ .product-code {
+ color: var(--text-muted);
+ font-size: 13px;
+ }
+
+ .product-description {
+ font-size: 13px;
+ color: var(--gray-800);
+ }
+
+ .product-image {
+ border-color: var(--table-border-color) !important;
+ padding: 15px;
+
+ @include media-breakpoint-between(xs, md) {
+ height: 300px;
+ width: 300px;
+ }
+
+ @include media-breakpoint-up(lg) {
+ height: 350px;
+ width: 350px;
+ }
+
+ img {
+ object-fit: contain;
+ }
+ }
+
+ .item-slideshow {
+ @include media-breakpoint-between(xs, md) {
+ max-height: 320px;
+ }
+
+ @include media-breakpoint-up(lg) {
+ max-height: 430px;
+ }
+
+ overflow: scroll;
+ }
+
+ .item-slideshow-image {
+ height: 4rem;
+ width: 6rem;
+ object-fit: contain;
+ padding: 0.5rem;
+ border: 1px solid var(--table-border-color);
+ border-radius: 4px;
+ cursor: pointer;
+
+ &:hover, &.active {
+ border-color: $primary;
+ }
+ }
+
+ .item-cart {
+ .product-price {
+ font-size: 20px;
+ color: var(--text-color);
+ font-weight: 600;
+
+ .formatted-price {
+ color: var(--text-muted);
+ font-size: var(--text-base);
+ }
+ }
+
+ .no-stock {
+ font-size: var(--text-base);
+ }
+ }
+}
+
+.item-configurator-dialog {
+ .modal-header {
+ padding: var(--padding-md) var(--padding-xl);
+ }
+
+ .modal-body {
+ padding: 0 var(--padding-xl);
+ padding-bottom: var(--padding-xl);
+
+ .status-area {
+ .alert {
+ padding: var(--padding-xs) var(--padding-sm);
+ font-size: var(--text-sm);
+ }
+ }
+
+ .form-layout {
+ max-height: 50vh;
+ overflow-y: auto;
+ }
+
+ .section-body {
+ .form-column {
+ .form-group {
+ .control-label {
+ font-size: var(--text-md);
+ color: var(--gray-700);
+ }
+
+ .help-box {
+ margin-top: 2px;
+ font-size: var(--text-sm);
+ }
+ }
+ }
+ }
+ }
+}
+
+.item-group-slideshow {
+ .item-group-description {
+ // max-width: 900px;
+ }
+
+ .carousel-inner.rounded-carousel {
+ border-radius: $card-border-radius;
+ }
+}
+
+.cart-icon {
+ .cart-badge {
+ position: relative;
+ top: -10px;
+ left: -12px;
+ background: var(--red-600);
+ width: 16px;
+ align-items: center;
+ height: 16px;
+ font-size: 10px;
+ border-radius: 50%;
+ }
+}
+
+
+#page-cart {
+ .shopping-cart-header {
+ font-weight: bold;
+ }
+
+ .cart-container {
+ color: var(--text-color);
+
+ .frappe-card {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ }
+
+ .cart-items-header {
+ font-weight: 600;
+ }
+
+ .cart-table {
+ th, tr, td {
+ border-color: var(--border-color);
+ border-width: 1px;
+ }
+
+ th {
+ font-weight: normal;
+ font-size: 13px;
+ color: var(--text-muted);
+ padding: var(--padding-sm) 0;
+ }
+
+ td {
+ padding: var(--padding-sm) 0;
+ color: var(--text-color);
+ }
+
+ .cart-items {
+ .item-title {
+ font-size: var(--text-base);
+ font-weight: 500;
+ color: var(--text-color);
+ }
+
+ .item-subtitle {
+ color: var(--text-muted);
+ font-size: var(--text-md);
+ }
+
+ .item-subtotal {
+ font-size: var(--text-base);
+ font-weight: 500;
+ }
+
+ .item-rate {
+ font-size: var(--text-md);
+ color: var(--text-muted);
+ }
+
+ textarea {
+ width: 40%;
+ }
+ }
+
+ .cart-tax-items {
+ .item-grand-total {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--text-color);
+ }
+ }
+ }
+
+ .cart-addresses {
+ hr {
+ border-color: var(--border-color);
+ }
+ }
+
+ .number-spinner {
+ width: 75%;
+ .cart-btn {
+ border: none;
+ background: var(--gray-100);
+ box-shadow: none;
+ height: 28px;
+ align-items: center;
+ display: flex;
+ }
+
+ .cart-qty {
+ height: 28px;
+ font-size: var(--text-md);
+ }
+ }
+
+ .place-order-container {
+ .btn-place-order {
+ width: 62%;
+ }
+ }
+ }
+}
+
+.cart-empty.frappe-card {
+ min-height: 76vh;
+ @include flex(flex, center, center, column);
+
+ .cart-empty-message {
+ font-size: 18px;
+ color: var(--text-color);
+ font-weight: bold;
+ }
+}
+
+.address-card {
+ .card-title {
+ font-size: var(--text-base);
+ font-weight: 500;
+ }
+
+ .card-body {
+ max-width: 80%;
+ }
+
+ .card-text {
+ font-size: var(--text-md);
+ color: var(--gray-700);
+ }
+
+ .card-link {
+ font-size: var(--text-md);
+
+ svg use {
+ stroke: var(--blue-500);
+ }
+ }
+
+ .btn-change-address {
+ color: var(--blue-500);
+ box-shadow: none;
+ border: 1px solid var(--blue-500);
+ }
+}
+
+.modal .address-card {
+ .card-body {
+ padding: var(--padding-sm);
+ border-radius: var(--border-radius);
+ border: 1px solid var(--dark-border-color);
+ }
+}
+
diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss
index 617e916..56b717c 100644
--- a/erpnext/public/scss/website.scss
+++ b/erpnext/public/scss/website.scss
@@ -1,29 +1,10 @@
-@import "frappe/public/scss/variables";
-
-.product-image img {
- min-height: 20rem;
- max-height: 30rem;
-}
+@import "frappe/public/scss/website/variables";
.filter-options {
max-height: 300px;
overflow: auto;
}
-.item-slideshow-image {
- height: 3rem;
- width: 3rem;
- object-fit: contain;
- padding: 0.5rem;
- border: 1px solid $border-color;
- border-radius: 4px;
- cursor: pointer;
-
- &:hover, &.active {
- border-color: $primary;
- }
-}
-
.address-card {
cursor: pointer;
position: relative;
@@ -43,10 +24,10 @@
.check {
display: inline-flex;
- padding: 0.25rem;
- background: $primary;
- color: white;
- border-radius: 50%;
+ padding: 0.25rem;
+ background: $primary;
+ color: white;
+ border-radius: 50%;
font-size: 12px;
width: 24px;
height: 24px;
diff --git a/erpnext/quality_management/desk_page/quality/quality.json b/erpnext/quality_management/desk_page/quality/quality.json
deleted file mode 100644
index 5ee7000..0000000
--- a/erpnext/quality_management/desk_page/quality/quality.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Goal and Procedure",
- "links": "[\n {\n \"description\": \"Quality Goal.\",\n \"label\": \"Quality Goal\",\n \"name\": \"Quality Goal\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Quality Procedure.\",\n \"label\": \"Quality Procedure\",\n \"name\": \"Quality Procedure\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Quality Procedures.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Tree of Procedures\",\n \"name\": \"Quality Procedure\",\n \"route\": \"#Tree/Quality Procedure\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Feedback",
- "links": "[\n {\n \"description\": \"Quality Feedback\",\n \"label\": \"Quality Feedback\",\n \"name\": \"Quality Feedback\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Quality Feedback Template\",\n \"label\": \"Quality Feedback Template\",\n \"name\": \"Quality Feedback Template\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Meeting",
- "links": "[\n {\n \"description\": \"Quality Meeting\",\n \"label\": \"Quality Meeting\",\n \"name\": \"Quality Meeting\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Review and Action",
- "links": "[\n {\n \"description\": \"Quality Review\",\n \"label\": \"Quality Review\",\n \"name\": \"Quality Review\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Quality Action\",\n \"label\": \"Quality Action\",\n \"name\": \"Quality Action\",\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [],
- "creation": "2020-03-02 15:49:28.632014",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends_another_page": 0,
- "icon": "",
- "idx": 0,
- "is_standard": 1,
- "label": "Quality",
- "modified": "2020-04-01 11:28:51.095012",
- "modified_by": "Administrator",
- "module": "Quality Management",
- "name": "Quality",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "label": "Quality Goal",
- "link_to": "Quality Goal",
- "type": "DocType"
- },
- {
- "label": "Quality Procedure",
- "link_to": "Quality Procedure",
- "type": "DocType"
- },
- {
- "label": "Quality Inspection",
- "link_to": "Quality Inspection",
- "type": "DocType"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/quality_management/doctype/non_conformance/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/quality_management/doctype/non_conformance/__init__.py
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.js b/erpnext/quality_management/doctype/non_conformance/non_conformance.js
new file mode 100644
index 0000000..e7f5eee
--- /dev/null
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Non Conformance', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.json b/erpnext/quality_management/doctype/non_conformance/non_conformance.json
new file mode 100644
index 0000000..8dfe2d6
--- /dev/null
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.json
@@ -0,0 +1,118 @@
+{
+ "actions": [],
+ "autoname": "format:QA-NC-{#####}",
+ "creation": "2020-10-21 14:49:50.350136",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "subject",
+ "procedure",
+ "process_owner",
+ "full_name",
+ "column_break_4",
+ "status",
+ "section_break_4",
+ "details",
+ "corrective_action",
+ "preventive_action"
+ ],
+ "fields": [
+ {
+ "fieldname": "subject",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Subject",
+ "reqd": 1
+ },
+ {
+ "fieldname": "procedure",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Procedure",
+ "options": "Quality Procedure",
+ "reqd": 1
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "options": "Open\nResolved\nCancelled",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "details",
+ "fieldtype": "Text Editor",
+ "label": "Details"
+ },
+ {
+ "fetch_from": "procedure.process_owner",
+ "fieldname": "process_owner",
+ "fieldtype": "Data",
+ "label": "Process Owner",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "process_owner.full_name",
+ "fieldname": "full_name",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Full Name"
+ },
+ {
+ "fieldname": "corrective_action",
+ "fieldtype": "Text Editor",
+ "label": "Corrective Action"
+ },
+ {
+ "fieldname": "preventive_action",
+ "fieldtype": "Text Editor",
+ "label": "Preventive Action"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-02-26 15:27:47.247814",
+ "modified_by": "Administrator",
+ "module": "Quality Management",
+ "name": "Non Conformance",
+ "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": "Employee",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.py b/erpnext/quality_management/doctype/non_conformance/non_conformance.py
new file mode 100644
index 0000000..d4e8cc7
--- /dev/null
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class NonConformance(Document):
+ pass
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
index 2ad7984..54f8b58 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestNonConformance(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.js b/erpnext/quality_management/doctype/quality_action/quality_action.js
index 7078247..e216a75 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.js
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.js
@@ -2,32 +2,5 @@
// For license information, please see license.txt
frappe.ui.form.on('Quality Action', {
- onload: function(frm) {
- frm.set_value("date", frappe.datetime.get_today());
- frm.refresh();
- },
- document_name: function(frm){
- frappe.call({
- "method": "frappe.client.get",
- args: {
- doctype: frm.doc.document_type,
- name: frm.doc.document_name
- },
- callback: function(data){
- frm.fields_dict.resolutions.grid.remove_all();
- let objectives = [];
- if(frm.doc.document_type === "Quality Review"){
- for(let i in data.message.reviews) objectives.push(data.message.reviews[i].review);
- } else {
- for(let j in data.message.parameters) objectives.push(data.message.parameters[j].feedback);
- }
- for (var objective in objectives){
- frm.add_child("resolutions");
- frm.fields_dict.resolutions.get_value()[objective].problem = objectives[objective];
- }
- frm.refresh();
- }
- });
- },
});
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.json b/erpnext/quality_management/doctype/quality_action/quality_action.json
index 8835b47..0cc2a98 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.json
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.json
@@ -1,32 +1,34 @@
{
- "autoname": "format:ACTN-{#####}",
+ "actions": [],
+ "autoname": "format:QA-ACT-{#####}",
"creation": "2018-10-02 11:40:43.666100",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"corrective_preventive",
- "document_type",
- "goal",
+ "review",
+ "feedback",
+ "status",
"cb_00",
"date",
- "document_name",
+ "goal",
"procedure",
- "status",
"sb_00",
"resolutions"
],
"fields": [
{
- "depends_on": "eval:doc.type == 'Quality Review'",
"fetch_from": "review.goal",
"fieldname": "goal",
"fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Goal",
- "options": "Quality Goal",
- "read_only": 1
+ "options": "Quality Goal"
},
{
+ "default": "Today",
"fieldname": "date",
"fieldtype": "Date",
"in_list_view": 1,
@@ -34,34 +36,20 @@
"read_only": 1
},
{
- "depends_on": "eval:doc.type == 'Quality Review'",
"fieldname": "procedure",
"fieldtype": "Link",
"label": "Procedure",
- "options": "Quality Procedure",
- "read_only": 1
+ "options": "Quality Procedure"
},
{
"default": "Open",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Status",
- "options": "Open\nClosed"
- },
- {
- "fieldname": "document_name",
- "fieldtype": "Dynamic Link",
- "label": "Document Name",
- "options": "document_type"
- },
- {
- "fieldname": "document_type",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Document Type",
- "options": "Quality Review\nQuality Feedback",
- "reqd": 1
+ "options": "Open\nCompleted",
+ "read_only": 1
},
{
"default": "Corrective",
@@ -86,9 +74,24 @@
"fieldtype": "Table",
"label": "Resolutions",
"options": "Quality Action Resolution"
+ },
+ {
+ "fieldname": "review",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Review",
+ "options": "Quality Review"
+ },
+ {
+ "fieldname": "feedback",
+ "fieldtype": "Link",
+ "label": "Feedback",
+ "options": "Quality Feedback"
}
],
- "modified": "2019-05-28 13:10:44.092497",
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-10-27 16:21:59.533937",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Action",
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.py b/erpnext/quality_management/doctype/quality_action/quality_action.py
index 88d4bd8..d6fa505 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.py
@@ -7,4 +7,5 @@
from frappe.model.document import Document
class QualityAction(Document):
- pass
\ No newline at end of file
+ def validate(self):
+ self.status = 'Open' if any([d.status=='Open' for d in self.resolutions]) else 'Completed'
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_action/test_quality_action.js b/erpnext/quality_management/doctype/quality_action/test_quality_action.js
deleted file mode 100644
index 34a8c86..0000000
--- a/erpnext/quality_management/doctype/quality_action/test_quality_action.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quality Action", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quality Actions
- () => frappe.tests.make('Quality Actions', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
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 51178d6..24b97ca 100644
--- a/erpnext/quality_management/doctype/quality_action/test_quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
@@ -5,42 +5,7 @@
import frappe
import unittest
-from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
-from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_unit
-from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_goal
-from erpnext.quality_management.doctype.quality_review.test_quality_review import create_review
class TestQualityAction(unittest.TestCase):
-
- def test_quality_action(self):
- create_procedure()
- create_unit()
- create_goal()
- create_review()
- test_create_action = create_action()
- test_get_action = get_action()
-
- self.assertEquals(test_create_action, test_get_action)
-
-def create_action():
- review = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
- action = frappe.get_doc({
- "doctype": "Quality Action",
- "action": "Corrective",
- "document_type": "Quality Review",
- "document_name": review,
- "date": frappe.utils.nowdate(),
- "goal": "GOAL-_Test Quality Goal",
- "procedure": "PRC-_Test Quality Procedure"
- })
- action_exist = frappe.db.exists("Quality Action", {"review": review})
-
- if not action_exist:
- action.insert()
- return action.name
- else:
- return action_exist
-
-def get_action():
- review = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
- return frappe.db.exists("Quality Action", {"document_name": review})
\ No newline at end of file
+ # quality action has no code
+ pass
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json
index a4e6aed..993274b 100644
--- a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json
+++ b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json
@@ -1,33 +1,54 @@
{
+ "actions": [],
"creation": "2019-05-26 20:36:44.337186",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"problem",
- "sb_00",
- "resolution"
+ "resolution",
+ "status",
+ "responsible",
+ "completion_by"
],
"fields": [
{
"fieldname": "problem",
"fieldtype": "Long Text",
"in_list_view": 1,
- "label": "Review"
- },
- {
- "fieldname": "sb_00",
- "fieldtype": "Section Break"
+ "label": "Problem"
},
{
"fieldname": "resolution",
"fieldtype": "Text Editor",
"in_list_view": 1,
"label": "Resolution"
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "options": "Open\nCompleted"
+ },
+ {
+ "fieldname": "responsible",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Responsible",
+ "options": "User"
+ },
+ {
+ "fieldname": "completion_by",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Completion By"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-05-28 13:09:50.435323",
+ "links": [],
+ "modified": "2020-10-21 12:59:25.566682",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Action Resolution",
diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js
index dac6ac4..6fb3267 100644
--- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js
+++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js
@@ -2,31 +2,9 @@
// For license information, please see license.txt
frappe.ui.form.on('Quality Feedback', {
- refresh: function(frm) {
- frm.set_value("date", frappe.datetime.get_today());
- },
-
template: function(frm) {
if (frm.doc.template) {
- frappe.call({
- "method": "frappe.client.get",
- args: {
- doctype: "Quality Feedback Template",
- name: frm.doc.template
- },
- callback: function(data) {
- if (data && data.message) {
- frm.fields_dict.parameters.grid.remove_all();
-
- // fetch parameters from template and autofill
- for (let template_parameter of data.message.parameters) {
- let row = frm.add_child("parameters");
- row.parameter = template_parameter.parameter;
- }
- frm.refresh();
- }
- }
- });
+ frm.call('set_parameters');
}
}
});
diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json
index ab9084f..f3bd0dd 100644
--- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json
+++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json
@@ -1,16 +1,15 @@
{
"actions": [],
- "autoname": "format:FDBK-{#####}",
+ "autoname": "format:QA-FB-{#####}",
"creation": "2019-05-26 21:23:05.308379",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "document_type",
"template",
"cb_00",
+ "document_type",
"document_name",
- "date",
"sb_00",
"parameters"
],
@@ -18,6 +17,7 @@
{
"fieldname": "template",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "Template",
"options": "Quality Feedback Template",
"reqd": 1
@@ -27,13 +27,6 @@
"fieldtype": "Column Break"
},
{
- "fieldname": "date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Date",
- "read_only": 1
- },
- {
"fieldname": "sb_00",
"fieldtype": "Section Break"
},
@@ -47,6 +40,7 @@
{
"fieldname": "document_type",
"fieldtype": "Select",
+ "in_list_view": 1,
"label": "Type",
"options": "User\nCustomer",
"reqd": 1
@@ -54,13 +48,20 @@
{
"fieldname": "document_name",
"fieldtype": "Dynamic Link",
+ "in_list_view": 1,
"label": "Feedback By",
"options": "document_type",
"reqd": 1
}
],
- "links": [],
- "modified": "2020-07-03 15:50:58.589302",
+ "links": [
+ {
+ "group": "Actions",
+ "link_doctype": "Quality Action",
+ "link_fieldname": "feedback"
+ }
+ ],
+ "modified": "2020-10-27 16:20:10.918544",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Feedback",
diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
index 9894181..bf82cc0 100644
--- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
@@ -7,4 +7,17 @@
from frappe.model.document import Document
class QualityFeedback(Document):
- pass
\ No newline at end of file
+ def set_parameters(self):
+ if self.template and not getattr(self, 'parameters', []):
+ for d in frappe.get_doc('Quality Feedback Template', self.template).parameters:
+ self.append('parameters', dict(
+ parameter = d.parameter,
+ rating = 1
+ ))
+
+ def validate(self):
+ if not self.document_name:
+ self.document_type ='User'
+ self.document_name = frappe.session.user
+ self.set_parameters()
+
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 3be1eb2..5a8bd5c 100644
--- a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
@@ -5,49 +5,27 @@
import frappe
import unittest
-from erpnext.quality_management.doctype.quality_feedback_template.test_quality_feedback_template import create_template
+
class TestQualityFeedback(unittest.TestCase):
-
def test_quality_feedback(self):
- create_template()
- test_create_feedback = create_feedback()
- test_get_feedback = get_feedback()
+ template = frappe.get_doc(dict(
+ doctype = 'Quality Feedback Template',
+ template = 'Test Template',
+ parameters = [
+ dict(parameter='Test Parameter 1'),
+ dict(parameter='Test Parameter 2')
+ ]
+ )).insert()
- self.assertEqual(test_create_feedback, test_get_feedback)
+ feedback = frappe.get_doc(dict(
+ doctype = 'Quality Feedback',
+ template = template.name,
+ document_type = 'User',
+ document_name = frappe.session.user
+ )).insert()
-def create_feedback():
- create_customer()
+ self.assertEqual(template.parameters[0].parameter, feedback.parameters[0].parameter)
- feedabck = frappe.get_doc({
- "doctype": "Quality Feedback",
- "template": "TMPL-_Test Feedback Template",
- "document_type": "Customer",
- "document_name": "Quality Feedback Customer",
- "date": frappe.utils.nowdate(),
- "parameters": [
- {
- "parameter": "Test Parameter",
- "rating": 3,
- "feedback": "Test Feedback"
- }
- ]
- })
-
- feedback_exists = frappe.db.exists("Quality Feedback", {"template": "TMPL-_Test Feedback Template"})
-
- if not feedback_exists:
- feedabck.insert()
- return feedabck.name
- else:
- return feedback_exists
-
-def get_feedback():
- return frappe.db.exists("Quality Feedback", {"template": "TMPL-_Test Feedback Template"})
-
-def create_customer():
- if not frappe.db.exists("Customer", {"customer_name": "Quality Feedback Customer"}):
- customer = frappe.get_doc({
- "doctype": "Customer",
- "customer_name": "Quality Feedback Customer"
- }).insert(ignore_permissions=True)
\ No newline at end of file
+ feedback.delete()
+ template.delete()
diff --git a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.json b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.json
index 5bd8920..ce5d4cf 100644
--- a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.json
+++ b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-05-26 21:25:01.715807",
"doctype": "DocType",
"editable_grid": 1,
@@ -39,12 +40,13 @@
"fieldname": "feedback",
"fieldtype": "Text Editor",
"in_list_view": 1,
- "label": "Feedback",
- "reqd": 1
+ "label": "Feedback"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-07-13 19:58:08.966141",
+ "links": [],
+ "modified": "2020-10-27 17:28:12.033145",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Feedback Parameter",
diff --git a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json
index bdc9dba..1696470 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json
+++ b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json
@@ -1,13 +1,12 @@
{
"actions": [],
- "autoname": "format:TMPL-{template}",
+ "autoname": "field:template",
"creation": "2019-05-26 21:17:24.283061",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"template",
- "cb_00",
"sb_00",
"parameters"
],
@@ -16,12 +15,9 @@
"fieldname": "template",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Template",
- "reqd": 1
- },
- {
- "fieldname": "cb_00",
- "fieldtype": "Column Break"
+ "label": "Template Name",
+ "reqd": 1,
+ "unique": 1
},
{
"fieldname": "sb_00",
@@ -35,8 +31,14 @@
"reqd": 1
}
],
- "links": [],
- "modified": "2020-07-03 16:06:03.749415",
+ "links": [
+ {
+ "group": "Records",
+ "link_doctype": "Quality Feedback",
+ "link_fieldname": "template"
+ }
+ ],
+ "modified": "2020-10-27 16:18:53.579688",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Feedback Template",
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 36dbe13..b3eed10 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
@@ -7,31 +7,4 @@
import unittest
class TestQualityFeedbackTemplate(unittest.TestCase):
-
- def test_quality_feedback_template(self):
- test_create_template = create_template()
- test_get_template = get_template()
-
- self.assertEqual(test_create_template, test_get_template)
-
-def create_template():
- template = frappe.get_doc({
- "doctype": "Quality Feedback Template",
- "template": "_Test Feedback Template",
- "parameters": [
- {
- "parameter": "Test Parameter"
- }
- ]
- })
-
- template_exists = frappe.db.exists("Quality Feedback Template", {"template": "_Test Feedback Template"})
-
- if not template_exists:
- template.insert()
- return template.name
- else:
- return template_exists
-
-def get_template():
- return frappe.db.exists("Quality Feedback Template", {"template": "_Test Feedback Template"})
\ No newline at end of file
+ pass
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.js b/erpnext/quality_management/doctype/quality_goal/quality_goal.js
index ff58c5a..40cb4d9 100644
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal.js
+++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.js
@@ -2,7 +2,6 @@
// For license information, please see license.txt
frappe.ui.form.on('Quality Goal', {
- refresh: function(frm) {
- frm.doc.created_by = frappe.session.user;
- }
+ // refresh: function(frm) {
+ // }
});
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.json b/erpnext/quality_management/doctype/quality_goal/quality_goal.json
index c326109..2680255 100644
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal.json
+++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.json
@@ -1,5 +1,6 @@
{
- "autoname": "format:GOAL-{goal}",
+ "actions": [],
+ "autoname": "field:goal",
"creation": "2018-10-02 12:17:41.727541",
"doctype": "DocType",
"editable_grid": 1,
@@ -7,28 +8,15 @@
"field_order": [
"goal",
"frequency",
- "created_by",
"cb_00",
"procedure",
"weekday",
- "quarter",
"date",
- "sb_00",
- "revision",
- "cb_01",
- "revised_on",
"sb_01",
"objectives"
],
"fields": [
{
- "fieldname": "created_by",
- "fieldtype": "Link",
- "label": "Created By",
- "options": "User",
- "read_only": 1
- },
- {
"default": "None",
"fieldname": "frequency",
"fieldtype": "Select",
@@ -51,20 +39,6 @@
"options": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30"
},
{
- "default": "0",
- "fieldname": "revision",
- "fieldtype": "Int",
- "label": "Revision",
- "read_only": 1
- },
- {
- "fieldname": "revised_on",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Revised On",
- "read_only": 1
- },
- {
"depends_on": "eval:doc.frequency == 'Weekly';",
"fieldname": "weekday",
"fieldtype": "Select",
@@ -76,15 +50,6 @@
"fieldtype": "Column Break"
},
{
- "fieldname": "sb_00",
- "fieldtype": "Section Break",
- "label": "Revision and Revised On"
- },
- {
- "fieldname": "cb_01",
- "fieldtype": "Column Break"
- },
- {
"fieldname": "sb_01",
"fieldtype": "Section Break",
"label": "Objectives"
@@ -101,18 +66,17 @@
"label": "Goal",
"reqd": 1,
"unique": 1
- },
- {
- "default": "January-April-July-October",
- "depends_on": "eval:doc.frequency == 'Quarterly';",
- "fieldname": "quarter",
- "fieldtype": "Select",
- "label": "Quarter",
- "options": "January-April-July-October",
- "read_only": 1
}
],
- "modified": "2019-05-28 14:49:12.768863",
+ "index_web_pages_for_search": 1,
+ "links": [
+ {
+ "group": "Review",
+ "link_doctype": "Quality Review",
+ "link_fieldname": "goal"
+ }
+ ],
+ "modified": "2020-10-27 15:57:59.368605",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Goal",
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.py b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
index 4ae015e..f3fe986 100644
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
@@ -8,7 +8,5 @@
from frappe.model.document import Document
class QualityGoal(Document):
-
def validate(self):
- self.revision += 1
- self.revised_on = frappe.utils.today()
+ pass
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal_dashboard.py b/erpnext/quality_management/doctype/quality_goal/quality_goal_dashboard.py
deleted file mode 100644
index 22af3c0..0000000
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal_dashboard.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from frappe import _
-
-def get_data():
- return {
- 'fieldname': 'goal',
- 'transactions': [
- {
- 'label': _('Review'),
- 'items': ['Quality Review']
- }
- ]
- }
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.js b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.js
deleted file mode 100644
index f8afe54..0000000
--- a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quality Goal", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quality Goal
- () => frappe.tests.make('Quality Goal', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
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 d77187a..f61d6e5 100644
--- a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
@@ -8,44 +8,18 @@
from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
class TestQualityGoal(unittest.TestCase):
-
def test_quality_goal(self):
- create_procedure()
- create_unit()
- test_create_goal = create_goal()
- test_get_goal = get_goal()
+ # no code, just a basic sanity check
+ goal = get_quality_goal()
+ self.assertTrue(goal)
+ goal.delete()
- self.assertEquals(test_create_goal, test_get_goal)
-
-def create_goal():
- goal = frappe.get_doc({
- "doctype": "Quality Goal",
- "goal": "_Test Quality Goal",
- "procedure": "PRC-_Test Quality Procedure",
- "objectives": [
- {
- "objective": "_Test Quality Objective",
- "target": "4",
- "uom": "_Test UOM"
- }
+def get_quality_goal():
+ return frappe.get_doc(dict(
+ doctype = 'Quality Goal',
+ goal = 'Test Quality Module',
+ frequency = 'Daily',
+ objectives = [
+ dict(objective = 'Check test cases', target='100', uom='Percent')
]
- })
- goal_exist = frappe.db.exists("Quality Goal", {"goal": goal.goal})
- if not goal_exist:
- goal.insert()
- return goal.name
- else:
- return goal_exist
-
-def get_goal():
- goal = frappe.db.exists("Quality Goal", "GOAL-_Test Quality Goal")
- return goal
-
-def create_unit():
- unit = frappe.get_doc({
- "doctype": "UOM",
- "uom_name": "_Test UOM",
- })
- unit_exist = frappe.db.exists("UOM", unit.uom_name)
- if not unit_exist:
- unit.insert()
+ )).insert()
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.js b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.js
index 32c7c33..eb7a8c3 100644
--- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.js
+++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.js
@@ -2,8 +2,5 @@
// For license information, please see license.txt
frappe.ui.form.on('Quality Meeting', {
- onload: function(frm){
- frm.set_value("date", frappe.datetime.get_today());
- frm.refresh();
- }
+
});
diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.json b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.json
index 7691fe3..e2125c3 100644
--- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.json
+++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.json
@@ -1,15 +1,13 @@
{
"actions": [],
- "autoname": "naming_series:",
+ "autoname": "format:QA-MEET-{YY}-{MM}-{DD}",
"creation": "2018-10-15 16:25:41.548432",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "naming_series",
- "date",
- "cb_00",
"status",
+ "cb_00",
"sb_00",
"agenda",
"sb_01",
@@ -17,13 +15,6 @@
],
"fields": [
{
- "fieldname": "date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Date",
- "read_only": 1
- },
- {
"default": "Open",
"fieldname": "status",
"fieldtype": "Select",
@@ -42,8 +33,7 @@
},
{
"fieldname": "sb_00",
- "fieldtype": "Section Break",
- "label": "Agenda"
+ "fieldtype": "Section Break"
},
{
"fieldname": "agenda",
@@ -53,18 +43,12 @@
},
{
"fieldname": "sb_01",
- "fieldtype": "Section Break",
- "label": "Minutes"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Naming Series",
- "options": "MTNG-.YYYY.-.MM.-.DD.-"
+ "fieldtype": "Section Break"
}
],
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-05-19 13:18:59.821740",
+ "modified": "2021-02-27 16:36:45.657883",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Meeting",
@@ -99,4 +83,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.js b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.js
deleted file mode 100644
index 196cc85..0000000
--- a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quality Meeting", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quality Meeting
- () => frappe.tests.make('Quality Meeting', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
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 e61b5df..754bccb 100644
--- a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
@@ -5,41 +5,7 @@
import frappe
import unittest
-from erpnext.quality_management.doctype.quality_review.test_quality_review import create_review
class TestQualityMeeting(unittest.TestCase):
- def test_quality_meeting(self):
- create_review()
- test_create_meeting = create_meeting()
- test_get_meeting = get_meeting()
- self.assertEquals(test_create_meeting, test_get_meeting)
-
-def create_meeting():
- meeting = frappe.get_doc({
- "doctype": "Quality Meeting",
- "status": "Open",
- "date": frappe.utils.nowdate(),
- "agenda": [
- {
- "agenda": "Test Agenda"
- }
- ],
- "minutes": [
- {
- "document_type": "Quality Review",
- "document_name": frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"}),
- "minute": "Test Minute"
- }
- ]
- })
- meeting_exist = frappe.db.exists("Quality Meeting", {"date": frappe.utils.nowdate(), "status": "Open"})
-
- if not meeting_exist:
- meeting.insert()
- return meeting.name
- else:
- return meeting_exist
-
-def get_meeting():
- meeting = frappe.db.exists("Quality Meeting", {"date": frappe.utils.nowdate(), "status": "Open"})
- return meeting
\ No newline at end of file
+ # nothing to test
+ pass
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
index cf2644e..ac87622 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
@@ -10,5 +10,13 @@
}
};
});
+
+ frm.set_query('parent_quality_procedure', function(){
+ return {
+ filters: {
+ is_group: 1
+ }
+ };
+ });
}
});
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json
index b3c0d94..f588f9a 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json
@@ -1,19 +1,22 @@
{
"actions": [],
"allow_rename": 1,
- "autoname": "format:PRC-{quality_procedure_name}",
+ "autoname": "field:quality_procedure_name",
"creation": "2018-10-06 00:06:29.756804",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"quality_procedure_name",
+ "process_owner",
+ "process_owner_full_name",
+ "section_break_3",
+ "processes",
+ "sb_00",
"parent_quality_procedure",
"is_group",
- "sb_00",
- "processes",
- "lft",
"rgt",
+ "lft",
"old_parent"
],
"fields": [
@@ -21,8 +24,7 @@
"fieldname": "parent_quality_procedure",
"fieldtype": "Link",
"label": "Parent Procedure",
- "options": "Quality Procedure",
- "read_only": 1
+ "options": "Quality Procedure"
},
{
"default": "0",
@@ -35,14 +37,14 @@
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
- "label": "Lft",
+ "label": "Left Index",
"read_only": 1
},
{
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
- "label": "Rgt",
+ "label": "Right Index",
"read_only": 1
},
{
@@ -55,7 +57,7 @@
{
"fieldname": "sb_00",
"fieldtype": "Section Break",
- "label": "Processes"
+ "label": "Parent"
},
{
"fieldname": "processes",
@@ -68,12 +70,52 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "Quality Procedure",
- "reqd": 1
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "process_owner",
+ "fieldtype": "Link",
+ "label": "Process Owner",
+ "options": "User"
+ },
+ {
+ "fieldname": "section_break_3",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fetch_from": "process_owner.full_name",
+ "fieldname": "process_owner_full_name",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Process Owner Full Name",
+ "print_hide": 1
}
],
"is_tree": 1,
- "links": [],
- "modified": "2020-06-17 17:25:03.434953",
+ "links": [
+ {
+ "group": "Reviews",
+ "link_doctype": "Quality Review",
+ "link_fieldname": "procedure"
+ },
+ {
+ "group": "Goals",
+ "link_doctype": "Quality Goal",
+ "link_fieldname": "procedure"
+ },
+ {
+ "group": "Actions",
+ "link_doctype": "Quality Action",
+ "link_fieldname": "procedure"
+ },
+ {
+ "group": "Actions",
+ "link_doctype": "Non Conformance",
+ "link_fieldname": "procedure"
+ }
+ ],
+ "modified": "2020-10-26 15:25:39.316088",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Procedure",
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index 1952e57..53f4e6c 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils.nestedset import NestedSet
+from frappe.utils.nestedset import NestedSet, rebuild_tree
from frappe import _
class QualityProcedure(NestedSet):
@@ -14,67 +14,58 @@
self.check_for_incorrect_child()
def on_update(self):
+ NestedSet.on_update(self)
self.set_parent()
def after_insert(self):
self.set_parent()
- #if Child is Added through Tree View.
+
+ # add child to parent if missing
if self.parent_quality_procedure:
- parent_quality_procedure = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
- parent_quality_procedure.append("processes", {"procedure": self.name})
- parent_quality_procedure.save()
+ parent = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
+ if not [d for d in parent.processes if d.procedure == self.name]:
+ parent.append("processes", {"procedure": self.name, "process_description": self.name})
+ parent.save()
def on_trash(self):
- if self.parent_quality_procedure:
- doc = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
- for process in doc.processes:
- if process.procedure == self.name:
- doc.processes.remove(process)
- doc.save(ignore_permissions=True)
-
- flag_is_group = 0
- doc.load_from_db()
-
- for process in doc.processes:
- flag_is_group = 1 if process.procedure else 0
-
- doc.is_group = 0 if flag_is_group == 0 else 1
- doc.save(ignore_permissions=True)
+ # clear from child table (sub procedures)
+ frappe.db.sql('''update `tabQuality Procedure Process`
+ set `procedure`='' where `procedure`=%s''', self.name)
+ NestedSet.on_trash(self, allow_root_deletion=True)
def set_parent(self):
for process in self.processes:
# Set parent for only those children who don't have a parent
- parent_quality_procedure = frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure")
- if not parent_quality_procedure and process.procedure:
+ has_parent = frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure")
+ if not has_parent and process.procedure:
frappe.db.set_value(self.doctype, process.procedure, "parent_quality_procedure", self.name)
def check_for_incorrect_child(self):
for process in self.processes:
if process.procedure:
+ self.is_group = 1
# Check if any child process belongs to another parent.
parent_quality_procedure = frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure")
if parent_quality_procedure and parent_quality_procedure != self.name:
- frappe.throw(_("{0} already has a Parent Procedure {1}.".format(frappe.bold(process.procedure), frappe.bold(parent_quality_procedure))),
+ frappe.throw(_("{0} already has a Parent Procedure {1}.").format(frappe.bold(process.procedure), frappe.bold(parent_quality_procedure)),
title=_("Invalid Child Procedure"))
- self.is_group = 1
@frappe.whitelist()
def get_children(doctype, parent=None, parent_quality_procedure=None, is_root=False):
if parent is None or parent == "All Quality Procedures":
parent = ""
- return frappe.db.sql("""
- select
- name as value,
- is_group as expandable
- from
- `tab{doctype}`
- where
- ifnull(parent_quality_procedure, "")={parent}
- """.format(
- doctype = doctype,
- parent=frappe.db.escape(parent)
- ), as_dict=1)
+ if parent:
+ parent_procedure = frappe.get_doc('Quality Procedure', parent)
+ # return the list in order
+ return [dict(
+ value=d.procedure,
+ expandable=frappe.db.get_value('Quality Procedure', d.procedure, 'is_group'))
+ for d in parent_procedure.processes if d.procedure
+ ]
+ else:
+ return frappe.get_all(doctype, fields=['name as value', 'is_group as expandable'],
+ filters = dict(parent_quality_procedure = parent), order_by='name asc')
@frappe.whitelist()
def add_node():
@@ -86,4 +77,4 @@
if args.parent_quality_procedure == 'All Quality Procedures':
args.parent_quality_procedure = None
- frappe.get_doc(args).insert()
\ No newline at end of file
+ return frappe.get_doc(args).insert()
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_dashboard.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_dashboard.py
deleted file mode 100644
index 407028b..0000000
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_dashboard.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from frappe import _
-
-def get_data():
- return {
- 'fieldname': 'procedure',
- 'transactions': [
- {
- 'label': _('Goal'),
- 'items': ['Quality Goal']
- },
- {
- 'label': _('Review'),
- 'items': ['Quality Review']
- },
- {
- 'label': _('Action'),
- 'items': ['Quality Action']
- }
- ],
- }
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
index ef48ab6..eeb4cf6 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js
@@ -15,7 +15,7 @@
}
},
],
- breadcrumb: "Setup",
+ breadcrumb: "Quality Management",
disable_add_node: true,
root_label: "All Quality Procedures",
get_tree_root: false,
diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.js b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.js
deleted file mode 100644
index 0a187eb..0000000
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quality Procedure", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quality Procedure
- () => frappe.tests.make('Quality Procedure', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
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 3289bb5..36bdf26 100644
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
@@ -6,54 +6,45 @@
import frappe
import unittest
-class TestQualityProcedure(unittest.TestCase):
- def test_quality_procedure(self):
- test_create_procedure = create_procedure()
- test_create_nested_procedure = create_nested_procedure()
- test_get_procedure, test_get_nested_procedure = get_procedure()
+from .quality_procedure import add_node
- self.assertEquals(test_create_procedure, test_get_procedure.get("name"))
- self.assertEquals(test_create_nested_procedure, test_get_nested_procedure.get("name"))
+class TestQualityProcedure(unittest.TestCase):
+ def test_add_node(self):
+ try:
+ procedure = frappe.get_doc(dict(
+ doctype = 'Quality Procedure',
+ quality_procedure_name = 'Test Procedure 1',
+ processes = [
+ dict(process_description = 'Test Step 1')
+ ]
+ )).insert()
+
+ frappe.form_dict = dict(doctype = 'Quality Procedure', quality_procedure_name = 'Test Child 1',
+ parent_quality_procedure = procedure.name, cmd='test', is_root='false')
+ node = add_node()
+
+ procedure.reload()
+
+ self.assertEqual(procedure.is_group, 1)
+
+ # child row created
+ self.assertTrue([d for d in procedure.processes if d.procedure == node.name])
+
+ node.delete()
+ procedure.reload()
+
+ # child unset
+ self.assertFalse([d for d in procedure.processes if d.name == node.name])
+
+ finally:
+ procedure.delete()
def create_procedure():
- procedure = frappe.get_doc({
- "doctype": "Quality Procedure",
- "quality_procedure_name": "_Test Quality Procedure",
- "processes": [
- {
- "process_description": "_Test Quality Procedure Table",
- }
+ return frappe.get_doc(dict(
+ doctype = 'Quality Procedure',
+ quality_procedure_name = 'Test Procedure 1',
+ is_group = 1,
+ processes = [
+ dict(process_description = 'Test Step 1')
]
- })
-
- procedure_exist = frappe.db.exists("Quality Procedure", "PRC-_Test Quality Procedure")
-
- if not procedure_exist:
- procedure.insert()
- return procedure.name
- else:
- return procedure_exist
-
-def create_nested_procedure():
- nested_procedure = frappe.get_doc({
- "doctype": "Quality Procedure",
- "quality_procedure_name": "_Test Nested Quality Procedure",
- "processes": [
- {
- "procedure": "PRC-_Test Quality Procedure"
- }
- ]
- })
-
- nested_procedure_exist = frappe.db.exists("Quality Procedure", "PRC-_Test Nested Quality Procedure")
-
- if not nested_procedure_exist:
- nested_procedure.insert()
- return nested_procedure.name
- else:
- return nested_procedure_exist
-
-def get_procedure():
- procedure = frappe.get_doc("Quality Procedure", "PRC-_Test Quality Procedure")
- nested_procedure = frappe.get_doc("Quality Procedure", "PRC-_Test Nested Quality Procedure")
- return {"name": procedure.name}, {"name": nested_procedure.name, "parent_quality_procedure": nested_procedure.parent_quality_procedure}
\ No newline at end of file
+ )).insert()
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json
index 3925dbb..aeca6ff 100644
--- a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json
+++ b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json
@@ -10,6 +10,7 @@
],
"fields": [
{
+ "columns": 8,
"fieldname": "process_description",
"fieldtype": "Text Editor",
"in_list_view": 1,
@@ -20,13 +21,14 @@
"fieldname": "procedure",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "Child Procedure",
+ "label": "Sub Procedure",
"options": "Quality Procedure"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-06-17 15:44:38.937915",
+ "modified": "2020-10-27 13:55:11.252945",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Procedure Process",
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.js b/erpnext/quality_management/doctype/quality_review/quality_review.js
index b624581..67371bf 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.js
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.js
@@ -2,9 +2,6 @@
// For license information, please see license.txt
frappe.ui.form.on('Quality Review', {
- onload: function(frm){
- frm.set_value("date", frappe.datetime.get_today());
- },
goal: function(frm) {
frappe.call({
"method": "frappe.client.get",
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.json b/erpnext/quality_management/doctype/quality_review/quality_review.json
index 76714ce..31ad341 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.json
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.json
@@ -1,6 +1,6 @@
{
"actions": [],
- "autoname": "format:REV-{#####}",
+ "autoname": "format:QA-REV-{#####}",
"creation": "2018-10-02 11:45:16.301955",
"doctype": "DocType",
"editable_grid": 1,
@@ -18,6 +18,7 @@
],
"fields": [
{
+ "default": "Today",
"fieldname": "date",
"fieldtype": "Date",
"in_list_view": 1,
@@ -50,7 +51,7 @@
"collapsible": 1,
"fieldname": "sb_01",
"fieldtype": "Section Break",
- "label": "Additional Information"
+ "label": "Notes"
},
{
"fieldname": "reviews",
@@ -63,7 +64,8 @@
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
- "options": "Open\nClosed"
+ "options": "Open\nPassed\nFailed",
+ "read_only": 1
},
{
"fieldname": "goal",
@@ -74,8 +76,15 @@
"reqd": 1
}
],
- "links": [],
- "modified": "2020-02-01 10:59:38.933115",
+ "index_web_pages_for_search": 1,
+ "links": [
+ {
+ "group": "Review",
+ "link_doctype": "Quality Action",
+ "link_fieldname": "review"
+ }
+ ],
+ "modified": "2020-10-21 12:56:47.046172",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Review",
@@ -120,5 +129,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "title_field": "goal",
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.py b/erpnext/quality_management/doctype/quality_review/quality_review.py
index 2bc8867..e3a8b07 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.py
@@ -7,7 +7,26 @@
from frappe.model.document import Document
class QualityReview(Document):
- pass
+ def validate(self):
+ # fetch targets from goal
+ if not self.reviews:
+ for d in frappe.get_doc('Quality Goal', self.goal).objectives:
+ self.append('reviews', dict(
+ objective = d.objective,
+ target = d.target,
+ uom = d.uom
+ ))
+
+ self.set_status()
+
+ def set_status(self):
+ # if any child item is failed, fail the parent
+ if not len(self.reviews or []) or any([d.status=='Open' for d in self.reviews]):
+ self.status = 'Open'
+ elif any([d.status=='Failed' for d in self.reviews]):
+ self.status = 'Failed'
+ else:
+ self.status = 'Passed'
def review():
day = frappe.utils.getdate().day
@@ -24,7 +43,7 @@
elif goal.frequency == 'Monthly' and goal.date == str(day):
create_review(goal.name)
- elif goal.frequency == 'Quarterly' and goal.data == str(day) and get_quarter(month):
+ elif goal.frequency == 'Quarterly' and day==1 and get_quarter(month):
create_review(goal.name)
def create_review(goal):
@@ -36,15 +55,6 @@
"date": frappe.utils.getdate()
})
- for objective in goal.objectives:
- review.append("reviews",
- {
- "objective": objective.objective,
- "target": objective.target,
- "uom": objective.uom
- }
- )
-
review.insert(ignore_permissions=True)
def get_quarter(month):
diff --git a/erpnext/quality_management/doctype/quality_review/test_quality_review.js b/erpnext/quality_management/doctype/quality_review/test_quality_review.js
deleted file mode 100644
index cf910b2..0000000
--- a/erpnext/quality_management/doctype/quality_review/test_quality_review.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Performance Monitoring", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Performance Monitoring
- () => frappe.tests.make('Performance Monitoring', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
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 8add6db..a7d92da 100644
--- a/erpnext/quality_management/doctype/quality_review/test_quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
@@ -5,42 +5,18 @@
import frappe
import unittest
-from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
-from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_unit
-from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_goal
+
+from ..quality_goal.test_quality_goal import get_quality_goal
+from .quality_review import review
class TestQualityReview(unittest.TestCase):
+ def test_review_creation(self):
+ quality_goal = get_quality_goal()
+ review()
- def test_quality_review(self):
- create_procedure()
- create_unit()
- create_goal()
- test_create_review = create_review()
- test_get_review = get_review()
- self.assertEquals(test_create_review, test_get_review)
+ # check if review exists
+ quality_review = frappe.get_doc('Quality Review', dict(goal = quality_goal.name))
+ self.assertEqual(quality_goal.objectives[0].target, quality_review.reviews[0].target)
+ quality_review.delete()
-def create_review():
- review = frappe.get_doc({
- "doctype": "Quality Review",
- "goal": "GOAL-_Test Quality Goal",
- "procedure": "PRC-_Test Quality Procedure",
- "date": frappe.utils.nowdate(),
- "reviews": [
- {
- "objective": "_Test Quality Objective",
- "target": "100",
- "uom": "_Test UOM",
- "review": "Test Review"
- }
- ]
- })
- review_exist = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
- if not review_exist:
- review.insert(ignore_permissions=True)
- return review.name
- else:
- return review_exist
-
-def get_review():
- review = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
- return review
\ No newline at end of file
+ quality_goal.delete()
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json
index 91f7bc0..3a750c2 100644
--- a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json
+++ b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-05-26 15:17:44.796958",
"doctype": "DocType",
"editable_grid": 1,
@@ -9,10 +10,12 @@
"target",
"uom",
"sb_00",
+ "status",
"review"
],
"fields": [
{
+ "columns": 3,
"fieldname": "objective",
"fieldtype": "Text",
"in_list_view": 1,
@@ -20,6 +23,7 @@
"read_only": 1
},
{
+ "columns": 2,
"fieldname": "target",
"fieldtype": "Data",
"in_list_view": 1,
@@ -27,6 +31,7 @@
"read_only": 1
},
{
+ "columns": 1,
"fetch_from": "target_unit",
"fieldname": "uom",
"fieldtype": "Link",
@@ -49,10 +54,20 @@
{
"fieldname": "cb_00",
"fieldtype": "Column Break"
+ },
+ {
+ "columns": 2,
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "options": "Open\nPassed\nFailed"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-05-26 16:14:12.586128",
+ "links": [],
+ "modified": "2020-10-27 16:28:20.908637",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Review Objective",
diff --git a/erpnext/quality_management/workspace/quality/quality.json b/erpnext/quality_management/workspace/quality/quality.json
new file mode 100644
index 0000000..e5fef43
--- /dev/null
+++ b/erpnext/quality_management/workspace/quality/quality.json
@@ -0,0 +1,190 @@
+{
+ "category": "Modules",
+ "charts": [],
+ "creation": "2020-03-02 15:49:28.632014",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "quality",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Quality",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Goal and Procedure",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Goal",
+ "link_to": "Quality Goal",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Procedure",
+ "link_to": "Quality Procedure",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tree of Procedures",
+ "link_to": "Quality Procedure",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Feedback",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Feedback",
+ "link_to": "Quality Feedback",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Feedback Template",
+ "link_to": "Quality Feedback Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Meeting",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Meeting",
+ "link_to": "Quality Meeting",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Review and Action",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Non Conformance",
+ "link_to": "Non Conformance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Review",
+ "link_to": "Quality Review",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Action",
+ "link_to": "Quality Action",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:35.120213",
+ "modified_by": "Administrator",
+ "module": "Quality Management",
+ "name": "Quality",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Grey",
+ "label": "Quality Goal",
+ "link_to": "Quality Goal",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "doc_view": "Tree",
+ "label": "Quality Procedure",
+ "link_to": "Quality Procedure",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "label": "Quality Inspection",
+ "link_to": "Quality Inspection",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "doc_view": "",
+ "format": "{} Open",
+ "label": "Quality Review",
+ "link_to": "Quality Review",
+ "stats_filter": "{\"status\": \"Open\"}",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "doc_view": "",
+ "format": "{} Open",
+ "label": "Quality Action",
+ "link_to": "Quality Action",
+ "stats_filter": "{\"status\": \"Open\"}",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "doc_view": "",
+ "format": "{} Open",
+ "label": "Non Conformance",
+ "link_to": "Non Conformance",
+ "stats_filter": "{\"status\": \"Open\"}",
+ "type": "DocType"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/regional/address_template/templates/luxembourg.html b/erpnext/regional/address_template/templates/luxembourg.html
new file mode 100644
index 0000000..75075e7
--- /dev/null
+++ b/erpnext/regional/address_template/templates/luxembourg.html
@@ -0,0 +1,4 @@
+{% if address_line1 %}{{ address_line1 }}<br>{% endif -%}
+{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}
+{% if pincode %}L-{{ pincode }}{% endif -%}{% if city %} {{ city }}{% endif %}<br>
+{% if country %}{{ country | upper }}{% endif %}
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.js b/erpnext/regional/doctype/datev_settings/datev_settings.js
index 69747b0..f047059 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.js
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.js
@@ -2,7 +2,7 @@
// For license information, please see license.txt
frappe.ui.form.on('DATEV Settings', {
- // refresh: function(frm) {
-
- // }
+ refresh: function(frm) {
+ frm.add_custom_button('Show Report', () => frappe.set_route('query-report', 'DATEV'), "fa fa-table");
+ }
});
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.json b/erpnext/regional/doctype/datev_settings/datev_settings.json
index 39486df..f60de4c 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.json
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "field:client",
"creation": "2019-08-13 23:56:34.259906",
"doctype": "DocType",
@@ -6,12 +7,14 @@
"engine": "InnoDB",
"field_order": [
"client",
- "column_break_2",
"client_number",
- "section_break_4",
+ "column_break_2",
+ "consultant_number",
"consultant",
+ "section_break_4",
+ "account_number_length",
"column_break_6",
- "consultant_number"
+ "temporary_against_account_number"
],
"fields": [
{
@@ -28,8 +31,8 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "Client ID",
- "reqd": 1,
- "length": 5
+ "length": 5,
+ "reqd": 1
},
{
"fieldname": "consultant",
@@ -43,8 +46,8 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "Consultant ID",
- "reqd": 1,
- "length": 7
+ "length": 7,
+ "reqd": 1
},
{
"fieldname": "column_break_2",
@@ -57,9 +60,24 @@
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "4",
+ "fieldname": "account_number_length",
+ "fieldtype": "Int",
+ "label": "Account Number Length",
+ "reqd": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "temporary_against_account_number",
+ "fieldtype": "Data",
+ "label": "Temporary Against Account Number",
+ "reqd": 1
}
],
- "modified": "2019-08-14 00:03:26.616460",
+ "links": [],
+ "modified": "2020-11-19 19:00:09.088816",
"modified_by": "Administrator",
"module": "Regional",
"name": "DATEV Settings",
@@ -104,4 +122,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/communication/doctype/call_log/__init__.py b/erpnext/regional/doctype/e_invoice_request_log/__init__.py
similarity index 100%
copy from erpnext/communication/doctype/call_log/__init__.py
copy to erpnext/regional/doctype/e_invoice_request_log/__init__.py
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
new file mode 100644
index 0000000..7b7ba96
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('E Invoice Request Log', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
new file mode 100644
index 0000000..3034370
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
@@ -0,0 +1,102 @@
+{
+ "actions": [],
+ "autoname": "EINV-REQ-.#####",
+ "creation": "2020-12-08 12:54:08.175992",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "user",
+ "url",
+ "headers",
+ "response",
+ "column_break_7",
+ "timestamp",
+ "reference_invoice",
+ "data"
+ ],
+ "fields": [
+ {
+ "fieldname": "user",
+ "fieldtype": "Link",
+ "label": "User",
+ "options": "User"
+ },
+ {
+ "fieldname": "reference_invoice",
+ "fieldtype": "Data",
+ "label": "Reference Invoice"
+ },
+ {
+ "fieldname": "headers",
+ "fieldtype": "Code",
+ "label": "Headers",
+ "options": "JSON"
+ },
+ {
+ "fieldname": "data",
+ "fieldtype": "Code",
+ "label": "Data",
+ "options": "JSON"
+ },
+ {
+ "default": "Now",
+ "fieldname": "timestamp",
+ "fieldtype": "Datetime",
+ "label": "Timestamp"
+ },
+ {
+ "fieldname": "response",
+ "fieldtype": "Code",
+ "label": "Response",
+ "options": "JSON"
+ },
+ {
+ "fieldname": "url",
+ "fieldtype": "Data",
+ "label": "URL"
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-01-13 12:06:57.253111",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "E Invoice Request Log",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
new file mode 100644
index 0000000..9150bdd
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class EInvoiceRequestLog(Document):
+ pass
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
index 2ad7984..c84e9a2 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestEInvoiceRequestLog(unittest.TestCase):
pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/regional/doctype/e_invoice_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/regional/doctype/e_invoice_settings/__init__.py
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
new file mode 100644
index 0000000..cc2d9f0
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
@@ -0,0 +1,11 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('E Invoice Settings', {
+ refresh(frm) {
+ const docs_link = 'https://docs.erpnext.com/docs/user/manual/en/regional/india/setup-e-invoicing';
+ frm.dashboard.set_headline(
+ __("Read {0} for more information on E Invoicing features.", [`<a href='${docs_link}'>documentation</a>`])
+ );
+ }
+});
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
new file mode 100644
index 0000000..db8bda7
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
@@ -0,0 +1,65 @@
+{
+ "actions": [],
+ "creation": "2020-09-24 16:23:16.235722",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "enable",
+ "section_break_2",
+ "sandbox_mode",
+ "credentials",
+ "auth_token",
+ "token_expiry"
+ ],
+ "fields": [
+ {
+ "default": "0",
+ "fieldname": "enable",
+ "fieldtype": "Check",
+ "label": "Enable"
+ },
+ {
+ "depends_on": "enable",
+ "fieldname": "section_break_2",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "auth_token",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "token_expiry",
+ "fieldtype": "Datetime",
+ "hidden": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "credentials",
+ "fieldtype": "Table",
+ "label": "Credentials",
+ "mandatory_depends_on": "enable",
+ "options": "E Invoice User"
+ },
+ {
+ "default": "0",
+ "fieldname": "sandbox_mode",
+ "fieldtype": "Check",
+ "label": "Sandbox Mode"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-01-13 12:04:49.449199",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "E Invoice Settings",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
new file mode 100644
index 0000000..c24ad88
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
@@ -0,0 +1,14 @@
+# -*- 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
+
+class EInvoiceSettings(Document):
+ def validate(self):
+ if self.enable and not self.credentials:
+ frappe.throw(_('You must add atleast one credentials to be able to use E Invoicing.'))
+
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
similarity index 79%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
index 2ad7984..a11ce63 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestEInvoiceSettings(unittest.TestCase):
pass
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/regional/doctype/e_invoice_user/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/regional/doctype/e_invoice_user/__init__.py
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
new file mode 100644
index 0000000..dd9d997
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
@@ -0,0 +1,48 @@
+{
+ "actions": [],
+ "creation": "2020-12-22 15:02:46.229474",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "gstin",
+ "username",
+ "password"
+ ],
+ "fields": [
+ {
+ "fieldname": "gstin",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "GSTIN",
+ "reqd": 1
+ },
+ {
+ "fieldname": "username",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Username",
+ "reqd": 1
+ },
+ {
+ "fieldname": "password",
+ "fieldtype": "Password",
+ "in_list_view": 1,
+ "label": "Password",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-12-22 15:10:53.466205",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "E Invoice User",
+ "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/regional/doctype/e_invoice_user/e_invoice_user.py b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
new file mode 100644
index 0000000..056c54f
--- /dev/null
+++ b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class EInvoiceUser(Document):
+ pass
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json
index 98c33ad..95b930c 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.json
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.json
@@ -1,222 +1,86 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-06-27 15:09:01.318003",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-06-27 15:09:01.318003",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "gst_summary",
+ "column_break_2",
+ "round_off_gst_values",
+ "gstin_email_sent_on",
+ "section_break_4",
+ "gst_accounts",
+ "b2c_limit"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "gst_summary",
- "fieldtype": "HTML",
- "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": "GST Summary",
- "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": "gst_summary",
+ "fieldtype": "HTML",
+ "label": "GST Summary",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "gstin_email_sent_on",
- "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": "GSTIN Email Sent On",
- "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,
- "unique": 0
- },
+ "fieldname": "gstin_email_sent_on",
+ "fieldtype": "Date",
+ "label": "GSTIN Email Sent On",
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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": "section_break_4",
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "gst_accounts",
- "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": "GST Accounts",
- "length": 0,
- "no_copy": 0,
- "options": "GST Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "gst_accounts",
+ "fieldtype": "Table",
+ "label": "GST Accounts",
+ "options": "GST Account",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "250000",
- "description": "Set Invoice Value for B2C. B2CL and B2CS calculated based on this invoice value.",
- "fieldname": "b2c_limit",
- "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": "B2C Limit",
- "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": "250000",
+ "description": "Set Invoice Value for B2C. B2CL and B2CS calculated based on this invoice value.",
+ "fieldname": "b2c_limit",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "B2C Limit",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 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
}
- ],
- "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": "2018-02-14 08:14:15.375181",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "GST Settings",
- "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
+ ],
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-01-28 17:19:47.969260",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GST Settings",
+ "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/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 787d557..a49996d 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -192,19 +192,20 @@
for d in self.report_dict["itc_elg"]["itc_avl"]:
itc_type = itc_type_map.get(d["ty"])
- gst_category = ["Registered Regular"]
if d["ty"] == 'ISRC':
- reverse_charge = "Y"
+ reverse_charge = ["Y"]
itc_type = 'All Other ITC'
gst_category = ['Unregistered', 'Overseas']
else:
- reverse_charge = "N"
+ gst_category = ['Unregistered', 'Overseas', 'Registered Regular']
+ reverse_charge = ["N", "Y"]
for account_head in self.account_heads:
for category in gst_category:
- for key in [['iamt', 'igst_account'], ['camt', 'cgst_account'], ['samt', 'sgst_account'], ['csamt', 'cess_account']]:
- d[key[0]] += flt(itc_details.get((category, itc_type, reverse_charge, account_head.get(key[1])), {}).get("amount"), 2)
+ for charge_type in reverse_charge:
+ for key in [['iamt', 'igst_account'], ['camt', 'cgst_account'], ['samt', 'sgst_account'], ['csamt', 'cess_account']]:
+ d[key[0]] += flt(itc_details.get((category, itc_type, charge_type, account_head.get(key[1])), {}).get("amount"), 2)
for key in ['iamt', 'camt', 'samt', 'csamt']:
net_itc[key] += flt(d[key], 2)
@@ -264,7 +265,8 @@
def get_itc_details(self):
itc_amount = frappe.db.sql("""
- select s.gst_category, sum(t.tax_amount_after_discount_amount) as tax_amount, t.account_head, s.eligibility_for_itc, s.reverse_charge
+ select s.gst_category, sum(t.base_tax_amount_after_discount_amount) as tax_amount,
+ t.account_head, s.eligibility_for_itc, s.reverse_charge
from `tabPurchase Invoice` s , `tabPurchase Taxes and Charges` t
where s.docstatus = 1 and t.parent = s.name
and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s
@@ -347,13 +349,12 @@
return inter_state_supply_details
def get_inward_nil_exempt(self, state):
-
inward_nil_exempt = frappe.db.sql(""" select p.place_of_supply, sum(i.base_amount) as base_amount,
i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
where p.docstatus = 1 and p.name = i.parent
- and i.is_nil_exempt = 1 or i.is_non_gst = 1 and
+ and (i.is_nil_exempt = 1 or i.is_non_gst = 1) and
month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s
- group by p.place_of_supply """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
+ group by p.place_of_supply, i.is_nil_exempt, i.is_non_gst""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
inward_nil_exempt_details = {
"gst": {
@@ -387,7 +388,7 @@
tax_template = 'Purchase Taxes and Charges'
tax_amounts = frappe.db.sql("""
- select s.gst_category, sum(t.tax_amount_after_discount_amount) as tax_amount, t.account_head
+ select s.gst_category, sum(t.base_tax_amount_after_discount_amount) as tax_amount, t.account_head
from `tab{doctype}` s , `tab{template}` t
where s.docstatus = 1 and t.parent = s.name and s.reverse_charge = %s
and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s
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 8174da2..023b4ed 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
@@ -14,8 +14,20 @@
test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
class TestGSTR3BReport(unittest.TestCase):
- def test_gstr_3b_report(self):
+ def setUp(self):
+ frappe.set_user("Administrator")
+ frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
+ frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company GST'")
+ frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
+
+ make_company()
+ make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
+ set_account_heads()
+ make_customers()
+ make_suppliers()
+
+ def test_gstr_3b_report(self):
month_number_mapping = {
1: "January",
2: "February",
@@ -31,17 +43,6 @@
12: "December"
}
- frappe.set_user("Administrator")
-
- frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
- frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company GST'")
- frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
-
- make_company()
- make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
- set_account_heads()
- make_customers()
- make_suppliers()
make_sales_invoice()
create_purchase_invoices()
@@ -67,6 +68,42 @@
self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50)
self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50)
+ def test_gst_rounding(self):
+ gst_settings = frappe.get_doc('GST Settings')
+ gst_settings.round_off_gst_values = 1
+ gst_settings.save()
+
+ current_country = frappe.flags.country
+ frappe.flags.country = 'India'
+
+ si = create_sales_invoice(company="_Test Company GST",
+ customer = '_Test GST Customer',
+ currency = 'INR',
+ warehouse = 'Finished Goods - _GST',
+ debit_to = 'Debtors - _GST',
+ income_account = 'Sales - _GST',
+ expense_account = 'Cost of Goods Sold - _GST',
+ cost_center = 'Main - _GST',
+ rate=216,
+ do_not_save=1
+ )
+
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "IGST - _GST",
+ "cost_center": "Main - _GST",
+ "description": "IGST @ 18.0",
+ "rate": 18
+ })
+
+ si.save()
+ # Check for 39 instead of 38.88
+ self.assertEqual(si.taxes[0].base_tax_amount_after_discount_amount, 39)
+
+ frappe.flags.country = current_country
+ gst_settings.round_off_gst_values = 1
+ gst_settings.save()
+
def make_sales_invoice():
si = create_sales_invoice(company="_Test Company GST",
customer = '_Test GST Customer',
@@ -145,7 +182,6 @@
si3.submit()
def create_purchase_invoices():
-
pi = make_purchase_invoice(
company="_Test Company GST",
supplier = '_Test Registered Supplier',
@@ -193,7 +229,6 @@
pi1.submit()
def make_suppliers():
-
if not frappe.db.exists("Supplier", "_Test Registered Supplier"):
frappe.get_doc({
"supplier_group": "_Test Supplier Group",
@@ -257,7 +292,6 @@
address.save()
def make_customers():
-
if not frappe.db.exists("Customer", "_Test GST Customer"):
frappe.get_doc({
"customer_group": "_Test Customer Group",
@@ -354,9 +388,9 @@
address.save()
def make_company():
-
if frappe.db.exists("Company", "_Test Company GST"):
return
+
company = frappe.new_doc("Company")
company.company_name = "_Test Company GST"
company.abbr = "_GST"
@@ -388,7 +422,6 @@
address.save()
def set_account_heads():
-
gst_settings = frappe.get_doc("GST Settings")
gst_account = frappe.get_all(
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 e8a8ed8..ad60db0 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -5,12 +5,16 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import getdate
+from frappe.utils import getdate, get_link_to_form
from frappe.model.document import Document
from erpnext.accounts.utils import get_fiscal_year
class LowerDeductionCertificate(Document):
def validate(self):
+ self.validate_dates()
+ self.validate_supplier_against_section_code()
+
+ def validate_dates(self):
if getdate(self.valid_upto) < getdate(self.valid_from):
frappe.throw(_("Valid Upto date cannot be before Valid From date"))
@@ -24,3 +28,20 @@
<= 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)
+ 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)))
+
+ def are_dates_overlapping(self,duplicate_certificate):
+ valid_from = duplicate_certificate.valid_from
+ valid_upto = duplicate_certificate.valid_upto
+ if valid_from <= getdate(self.valid_from) <= valid_upto:
+ return True
+ elif valid_from <= getdate(self.valid_upto) <= valid_upto:
+ return True
+ elif getdate(self.valid_from) <= valid_from and valid_upto <= getdate(self.valid_upto):
+ return True
+ return False
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/regional/doctype/tax_exemption_80g_certificate/__init__.py
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js
new file mode 100644
index 0000000..54cde9c
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.js
@@ -0,0 +1,67 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Tax Exemption 80G Certificate', {
+ refresh: function(frm) {
+ if (frm.doc.donor) {
+ frm.set_query('donation', function() {
+ return {
+ filters: {
+ docstatus: 1,
+ donor: frm.doc.donor
+ }
+ };
+ });
+ }
+ },
+
+ recipient: function(frm) {
+ if (frm.doc.recipient === 'Donor') {
+ frm.set_value({
+ 'member': '',
+ 'member_name': '',
+ 'member_email': '',
+ 'member_pan_number': '',
+ 'fiscal_year': '',
+ 'total': 0,
+ 'payments': []
+ });
+ } else {
+ frm.set_value({
+ 'donor': '',
+ 'donor_name': '',
+ 'donor_email': '',
+ 'donor_pan_number': '',
+ 'donation': '',
+ 'date_of_donation': '',
+ 'amount': 0,
+ 'mode_of_payment': '',
+ 'razorpay_payment_id': ''
+ });
+ }
+ },
+
+ get_payments: function(frm) {
+ frm.call({
+ doc: frm.doc,
+ method: 'get_payments',
+ freeze: true
+ });
+ },
+
+ company: function(frm) {
+ if ((frm.doc.member || frm.doc.donor) && frm.doc.company) {
+ frm.call({
+ doc: frm.doc,
+ method: 'set_company_address',
+ freeze: true
+ });
+ }
+ },
+
+ donation: function(frm) {
+ if (frm.doc.recipient === 'Donor' && !frm.doc.donor) {
+ frappe.msgprint(__('Please select donor first'));
+ }
+ }
+});
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json
new file mode 100644
index 0000000..9eee722
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.json
@@ -0,0 +1,297 @@
+{
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2021-02-15 12:37:21.577042",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "recipient",
+ "member",
+ "member_name",
+ "member_email",
+ "member_pan_number",
+ "donor",
+ "donor_name",
+ "donor_email",
+ "donor_pan_number",
+ "column_break_4",
+ "date",
+ "fiscal_year",
+ "section_break_11",
+ "company",
+ "company_address",
+ "company_address_display",
+ "column_break_14",
+ "company_pan_number",
+ "company_80g_number",
+ "company_80g_wef",
+ "title",
+ "section_break_6",
+ "get_payments",
+ "payments",
+ "total",
+ "donation_details_section",
+ "donation",
+ "date_of_donation",
+ "amount",
+ "column_break_27",
+ "mode_of_payment",
+ "razorpay_payment_id"
+ ],
+ "fields": [
+ {
+ "fieldname": "recipient",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Certificate Recipient",
+ "options": "Member\nDonor",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Member\";",
+ "fieldname": "member",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Member",
+ "mandatory_depends_on": "eval:doc.recipient === \"Member\";",
+ "options": "Member"
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Member\";",
+ "fetch_from": "member.member_name",
+ "fieldname": "member_name",
+ "fieldtype": "Data",
+ "label": "Member Name",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Donor\";",
+ "fieldname": "donor",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Donor",
+ "mandatory_depends_on": "eval:doc.recipient === \"Donor\";",
+ "options": "Donor"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Member\";",
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "payments",
+ "fieldtype": "Table",
+ "label": "Payments",
+ "options": "Tax Exemption 80G Certificate Detail"
+ },
+ {
+ "fieldname": "total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Member\";",
+ "fieldname": "fiscal_year",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Fiscal Year",
+ "options": "Fiscal Year"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "get_payments",
+ "fieldtype": "Button",
+ "label": "Get Memberships"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "NPO-80G-.YYYY.-"
+ },
+ {
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break",
+ "label": "Company Details"
+ },
+ {
+ "fieldname": "company_address",
+ "fieldtype": "Link",
+ "label": "Company Address",
+ "options": "Address"
+ },
+ {
+ "fieldname": "column_break_14",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "company.pan_details",
+ "fieldname": "company_pan_number",
+ "fieldtype": "Data",
+ "label": "PAN Number",
+ "read_only": 1
+ },
+ {
+ "fieldname": "company_address_display",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "label": "Company Address Display",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fetch_from": "company.company_80g_number",
+ "fieldname": "company_80g_number",
+ "fieldtype": "Data",
+ "label": "80G Number",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "company.with_effect_from",
+ "fieldname": "company_80g_wef",
+ "fieldtype": "Date",
+ "label": "80G With Effect From",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Donor\";",
+ "fieldname": "donation_details_section",
+ "fieldtype": "Section Break",
+ "label": "Donation Details"
+ },
+ {
+ "fieldname": "donation",
+ "fieldtype": "Link",
+ "label": "Donation",
+ "mandatory_depends_on": "eval:doc.recipient === \"Donor\";",
+ "options": "Donation"
+ },
+ {
+ "fetch_from": "donation.amount",
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Amount",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "donation.mode_of_payment",
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "donation.razorpay_payment_id",
+ "fieldname": "razorpay_payment_id",
+ "fieldtype": "Data",
+ "label": "RazorPay Payment ID",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "donation.date",
+ "fieldname": "date_of_donation",
+ "fieldtype": "Date",
+ "label": "Date of Donation",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_27",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Donor\";",
+ "fetch_from": "donor.donor_name",
+ "fieldname": "donor_name",
+ "fieldtype": "Data",
+ "label": "Donor Name",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Donor\";",
+ "fetch_from": "donor.email",
+ "fieldname": "donor_email",
+ "fieldtype": "Data",
+ "label": "Email",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Member\";",
+ "fetch_from": "member.email_id",
+ "fieldname": "member_email",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Email",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Member\";",
+ "fetch_from": "member.pan_number",
+ "fieldname": "member_pan_number",
+ "fieldtype": "Data",
+ "label": "PAN Details",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.recipient === \"Donor\";",
+ "fetch_from": "donor.pan_number",
+ "fieldname": "donor_pan_number",
+ "fieldtype": "Data",
+ "label": "PAN Details",
+ "read_only": 1
+ },
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "print_hide": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-02-22 00:03:34.215633",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Tax Exemption 80G Certificate",
+ "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": "member, member_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "title",
+ "track_changes": 1
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..41c7b23
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
@@ -0,0 +1,102 @@
+# -*- 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
+from frappe.utils import getdate, flt, get_link_to_form
+from erpnext.accounts.utils import get_fiscal_year
+from frappe.contacts.doctype.address.address import get_company_address
+
+class TaxExemption80GCertificate(Document):
+ def validate(self):
+ self.validate_date()
+ self.validate_duplicates()
+ self.validate_company_details()
+ self.set_company_address()
+ self.calculate_total()
+ self.set_title()
+
+ def validate_date(self):
+ if self.recipient == 'Member':
+ if getdate(self.date):
+ fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
+
+ if not (fiscal_year.year_start_date <= getdate(self.date) \
+ <= fiscal_year.year_end_date):
+ frappe.throw(_('The Certificate Date is not in the Fiscal Year {0}').format(frappe.bold(self.fiscal_year)))
+
+ def validate_duplicates(self):
+ if self.recipient == 'Donor':
+ certificate = frappe.db.exists(self.doctype, {
+ 'donation': self.donation,
+ 'name': ('!=', self.name)
+ })
+ if certificate:
+ frappe.throw(_('An 80G Certificate {0} already exists for the donation {1}').format(
+ get_link_to_form(self.doctype, certificate), frappe.bold(self.donation)
+ ), title=_('Duplicate Certificate'))
+
+ def validate_company_details(self):
+ fields = ['company_80g_number', 'with_effect_from', 'pan_details']
+ company_details = frappe.db.get_value('Company', self.company, fields, as_dict=True)
+ if not company_details.company_80g_number:
+ frappe.throw(_('Please set the {0} for company {1}').format(frappe.bold('80G Number'),
+ get_link_to_form('Company', self.company)))
+
+ if not company_details.pan_details:
+ frappe.throw(_('Please set the {0} for company {1}').format(frappe.bold('PAN Number'),
+ get_link_to_form('Company', self.company)))
+
+ def set_company_address(self):
+ address = get_company_address(self.company)
+ self.company_address = address.company_address
+ self.company_address_display = address.company_address_display
+
+ def calculate_total(self):
+ if self.recipient == 'Donor':
+ return
+
+ total = 0
+ for entry in self.payments:
+ total += flt(entry.amount)
+ self.total = total
+
+ def set_title(self):
+ if self.recipient == 'Member':
+ self.title = self.member_name
+ else:
+ self.title = self.donor_name
+
+ def get_payments(self):
+ if not self.member:
+ frappe.throw(_('Please select a Member first.'))
+
+ fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
+
+ memberships = frappe.db.get_all('Membership', {
+ 'member': self.member,
+ 'from_date': ['between', (fiscal_year.year_start_date, fiscal_year.year_end_date)],
+ 'to_date': ['between', (fiscal_year.year_start_date, fiscal_year.year_end_date)],
+ 'membership_status': ('!=', 'Cancelled')
+ }, ['from_date', 'amount', 'name', 'invoice', 'payment_id'], order_by='from_date')
+
+ if not memberships:
+ frappe.msgprint(_('No Membership Payments found against the Member {0}').format(self.member))
+
+ total = 0
+ self.payments = []
+
+ for doc in memberships:
+ self.append('payments', {
+ 'date': doc.from_date,
+ 'amount': doc.amount,
+ 'invoice_id': doc.invoice,
+ 'razorpay_payment_id': doc.payment_id,
+ 'membership': doc.name
+ })
+ total += flt(doc.amount)
+
+ self.total = total
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
new file mode 100644
index 0000000..346ebbf
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.utils import getdate
+from erpnext.accounts.utils import get_fiscal_year
+from erpnext.non_profit.doctype.donation.test_donation import create_donor, create_mode_of_payment, create_donor_type
+from erpnext.non_profit.doctype.donation.donation import create_donation
+from erpnext.non_profit.doctype.membership.test_membership import setup_membership, make_membership
+from erpnext.non_profit.doctype.member.member import create_member
+
+class TestTaxExemption80GCertificate(unittest.TestCase):
+ def setUp(self):
+ frappe.db.sql('delete from `tabTax Exemption 80G Certificate`')
+ frappe.db.sql('delete from `tabMembership`')
+ create_donor_type()
+ settings = frappe.get_doc('Non Profit Settings')
+ settings.company = '_Test Company'
+ settings.donation_company = '_Test Company'
+ settings.default_donor_type = '_Test Donor'
+ settings.creation_user = 'Administrator'
+ settings.save()
+
+ company = frappe.get_doc('Company', '_Test Company')
+ company.pan_details = 'BBBTI3374C'
+ company.company_80g_number = 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087'
+ company.with_effect_from = getdate()
+ company.save()
+
+ def test_duplicate_donation_certificate(self):
+ donor = create_donor()
+ create_mode_of_payment()
+ payment = frappe._dict({
+ 'amount': 100,
+ 'method': 'Debit Card',
+ 'id': 'pay_MeXAmsgeKOhq7O'
+ })
+ donation = create_donation(donor, payment)
+
+ args = frappe._dict({
+ 'recipient': 'Donor',
+ 'donor': donor.name,
+ 'donation': donation.name
+ })
+ certificate = create_80g_certificate(args)
+ certificate.insert()
+
+ # check company details
+ self.assertEquals(certificate.company_pan_number, 'BBBTI3374C')
+ self.assertEquals(certificate.company_80g_number, 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087')
+
+ # check donation details
+ self.assertEquals(certificate.amount, donation.amount)
+
+ duplicate_certificate = create_80g_certificate(args)
+ # duplicate validation
+ self.assertRaises(frappe.ValidationError, duplicate_certificate.insert)
+
+ def test_membership_80g_certificate(self):
+ plan = setup_membership()
+
+ # make test member
+ member_doc = create_member(frappe._dict({
+ 'fullname': "_Test_Member",
+ 'email': "_test_member_erpnext@example.com",
+ 'plan_id': plan.name
+ }))
+ member_doc.make_customer_and_link()
+ member = member_doc.name
+
+ membership = make_membership(member, { "from_date": getdate() })
+ invoice = membership.generate_invoice(save=True)
+
+ args = frappe._dict({
+ 'recipient': 'Member',
+ 'member': member,
+ 'fiscal_year': get_fiscal_year(getdate(), as_dict=True).get('name')
+ })
+ certificate = create_80g_certificate(args)
+ certificate.get_payments()
+ certificate.insert()
+
+ self.assertEquals(len(certificate.payments), 1)
+ self.assertEquals(certificate.payments[0].amount, membership.amount)
+ self.assertEquals(certificate.payments[0].invoice_id, invoice.name)
+
+
+def create_80g_certificate(args):
+ certificate = frappe.get_doc({
+ 'doctype': 'Tax Exemption 80G Certificate',
+ 'recipient': args.recipient,
+ 'date': getdate(),
+ 'company': '_Test Company'
+ })
+
+ certificate.update(args)
+
+ return certificate
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/regional/doctype/tax_exemption_80g_certificate_detail/__init__.py
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json
new file mode 100644
index 0000000..dfa817d
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.json
@@ -0,0 +1,66 @@
+{
+ "actions": [],
+ "creation": "2021-02-15 12:43:52.754124",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "date",
+ "amount",
+ "invoice_id",
+ "column_break_4",
+ "razorpay_payment_id",
+ "membership"
+ ],
+ "fields": [
+ {
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "reqd": 1
+ },
+ {
+ "fieldname": "invoice_id",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Invoice ID",
+ "options": "Sales Invoice",
+ "reqd": 1
+ },
+ {
+ "fieldname": "razorpay_payment_id",
+ "fieldtype": "Data",
+ "label": "Razorpay Payment ID"
+ },
+ {
+ "fieldname": "membership",
+ "fieldtype": "Link",
+ "label": "Membership",
+ "options": "Membership"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-15 16:35:10.777587",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Tax Exemption 80G Certificate Detail",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..bdad798
--- /dev/null
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
@@ -0,0 +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 TaxExemption80GCertificateDetail(Document):
+ pass
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/regional/doctype/uae_vat_account/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/regional/doctype/uae_vat_account/__init__.py
diff --git a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.json b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.json
new file mode 100644
index 0000000..73a8169
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.json
@@ -0,0 +1,35 @@
+{
+ "actions": [],
+ "autoname": "account",
+ "creation": "2020-09-28 11:30:45.472053",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "account"
+ ],
+ "fields": [
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_preview": 1,
+ "label": "Account",
+ "options": "Account"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-09-28 12:02:56.444007",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "UAE VAT Account",
+ "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/regional/doctype/uae_vat_account/uae_vat_account.py b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
new file mode 100644
index 0000000..80d6b3a
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class UAEVATAccount(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/regional/doctype/uae_vat_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/regional/doctype/uae_vat_settings/__init__.py
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
similarity index 79%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
index 2ad7984..b88439f 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestUAEVATSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.js b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.js
new file mode 100644
index 0000000..07a9301
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('UAE VAT Settings', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.json b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.json
new file mode 100644
index 0000000..1ff5680
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.json
@@ -0,0 +1,42 @@
+{
+ "actions": [],
+ "autoname": "field:company",
+ "creation": "2020-09-25 12:48:51.463265",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "uae_vat_accounts"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "uae_vat_accounts",
+ "fieldtype": "Table",
+ "label": "UAE VAT Accounts",
+ "options": "UAE VAT Account",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-12-25 20:20:22.342426",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "UAE VAT Settings",
+ "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/regional/doctype/uae_vat_settings/uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
new file mode 100644
index 0000000..20dc604
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class UAEVATSettings(Document):
+ pass
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index aae734f..f138a80 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -104,9 +104,9 @@
# L = Tax client number (Mandantennummer)
datev_settings.get('client_number', '00000'),
# M = Start of the fiscal year (Wirtschaftsjahresbeginn)
- frappe.utils.formatdate(frappe.defaults.get_user_default('year_start_date'), 'yyyyMMdd'),
+ frappe.utils.formatdate(filters.get('fiscal_year_start'), 'yyyyMMdd'),
# N = Length of account numbers (Sachkontenlänge)
- datev_settings.get('account_number_length', '4'),
+ str(filters.get('account_number_length', 4)),
# O = Transaction batch start date (YYYYMMDD)
frappe.utils.formatdate(filters.get('from_date'), 'yyyyMMdd') if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
# P = Transaction batch end date (YYYYMMDD)
@@ -155,20 +155,22 @@
return header
-def download_csv_files_as_zip(csv_data_list):
+def zip_and_download(zip_filename, csv_files):
"""
Put CSV files in a zip archive and send that to the client.
Params:
- csv_data_list -- list of dicts [{'file_name': 'EXTF_Buchunsstapel.zip', 'csv_data': get_datev_csv()}]
+ zip_filename Name of the zip file
+ csv_files list of dicts [{'file_name': 'my_file.csv', 'csv_data': 'comma,separated,values'}]
"""
zip_buffer = BytesIO()
- datev_zip = zipfile.ZipFile(zip_buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
- for csv_file in csv_data_list:
- datev_zip.writestr(csv_file.get('file_name'), csv_file.get('csv_data'))
- datev_zip.close()
+ zip_file = zipfile.ZipFile(zip_buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
+ for csv_file in csv_files:
+ zip_file.writestr(csv_file.get('file_name'), csv_file.get('csv_data'))
+
+ zip_file.close()
frappe.response['filecontent'] = zip_buffer.getvalue()
- frappe.response['filename'] = 'DATEV.zip'
+ frappe.response['filename'] = zip_filename
frappe.response['type'] = 'binary'
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index d6221a8..378b735 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -20,6 +20,7 @@
'Jharkhand',
'Karnataka',
'Kerala',
+ 'Ladakh',
'Lakshadweep Islands',
'Madhya Pradesh',
'Maharashtra',
@@ -59,6 +60,7 @@
"Jharkhand": "20",
"Karnataka": "29",
"Kerala": "32",
+ "Ladakh": "38",
"Lakshadweep Islands": "31",
"Madhya Pradesh": "23",
"Maharashtra": "27",
@@ -80,4 +82,4 @@
"West Bengal": "19",
}
-number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
\ No newline at end of file
+number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
diff --git a/erpnext/config/__init__.py b/erpnext/regional/india/e_invoice/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/regional/india/e_invoice/__init__.py
diff --git a/erpnext/regional/india/e_invoice/einv_item_template.json b/erpnext/regional/india/e_invoice/einv_item_template.json
new file mode 100644
index 0000000..78e5651
--- /dev/null
+++ b/erpnext/regional/india/e_invoice/einv_item_template.json
@@ -0,0 +1,31 @@
+{{
+ "SlNo": "{item.sr_no}",
+ "PrdDesc": "{item.description}",
+ "IsServc": "{item.is_service_item}",
+ "HsnCd": "{item.gst_hsn_code}",
+ "Barcde": "{item.barcode}",
+ "Unit": "{item.uom}",
+ "Qty": "{item.qty}",
+ "FreeQty": "{item.free_qty}",
+ "UnitPrice": "{item.unit_rate}",
+ "TotAmt": "{item.gross_amount}",
+ "Discount": "{item.discount_amount}",
+ "AssAmt": "{item.taxable_value}",
+ "PrdSlNo": "{item.serial_no}",
+ "GstRt": "{item.tax_rate}",
+ "IgstAmt": "{item.igst_amount}",
+ "CgstAmt": "{item.cgst_amount}",
+ "SgstAmt": "{item.sgst_amount}",
+ "CesRt": "{item.cess_rate}",
+ "CesAmt": "{item.cess_amount}",
+ "CesNonAdvlAmt": "{item.cess_nadv_amount}",
+ "StateCesRt": "{item.state_cess_rate}",
+ "StateCesAmt": "{item.state_cess_amount}",
+ "StateCesNonAdvlAmt": "{item.state_cess_nadv_amount}",
+ "OthChrg": "{item.other_charges}",
+ "TotItemVal": "{item.total_value}",
+ "BchDtls": {{
+ "Nm": "{item.batch_no}",
+ "ExpDt": "{item.batch_expiry_date}"
+ }}
+}}
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/einv_template.json b/erpnext/regional/india/e_invoice/einv_template.json
new file mode 100644
index 0000000..60f490d
--- /dev/null
+++ b/erpnext/regional/india/e_invoice/einv_template.json
@@ -0,0 +1,110 @@
+{{
+ "Version": "1.1",
+ "TranDtls": {{
+ "TaxSch": "{transaction_details.tax_scheme}",
+ "SupTyp": "{transaction_details.supply_type}",
+ "RegRev": "{transaction_details.reverse_charge}",
+ "EcmGstin": "{transaction_details.ecom_gstin}",
+ "IgstOnIntra": "{transaction_details.igst_on_intra}"
+ }},
+ "DocDtls": {{
+ "Typ": "{doc_details.invoice_type}",
+ "No": "{doc_details.invoice_name}",
+ "Dt": "{doc_details.invoice_date}"
+ }},
+ "SellerDtls": {{
+ "Gstin": "{seller_details.gstin}",
+ "LglNm": "{seller_details.legal_name}",
+ "TrdNm": "{seller_details.trade_name}",
+ "Loc": "{seller_details.location}",
+ "Pin": "{seller_details.pincode}",
+ "Stcd": "{seller_details.state_code}",
+ "Addr1": "{seller_details.address_line1}",
+ "Addr2": "{seller_details.address_line2}",
+ "Ph": "{seller_details.phone}",
+ "Em": "{seller_details.email}"
+ }},
+ "BuyerDtls": {{
+ "Gstin": "{buyer_details.gstin}",
+ "LglNm": "{buyer_details.legal_name}",
+ "TrdNm": "{buyer_details.trade_name}",
+ "Addr1": "{buyer_details.address_line1}",
+ "Addr2": "{buyer_details.address_line2}",
+ "Loc": "{buyer_details.location}",
+ "Pin": "{buyer_details.pincode}",
+ "Stcd": "{buyer_details.state_code}",
+ "Ph": "{buyer_details.phone}",
+ "Em": "{buyer_details.email}",
+ "Pos": "{buyer_details.place_of_supply}"
+ }},
+ "DispDtls": {{
+ "Nm": "{dispatch_details.company_name}",
+ "Addr1": "{dispatch_details.address_line1}",
+ "Addr2": "{dispatch_details.address_line2}",
+ "Loc": "{dispatch_details.location}",
+ "Pin": "{dispatch_details.pincode}",
+ "Stcd": "{dispatch_details.state_code}"
+ }},
+ "ShipDtls": {{
+ "Gstin": "{shipping_details.gstin}",
+ "LglNm": "{shipping_details.legal_name}",
+ "TrdNm": "{shipping_details.trader_name}",
+ "Addr1": "{shipping_details.address_line1}",
+ "Addr2": "{shipping_details.address_line2}",
+ "Loc": "{shipping_details.location}",
+ "Pin": "{shipping_details.pincode}",
+ "Stcd": "{shipping_details.state_code}"
+ }},
+ "ItemList": [
+ {item_list}
+ ],
+ "ValDtls": {{
+ "AssVal": "{invoice_value_details.base_total}",
+ "CgstVal": "{invoice_value_details.total_cgst_amt}",
+ "SgstVal": "{invoice_value_details.total_sgst_amt}",
+ "IgstVal": "{invoice_value_details.total_igst_amt}",
+ "CesVal": "{invoice_value_details.total_cess_amt}",
+ "Discount": "{invoice_value_details.invoice_discount_amt}",
+ "RndOffAmt": "{invoice_value_details.round_off}",
+ "OthChrg": "{invoice_value_details.total_other_charges}",
+ "TotInvVal": "{invoice_value_details.base_grand_total}",
+ "TotInvValFc": "{invoice_value_details.grand_total}"
+ }},
+ "PayDtls": {{
+ "Nm": "{payment_details.payee_name}",
+ "AccDet": "{payment_details.account_no}",
+ "Mode": "{payment_details.mode_of_payment}",
+ "FinInsBr": "{payment_details.ifsc_code}",
+ "PayTerm": "{payment_details.terms}",
+ "PaidAmt": "{payment_details.paid_amount}",
+ "PaymtDue": "{payment_details.outstanding_amount}"
+ }},
+ "RefDtls": {{
+ "DocPerdDtls": {{
+ "InvStDt": "{period_details.start_date}",
+ "InvEndDt": "{period_details.end_date}"
+ }},
+ "PrecDocDtls": [{{
+ "InvNo": "{prev_doc_details.invoice_name}",
+ "InvDt": "{prev_doc_details.invoice_date}"
+ }}]
+ }},
+ "ExpDtls": {{
+ "ShipBNo": "{export_details.bill_no}",
+ "ShipBDt": "{export_details.bill_date}",
+ "Port": "{export_details.port}",
+ "ForCur": "{export_details.foreign_curr_code}",
+ "CntCode": "{export_details.country_code}",
+ "ExpDuty": "{export_details.export_duty}"
+ }},
+ "EwbDtls": {{
+ "TransId": "{eway_bill_details.gstin}",
+ "TransName": "{eway_bill_details.name}",
+ "TransMode": "{eway_bill_details.mode_of_transport}",
+ "Distance": "{eway_bill_details.distance}",
+ "TransDocNo": "{eway_bill_details.document_name}",
+ "TransDocDt": "{eway_bill_details.document_date}",
+ "VehNo": "{eway_bill_details.vehicle_no}",
+ "VehType": "{eway_bill_details.vehicle_type}"
+ }}
+}}
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/einv_validation.json b/erpnext/regional/india/e_invoice/einv_validation.json
new file mode 100644
index 0000000..86290cf
--- /dev/null
+++ b/erpnext/regional/india/e_invoice/einv_validation.json
@@ -0,0 +1,956 @@
+{
+ "Version": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 6,
+ "description": "Version of the schema"
+ },
+ "Irn": {
+ "type": "string",
+ "minLength": 64,
+ "maxLength": 64,
+ "description": "Invoice Reference Number"
+ },
+ "TranDtls": {
+ "type": "object",
+ "properties": {
+ "TaxSch": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 10,
+ "enum": ["GST"],
+ "description": "GST- Goods and Services Tax Scheme"
+ },
+ "SupTyp": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 10,
+ "enum": ["B2B", "SEZWP", "SEZWOP", "EXPWP", "EXPWOP", "DEXP"],
+ "description": "Type of Supply: B2B-Business to Business, SEZWP - SEZ with payment, SEZWOP - SEZ without payment, EXPWP - Export with Payment, EXPWOP - Export without payment,DEXP - Deemed Export"
+ },
+ "RegRev": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1,
+ "enum": ["Y", "N"],
+ "description": "Y- whether the tax liability is payable under reverse charge"
+ },
+ "EcmGstin": {
+ "type": "string",
+ "minLength": 15,
+ "maxLength": 15,
+ "pattern": "([0-9]{2}[0-9A-Z]{13})",
+ "description": "E-Commerce GSTIN",
+ "validationMsg": "E-Commerce GSTIN is invalid"
+ },
+ "IgstOnIntra": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1,
+ "enum": ["Y", "N"],
+ "description": "Y- indicates the supply is intra state but chargeable to IGST"
+ }
+ },
+ "required": ["TaxSch", "SupTyp"]
+ },
+ "DocDtls": {
+ "type": "object",
+ "properties": {
+ "Typ": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 3,
+ "enum": ["INV", "CRN", "DBN"],
+ "description": "Document Type"
+ },
+ "No": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 16,
+ "pattern": "^([A-Z1-9]{1}[A-Z0-9/-]{0,15})$",
+ "description": "Document Number",
+ "validationMsg": "Document Number should not be starting with 0, / and -"
+ },
+ "Dt": {
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Document Date"
+ }
+ },
+ "required": ["Typ", "No", "Dt"]
+ },
+ "SellerDtls": {
+ "type": "object",
+ "properties": {
+ "Gstin": {
+ "type": "string",
+ "minLength": 15,
+ "maxLength": 15,
+ "pattern": "([0-9]{2}[0-9A-Z]{13})",
+ "description": "Supplier GSTIN",
+ "validationMsg": "Company GSTIN is invalid"
+ },
+ "LglNm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Legal Name"
+ },
+ "TrdNm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Tradename"
+ },
+ "Addr1": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Address Line 1"
+ },
+ "Addr2": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Address Line 2"
+ },
+ "Loc": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 50,
+ "description": "Location"
+ },
+ "Pin": {
+ "type": "number",
+ "minimum": 100000,
+ "maximum": 999999,
+ "description": "Pincode"
+ },
+ "Stcd": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 2,
+ "description": "Supplier State Code"
+ },
+ "Ph": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 12,
+ "description": "Phone"
+ },
+ "Em": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 100,
+ "description": "Email-Id"
+ }
+ },
+ "required": ["Gstin", "LglNm", "Addr1", "Loc", "Pin", "Stcd"]
+ },
+ "BuyerDtls": {
+ "type": "object",
+ "properties": {
+ "Gstin": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 15,
+ "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
+ "description": "Buyer GSTIN",
+ "validationMsg": "Customer GSTIN is invalid"
+ },
+ "LglNm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Legal Name"
+ },
+ "TrdNm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Trade Name"
+ },
+ "Pos": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 2,
+ "description": "Place of Supply State code"
+ },
+ "Addr1": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Address Line 1"
+ },
+ "Addr2": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Address Line 2"
+ },
+ "Loc": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Location"
+ },
+ "Pin": {
+ "type": "number",
+ "minimum": 100000,
+ "maximum": 999999,
+ "description": "Pincode"
+ },
+ "Stcd": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 2,
+ "description": "Buyer State Code"
+ },
+ "Ph": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 12,
+ "description": "Phone"
+ },
+ "Em": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 100,
+ "description": "Email-Id"
+ }
+ },
+ "required": ["Gstin", "LglNm", "Pos", "Addr1", "Loc", "Stcd"]
+ },
+ "DispDtls": {
+ "type": "object",
+ "properties": {
+ "Nm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Dispatch Address Name"
+ },
+ "Addr1": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Address Line 1"
+ },
+ "Addr2": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Address Line 2"
+ },
+ "Loc": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Location"
+ },
+ "Pin": {
+ "type": "number",
+ "minimum": 100000,
+ "maximum": 999999,
+ "description": "Pincode"
+ },
+ "Stcd": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 2,
+ "description": "State Code"
+ }
+ },
+ "required": ["Nm", "Addr1", "Loc", "Pin", "Stcd"]
+ },
+ "ShipDtls": {
+ "type": "object",
+ "properties": {
+ "Gstin": {
+ "type": "string",
+ "maxLength": 15,
+ "minLength": 3,
+ "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
+ "description": "Shipping Address GSTIN",
+ "validationMsg": "Shipping Address GSTIN is invalid"
+ },
+ "LglNm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Legal Name"
+ },
+ "TrdNm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Trade Name"
+ },
+ "Addr1": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Address Line 1"
+ },
+ "Addr2": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Address Line 2"
+ },
+ "Loc": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Location"
+ },
+ "Pin": {
+ "type": "number",
+ "minimum": 100000,
+ "maximum": 999999,
+ "description": "Pincode"
+ },
+ "Stcd": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 2,
+ "description": "State Code"
+ }
+ },
+ "required": ["LglNm", "Addr1", "Loc", "Pin", "Stcd"]
+ },
+ "ItemList": {
+ "type": "Array",
+ "properties": {
+ "SlNo": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 6,
+ "description": "Serial No. of Item"
+ },
+ "PrdDesc": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 300,
+ "description": "Item Name"
+ },
+ "IsServc": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1,
+ "enum": ["Y", "N"],
+ "description": "Is Service Item"
+ },
+ "HsnCd": {
+ "type": "string",
+ "minLength": 4,
+ "maxLength": 8,
+ "description": "HSN Code"
+ },
+ "Barcde": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 30,
+ "description": "Barcode"
+ },
+ "Qty": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 9999999999.999,
+ "description": "Quantity"
+ },
+ "FreeQty": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 9999999999.999,
+ "description": "Free Quantity"
+ },
+ "Unit": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 8,
+ "description": "UOM"
+ },
+ "UnitPrice": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.999,
+ "description": "Rate"
+ },
+ "TotAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Gross Amount"
+ },
+ "Discount": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Discount"
+ },
+ "PreTaxVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Pre tax value"
+ },
+ "AssAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Taxable Value"
+ },
+ "GstRt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999.999,
+ "description": "GST Rate"
+ },
+ "IgstAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "IGST Amount"
+ },
+ "CgstAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "CGST Amount"
+ },
+ "SgstAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "SGST Amount"
+ },
+ "CesRt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999.999,
+ "description": "Cess Rate"
+ },
+ "CesAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Cess Amount (Advalorem)"
+ },
+ "CesNonAdvlAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Cess Amount (Non-Advalorem)"
+ },
+ "StateCesRt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999.999,
+ "description": "State CESS Rate"
+ },
+ "StateCesAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "State CESS Amount"
+ },
+ "StateCesNonAdvlAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "State CESS Amount (Non Advalorem)"
+ },
+ "OthChrg": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Other Charges"
+ },
+ "TotItemVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Total Item Value"
+ },
+ "OrdLineRef": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 50,
+ "description": "Order line reference"
+ },
+ "OrgCntry": {
+ "type": "string",
+ "minLength": 2,
+ "maxLength": 2,
+ "description": "Origin Country"
+ },
+ "PrdSlNo": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "description": "Serial number"
+ },
+ "BchDtls": {
+ "type": "object",
+ "properties": {
+ "Nm": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 20,
+ "description": "Batch number"
+ },
+ "ExpDt": {
+ "type": "string",
+ "maxLength": 10,
+ "minLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Batch Expiry Date"
+ },
+ "WrDt": {
+ "type": "string",
+ "maxLength": 10,
+ "minLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Warranty Date"
+ }
+ },
+ "required": ["Nm"]
+ },
+ "AttribDtls": {
+ "type": "Array",
+ "Attribute": {
+ "type": "object",
+ "properties": {
+ "Nm": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Attribute name of the item"
+ },
+ "Val": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Attribute value of the item"
+ }
+ }
+ }
+ }
+ },
+ "required": [
+ "SlNo",
+ "IsServc",
+ "HsnCd",
+ "UnitPrice",
+ "TotAmt",
+ "AssAmt",
+ "GstRt",
+ "TotItemVal"
+ ]
+ },
+ "ValDtls": {
+ "type": "object",
+ "properties": {
+ "AssVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Total Assessable value of all items"
+ },
+ "CgstVal": {
+ "type": "number",
+ "maximum": 99999999999999.99,
+ "minimum": 0,
+ "description": "Total CGST value of all items"
+ },
+ "SgstVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Total SGST value of all items"
+ },
+ "IgstVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Total IGST value of all items"
+ },
+ "CesVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Total CESS value of all items"
+ },
+ "StCesVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Total State CESS value of all items"
+ },
+ "Discount": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Invoice Discount"
+ },
+ "OthChrg": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Other Charges"
+ },
+ "RndOffAmt": {
+ "type": "number",
+ "minimum": -99.99,
+ "maximum": 99.99,
+ "description": "Rounded off Amount"
+ },
+ "TotInvVal": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Final Invoice Value "
+ },
+ "TotInvValFc": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Final Invoice value in Foreign Currency"
+ }
+ },
+ "required": ["AssVal", "TotInvVal"]
+ },
+ "PayDtls": {
+ "type": "object",
+ "properties": {
+ "Nm": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Payee Name"
+ },
+ "AccDet": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 18,
+ "description": "Bank Account Number of Payee"
+ },
+ "Mode": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 18,
+ "description": "Mode of Payment"
+ },
+ "FinInsBr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 11,
+ "description": "Branch or IFSC code"
+ },
+ "PayTerm": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Terms of Payment"
+ },
+ "PayInstr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Payment Instruction"
+ },
+ "CrTrn": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Credit Transfer"
+ },
+ "DirDr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Direct Debit"
+ },
+ "CrDay": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 9999,
+ "description": "Credit Days"
+ },
+ "PaidAmt": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Advance Amount"
+ },
+ "PaymtDue": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 99999999999999.99,
+ "description": "Outstanding Amount"
+ }
+ }
+ },
+ "RefDtls": {
+ "type": "object",
+ "properties": {
+ "InvRm": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 3,
+ "pattern": "^[0-9A-Za-z/-]{3,100}$",
+ "description": "Remarks/Note"
+ },
+ "DocPerdDtls": {
+ "type": "object",
+ "properties": {
+ "InvStDt": {
+ "type": "string",
+ "maxLength": 10,
+ "minLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Invoice Period Start Date"
+ },
+ "InvEndDt": {
+ "type": "string",
+ "maxLength": 10,
+ "minLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Invoice Period End Date"
+ }
+ },
+ "required": ["InvStDt ", "InvEndDt "]
+ },
+ "PrecDocDtls": {
+ "type": "object",
+ "properties": {
+ "InvNo": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 16,
+ "pattern": "^[1-9A-Z]{1}[0-9A-Z/-]{1,15}$",
+ "description": "Reference of Original Invoice"
+ },
+ "InvDt": {
+ "type": "string",
+ "maxLength": 10,
+ "minLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Date of Orginal Invoice"
+ },
+ "OthRefNo": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "description": "Other Reference"
+ }
+ }
+ },
+ "required": ["InvNo", "InvDt"],
+ "ContrDtls": {
+ "type": "object",
+ "properties": {
+ "RecAdvRefr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "pattern": "^([0-9A-Za-z/-]){1,20}$",
+ "description": "Receipt Advice No."
+ },
+ "RecAdvDt": {
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Date of receipt advice"
+ },
+ "TendRefr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "pattern": "^([0-9A-Za-z/-]){1,20}$",
+ "description": "Lot/Batch Reference No."
+ },
+ "ContrRefr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "pattern": "^([0-9A-Za-z/-]){1,20}$",
+ "description": "Contract Reference Number"
+ },
+ "ExtRefr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "pattern": "^([0-9A-Za-z/-]){1,20}$",
+ "description": "Any other reference"
+ },
+ "ProjRefr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "pattern": "^([0-9A-Za-z/-]){1,20}$",
+ "description": "Project Reference Number"
+ },
+ "PORefr": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 16,
+ "pattern": "^([0-9A-Za-z/-]){1,16}$",
+ "description": "PO Reference Number"
+ },
+ "PORefDt": {
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "PO Reference date"
+ }
+ }
+ }
+ }
+ },
+ "AddlDocDtls": {
+ "type": "Array",
+ "properties": {
+ "Url": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Supporting document URL"
+ },
+ "Docs": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 1000,
+ "description": "Supporting document in Base64 Format"
+ },
+ "Info": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 1000,
+ "description": "Any additional information"
+ }
+ }
+ },
+
+ "ExpDtls": {
+ "type": "object",
+ "properties": {
+ "ShipBNo": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20,
+ "description": "Shipping Bill No."
+ },
+ "ShipBDt": {
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Shipping Bill Date"
+ },
+ "Port": {
+ "type": "string",
+ "minLength": 2,
+ "maxLength": 10,
+ "pattern": "^[0-9A-Za-z]{2,10}$",
+ "description": "Port Code. Refer the master"
+ },
+ "RefClm": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1,
+ "description": "Claiming Refund. Y/N"
+ },
+ "ForCur": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 16,
+ "description": "Additional Currency Code. Refer the master"
+ },
+ "CntCode": {
+ "type": "string",
+ "minLength": 2,
+ "maxLength": 2,
+ "description": "Country Code. Refer the master"
+ },
+ "ExpDuty": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 999999999999.99,
+ "description": "Export Duty"
+ }
+ }
+ },
+ "EwbDtls": {
+ "type": "object",
+ "properties": {
+ "TransId": {
+ "type": "string",
+ "minLength": 15,
+ "maxLength": 15,
+ "description": "Transporter GSTIN"
+ },
+ "TransName": {
+ "type": "string",
+ "minLength": 3,
+ "maxLength": 100,
+ "description": "Transporter Name"
+ },
+ "TransMode": {
+ "type": "string",
+ "maxLength": 1,
+ "minLength": 1,
+ "enum": ["1", "2", "3", "4"],
+ "description": "Mode of Transport"
+ },
+ "Distance": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 9999,
+ "description": "Distance"
+ },
+ "TransDocNo": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 15,
+ "pattern": "^([0-9A-Z/-]){1,15}$",
+ "description": "Tranport Document Number"
+ },
+ "TransDocDt": {
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 10,
+ "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
+ "description": "Transport Document Date"
+ },
+ "VehNo": {
+ "type": "string",
+ "minLength": 4,
+ "maxLength": 20,
+ "description": "Vehicle Number"
+ },
+ "VehType": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1,
+ "enum": ["O", "R"],
+ "description": "Vehicle Type"
+ }
+ },
+ "required": ["Distance"]
+ },
+ "required": [
+ "Version",
+ "TranDtls",
+ "DocDtls",
+ "SellerDtls",
+ "BuyerDtls",
+ "ItemList",
+ "ValDtls"
+ ]
+}
diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js
new file mode 100644
index 0000000..7cd64f2
--- /dev/null
+++ b/erpnext/regional/india/e_invoice/einvoice.js
@@ -0,0 +1,307 @@
+erpnext.setup_einvoice_actions = (doctype) => {
+ frappe.ui.form.on(doctype, {
+ async refresh(frm) {
+ const einvoicing_enabled = await frappe.db.get_single_value("E Invoice Settings", "enable");
+ const supply_type = frm.doc.gst_category;
+ const valid_supply_type = ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type);
+ const company_transaction = frm.doc.billing_address_gstin == frm.doc.company_gstin;
+
+ if (cint(einvoicing_enabled) == 0 || !valid_supply_type || company_transaction) return;
+
+ const { doctype, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
+
+ const add_custom_button = (label, action) => {
+ if (!frm.custom_buttons[label]) {
+ frm.add_custom_button(label, action, __('E Invoicing'));
+ }
+ };
+
+ if (!irn && !__unsaved) {
+ const action = () => {
+ if (frm.doc.__unsaved) {
+ frappe.throw(__('Please save the document to generate IRN.'));
+ }
+ frappe.call({
+ method: 'erpnext.regional.india.e_invoice.utils.get_einvoice',
+ args: { doctype, docname: name },
+ freeze: true,
+ callback: (res) => {
+ const einvoice = res.message;
+ show_einvoice_preview(frm, einvoice);
+ }
+ });
+ };
+
+ add_custom_button(__("Generate IRN"), action);
+ }
+
+ if (irn && !irn_cancelled && !ewaybill) {
+ const fields = [
+ {
+ "label": "Reason",
+ "fieldname": "reason",
+ "fieldtype": "Select",
+ "reqd": 1,
+ "default": "1-Duplicate",
+ "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
+ },
+ {
+ "label": "Remark",
+ "fieldname": "remark",
+ "fieldtype": "Data",
+ "reqd": 1
+ }
+ ];
+ const action = () => {
+ const d = new frappe.ui.Dialog({
+ title: __("Cancel IRN"),
+ fields: fields,
+ primary_action: function() {
+ const data = d.get_values();
+ frappe.call({
+ method: 'erpnext.regional.india.e_invoice.utils.cancel_irn',
+ args: {
+ doctype,
+ docname: name,
+ irn: irn,
+ reason: data.reason.split('-')[0],
+ remark: data.remark
+ },
+ freeze: true,
+ callback: () => frm.reload_doc() || d.hide(),
+ error: () => d.hide()
+ });
+ },
+ primary_action_label: __('Submit')
+ });
+ d.show();
+ };
+ add_custom_button(__("Cancel IRN"), action);
+ }
+
+ if (irn && !irn_cancelled && !ewaybill) {
+ const action = () => {
+ const d = new frappe.ui.Dialog({
+ title: __('Generate E-Way Bill'),
+ size: "large",
+ fields: get_ewaybill_fields(frm),
+ primary_action: function() {
+ const data = d.get_values();
+ frappe.call({
+ method: 'erpnext.regional.india.e_invoice.utils.generate_eway_bill',
+ args: {
+ doctype,
+ docname: name,
+ irn,
+ ...data
+ },
+ freeze: true,
+ callback: () => frm.reload_doc() || d.hide(),
+ error: () => d.hide()
+ });
+ },
+ primary_action_label: __('Submit')
+ });
+ d.show();
+ };
+
+ add_custom_button(__("Generate E-Way Bill"), action);
+ }
+
+ if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
+ const fields = [
+ {
+ "label": "Reason",
+ "fieldname": "reason",
+ "fieldtype": "Select",
+ "reqd": 1,
+ "default": "1-Duplicate",
+ "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
+ },
+ {
+ "label": "Remark",
+ "fieldname": "remark",
+ "fieldtype": "Data",
+ "reqd": 1
+ }
+ ];
+ const action = () => {
+ const d = new frappe.ui.Dialog({
+ title: __('Cancel E-Way Bill'),
+ fields: fields,
+ primary_action: function() {
+ const data = d.get_values();
+ frappe.call({
+ method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill',
+ args: {
+ doctype,
+ docname: name,
+ eway_bill: ewaybill,
+ reason: data.reason.split('-')[0],
+ remark: data.remark
+ },
+ freeze: true,
+ callback: () => frm.reload_doc() || d.hide(),
+ error: () => d.hide()
+ });
+ },
+ primary_action_label: __('Submit')
+ });
+ d.show();
+ };
+ add_custom_button(__("Cancel E-Way Bill"), action);
+ }
+ }
+ });
+};
+
+const get_ewaybill_fields = (frm) => {
+ return [
+ {
+ 'fieldname': 'transporter',
+ 'label': 'Transporter',
+ 'fieldtype': 'Link',
+ 'options': 'Supplier',
+ 'default': frm.doc.transporter
+ },
+ {
+ 'fieldname': 'gst_transporter_id',
+ 'label': 'GST Transporter ID',
+ 'fieldtype': 'Data',
+ 'fetch_from': 'transporter.gst_transporter_id',
+ 'default': frm.doc.gst_transporter_id
+ },
+ {
+ 'fieldname': 'driver',
+ 'label': 'Driver',
+ 'fieldtype': 'Link',
+ 'options': 'Driver',
+ 'default': frm.doc.driver
+ },
+ {
+ 'fieldname': 'lr_no',
+ 'label': 'Transport Receipt No',
+ 'fieldtype': 'Data',
+ 'default': frm.doc.lr_no
+ },
+ {
+ 'fieldname': 'vehicle_no',
+ 'label': 'Vehicle No',
+ 'fieldtype': 'Data',
+ 'default': frm.doc.vehicle_no
+ },
+ {
+ 'fieldname': 'distance',
+ 'label': 'Distance (in km)',
+ 'fieldtype': 'Float',
+ 'default': frm.doc.distance
+ },
+ {
+ 'fieldname': 'transporter_col_break',
+ 'fieldtype': 'Column Break',
+ },
+ {
+ 'fieldname': 'transporter_name',
+ 'label': 'Transporter Name',
+ 'fieldtype': 'Data',
+ 'fetch_from': 'transporter.name',
+ 'read_only': 1,
+ 'default': frm.doc.transporter_name
+ },
+ {
+ 'fieldname': 'mode_of_transport',
+ 'label': 'Mode of Transport',
+ 'fieldtype': 'Select',
+ 'options': `\nRoad\nAir\nRail\nShip`,
+ 'default': frm.doc.mode_of_transport
+ },
+ {
+ 'fieldname': 'driver_name',
+ 'label': 'Driver Name',
+ 'fieldtype': 'Data',
+ 'fetch_from': 'driver.full_name',
+ 'read_only': 1,
+ 'default': frm.doc.driver_name
+ },
+ {
+ 'fieldname': 'lr_date',
+ 'label': 'Transport Receipt Date',
+ 'fieldtype': 'Date',
+ 'default': frm.doc.lr_date
+ },
+ {
+ 'fieldname': 'gst_vehicle_type',
+ 'label': 'GST Vehicle Type',
+ 'fieldtype': 'Select',
+ 'options': `Regular\nOver Dimensional Cargo (ODC)`,
+ 'depends_on': 'eval:(doc.mode_of_transport === "Road")',
+ 'default': frm.doc.gst_vehicle_type
+ }
+ ];
+};
+
+const request_irn_generation = (frm) => {
+ frappe.call({
+ method: 'erpnext.regional.india.e_invoice.utils.generate_irn',
+ args: { doctype: frm.doc.doctype, docname: frm.doc.name },
+ freeze: true,
+ callback: () => frm.reload_doc()
+ });
+};
+
+const get_preview_dialog = (frm, action) => {
+ const dialog = new frappe.ui.Dialog({
+ title: __("Preview"),
+ size: "large",
+ fields: [
+ {
+ "label": "Preview",
+ "fieldname": "preview_html",
+ "fieldtype": "HTML"
+ }
+ ],
+ primary_action: () => action(frm) || dialog.hide(),
+ primary_action_label: __('Generate IRN')
+ });
+ return dialog;
+};
+
+const show_einvoice_preview = (frm, einvoice) => {
+ const preview_dialog = get_preview_dialog(frm, request_irn_generation);
+
+ // initialize e-invoice fields
+ einvoice["Irn"] = einvoice["AckNo"] = ''; einvoice["AckDt"] = frappe.datetime.nowdate();
+ frm.doc.signed_einvoice = JSON.stringify(einvoice);
+
+ // initialize preview wrapper
+ const $preview_wrapper = preview_dialog.get_field("preview_html").$wrapper;
+ $preview_wrapper.html(
+ `<div>
+ <div class="print-preview">
+ <div class="print-format"></div>
+ </div>
+ <div class="page-break-message text-muted text-center text-medium margin-top"></div>
+ </div>`
+ );
+
+ frappe.call({
+ method: "frappe.www.printview.get_html_and_style",
+ args: {
+ doc: frm.doc,
+ print_format: "GST E-Invoice",
+ no_letterhead: 1
+ },
+ callback: function (r) {
+ if (!r.exc) {
+ $preview_wrapper.find(".print-format").html(r.message.html);
+ const style = `
+ .print-format { box-shadow: 0px 0px 5px rgba(0,0,0,0.2); padding: 0.30in; min-height: 80vh; }
+ .print-preview { min-height: 0px; }
+ .modal-dialog { width: 720px; }`;
+
+ frappe.dom.set_style(style, "custom-print-style");
+ preview_dialog.show();
+ }
+ }
+ });
+};
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
new file mode 100644
index 0000000..96f7f1b
--- /dev/null
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -0,0 +1,851 @@
+# -*- 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 os
+import re
+import jwt
+import sys
+import json
+import base64
+import frappe
+import six
+import traceback
+import io
+from frappe import _, bold
+from pyqrcode import create as qrcreate
+from frappe.integrations.utils import make_post_request, make_get_request
+from erpnext.regional.india.utils import get_gst_accounts, get_place_of_supply
+from frappe.utils.data import cstr, cint, format_date, flt, time_diff_in_seconds, now_datetime, add_to_date, get_link_to_form
+
+def validate_einvoice_fields(doc):
+ einvoicing_enabled = cint(frappe.db.get_value('E Invoice Settings', 'E Invoice Settings', 'enable'))
+ invalid_doctype = doc.doctype != 'Sales Invoice'
+ invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
+ company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
+ no_taxes_applied = not doc.get('taxes')
+
+ if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction or no_taxes_applied:
+ return
+
+ if doc.docstatus == 0 and doc._action == 'save':
+ if doc.irn:
+ frappe.throw(_('You cannot edit the invoice after generating IRN'), title=_('Edit Not Allowed'))
+ if len(doc.name) > 16:
+ raise_document_name_too_long_error()
+
+ elif doc.docstatus == 1 and doc._action == 'submit' and not doc.irn:
+ frappe.throw(_('You must generate IRN before submitting the document.'), title=_('Missing IRN'))
+
+ elif doc.irn and doc.docstatus == 2 and doc._action == 'cancel' and not doc.irn_cancelled:
+ frappe.throw(_('You must cancel IRN before cancelling the document.'), title=_('Cancel Not Allowed'))
+
+def raise_document_name_too_long_error():
+ title = _('Document ID Too Long')
+ msg = _('As you have E-Invoicing enabled, to be able to generate IRN for this invoice, ')
+ msg += _('document id {} exceed 16 letters. ').format(bold(_('should not')))
+ msg += '<br><br>'
+ msg += _('You must {} your {} in order to have document id of {} length 16. ').format(
+ bold(_('modify')), bold(_('naming series')), bold(_('maximum'))
+ )
+ msg += _('Please account for ammended documents too. ')
+ frappe.throw(msg, title=title)
+
+def read_json(name):
+ file_path = os.path.join(os.path.dirname(__file__), '{name}.json'.format(name=name))
+ with open(file_path, 'r') as f:
+ return cstr(f.read())
+
+def get_transaction_details(invoice):
+ supply_type = ''
+ if invoice.gst_category == 'Registered Regular': supply_type = 'B2B'
+ elif invoice.gst_category == 'SEZ': supply_type = 'SEZWOP'
+ elif invoice.gst_category == 'Overseas': supply_type = 'EXPWOP'
+ elif invoice.gst_category == 'Deemed Export': supply_type = 'DEXP'
+
+ if not supply_type:
+ rr, sez, overseas, export = bold('Registered Regular'), bold('SEZ'), bold('Overseas'), bold('Deemed Export')
+ frappe.throw(_('GST category should be one of {}, {}, {}, {}').format(rr, sez, overseas, export),
+ title=_('Invalid Supply Type'))
+
+ return frappe._dict(dict(
+ tax_scheme='GST',
+ supply_type=supply_type,
+ reverse_charge=invoice.reverse_charge
+ ))
+
+def get_doc_details(invoice):
+ invoice_type = 'CRN' if invoice.is_return else 'INV'
+
+ invoice_name = invoice.name
+ invoice_date = format_date(invoice.posting_date, 'dd/mm/yyyy')
+
+ return frappe._dict(dict(
+ invoice_type=invoice_type,
+ invoice_name=invoice_name,
+ invoice_date=invoice_date
+ ))
+
+def get_party_details(address_name):
+ d = frappe.get_all('Address', filters={'name': address_name}, fields=['*'])[0]
+
+ if (not d.gstin
+ or not d.city
+ or not d.pincode
+ or not d.address_title
+ or not d.address_line1
+ or not d.gst_state_number):
+
+ frappe.throw(
+ msg=_('Address lines, city, pincode, gstin is mandatory for address {}. Please set them and try again.').format(
+ get_link_to_form('Address', address_name)
+ ),
+ title=_('Missing Address Fields')
+ )
+
+ if d.gst_state_number == 97:
+ # according to einvoice standard
+ pincode = 999999
+
+ return frappe._dict(dict(
+ gstin=d.gstin,
+ legal_name=sanitize_for_json(d.address_title),
+ location=sanitize_for_json(d.city),
+ pincode=d.pincode,
+ state_code=d.gst_state_number,
+ address_line1=sanitize_for_json(d.address_line1),
+ address_line2=sanitize_for_json(d.address_line2)
+ ))
+
+def get_gstin_details(gstin):
+ if not hasattr(frappe.local, 'gstin_cache'):
+ frappe.local.gstin_cache = {}
+
+ key = gstin
+ details = frappe.local.gstin_cache.get(key)
+ if details:
+ return details
+
+ details = frappe.cache().hget('gstin_cache', key)
+ if details:
+ frappe.local.gstin_cache[key] = details
+ return details
+
+ if not details:
+ return GSPConnector.get_gstin_details(gstin)
+
+def get_overseas_address_details(address_name):
+ address_title, address_line1, address_line2, city = frappe.db.get_value(
+ 'Address', address_name, ['address_title', 'address_line1', 'address_line2', 'city']
+ )
+
+ if not address_title or not address_line1 or not city:
+ frappe.throw(
+ msg=_('Address lines and city is mandatory for address {}. Please set them and try again.').format(
+ get_link_to_form('Address', address_name)
+ ),
+ title=_('Missing Address Fields')
+ )
+
+ return frappe._dict(dict(
+ gstin='URP',
+ legal_name=sanitize_for_json(address_title),
+ location=city,
+ address_line1=sanitize_for_json(address_line1),
+ address_line2=sanitize_for_json(address_line2),
+ pincode=999999, state_code=96, place_of_supply=96
+ ))
+
+def get_item_list(invoice):
+ item_list = []
+
+ for d in invoice.items:
+ einvoice_item_schema = read_json('einv_item_template')
+ item = frappe._dict({})
+ item.update(d.as_dict())
+
+ item.sr_no = d.idx
+ item.description = sanitize_for_json(d.item_name)
+
+ item.qty = abs(item.qty)
+ item.discount_amount = 0
+ item.unit_rate = abs(item.base_net_amount / item.qty)
+ item.gross_amount = abs(item.base_net_amount)
+ item.taxable_value = abs(item.base_net_amount)
+
+ item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None
+ item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None
+ item.is_service_item = 'N' if frappe.db.get_value('Item', d.item_code, 'is_stock_item') else 'Y'
+ item.serial_no = ""
+
+ item = update_item_taxes(invoice, item)
+
+ item.total_value = abs(
+ item.taxable_value + item.igst_amount + item.sgst_amount +
+ item.cgst_amount + item.cess_amount + item.cess_nadv_amount + item.other_charges
+ )
+ einv_item = einvoice_item_schema.format(item=item)
+ item_list.append(einv_item)
+
+ return ', '.join(item_list)
+
+def update_item_taxes(invoice, item):
+ gst_accounts = get_gst_accounts(invoice.company)
+ gst_accounts_list = [d for accounts in gst_accounts.values() for d in accounts if d]
+
+ for attr in [
+ 'tax_rate', 'cess_rate', 'cess_nadv_amount',
+ 'cgst_amount', 'sgst_amount', 'igst_amount',
+ 'cess_amount', 'cess_nadv_amount', 'other_charges'
+ ]:
+ item[attr] = 0
+
+ for t in invoice.taxes:
+ is_applicable = t.tax_amount and t.account_head in gst_accounts_list
+ if is_applicable:
+ # this contains item wise tax rate & tax amount (incl. discount)
+ item_tax_detail = json.loads(t.item_wise_tax_detail).get(item.item_code)
+
+ item_tax_rate = item_tax_detail[0]
+ # item tax amount excluding discount amount
+ item_tax_amount = (item_tax_rate / 100) * item.base_net_amount
+
+ if t.account_head in gst_accounts.cess_account:
+ item_tax_amount_after_discount = item_tax_detail[1]
+ if t.charge_type == 'On Item Quantity':
+ item.cess_nadv_amount += abs(item_tax_amount_after_discount)
+ else:
+ item.cess_rate += item_tax_rate
+ item.cess_amount += abs(item_tax_amount_after_discount)
+
+ for tax_type in ['igst', 'cgst', 'sgst']:
+ if t.account_head in gst_accounts[f'{tax_type}_account']:
+ item.tax_rate += item_tax_rate
+ item[f'{tax_type}_amount'] += abs(item_tax_amount)
+
+ return item
+
+def get_invoice_value_details(invoice):
+ invoice_value_details = frappe._dict(dict())
+
+ if invoice.apply_discount_on == 'Net Total' and invoice.discount_amount:
+ invoice_value_details.base_total = abs(invoice.base_total)
+ invoice_value_details.invoice_discount_amt = abs(invoice.base_discount_amount)
+ else:
+ invoice_value_details.base_total = abs(invoice.base_net_total)
+ # since tax already considers discount amount
+ invoice_value_details.invoice_discount_amt = 0
+
+ invoice_value_details.round_off = invoice.base_rounding_adjustment
+ invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
+ invoice_value_details.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total)
+
+ invoice_value_details = update_invoice_taxes(invoice, invoice_value_details)
+
+ return invoice_value_details
+
+def update_invoice_taxes(invoice, invoice_value_details):
+ gst_accounts = get_gst_accounts(invoice.company)
+ gst_accounts_list = [d for accounts in gst_accounts.values() for d in accounts if d]
+
+ invoice_value_details.total_cgst_amt = 0
+ invoice_value_details.total_sgst_amt = 0
+ invoice_value_details.total_igst_amt = 0
+ invoice_value_details.total_cess_amt = 0
+ invoice_value_details.total_other_charges = 0
+ for t in invoice.taxes:
+ if t.account_head in gst_accounts_list:
+ if t.account_head in gst_accounts.cess_account:
+ # using after discount amt since item also uses after discount amt for cess calc
+ invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount)
+
+ for tax_type in ['igst', 'cgst', 'sgst']:
+ if t.account_head in gst_accounts[f'{tax_type}_account']:
+ invoice_value_details[f'total_{tax_type}_amt'] += abs(t.base_tax_amount_after_discount_amount)
+ else:
+ invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount)
+
+ return invoice_value_details
+
+def get_payment_details(invoice):
+ payee_name = invoice.company
+ mode_of_payment = ', '.join([d.mode_of_payment for d in invoice.payments])
+ paid_amount = invoice.base_paid_amount
+ outstanding_amount = invoice.outstanding_amount
+
+ return frappe._dict(dict(
+ payee_name=payee_name, mode_of_payment=mode_of_payment,
+ paid_amount=paid_amount, outstanding_amount=outstanding_amount
+ ))
+
+def get_return_doc_reference(invoice):
+ invoice_date = frappe.db.get_value('Sales Invoice', invoice.return_against, 'posting_date')
+ return frappe._dict(dict(
+ invoice_name=invoice.return_against, invoice_date=format_date(invoice_date, 'dd/mm/yyyy')
+ ))
+
+def get_eway_bill_details(invoice):
+ if invoice.is_return:
+ frappe.throw(_('E-Way Bill cannot be generated for Credit Notes & Debit Notes'), title=_('E Invoice Validation Failed'))
+
+ mode_of_transport = { '': '', 'Road': '1', 'Air': '2', 'Rail': '3', 'Ship': '4' }
+ vehicle_type = { 'Regular': 'R', 'Over Dimensional Cargo (ODC)': 'O' }
+
+ return frappe._dict(dict(
+ gstin=invoice.gst_transporter_id,
+ name=invoice.transporter_name,
+ mode_of_transport=mode_of_transport[invoice.mode_of_transport],
+ distance=invoice.distance or 0,
+ document_name=invoice.lr_no,
+ document_date=format_date(invoice.lr_date, 'dd/mm/yyyy'),
+ vehicle_no=invoice.vehicle_no,
+ vehicle_type=vehicle_type[invoice.gst_vehicle_type]
+ ))
+
+def validate_mandatory_fields(invoice):
+ if not invoice.company_address:
+ frappe.throw(_('Company Address is mandatory to fetch company GSTIN details.'), title=_('Missing Fields'))
+ if not invoice.customer_address:
+ frappe.throw(_('Customer Address is mandatory to fetch customer GSTIN details.'), title=_('Missing Fields'))
+ if not frappe.db.get_value('Address', invoice.company_address, 'gstin'):
+ frappe.throw(
+ _('GSTIN is mandatory to fetch company GSTIN details. Please enter GSTIN in selected company address.'),
+ title=_('Missing Fields')
+ )
+ if invoice.gst_category != 'Overseas' and not frappe.db.get_value('Address', invoice.customer_address, 'gstin'):
+ frappe.throw(
+ _('GSTIN is mandatory to fetch customer GSTIN details. Please enter GSTIN in selected customer address.'),
+ title=_('Missing Fields')
+ )
+
+def make_einvoice(invoice):
+ validate_mandatory_fields(invoice)
+
+ schema = read_json('einv_template')
+
+ transaction_details = get_transaction_details(invoice)
+ item_list = get_item_list(invoice)
+ doc_details = get_doc_details(invoice)
+ invoice_value_details = get_invoice_value_details(invoice)
+ seller_details = get_party_details(invoice.company_address)
+
+ if invoice.gst_category == 'Overseas':
+ buyer_details = get_overseas_address_details(invoice.customer_address)
+ else:
+ buyer_details = get_party_details(invoice.customer_address)
+ place_of_supply = get_place_of_supply(invoice, invoice.doctype) or sanitize_for_json(invoice.billing_address_gstin)
+ place_of_supply = place_of_supply[:2]
+ buyer_details.update(dict(place_of_supply=place_of_supply))
+
+ shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
+ if invoice.shipping_address_name and invoice.customer_address != invoice.shipping_address_name:
+ if invoice.gst_category == 'Overseas':
+ shipping_details = get_overseas_address_details(invoice.shipping_address_name)
+ else:
+ shipping_details = get_party_details(invoice.shipping_address_name)
+
+ if invoice.is_pos and invoice.base_paid_amount:
+ payment_details = get_payment_details(invoice)
+
+ if invoice.is_return and invoice.return_against:
+ prev_doc_details = get_return_doc_reference(invoice)
+
+ if invoice.transporter:
+ eway_bill_details = get_eway_bill_details(invoice)
+
+ # not yet implemented
+ dispatch_details = period_details = export_details = frappe._dict({})
+
+ einvoice = schema.format(
+ transaction_details=transaction_details, doc_details=doc_details, dispatch_details=dispatch_details,
+ seller_details=seller_details, buyer_details=buyer_details, shipping_details=shipping_details,
+ item_list=item_list, invoice_value_details=invoice_value_details, payment_details=payment_details,
+ period_details=period_details, prev_doc_details=prev_doc_details,
+ export_details=export_details, eway_bill_details=eway_bill_details
+ )
+ einvoice = safe_json_load(einvoice)
+
+ validations = json.loads(read_json('einv_validation'))
+ errors = validate_einvoice(validations, einvoice)
+ if errors:
+ message = "\n".join([
+ "E Invoice: ", json.dumps(einvoice, indent=4),
+ "-" * 50,
+ "Errors: ", json.dumps(errors, indent=4)
+ ])
+ frappe.log_error(title="E Invoice Validation Failed", message=message)
+ frappe.throw(errors, title=_('E Invoice Validation Failed'), as_list=1)
+
+ return einvoice
+
+def safe_json_load(json_string):
+ JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError
+
+ try:
+ return json.loads(json_string)
+ except JSONDecodeError as e:
+ # print a snippet of 40 characters around the location where error occured
+ pos = e.pos
+ start, end = max(0, pos-20), min(len(json_string)-1, pos+20)
+ snippet = json_string[start:end]
+ frappe.throw(_("Error in input data. Please check for any special characters near following input: <br> {}").format(snippet))
+
+def validate_einvoice(validations, einvoice, errors=[]):
+ for fieldname, field_validation in validations.items():
+ value = einvoice.get(fieldname, None)
+ if not value or value == "None":
+ # remove keys with empty values
+ einvoice.pop(fieldname, None)
+ continue
+
+ value_type = field_validation.get("type").lower()
+ if value_type in ['object', 'array']:
+ child_validations = field_validation.get('properties')
+
+ if isinstance(value, list):
+ for d in value:
+ validate_einvoice(child_validations, d, errors)
+ if not d:
+ # remove empty dicts
+ einvoice.pop(fieldname, None)
+ else:
+ validate_einvoice(child_validations, value, errors)
+ if not value:
+ # remove empty dicts
+ einvoice.pop(fieldname, None)
+ continue
+
+ # convert to int or str
+ if value_type == 'string':
+ einvoice[fieldname] = str(value)
+ elif value_type == 'number':
+ is_integer = '.' not in str(field_validation.get('maximum'))
+ precision = 3 if '.999' in str(field_validation.get('maximum')) else 2
+ einvoice[fieldname] = flt(value, precision) if not is_integer else cint(value)
+ value = einvoice[fieldname]
+
+ max_length = field_validation.get('maxLength')
+ minimum = flt(field_validation.get('minimum'))
+ maximum = flt(field_validation.get('maximum'))
+ pattern_str = field_validation.get('pattern')
+ pattern = re.compile(pattern_str or '')
+
+ label = field_validation.get('description') or fieldname
+
+ if value_type == 'string' and len(value) > max_length:
+ errors.append(_('{} should not exceed {} characters').format(label, max_length))
+ if value_type == 'number' and (value > maximum or value < minimum):
+ errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
+ if pattern_str and not pattern.match(value):
+ errors.append(field_validation.get('validationMsg'))
+
+ return errors
+
+class RequestFailed(Exception): pass
+
+class GSPConnector():
+ def __init__(self, doctype=None, docname=None):
+ self.e_invoice_settings = frappe.get_cached_doc('E Invoice Settings')
+ sandbox_mode = self.e_invoice_settings.sandbox_mode
+
+ self.invoice = frappe.get_cached_doc(doctype, docname) if doctype and docname else None
+ self.credentials = self.get_credentials()
+
+ # authenticate url is same for sandbox & live
+ self.authenticate_url = 'https://gsp.adaequare.com/gsp/authenticate?grant_type=token'
+ self.base_url = 'https://gsp.adaequare.com' if not sandbox_mode else 'https://gsp.adaequare.com/test'
+
+ self.cancel_irn_url = self.base_url + '/enriched/ei/api/invoice/cancel'
+ self.irn_details_url = self.base_url + '/enriched/ei/api/invoice/irn'
+ self.generate_irn_url = self.base_url + '/enriched/ei/api/invoice'
+ self.gstin_details_url = self.base_url + '/enriched/ei/api/master/gstin'
+ self.cancel_ewaybill_url = self.base_url + '/enriched/ewb/ewayapi?action=CANEWB'
+ self.generate_ewaybill_url = self.base_url + '/enriched/ei/api/ewaybill'
+
+ def get_credentials(self):
+ if self.invoice:
+ gstin = self.get_seller_gstin()
+ if not self.e_invoice_settings.enable:
+ frappe.throw(_("E-Invoicing is disabled. Please enable it from {} to generate e-invoices.").format(get_link_to_form("E Invoice Settings", "E Invoice Settings")))
+ credentials = next(d for d in self.e_invoice_settings.credentials if d.gstin == gstin)
+ else:
+ credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
+ return credentials
+
+ def get_seller_gstin(self):
+ gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
+ if not gstin:
+ frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
+ return gstin
+
+ def get_auth_token(self):
+ if time_diff_in_seconds(self.e_invoice_settings.token_expiry, now_datetime()) < 150.0:
+ self.fetch_auth_token()
+
+ return self.e_invoice_settings.auth_token
+
+ def make_request(self, request_type, url, headers=None, data=None):
+ if request_type == 'post':
+ res = make_post_request(url, headers=headers, data=data)
+ else:
+ res = make_get_request(url, headers=headers, data=data)
+
+ self.log_request(url, headers, data, res)
+ return res
+
+ def log_request(self, url, headers, data, res):
+ headers.update({ 'password': self.credentials.password })
+ request_log = frappe.get_doc({
+ "doctype": "E Invoice Request Log",
+ "user": frappe.session.user,
+ "reference_invoice": self.invoice.name if self.invoice else None,
+ "url": url,
+ "headers": json.dumps(headers, indent=4) if headers else None,
+ "data": json.dumps(data, indent=4) if isinstance(data, dict) else data,
+ "response": json.dumps(res, indent=4) if res else None
+ })
+ request_log.save(ignore_permissions=True)
+ frappe.db.commit()
+
+ def fetch_auth_token(self):
+ headers = {
+ 'gspappid': frappe.conf.einvoice_client_id,
+ 'gspappsecret': frappe.conf.einvoice_client_secret
+ }
+ res = {}
+ try:
+ res = self.make_request('post', self.authenticate_url, headers)
+ self.e_invoice_settings.auth_token = "{} {}".format(res.get('token_type'), res.get('access_token'))
+ self.e_invoice_settings.token_expiry = add_to_date(None, seconds=res.get('expires_in'))
+ self.e_invoice_settings.save(ignore_permissions=True)
+ self.e_invoice_settings.reload()
+
+ except Exception:
+ self.log_error(res)
+ self.raise_error(True)
+
+ def get_headers(self):
+ return {
+ 'content-type': 'application/json',
+ 'user_name': self.credentials.username,
+ 'password': self.credentials.get_password(),
+ 'gstin': self.credentials.gstin,
+ 'authorization': self.get_auth_token(),
+ 'requestid': str(base64.b64encode(os.urandom(18))),
+ }
+
+ def fetch_gstin_details(self, gstin):
+ headers = self.get_headers()
+
+ try:
+ params = '?gstin={gstin}'.format(gstin=gstin)
+ res = self.make_request('get', self.gstin_details_url + params, headers)
+ if res.get('success'):
+ return res.get('result')
+ else:
+ self.log_error(res)
+ raise RequestFailed
+
+ except RequestFailed:
+ self.raise_error()
+
+ except Exception:
+ self.log_error()
+ self.raise_error(True)
+
+ @staticmethod
+ def get_gstin_details(gstin):
+ '''fetch and cache GSTIN details'''
+ if not hasattr(frappe.local, 'gstin_cache'):
+ frappe.local.gstin_cache = {}
+
+ key = gstin
+ gsp_connector = GSPConnector()
+ details = gsp_connector.fetch_gstin_details(gstin)
+
+ frappe.local.gstin_cache[key] = details
+ frappe.cache().hset('gstin_cache', key, details)
+ return details
+
+ def generate_irn(self):
+ headers = self.get_headers()
+ einvoice = make_einvoice(self.invoice)
+ data = json.dumps(einvoice, indent=4)
+
+ try:
+ res = self.make_request('post', self.generate_irn_url, headers, data)
+ if res.get('success'):
+ self.set_einvoice_data(res.get('result'))
+
+ elif '2150' in res.get('message'):
+ # IRN already generated but not updated in invoice
+ # Extract the IRN from the response description and fetch irn details
+ irn = res.get('result')[0].get('Desc').get('Irn')
+ irn_details = self.get_irn_details(irn)
+ if irn_details:
+ self.set_einvoice_data(irn_details)
+ else:
+ raise RequestFailed('IRN has already been generated for the invoice but cannot fetch details for the it. \
+ Contact ERPNext support to resolve the issue.')
+
+ else:
+ raise RequestFailed
+
+ except RequestFailed:
+ errors = self.sanitize_error_message(res.get('message'))
+ self.raise_error(errors=errors)
+
+ except Exception:
+ self.log_error(data)
+ self.raise_error(True)
+
+ def get_irn_details(self, irn):
+ headers = self.get_headers()
+
+ try:
+ params = '?irn={irn}'.format(irn=irn)
+ res = self.make_request('get', self.irn_details_url + params, headers)
+ if res.get('success'):
+ return res.get('result')
+ else:
+ raise RequestFailed
+
+ except RequestFailed:
+ errors = self.sanitize_error_message(res.get('message'))
+ self.raise_error(errors=errors)
+
+ except Exception:
+ self.log_error()
+ self.raise_error(True)
+
+ def cancel_irn(self, irn, reason, remark):
+ headers = self.get_headers()
+ data = json.dumps({
+ 'Irn': irn,
+ 'Cnlrsn': reason,
+ 'Cnlrem': remark
+ }, indent=4)
+
+ try:
+ res = self.make_request('post', self.cancel_irn_url, headers, data)
+ if res.get('success'):
+ self.invoice.irn_cancelled = 1
+ self.invoice.flags.updater_reference = {
+ 'doctype': self.invoice.doctype,
+ 'docname': self.invoice.name,
+ 'label': _('IRN Cancelled - {}').format(remark)
+ }
+ self.update_invoice()
+
+ else:
+ raise RequestFailed
+
+ except RequestFailed:
+ errors = self.sanitize_error_message(res.get('message'))
+ self.raise_error(errors=errors)
+
+ except Exception:
+ self.log_error(data)
+ self.raise_error(True)
+
+ def generate_eway_bill(self, **kwargs):
+ args = frappe._dict(kwargs)
+
+ headers = self.get_headers()
+ eway_bill_details = get_eway_bill_details(args)
+ data = json.dumps({
+ 'Irn': args.irn,
+ 'Distance': cint(eway_bill_details.distance),
+ 'TransMode': eway_bill_details.mode_of_transport,
+ 'TransId': eway_bill_details.gstin,
+ 'TransName': eway_bill_details.transporter,
+ 'TrnDocDt': eway_bill_details.document_date,
+ 'TrnDocNo': eway_bill_details.document_name,
+ 'VehNo': eway_bill_details.vehicle_no,
+ 'VehType': eway_bill_details.vehicle_type
+ }, indent=4)
+
+ try:
+ res = self.make_request('post', self.generate_ewaybill_url, headers, data)
+ if res.get('success'):
+ self.invoice.ewaybill = res.get('result').get('EwbNo')
+ self.invoice.eway_bill_cancelled = 0
+ self.invoice.update(args)
+ self.invoice.flags.updater_reference = {
+ 'doctype': self.invoice.doctype,
+ 'docname': self.invoice.name,
+ 'label': _('E-Way Bill Generated')
+ }
+ self.update_invoice()
+
+ else:
+ raise RequestFailed
+
+ except RequestFailed:
+ errors = self.sanitize_error_message(res.get('message'))
+ self.raise_error(errors=errors)
+
+ except Exception:
+ self.log_error(data)
+ self.raise_error(True)
+
+ def cancel_eway_bill(self, eway_bill, reason, remark):
+ headers = self.get_headers()
+ data = json.dumps({
+ 'ewbNo': eway_bill,
+ 'cancelRsnCode': reason,
+ 'cancelRmrk': remark
+ }, indent=4)
+ headers["username"] = headers["user_name"]
+ del headers["user_name"]
+ try:
+ res = self.make_request('post', self.cancel_ewaybill_url, headers, data)
+ if res.get('success'):
+ self.invoice.ewaybill = ''
+ self.invoice.eway_bill_cancelled = 1
+ self.invoice.flags.updater_reference = {
+ 'doctype': self.invoice.doctype,
+ 'docname': self.invoice.name,
+ 'label': _('E-Way Bill Cancelled - {}').format(remark)
+ }
+ self.update_invoice()
+
+ else:
+ raise RequestFailed
+
+ except RequestFailed:
+ errors = self.sanitize_error_message(res.get('message'))
+ self.raise_error(errors=errors)
+
+ except Exception:
+ self.log_error(data)
+ self.raise_error(True)
+
+ def sanitize_error_message(self, message):
+ '''
+ On validation errors, response message looks something like this:
+ message = '2174 : For inter-state transaction, CGST and SGST amounts are not applicable; only IGST amount is applicable,
+ 3095 : Supplier GSTIN is inactive'
+ we search for string between ':' to extract the error messages
+ errors = [
+ ': For inter-state transaction, CGST and SGST amounts are not applicable; only IGST amount is applicable, 3095 ',
+ ': Test'
+ ]
+ then we trim down the message by looping over errors
+ '''
+ errors = re.findall(': [^:]+', message)
+ for idx, e in enumerate(errors):
+ # remove colons
+ errors[idx] = errors[idx].replace(':', '').strip()
+ # if not last
+ if idx != len(errors) - 1:
+ # remove last 7 chars eg: ', 3095 '
+ errors[idx] = errors[idx][:-6]
+
+ return errors
+
+ def log_error(self, data={}):
+ if not isinstance(data, dict):
+ data = json.loads(data)
+
+ seperator = "--" * 50
+ err_tb = traceback.format_exc()
+ err_msg = str(sys.exc_info()[1])
+ data = json.dumps(data, indent=4)
+
+ message = "\n".join([
+ "Error", err_msg, seperator,
+ "Data:", data, seperator,
+ "Exception:", err_tb
+ ])
+ frappe.log_error(title=_('E Invoice Request Failed'), message=message)
+
+ def raise_error(self, raise_exception=False, errors=[]):
+ title = _('E Invoice Request Failed')
+ if errors:
+ frappe.throw(errors, title=title, as_list=1)
+ else:
+ link_to_error_list = '<a href="desk#List/Error Log/List?method=E Invoice Request Failed">Error Log</a>'
+ frappe.msgprint(
+ _('An error occurred while making e-invoicing request. Please check {} for more information.').format(link_to_error_list),
+ title=title,
+ raise_exception=raise_exception,
+ indicator='red'
+ )
+
+ def set_einvoice_data(self, res):
+ enc_signed_invoice = res.get('SignedInvoice')
+ dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
+
+ self.invoice.irn = res.get('Irn')
+ self.invoice.ewaybill = res.get('EwbNo')
+ self.invoice.signed_einvoice = dec_signed_invoice
+ self.invoice.signed_qr_code = res.get('SignedQRCode')
+
+ self.attach_qrcode_image()
+
+ self.invoice.flags.updater_reference = {
+ 'doctype': self.invoice.doctype,
+ 'docname': self.invoice.name,
+ 'label': _('IRN Generated')
+ }
+ self.update_invoice()
+
+ def attach_qrcode_image(self):
+ qrcode = self.invoice.signed_qr_code
+ doctype = self.invoice.doctype
+ docname = self.invoice.name
+ filename = 'QRCode_{}.png'.format(docname).replace(os.path.sep, "__")
+
+ qr_image = io.BytesIO()
+ url = qrcreate(qrcode, error='L')
+ url.png(qr_image, scale=2, quiet_zone=1)
+ _file = frappe.get_doc({
+ "doctype": "File",
+ "file_name": filename,
+ "attached_to_doctype": doctype,
+ "attached_to_name": docname,
+ "attached_to_field": "qrcode_image",
+ "is_private": 1,
+ "content": qr_image.getvalue()})
+ _file.save()
+ frappe.db.commit()
+ self.invoice.qrcode_image = _file.file_url
+
+ def update_invoice(self):
+ self.invoice.flags.ignore_validate_update_after_submit = True
+ self.invoice.flags.ignore_validate = True
+ self.invoice.save()
+
+
+def sanitize_for_json(string):
+ """Escape JSON specific characters from a string."""
+
+ # json.dumps adds double-quotes to the string. Indexing to remove them.
+ return json.dumps(string)[1:-1]
+
+@frappe.whitelist()
+def get_einvoice(doctype, docname):
+ invoice = frappe.get_doc(doctype, docname)
+ return make_einvoice(invoice)
+
+@frappe.whitelist()
+def generate_irn(doctype, docname):
+ gsp_connector = GSPConnector(doctype, docname)
+ gsp_connector.generate_irn()
+
+@frappe.whitelist()
+def cancel_irn(doctype, docname, irn, reason, remark):
+ gsp_connector = GSPConnector(doctype, docname)
+ gsp_connector.cancel_irn(irn, reason, remark)
+
+@frappe.whitelist()
+def generate_eway_bill(doctype, docname, **kwargs):
+ gsp_connector = GSPConnector(doctype, docname)
+ gsp_connector.generate_eway_bill(**kwargs)
+
+@frappe.whitelist()
+def cancel_eway_bill(doctype, docname, eway_bill, reason, remark):
+ gsp_connector = GSPConnector(doctype, docname)
+ gsp_connector.cancel_eway_bill(eway_bill, reason, remark)
diff --git a/erpnext/regional/india/gst_state_code_data.json b/erpnext/regional/india/gst_state_code_data.json
index ff88e0f..8481c27 100644
--- a/erpnext/regional/india/gst_state_code_data.json
+++ b/erpnext/regional/india/gst_state_code_data.json
@@ -168,5 +168,10 @@
"state_number": "37",
"state_code": "AD",
"state_name": "Andhra Pradesh (New)"
+ },
+ {
+ "state_number": "38",
+ "state_code": "LA",
+ "state_name": "Ladakh"
}
]
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index cbcd6e3..ee49aae 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -7,7 +7,7 @@
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
from erpnext.regional.india import states
-from erpnext.accounts.utils import get_fiscal_year
+from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
from frappe.utils import today
def setup(company=None, patch=True):
@@ -21,6 +21,7 @@
add_permissions()
add_custom_roles_for_reports()
frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test)
+ create_gratuity_rule()
add_print_formats()
def add_hsn_sac_codes():
@@ -87,7 +88,7 @@
)).insert()
def add_permissions():
- for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'):
+ for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate', 'E Invoice Settings'):
add_permission(doctype, 'All', 0)
for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
add_permission(doctype, role, 0)
@@ -103,9 +104,11 @@
def add_print_formats():
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
frappe.reload_doc("accounts", "print_format", "gst_pos_invoice")
+ frappe.reload_doc("accounts", "print_format", "GST E-Invoice")
- frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where
- name in('GST POS Invoice', 'GST Tax Invoice') """)
+ frappe.db.set_value("Print Format", "GST POS Invoice", "disabled", 0)
+ frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0)
+ frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0)
def make_custom_fields(update=True):
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
@@ -351,7 +354,6 @@
'label': 'Mode of Transport',
'fieldtype': 'Select',
'options': '\nRoad\nAir\nRail\nShip',
- 'default': 'Road',
'insert_after': 'transporter_name',
'print_hide': 1,
'translatable': 0
@@ -388,13 +390,34 @@
'fieldname': 'ewaybill',
'label': 'E-Way Bill No.',
'fieldtype': 'Data',
- 'depends_on': 'eval:(doc.docstatus === 1)',
+ 'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)',
'allow_on_submit': 1,
'insert_after': 'tax_id',
'translatable': 0
}
]
+ si_einvoice_fields = [
+ dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
+ depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
+
+ dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
+
+ dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
+
+ dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
+ depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+
+ dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
+ depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+
+ dict(fieldname='signed_einvoice', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
+
+ dict(fieldname='signed_qr_code', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
+
+ dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, no_copy=1, print_hide=1, read_only=1)
+ ]
+
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -407,7 +430,7 @@
'Purchase Invoice': purchase_invoice_gst_category + invoice_gst_fields + purchase_invoice_itc_fields + purchase_invoice_gst_fields,
'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,
+ 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields,
'Sales Order': sales_invoice_gst_fields,
'Tax Category': inter_state_gst_field,
@@ -477,6 +500,14 @@
fieldtype='Link', options='Salary Component', insert_after='basic_component'),
dict(fieldname='arrear_component', label='Arrear Component',
fieldtype='Link', options='Salary Component', insert_after='hra_component'),
+ dict(fieldname='non_profit_section', label='Non Profit Settings',
+ fieldtype='Section Break', insert_after='asset_received_but_not_billed', collapsible=1),
+ dict(fieldname='company_80g_number', label='80G Number',
+ fieldtype='Data', insert_after='non_profit_section'),
+ dict(fieldname='with_effect_from', label='80G With Effect From',
+ fieldtype='Date', insert_after='company_80g_number'),
+ dict(fieldname='pan_details', label='PAN Number',
+ fieldtype='Data', insert_after='with_effect_from')
],
'Employee Tax Exemption Declaration':[
dict(fieldname='hra_section', label='HRA Exemption',
@@ -559,7 +590,15 @@
'options': '\nWith Payment of Tax\nWithout Payment of Tax'
}
],
- "Member": [
+ 'Member': [
+ {
+ 'fieldname': 'pan_number',
+ 'label': 'PAN Details',
+ 'fieldtype': 'Data',
+ 'insert_after': 'email_id'
+ }
+ ],
+ 'Donor': [
{
'fieldname': 'pan_number',
'label': 'PAN Details',
@@ -608,13 +647,18 @@
def set_tax_withholding_category(company):
accounts = []
+ fiscal_year = None
abbr = frappe.get_value("Company", company, "abbr")
tds_account = frappe.get_value("Account", 'TDS Payable - {0}'.format(abbr), 'name')
if company and tds_account:
accounts = [dict(company=company, account=tds_account)]
- fiscal_year = get_fiscal_year(today(), company=company)[0]
+ try:
+ fiscal_year = get_fiscal_year(today(), verbose=0, company=company)[0]
+ except FiscalYearError:
+ pass
+
docs = get_tds_details(accounts, fiscal_year)
for d in docs:
@@ -629,11 +673,14 @@
if accounts:
doc.append("accounts", accounts[0])
- # 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]
- if not fy_exist:
- doc.append("rates", d.get('rates')[0])
+ if fiscal_year:
+ # 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]
+ if not fy_exist:
+ doc.append("rates", d.get('rates')[0])
+ doc.flags.ignore_permissions = True
+ doc.flags.ignore_mandatory = True
doc.save()
def set_tds_account(docs, company):
@@ -793,4 +840,24 @@
doctype="Tax Withholding Category", accounts=accounts,
rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
"single_threshold": 2500, "cumulative_threshold": 0}])
- ]
\ No newline at end of file
+ ]
+
+def create_gratuity_rule():
+
+ # Standard Indain Gratuity Rule
+ if not frappe.db.exists("Gratuity Rule", "Indian Standard Gratuity Rule"):
+ rule = frappe.new_doc("Gratuity Rule")
+ rule.name = "Indian Standard Gratuity Rule"
+ rule.calculate_gratuity_amount_based_on = "Current Slab"
+ rule.work_experience_calculation_method = "Round Off Work Experience"
+ rule.minimum_year_for_gratuity = 5
+
+ fraction = 15/26
+ rule.append("gratuity_rule_slabs", {
+ "from_year": 0,
+ "to_year":0,
+ "fraction_of_applicable_earnings": fraction
+ })
+
+ rule.flags.ignore_mandatory = True
+ rule.save()
\ No newline at end of file
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
index 3b6a28f..d3b7ea3 100644
--- a/erpnext/regional/india/taxes.js
+++ b/erpnext/regional/india/taxes.js
@@ -12,6 +12,9 @@
tax_category: function(frm) {
frm.trigger('get_tax_template');
},
+ customer_address: function(frm) {
+ frm.trigger('get_tax_template');
+ },
get_tax_template: function(frm) {
if (!frm.doc.company) return;
@@ -19,6 +22,7 @@
'shipping_address': frm.doc.shipping_address || '',
'shipping_address_name': frm.doc.shipping_address_name || '',
'customer_address': frm.doc.customer_address || '',
+ 'supplier_address': frm.doc.supplier_address,
'customer': frm.doc.customer,
'supplier': frm.doc.supplier,
'supplier_gstin': frm.doc.supplier_gstin,
@@ -31,19 +35,18 @@
args: {
party_details: JSON.stringify(party_details),
doctype: frm.doc.doctype,
- company: frm.doc.company,
- return_taxes: 1
+ company: frm.doc.company
},
+ debounce: 2000,
callback: function(r) {
if(r.message) {
frm.set_value('taxes_and_charges', r.message.taxes_and_charges);
- } else if (frm.doc.is_internal_supplier || frm.doc.is_internal_customer) {
- frm.set_value('taxes_and_charges', '');
- frm.set_value('taxes', []);
+ frm.set_value('taxes', r.message.taxes);
+ frm.set_value('place_of_supply', r.message.place_of_supply);
}
}
});
}
});
-};
+}
diff --git a/erpnext/regional/india/test_utils.py b/erpnext/regional/india/test_utils.py
new file mode 100644
index 0000000..7ce27f6
--- /dev/null
+++ b/erpnext/regional/india/test_utils.py
@@ -0,0 +1,38 @@
+from __future__ import unicode_literals
+
+import unittest
+import frappe
+from unittest.mock import patch
+from erpnext.regional.india.utils import validate_document_name
+
+
+class TestIndiaUtils(unittest.TestCase):
+ @patch("frappe.get_cached_value")
+ def test_validate_document_name(self, mock_get_cached):
+ mock_get_cached.return_value = "India" # mock country
+ posting_date = "2021-05-01"
+
+ invalid_names = [ "SI$1231", "012345678901234567", "SI 2020 05",
+ "SI.2020.0001", "PI2021 - 001" ]
+ for name in invalid_names:
+ doc = frappe._dict(name=name, posting_date=posting_date)
+ self.assertRaises(frappe.ValidationError, validate_document_name, doc)
+
+ valid_names = [ "012345678901236", "SI/2020/0001", "SI/2020-0001",
+ "2020-PI-0001", "PI2020-0001" ]
+ for name in valid_names:
+ doc = frappe._dict(name=name, posting_date=posting_date)
+ try:
+ validate_document_name(doc)
+ except frappe.ValidationError:
+ self.fail("Valid name {} throwing error".format(name))
+
+ @patch("frappe.get_cached_value")
+ def test_validate_document_name_not_india(self, mock_get_cached):
+ mock_get_cached.return_value = "Not India"
+ doc = frappe._dict(name="SI$123", posting_date="2021-05-01")
+
+ try:
+ validate_document_name(doc)
+ except frappe.ValidationError:
+ self.fail("Regional validation related to India are being applied to other countries")
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 69e47a4..3637de4 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -2,7 +2,7 @@
import frappe, re, json
from frappe import _
import erpnext
-from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words
+from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words, getdate
from erpnext.regional.india import states, state_numbers
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.controllers.accounts_controller import get_taxes_and_charges
@@ -12,6 +12,14 @@
from six import string_types
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.accounts.utils import get_account_currency
+from frappe.model.utils import get_fetch_values
+
+
+GST_INVOICE_NUMBER_FORMAT = re.compile(r"^[a-zA-Z0-9\-/]+$") #alphanumeric and - /
+GSTIN_FORMAT = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
+GSTIN_UIN_FORMAT = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
+PAN_NUMBER_FORMAT = re.compile("[A-Z]{5}[0-9]{4}[A-Z]{1}")
+
def validate_gstin_for_india(doc, method):
if hasattr(doc, 'gst_state') and doc.gst_state:
@@ -36,21 +44,36 @@
frappe.throw(_("Invalid GSTIN! A GSTIN must have 15 characters."))
if gst_category and gst_category == 'UIN Holders':
- p = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
- if not p.match(doc.gstin):
+ if not GSTIN_UIN_FORMAT.match(doc.gstin):
frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers"))
else:
- p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
- if not p.match(doc.gstin):
+ if not GSTIN_FORMAT.match(doc.gstin):
frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN."))
validate_gstin_check_digit(doc.gstin)
set_gst_state_and_state_number(doc)
+ if not doc.gst_state:
+ frappe.throw(_("Please Enter GST state"))
+
if doc.gst_state_number != doc.gstin[:2]:
frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
.format(doc.gst_state_number))
+def validate_pan_for_india(doc, method):
+ if doc.get('country') != 'India' or not doc.pan:
+ return
+
+ if not PAN_NUMBER_FORMAT.match(doc.pan):
+ frappe.throw(_("Invalid PAN No. The input you've entered doesn't match the format of PAN."))
+
+def validate_tax_category(doc, method):
+ if doc.get('gst_state') and frappe.db.get_value('Tax Category', {'gst_state': doc.gst_state, 'is_inter_state': doc.is_inter_state}):
+ if doc.is_inter_state:
+ frappe.throw(_("Inter State tax category for GST State {0} already exists").format(doc.gst_state))
+ else:
+ frappe.throw(_("Intra State tax category for GST State {0} already exists").format(doc.gst_state))
+
def update_gst_category(doc, method):
for link in doc.links:
if link.link_doctype in ['Customer', 'Supplier']:
@@ -85,8 +108,7 @@
total += digit
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
- frappe.throw(_("""Invalid {0}! The check digit validation has failed.
- Please ensure you've typed the {0} correctly.""".format(label)))
+ 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'):
@@ -130,6 +152,20 @@
def set_place_of_supply(doc, method=None):
doc.place_of_supply = get_place_of_supply(doc, doc.doctype)
+def validate_document_name(doc, method=None):
+ """Validate GST invoice number requirements."""
+ country = frappe.get_cached_value("Company", doc.company, "country")
+
+ # Date was chosen as start of next FY to avoid irritating current users.
+ if country != "India" or getdate(doc.posting_date) < getdate("2021-04-01"):
+ return
+
+ if len(doc.name) > 16:
+ frappe.throw(_("Maximum length of document number should be 16 characters as per GST rules. Please change the naming series."))
+
+ if not GST_INVOICE_NUMBER_FORMAT.match(doc.name):
+ frappe.throw(_("Document name should only contain alphanumeric values, dash(-) and slash(/) characters as per GST rules. Please change the naming series."))
+
# don't remove this function it is used in tests
def test_method():
'''test function'''
@@ -139,7 +175,7 @@
if not frappe.get_meta('Address').has_field('gst_state'): return
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
- address_name = party_details.shipping_address_name or party_details.customer_address
+ address_name = party_details.customer_address or party_details.shipping_address_name
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
address_name = party_details.shipping_address or party_details.supplier_address
@@ -150,17 +186,19 @@
return cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
@frappe.whitelist()
-def get_regional_address_details(party_details, doctype, company, return_taxes=None):
+def get_regional_address_details(party_details, doctype, company):
if isinstance(party_details, string_types):
party_details = json.loads(party_details)
party_details = frappe._dict(party_details)
+ update_party_details(party_details, doctype)
+
party_details.place_of_supply = get_place_of_supply(party_details, doctype)
if is_internal_transfer(party_details, doctype):
party_details.taxes_and_charges = ''
- party_details.taxes = ''
- return
+ party_details.taxes = []
+ return party_details
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
master_doctype = "Sales Taxes and Charges Template"
@@ -168,26 +206,26 @@
get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges') and return_taxes:
+ if party_details.get('taxes_and_charges'):
return party_details
if not party_details.company_gstin:
- return
+ return party_details
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
master_doctype = "Purchase Taxes and Charges Template"
get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
get_tax_template_based_on_category(master_doctype, company, party_details)
- if party_details.get('taxes_and_charges') and return_taxes:
+ if party_details.get('taxes_and_charges'):
return party_details
if not party_details.supplier_gstin:
- return
+ return party_details
- if not party_details.place_of_supply: return
+ if not party_details.place_of_supply: return party_details
- if not party_details.company_gstin: return
+ if not party_details.company_gstin: return party_details
if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
@@ -197,12 +235,16 @@
default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
if not default_tax:
- return
+ return party_details
party_details["taxes_and_charges"] = default_tax
party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
- if return_taxes:
- return party_details
+ return party_details
+
+def update_party_details(party_details, doctype):
+ for address_field in ['shipping_address', 'company_address', 'supplier_address', 'shipping_address_name', 'customer_address']:
+ if party_details.get(address_field):
+ party_details.update(get_fetch_values(doctype, address_field, party_details.get(address_field)))
def is_internal_transfer(party_details, doctype):
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
@@ -236,7 +278,7 @@
if tax_category.gst_state == number_state_mapping[state_code] or \
(not default_tax and not tax_category.gst_state):
default_tax = frappe.db.get_value(master_doctype,
- {'disabled': 0, 'tax_category': tax_category.name}, 'name')
+ {'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
return default_tax
def get_tax_template_for_sez(party_details, master_doctype, company, party_type):
@@ -517,6 +559,9 @@
data.actualToStateCode = data.toStateCode
shipping_address = billing_address
+ if doc.gst_category == 'SEZ':
+ data.toStateCode = 99
+
return data
def get_item_list(data, doc):
@@ -674,25 +719,12 @@
if country != 'India':
return
- if not doc.total_taxes_and_charges:
+ gst_tax, base_gst_tax = get_gst_tax_amount(doc)
+
+ if not base_gst_tax:
return
if doc.reverse_charge == 'Y':
- gst_accounts = get_gst_accounts(doc.company)
- gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
- + gst_accounts.get('igst_account')
-
- base_gst_tax = 0
- gst_tax = 0
-
- for tax in doc.get('taxes'):
- if tax.category not in ("Total", "Valuation and Total"):
- continue
-
- if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
- base_gst_tax += tax.base_tax_amount_after_discount_amount
- gst_tax += tax.tax_amount_after_discount_amount
-
doc.taxes_and_charges_added -= gst_tax
doc.total_taxes_and_charges -= gst_tax
doc.base_taxes_and_charges_added -= base_gst_tax
@@ -726,6 +758,11 @@
if country != 'India':
return gl_entries
+ gst_tax, base_gst_tax = get_gst_tax_amount(doc)
+
+ if not base_gst_tax:
+ return gl_entries
+
if doc.reverse_charge == 'Y':
gst_accounts = get_gst_accounts(doc.company)
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
@@ -752,4 +789,46 @@
}, account_currency, item=tax)
)
- return gl_entries
\ No newline at end of file
+ return gl_entries
+
+def get_gst_tax_amount(doc):
+ gst_accounts = get_gst_accounts(doc.company)
+ gst_account_list = gst_accounts.get('cgst_account', []) + gst_accounts.get('sgst_account', []) \
+ + gst_accounts.get('igst_account', [])
+
+ base_gst_tax = 0
+ gst_tax = 0
+
+ for tax in doc.get('taxes'):
+ if tax.category not in ("Total", "Valuation and Total"):
+ continue
+
+ if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
+ base_gst_tax += tax.base_tax_amount_after_discount_amount
+ gst_tax += tax.tax_amount_after_discount_amount
+
+ return gst_tax, base_gst_tax
+
+@frappe.whitelist()
+def get_regional_round_off_accounts(company, account_list):
+ country = frappe.get_cached_value('Company', company, 'country')
+
+ if country != 'India':
+ return
+
+ if isinstance(account_list, string_types):
+ account_list = json.loads(account_list)
+
+ if not frappe.db.get_single_value('GST Settings', 'round_off_gst_values'):
+ return
+
+ gst_accounts = get_gst_accounts(company)
+
+ gst_account_list = []
+ for account in ['cgst_account', 'sgst_account', 'igst_account']:
+ if account in gst_accounts:
+ gst_account_list += gst_accounts.get(account)
+
+ account_list.extend(gst_account_list)
+
+ return account_list
diff --git a/erpnext/regional/italy/sales_invoice.js b/erpnext/regional/italy/sales_invoice.js
index 586a529..b54ac53 100644
--- a/erpnext/regional/italy/sales_invoice.js
+++ b/erpnext/regional/italy/sales_invoice.js
@@ -11,15 +11,10 @@
callback: function(r) {
frm.reload_doc();
if(r.message) {
- var w = window.open(
- frappe.urllib.get_full_url(
- "/api/method/erpnext.regional.italy.utils.download_e_invoice_file?"
- + "file_name=" + r.message
- )
- )
- if (!w) {
- frappe.msgprint(__("Please enable pop-ups")); return;
- }
+ open_url_post(frappe.request.url, {
+ cmd: 'frappe.core.doctype.file.file.download_file',
+ file_url: r.message
+ });
}
}
});
diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py
index 6ab7341..a1f5bb9 100644
--- a/erpnext/regional/italy/setup.py
+++ b/erpnext/regional/italy/setup.py
@@ -127,12 +127,9 @@
options="\n".join(map(lambda x: frappe.safe_decode(x, encoding='utf-8'), vat_collectability_options)),
fetch_from="company.vat_collectability"),
dict(fieldname='sb_e_invoicing_reference', label='E-Invoicing',
- fieldtype='Section Break', insert_after='pos_total_qty', print_hide=1),
- dict(fieldname='company_tax_id', label='Company Tax ID',
- fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1,
- fetch_from="company.tax_id"),
+ fieldtype='Section Break', insert_after='against_income_account', print_hide=1),
dict(fieldname='company_fiscal_code', label='Company Fiscal Code',
- fieldtype='Data', insert_after='company_tax_id', print_hide=1, read_only=1,
+ fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1,
fetch_from="company.fiscal_code"),
dict(fieldname='company_fiscal_regime', label='Company Fiscal Regime',
fieldtype='Data', insert_after='company_fiscal_code', print_hide=1, read_only=1,
@@ -189,9 +186,7 @@
def setup_report():
report_name = 'Electronic Invoice Register'
-
- frappe.db.sql(""" update `tabReport` set disabled = 0 where
- name = %s """, report_name)
+ frappe.db.set_value("Report", report_name, "disabled", 0)
if not frappe.db.get_value('Custom Role', dict(report=report_name)):
frappe.get_doc(dict(
@@ -219,4 +214,4 @@
update_permission_property(doctype, 'Accounts Manager', 0, 'delete', 1)
add_permission(doctype, 'Accounts Manager', 1)
update_permission_property(doctype, 'Accounts Manager', 1, 'write', 1)
- update_permission_property(doctype, 'Accounts Manager', 1, 'create', 1)
\ No newline at end of file
+ update_permission_property(doctype, 'Accounts Manager', 1, 'create', 1)
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index 6842fb2..08573cd 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
-import frappe, json, os
+import io
+import json
+import frappe
from frappe.utils import flt, cstr
from erpnext.controllers.taxes_and_totals import get_itemised_tax
from frappe import _
@@ -28,20 +30,22 @@
@frappe.whitelist()
def export_invoices(filters=None):
- saved_xmls = []
+ frappe.has_permission('Sales Invoice', throw=True)
- invoices = frappe.get_all("Sales Invoice", filters=get_conditions(filters), fields=["*"])
+ invoices = frappe.get_all(
+ "Sales Invoice",
+ filters=get_conditions(filters),
+ fields=["name", "company_tax_id"]
+ )
- for invoice in invoices:
- attachments = get_e_invoice_attachments(invoice)
- saved_xmls += [attachment.file_name for attachment in attachments]
+ attachments = get_e_invoice_attachments(invoices)
- zip_filename = "{0}-einvoices.zip".format(frappe.utils.get_datetime().strftime("%Y%m%d_%H%M%S"))
+ zip_filename = "{0}-einvoices.zip".format(
+ frappe.utils.get_datetime().strftime("%Y%m%d_%H%M%S"))
- download_zip(saved_xmls, zip_filename)
+ download_zip(attachments, zip_filename)
-@frappe.whitelist()
def prepare_invoice(invoice, progressive_number):
#set company information
company = frappe.get_doc("Company", invoice.company)
@@ -98,7 +102,7 @@
def get_conditions(filters):
filters = json.loads(filters)
- conditions = {"docstatus": 1}
+ conditions = {"docstatus": 1, "company_tax_id": ("!=", "")}
if filters.get("company"): conditions["company"] = filters["company"]
if filters.get("customer"): conditions["customer"] = filters["customer"]
@@ -111,23 +115,22 @@
return conditions
-#TODO: Use function from frappe once PR #6853 is merged.
+
def download_zip(files, output_filename):
- from zipfile import ZipFile
+ import zipfile
- input_files = [frappe.get_site_path('private', 'files', filename) for filename in files]
- output_path = frappe.get_site_path('private', 'files', output_filename)
+ zip_stream = io.BytesIO()
+ with zipfile.ZipFile(zip_stream, 'w', zipfile.ZIP_DEFLATED) as zip_file:
+ for file in files:
+ file_path = frappe.utils.get_files_path(
+ file.file_name, is_private=file.is_private)
- with ZipFile(output_path, 'w') as output_zip:
- for input_file in input_files:
- output_zip.write(input_file, arcname=os.path.basename(input_file))
-
- with open(output_path, 'rb') as fileobj:
- filedata = fileobj.read()
+ zip_file.write(file_path, arcname=file.file_name)
frappe.local.response.filename = output_filename
- frappe.local.response.filecontent = filedata
+ frappe.local.response.filecontent = zip_stream.getvalue()
frappe.local.response.type = "download"
+ zip_stream.close()
def get_invoice_summary(items, taxes):
summary_data = frappe._dict()
@@ -307,23 +310,12 @@
@frappe.whitelist()
def generate_single_invoice(docname):
doc = frappe.get_doc("Sales Invoice", docname)
-
+ frappe.has_permission("Sales Invoice", doc=doc, throw=True)
e_invoice = prepare_and_attach_invoice(doc, True)
+ return e_invoice.file_url
- return e_invoice.file_name
-
-@frappe.whitelist()
-def download_e_invoice_file(file_name):
- content = None
- with open(frappe.get_site_path('private', 'files', file_name), "r") as f:
- content = f.read()
-
- frappe.local.response.filename = file_name
- frappe.local.response.filecontent = content
- frappe.local.response.type = "download"
-
-#Delete e-invoice attachment on cancel.
+# Delete e-invoice attachment on cancel.
def sales_invoice_on_cancel(doc, method):
if get_company_country(doc.company) not in ['Italy',
'Italia', 'Italian Republic', 'Repubblica Italiana']:
@@ -335,16 +327,38 @@
def get_company_country(company):
return frappe.get_cached_value('Company', company, 'country')
-def get_e_invoice_attachments(invoice):
- if not invoice.company_tax_id:
- return []
+def get_e_invoice_attachments(invoices):
+ if not isinstance(invoices, list):
+ if not invoices.company_tax_id:
+ return
+
+ invoices = [invoices]
+
+ tax_id_map = {
+ invoice.name: (
+ invoice.company_tax_id
+ if invoice.company_tax_id.startswith("IT")
+ else "IT" + invoice.company_tax_id
+ ) for invoice in invoices
+ }
+
+ attachments = frappe.get_all(
+ "File",
+ fields=("name", "file_name", "attached_to_name", "is_private"),
+ filters= {
+ "attached_to_name": ('in', tax_id_map),
+ "attached_to_doctype": 'Sales Invoice'
+ }
+ )
out = []
- attachments = get_attachments(invoice.doctype, invoice.name)
- company_tax_id = invoice.company_tax_id if invoice.company_tax_id.startswith("IT") else "IT" + invoice.company_tax_id
-
for attachment in attachments:
- if attachment.file_name and attachment.file_name.startswith(company_tax_id) and attachment.file_name.endswith(".xml"):
+ if (
+ attachment.file_name
+ and attachment.file_name.endswith(".xml")
+ and attachment.file_name.startswith(
+ tax_id_map.get(attachment.attached_to_name))
+ ):
out.append(attachment)
return out
diff --git a/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json b/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json
new file mode 100644
index 0000000..a8da0bd
--- /dev/null
+++ b/erpnext/regional/print_format/80g_certificate_for_donation/80g_certificate_for_donation.json
@@ -0,0 +1,26 @@
+{
+ "absolute_value": 0,
+ "align_labels_right": 0,
+ "creation": "2021-02-22 00:17:33.878581",
+ "css": ".details {\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n line-height: 150%;\n}\n\n.certificate-footer {\n font-size: 15px;\n font-family: Tahoma, sans-serif;\n line-height: 140%;\n margin-top: 120px;\n}\n\n.company-address {\n color: #666666;\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n}",
+ "custom_format": 1,
+ "default_print_language": "en",
+ "disabled": 0,
+ "doc_type": "Tax Exemption 80G Certificate",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "{% if letter_head and not no_letterhead -%}\n <div class=\"letter-head\">{{ letter_head }}</div>\n{%- endif %}\n\n<div>\n <h3 class=\"text-center\">{{ doc.company }} 80G Donor Certificate</h3>\n</div>\n<br><br>\n\n<div class=\"details\">\n <p> <b>{{ _(\"Certificate No. : \") }}</b> {{ doc.name }} </p>\n <p>\n \t<b>{{ _(\"Date\") }} :</b> {{ doc.get_formatted(\"date\") }}<br>\n </p>\n <br><br>\n \n <div>\n\n This is to confirm that the {{ doc.company }} received an amount of <b>{{doc.get_formatted(\"amount\")}}</b>\n from <b>{{ doc.donor_name }}</b>\n {% if doc.pan_number -%}\n bearing PAN Number {{ doc.member_pan_number }}\n {%- endif %}\n\n via the Mode of Payment {{doc.mode_of_payment}}\n\n {% if doc.razorpay_payment_id -%}\n bearing RazorPay Payment ID {{ doc.razorpay_payment_id }}\n {%- endif %}\n\n on {{ doc.get_formatted(\"date_of_donation\") }}\n <br><br>\n \n <p>\n We thank you for your contribution towards the corpus of the {{ doc.company }} and helping support our work.\n </p>\n\n </div>\n</div>\n\n<br><br>\n<p class=\"company-address text-left\"> {{doc.company_address_display }}</p>\n\n<div class=\"certificate-footer text-center\">\n <p><i>Computer generated receipt - Does not require signature</i></p><br>\n \n {% if doc.company_pan_number %}\n <p>\n <b>{{ doc.company }}'s PAN Account No :</b> {{ doc.company_pan_number }}\n <p><br>\n {% endif %}\n \n <p>\n <b>80G Number : </b> {{ doc.company_80g_number }}\n {% if doc.company_80g_wef %}\n ( w.e.f. {{ doc.get_formatted('company_80g_wef') }} )\n {% endif %}\n </p><br>\n</div>",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2021-02-22 00:20:08.516600",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "80G Certificate for Donation",
+ "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/accounts/page/bank_reconciliation/__init__.py b/erpnext/regional/print_format/80g_certificate_for_donation/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/regional/print_format/80g_certificate_for_donation/__init__.py
diff --git a/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json b/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json
new file mode 100644
index 0000000..f1b15aa
--- /dev/null
+++ b/erpnext/regional/print_format/80g_certificate_for_membership/80g_certificate_for_membership.json
@@ -0,0 +1,26 @@
+{
+ "absolute_value": 0,
+ "align_labels_right": 0,
+ "creation": "2021-02-15 16:53:55.026611",
+ "css": ".details {\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n line-height: 150%;\n}\n\n.certificate-footer {\n font-size: 15px;\n font-family: Tahoma, sans-serif;\n line-height: 140%;\n margin-top: 120px;\n}\n\n.company-address {\n color: #666666;\n font-size: 15px;\n font-family: Tahoma, sans-serif;;\n}",
+ "custom_format": 1,
+ "default_print_language": "en",
+ "disabled": 0,
+ "doc_type": "Tax Exemption 80G Certificate",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "{% if letter_head and not no_letterhead -%}\n <div class=\"letter-head\">{{ letter_head }}</div>\n{%- endif %}\n\n<div>\n <h3 class=\"text-center\">{{ doc.company }} Members 80G Donor Certificate</h3>\n <h3 class=\"text-center\">Financial Cycle {{ doc.fiscal_year }}</h3>\n</div>\n<br><br>\n\n<div class=\"details\">\n <p> <b>{{ _(\"Certificate No. : \") }}</b> {{ doc.name }} </p>\n <p>\n \t<b>{{ _(\"Date\") }} :</b> {{ doc.get_formatted(\"date\") }}<br>\n </p>\n <br><br>\n \n <div>\n This is to confirm that the {{ doc.company }} received a total amount of <b>{{doc.get_formatted(\"total\")}}</b>\n from <b>{{ doc.member_name }}</b>\n {% if doc.pan_number -%}\n bearing PAN Number {{ doc.member_pan_number }}\n {%- endif %}\n as per the payment details given below:\n \n <br><br>\n <table class=\"table table-bordered table-condensed\">\n \t<thead>\n \t\t<tr>\n \t\t\t<th >{{ _(\"Date\") }}</th>\n \t\t\t<th class=\"text-right\">{{ _(\"Amount\") }}</th>\n \t\t\t<th class=\"text-right\">{{ _(\"Invoice ID\") }}</th>\n \t\t</tr>\n \t</thead>\n \t<tbody>\n \t\t{%- for payment in doc.payments -%}\n \t\t<tr>\n \t\t\t<td> {{ payment.date }} </td>\n \t\t\t<td class=\"text-right\">{{ payment.get_formatted(\"amount\") }}</td>\n \t\t\t<td class=\"text-right\">{{ payment.invoice_id }}</td>\n \t\t</tr>\n \t\t{%- endfor -%}\n \t</tbody>\n </table>\n \n <br>\n \n <p>\n We thank you for your contribution towards the corpus of the {{ doc.company }} and helping support our work.\n </p>\n\n </div>\n</div>\n\n<br><br>\n<p class=\"company-address text-left\"> {{doc.company_address_display }}</p>\n\n<div class=\"certificate-footer text-center\">\n <p><i>Computer generated receipt - Does not require signature</i></p><br>\n \n {% if doc.company_pan_number %}\n <p>\n <b>{{ doc.company }}'s PAN Account No :</b> {{ doc.company_pan_number }}\n <p><br>\n {% endif %}\n \n <p>\n <b>80G Number : </b> {{ doc.company_80g_number }}\n {% if doc.company_80g_wef %}\n ( w.e.f. {{ doc.get_formatted('company_80g_wef') }} )\n {% endif %}\n </p><br>\n</div>",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2021-02-21 23:29:00.778973",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "80G Certificate for Membership",
+ "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/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/regional/print_format/80g_certificate_for_membership/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/regional/print_format/80g_certificate_for_membership/__init__.py
diff --git a/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json b/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json
index ce8c44a..e59700f 100644
--- a/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json
+++ b/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json
@@ -1,23 +1,26 @@
-[
- {
- "align_labels_right": 0,
- "css": "",
- "custom_format": 1,
- "default_print_language": "en",
- "disabled": 0,
- "doc_type": "Supplier",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>TAX Invoice<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name_in_arabic\", \"label\": \"Customer Name in Arabic\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_trn\", \"label\": \"Company TRN\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_code\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"charge_type\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"row_id\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"account_head\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"cost_center\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount_after_discount_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_total\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_tax_amount_after_discount_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"item_wise_tax_detail\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"align\": \"left\", \"label\": \"In Words\"}]",
- "html": "<div id=\"copy_a\" style=\"position: relative; top:0cm; width:17cm;height:28.0cm;\">\n <table>\n <tbody>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:86mm\" colspan=\"4\"; rowspan=\"3\">PAYER'S name, street address, city or town, state or province, country, ZIP<br>or foreign postal code, and telephone no.<br>\n\t{{company if company else \"\"}}<br>\n\t{{payer_street_address if payer_street_address else \"\"}}\n</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">1 Rents</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:25mm\" rowspan=\"2\">OMB No. 1545-0115<br><yone>20</yone><ytwo>18</ytwo><br>Form 1099-MISC</td>\n <td class=\"lbs bbs\" style=\"width:38mm\" colspan=\"2\" rowspan=\"2\">Miscellaneous Income</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">2 Royalties</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\" >3 Other Income<br>\n\t{{payments if payments else \"\"}}\n\t</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">4 Federal Income tax withheld</td>\n <td class=\"tbs lbs bbs\" style=\"width:29mm\" rowspan=\"2\">Copy A<br>For<br>Internal Revenue<br>Service Center<br><br>File with Form 1096</td>\n </tr>\n <tr style=\"height:16mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:43mm\">PAYER'S TIN<br>\n\t{{company_tin if company_tin else \"\"}}\n\t</td>\n \n <td class=\"tbs rbs lbs bbs\" colspan=\"3\">RECIPIENT'S TIN<br><br>\n {{tax_id if tax_id else \"None\"}}\n</td>\n <td class=\"tbs rbs lbs bbs\" >Fishing boat proceeds</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">6 Medical and health care payments</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\">RECIPIENT'S name <br>\n {{supplier if supplier else \"\"}}\n </td>\n <td class=\"tbs rbs lbs bbs\" >7 Nonemployee compensation<br>\n\t</td> \n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Substitute payments in lieu of dividends or interest</td>\n <td class=\"tbs lbs bbs\" rowspan=\"6\">For Privacy Act<br>and Paperwork<br>Reduction Act<br>Notice, see the<br>2018 General<br>Instructions for<br>Certain<br>Information<br>Returns.</td>\n </tr>\n <tr style=\"height:6mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">Street address (including apt. no.)<br>\n\t{{recipient_street_address if recipient_street_address else \"\"}}\n\t</td>\n <td class=\"tbs rbs lbs bbs\" >$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:7mm\">\n <td class=\"tbs rbs lbs bbs\" rowspan=\"2\">9 Payer made direct sales of<br>$5,000 or more of consumer products<br>to a buyer<br>(recipient) for resale</td>\n <td class=\"tbs rbs lbs\" colspan=\"2\">10 Crop insurance proceeds</td>\n </tr>\n <tr style=\"height:5mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">City or town, state or province, country, and ZIP or foreign postal code<br>\n\t{{recipient_city_state if recipient_city_state else \"\"}}\n</td>\n <td style=\"vertical-align:bottom\" class=\" rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\" >11</td>\n <td class=\"tbs rbs lbs bbs\" colspan=2>12</td>\n </tr>\n <tr style=\"height:13mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Account number (see instructions)</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:16mm\">FACTA filing<br>requirement</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:14mm\">2nd TIN not.</td>\n <td class=\"tbs rbs lbs bbs\" >13 Excess golden parachute payments<br>$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">14 Gross proceeds paid to an<br>attorney<br>$___________</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs \" >15a Section 409A deferrals</td>\n <td class=\"tbs rbs lbs \" colspan=\"3\">15b Section 409 income</td>\n <td class=\"tbs rbs lbs \" >16 State tax withheld</td>\n <td class=\"tbs rbs lbs \" colspan=\"2\">17 State/Payer's state no.</td>\n <td class=\"tbs lbs\" >18 State income</td>\n </tr>\n <tr>\n <td class=\"lbs rbs bbs\">$</td>\n <td class=\"lbs rbs bbs\" colspan=\"3\">$</td>\n <td class=\"lbs rbs bbs tbd\">$</td>\n <td class=\"lbs rbs bbs tbd\" colspan=\"2\"></td>\n <td class=\"lbs bbs tbd\">$</td>\n </tr>\n\n <tr style=\"height:8mm\">\n <td class=\"tbs\" colspan=\"8\">Form 1099-MISC Cat. No. 14425J www.irs.gov/Form1099MISC Department of the Treasury - Internal Revenue Service</td>\n </tr>\n\n </tbody>\n</table>\n</div>\n<div id=\"copy_1\" style=\"position: relative; top:0cm; width:17cm;height:28.0cm;\">\n <table>\n <tbody>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:86mm\" colspan=\"4\"; rowspan=\"3\">PAYER'S name, street address, city or town, state or province, country, ZIP<br>or foreign postal code, and telephone no.<br>\n {{company if company else \"\"}}<br>\n \t{{payer_street_address if payer_street_address else \"\"}}</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">1 Rents</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:25mm\" rowspan=\"2\">OMB No. 1545-0115<br><yone>20</yone><ytwo>18</ytwo><br>Form 1099-MISC</td>\n <td class=\"lbs bbs\" style=\"width:38mm\" colspan=\"2\" rowspan=\"2\">Miscellaneous Income</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">2 Royalties</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\" >3 Other Income<br>\n\t{{payments if payments else \"\"}}\n\t</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">4 Federal Income tax withheld</td>\n <td class=\"tbs lbs bbs\" style=\"width:29mm\" rowspan=\"2\">Copy 1<br>For State Tax<br>Department</td>\n </tr>\n <tr style=\"height:16mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:43mm\">PAYER'S TIN<br>\n\t{{company_tin if company_tin else \"\"}}\n\t</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"3\">RECIPIENT'S TIN<br>\n\t{{tax_id if tax_id else \"\"}}\n\t</td>\n <td class=\"tbs rbs lbs bbs\" >Fishing boat proceeds</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">6 Medical and health care payments</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\">RECIPIENT'S name</td>\n {{supplier if supplier else \"\"}}\n <td class=\"tbs rbs lbs bbs\" >7 Nonemployee compensation<br>\n\t</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Substitute payments in lieu of dividends or interest</td>\n <td class=\"tbs lbs bbs\" rowspan=\"6\"></td>\n </tr>\n <tr style=\"height:6mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">Street address (including apt. no.)<br>\n\t{{recipient_street_address if recipient_street_address else \"\"}}\n\t</td>\n <td class=\"tbs rbs lbs bbs\" >$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:7mm\">\n <td class=\"tbs rbs lbs bbs\" rowspan=\"2\">9 Payer made direct sales of<br>$5,000 or more of consumer products<br>to a buyer<br>(recipient) for resale</td>\n <td class=\"tbs rbs lbs\" colspan=\"2\">10 Crop insurance proceeds</td>\n </tr>\n <tr style=\"height:5mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">City or town, state or province, country, and ZIP or foreign postal code<br>\n\t{{recipient_city_state if recipient_city_state else \"\"}}\n\t</td>\n <td style=\"vertical-align:bottom\" class=\" rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\" >11</td>\n <td class=\"tbs rbs lbs bbs\" colspan=2>12</td>\n </tr>\n <tr style=\"height:13mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Account number (see instructions)</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:16mm\">FACTA filing<br>requirement</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:14mm\">2nd TIN not.</td>\n <td class=\"tbs rbs lbs bbs\" >13 Excess golden parachute payments<br>$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">14 Gross proceeds paid to an<br>attorney<br>$___________</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs \" >15a Section 409A deferrals</td>\n <td class=\"tbs rbs lbs \" colspan=\"3\">15b Section 409 income</td>\n <td class=\"tbs rbs lbs \" >16 State tax withheld</td>\n <td class=\"tbs rbs lbs \" colspan=\"2\">17 State/Payer's state no.</td>\n <td class=\"tbs lbs\" >18 State income</td>\n </tr>\n <tr>\n <td class=\"lbs rbs bbs\">$</td>\n <td class=\"lbs rbs bbs\" colspan=\"3\">$</td>\n <td class=\"lbs rbs bbs tbd\">$</td>\n <td class=\"lbs rbs bbs tbd\" colspan=\"2\"></td>\n <td class=\"lbs bbs tbd\">$</td>\n </tr>\n\n <tr style=\"height:8mm\">\n <td class=\"tbs\" colspan=\"8\">Form 1099-MISC Cat. No. 14425J www.irs.gov/Form1099MISC Department of the Treasury - Internal Revenue Service</td>\n </tr>\n\n </tbody>\n</table>\n</div>\n<style>\nbody {\n font-family: 'Helvetica', sans-serif;\n font-size: 5.66pt;\n}\nyone {\n font-family: 'Helvetica', sans-serif;\n font-size: 14pt;\n color: black;\n -webkit-text-fill-color: white; /* Will override color (regardless of order) */\n -webkit-text-stroke-width: 1px;\n -webkit-text-stroke-color: black;\n}\nytwo {\n font-family: 'Helvetica', sans-serif;\n font-size: 14pt;\n color: black;\n -webkit-text-stroke-width: 1px;\n -webkit-text-stroke-color: black;\n}\n\ntable, th, td {\n font-family: 'Helvetica', sans-serif;\n font-size: 5.66pt;\n border: none;\n}\n\n.tbs {\n border-top: 1px solid black;\n}\n\n.bbs {\n border-bottom: 1px solid black;\n}\n.lbs {\n border-left: 1px solid black;\n}\n.rbs {\n border-right: 1px solid black;\n}\n.allBorder {\n border-top: 1px solid black;\n border-right: 1px solid black;\n border-left: 1px solid black;\n borter-bottom: 1px solid black;\n}\n.bottomBorderOnlyDashed {\n\tborder-bottom: 1px dashed black;\n}\n.tbd {\n\tborder-top: 1px dashed black;\n}\n.address {\n\tvertical-align: bottom;\n}\n</style>",
- "line_breaks": 0,
- "modified": "2018-10-08 14:56:56.912851",
- "module": "Regional",
- "name": "IRS 1099 Form",
- "print_format_builder": 1,
- "print_format_type": "Server",
- "show_section_headings": 0,
- "standard": "No"
- }
-]
+{
+ "align_labels_right": 0,
+ "creation": "2020-11-09 16:01:26.096002",
+ "css": "",
+ "custom_format": 1,
+ "default_print_language": "en",
+ "disabled": 0,
+ "doc_type": "Supplier",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>TAX Invoice<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name_in_arabic\", \"label\": \"Customer Name in Arabic\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_trn\", \"label\": \"Company TRN\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_code\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"charge_type\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"row_id\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"account_head\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"cost_center\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount_after_discount_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_total\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_tax_amount_after_discount_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"item_wise_tax_detail\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"align\": \"left\", \"label\": \"In Words\"}]",
+ "html": "<div id=\"copy_a\" style=\"position: relative; top:0cm; width:17cm;height:28.0cm;\">\n <table>\n <tbody>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:86mm\" colspan=\"4\" ; rowspan=\"3\">PAYER'S name, street address,\n city or town, state or province, country, ZIP<br>or foreign postal code, and telephone no.<br>\n {{ company or \"\" }}<br>\n {{ payer_street_address or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">1 Rents</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:25mm\" rowspan=\"2\">OMB No. 1545-0115<br>\n <yone>{{ fiscal_year[:2] }}</yone>\n <ytwo>{{ fiscal_year[-2:] }}</ytwo><br>Form 1099-MISC\n </td>\n <td class=\"lbs bbs\" style=\"width:38mm\" colspan=\"2\" rowspan=\"2\">Miscellaneous Income</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">2 Royalties</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\">3 Other Income<br>{{ payments or \"\" }}</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">4 Federal Income tax withheld</td>\n <td class=\"tbs lbs bbs\" style=\"width:29mm\" rowspan=\"2\">Copy A<br>For<br>Internal Revenue<br>Service\n Center<br><br>File with Form 1096</td>\n </tr>\n <tr style=\"height:16mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:43mm\">PAYER'S TIN<br>{{ company_tin or \"\" }}</td>\n\n <td class=\"tbs rbs lbs bbs\" colspan=\"3\">RECIPIENT'S TIN<br><br>{{ tax_id or \"None\" }}</td>\n <td class=\"tbs rbs lbs bbs\">Fishing boat proceeds</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">6 Medical and health care payments</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\">RECIPIENT'S name <br>{{ supplier or \"\" }}</td>\n <td class=\"tbs rbs lbs bbs\">7 Nonemployee compensation<br>\n </td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Substitute payments in lieu of dividends or interest</td>\n <td class=\"tbs lbs bbs\" rowspan=\"6\">For Privacy Act<br>and Paperwork<br>Reduction Act<br>Notice, see\n the<br>2018 General<br>Instructions for<br>Certain<br>Information<br>Returns.</td>\n </tr>\n <tr style=\"height:6mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">Street address (including apt. no.)<br>\n {{ recipient_street_address or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\">$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:7mm\">\n <td class=\"tbs rbs lbs bbs\" rowspan=\"2\">9 Payer made direct sales of<br>$5,000 or more of consumer\n products<br>to a buyer<br>(recipient) for resale</td>\n <td class=\"tbs rbs lbs\" colspan=\"2\">10 Crop insurance proceeds</td>\n </tr>\n <tr style=\"height:5mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">City or town, state or province, country, and ZIP or\n foreign postal code<br>\n {{ recipient_city_state or \"\" }}\n </td>\n <td style=\"vertical-align:bottom\" class=\" rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\">11</td>\n <td class=\"tbs rbs lbs bbs\" colspan=2>12</td>\n </tr>\n <tr style=\"height:13mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Account number (see instructions)</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:16mm\">FACTA filing<br>requirement</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:14mm\">2nd TIN not.</td>\n <td class=\"tbs rbs lbs bbs\">13 Excess golden parachute payments<br>$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">14 Gross proceeds paid to an<br>attorney<br>$___________</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs \">15a Section 409A deferrals</td>\n <td class=\"tbs rbs lbs \" colspan=\"3\">15b Section 409 income</td>\n <td class=\"tbs rbs lbs \">16 State tax withheld</td>\n <td class=\"tbs rbs lbs \" colspan=\"2\">17 State/Payer's state no.</td>\n <td class=\"tbs lbs\">18 State income</td>\n </tr>\n <tr>\n <td class=\"lbs rbs bbs\">$</td>\n <td class=\"lbs rbs bbs\" colspan=\"3\">$</td>\n <td class=\"lbs rbs bbs tbd\">$</td>\n <td class=\"lbs rbs bbs tbd\" colspan=\"2\"></td>\n <td class=\"lbs bbs tbd\">$</td>\n </tr>\n\n <tr style=\"height:8mm\">\n <td class=\"tbs\" colspan=\"8\">Form 1099-MISC Cat. No. 14425J www.irs.gov/Form1099MISC Department of the\n Treasury - Internal Revenue Service</td>\n </tr>\n\n </tbody>\n </table>\n</div>\n<div id=\"copy_1\" style=\"position: relative; top:0cm; width:17cm;height:28.0cm;\">\n <table>\n <tbody>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:86mm\" colspan=\"4\" ; rowspan=\"3\">PAYER'S name, street address,\n city or town, state or province, country, ZIP<br>or foreign postal code, and telephone no.<br>\n {{ company or \"\"}}<b r>\n {{ payer_street_address or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">1 Rents</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:25mm\" rowspan=\"2\">OMB No. 1545-0115<br>\n <yone>{{ fiscal_year[:2] }}</yone>\n <ytwo>{{ fiscal_year[-2:] }}</ytwo><br>Form 1099-MISC\n </td>\n <td class=\"lbs bbs\" style=\"width:38mm\" colspan=\"2\" rowspan=\"2\">Miscellaneous Income</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:35mm\">2 Royalties</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\">3 Other Income<br>\n {{ payments or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">4 Federal Income tax withheld</td>\n <td class=\"tbs lbs bbs\" style=\"width:29mm\" rowspan=\"2\">Copy 1<br>For State Tax<br>Department</td>\n </tr>\n <tr style=\"height:16mm\">\n <td class=\"tbs rbs lbs bbs\" style=\"width:43mm\">PAYER'S TIN<br>\n {{ company_tin or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"3\">RECIPIENT'S TIN<br>\n {{ tax_id or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\">Fishing boat proceeds</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">6 Medical and health care payments</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\">RECIPIENT'S name</td>\n {{ supplier or \"\" }}\n <td class=\"tbs rbs lbs bbs\">7 Nonemployee compensation<br>\n </td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Substitute payments in lieu of dividends or interest</td>\n <td class=\"tbs lbs bbs\" rowspan=\"6\"></td>\n </tr>\n <tr style=\"height:6mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">Street address (including apt. no.)<br>\n {{ recipient_street_address or \"\" }}\n </td>\n <td class=\"tbs rbs lbs bbs\">$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:7mm\">\n <td class=\"tbs rbs lbs bbs\" rowspan=\"2\">9 Payer made direct sales of<br>$5,000 or more of consumer\n products<br>to a buyer<br>(recipient) for resale</td>\n <td class=\"tbs rbs lbs\" colspan=\"2\">10 Crop insurance proceeds</td>\n </tr>\n <tr style=\"height:5mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"4\" rowspan=\"2\">City or town, state or province, country, and ZIP or\n foreign postal code<br>\n {{ recipient_city_state or \"\" }}\n </td>\n <td style=\"vertical-align:bottom\" class=\" rbs lbs bbs\" colspan=\"2\">$___________</td>\n </tr>\n <tr style=\"height:9mm\">\n <td class=\"tbs rbs lbs bbs\">11</td>\n <td class=\"tbs rbs lbs bbs\" colspan=2>12</td>\n </tr>\n <tr style=\"height:13mm\">\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">Account number (see instructions)</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:16mm\">FACTA filing<br>requirement</td>\n <td class=\"tbs rbs lbs bbs\" style=\"width:14mm\">2nd TIN not.</td>\n <td class=\"tbs rbs lbs bbs\">13 Excess golden parachute payments<br>$___________</td>\n <td class=\"tbs rbs lbs bbs\" colspan=\"2\">14 Gross proceeds paid to an<br>attorney<br>$___________</td>\n </tr>\n <tr style=\"height:12mm\">\n <td class=\"tbs rbs lbs \">15a Section 409A deferrals</td>\n <td class=\"tbs rbs lbs \" colspan=\"3\">15b Section 409 income</td>\n <td class=\"tbs rbs lbs \">16 State tax withheld</td>\n <td class=\"tbs rbs lbs \" colspan=\"2\">17 State/Payer's state no.</td>\n <td class=\"tbs lbs\">18 State income</td>\n </tr>\n <tr>\n <td class=\"lbs rbs bbs\">$</td>\n <td class=\"lbs rbs bbs\" colspan=\"3\">$</td>\n <td class=\"lbs rbs bbs tbd\">$</td>\n <td class=\"lbs rbs bbs tbd\" colspan=\"2\"></td>\n <td class=\"lbs bbs tbd\">$</td>\n </tr>\n\n <tr style=\"height:8mm\">\n <td class=\"tbs\" colspan=\"8\">Form 1099-MISC Cat. No. 14425J www.irs.gov/Form1099MISC Department of the\n Treasury - Internal Revenue Service</td>\n </tr>\n\n </tbody>\n </table>\n</div>\n<style>\n body {\n font-family: 'Helvetica', sans-serif;\n font-size: 5.66pt;\n }\n\n yone {\n font-family: 'Helvetica', sans-serif;\n font-size: 14pt;\n color: black;\n -webkit-text-fill-color: white;\n /* Will override color (regardless of order) */\n -webkit-text-stroke-width: 1px;\n -webkit-text-stroke-color: black;\n }\n\n ytwo {\n font-family: 'Helvetica', sans-serif;\n font-size: 14pt;\n color: black;\n -webkit-text-stroke-width: 1px;\n -webkit-text-stroke-color: black;\n }\n\n table,\n th,\n td {\n font-family: 'Helvetica', sans-serif;\n font-size: 5.66pt;\n border: none;\n }\n\n .tbs {\n border-top: 1px solid black;\n }\n\n .bbs {\n border-bottom: 1px solid black;\n }\n\n .lbs {\n border-left: 1px solid black;\n }\n\n .rbs {\n border-right: 1px solid black;\n }\n\n .allBorder {\n border-top: 1px solid black;\n border-right: 1px solid black;\n border-left: 1px solid black;\n border-bottom: 1px solid black;\n }\n\n .bottomBorderOnlyDashed {\n border-bottom: 1px dashed black;\n }\n\n .tbd {\n border-top: 1px dashed black;\n }\n\n .address {\n vertical-align: bottom;\n }\n</style>",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2021-01-19 07:25:16.333666",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "IRS 1099 Form",
+ "owner": "Administrator",
+ "print_format_builder": 1,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 0,
+ "standard": "No"
+}
\ No newline at end of file
diff --git a/erpnext/regional/report/datev/datev.js b/erpnext/regional/report/datev/datev.js
index 55f12cf..4124e3d 100644
--- a/erpnext/regional/report/datev/datev.js
+++ b/erpnext/regional/report/datev/datev.js
@@ -11,14 +11,14 @@
{
"fieldname": "from_date",
"label": __("From Date"),
- "default": frappe.datetime.month_start(),
+ "default": moment().subtract(1, 'month').startOf('month').format(),
"fieldtype": "Date",
"reqd": 1
},
{
"fieldname": "to_date",
"label": __("To Date"),
- "default": frappe.datetime.now_date(),
+ "default": moment().subtract(1, 'month').endOf('month').format(),
"fieldtype": "Date",
"reqd": 1
},
@@ -30,9 +30,23 @@
}
],
onload: function(query_report) {
+ let company = frappe.query_report.get_filter_value('company');
+ frappe.db.exists('DATEV Settings', company).then((settings_exist) => {
+ if (!settings_exist) {
+ frappe.confirm(__('DATEV Settings for your Company are missing. Would you like to create them now?'),
+ () => frappe.new_doc('DATEV Settings', {'company': company})
+ );
+ }
+ });
+
query_report.page.add_menu_item(__("Download DATEV File"), () => {
const filters = JSON.stringify(query_report.get_values());
window.open(`/api/method/erpnext.regional.report.datev.datev.download_datev_csv?filters=${filters}`);
});
+
+ query_report.page.add_menu_item(__("Change DATEV Settings"), () => {
+ let company = frappe.query_report.get_filter_value('company'); // read company from filters again – it might have changed by now.
+ frappe.set_route('Form', 'DATEV Settings', company);
+ });
}
};
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index dd818e6..cbc9478 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -11,9 +11,11 @@
import json
import frappe
-from frappe import _
from six import string_types
-from erpnext.regional.germany.utils.datev.datev_csv import download_csv_files_as_zip, get_datev_csv
+
+from frappe import _
+from erpnext.accounts.utils import get_fiscal_year
+from erpnext.regional.germany.utils.datev.datev_csv import zip_and_download, get_datev_csv
from erpnext.regional.germany.utils.datev.datev_constants import Transactions, DebtorsCreditors, AccountNames
COLUMNS = [
@@ -92,25 +94,46 @@
def execute(filters=None):
"""Entry point for frappe."""
- validate(filters)
- return COLUMNS, get_transactions(filters, as_dict=0)
+ data = []
+ if filters and validate(filters):
+ fn = 'temporary_against_account_number'
+ filters[fn] = frappe.get_value('DATEV Settings', filters.get('company'), fn)
+ data = get_transactions(filters, as_dict=0)
+
+ return COLUMNS, data
def validate(filters):
"""Make sure all mandatory filters and settings are present."""
- if not filters.get('company'):
+ company = filters.get('company')
+ if not company:
frappe.throw(_('<b>Company</b> is a mandatory filter.'))
- if not filters.get('from_date'):
+ from_date = filters.get('from_date')
+ if not from_date:
frappe.throw(_('<b>From Date</b> is a mandatory filter.'))
- if not filters.get('to_date'):
+ to_date = filters.get('to_date')
+ if not to_date:
frappe.throw(_('<b>To Date</b> is a mandatory filter.'))
- try:
- frappe.get_doc('DATEV Settings', filters.get('company'))
- except frappe.DoesNotExistError:
- frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company')))
+ validate_fiscal_year(from_date, to_date, company)
+
+ if not frappe.db.exists('DATEV Settings', filters.get('company')):
+ frappe.log_error(_('Please create {} for Company {}.').format(
+ '<a href="desk#List/DATEV%20Settings/List">{}</a>'.format(_('DATEV Settings')),
+ frappe.bold(filters.get('company'))
+ ))
+ return False
+
+ return True
+
+
+def validate_fiscal_year(from_date, to_date, company):
+ from_fiscal_year = get_fiscal_year(date=from_date, company=company)
+ to_fiscal_year = get_fiscal_year(date=to_date, company=company)
+ if from_fiscal_year != to_fiscal_year:
+ frappe.throw(_('Dates {} and {} are not in the same fiscal year.').format(from_date, to_date))
def get_transactions(filters, as_dict=1):
@@ -135,11 +158,11 @@
case gl.debit when 0 then 'H' else 'S' end as 'Soll/Haben-Kennzeichen',
/* account number or, if empty, party account number */
- coalesce(acc.account_number, acc_pa.account_number) as 'Konto',
+ acc.account_number as 'Konto',
/* against number or, if empty, party against number */
- coalesce(acc_against.account_number, acc_against_pa.account_number) as 'Gegenkonto (ohne BU-Schlüssel)',
-
+ %(temporary_against_account_number)s as 'Gegenkonto (ohne BU-Schlüssel)',
+
gl.posting_date as 'Belegdatum',
gl.voucher_no as 'Belegfeld 1',
LEFT(gl.remarks, 60) as 'Buchungstext',
@@ -150,27 +173,10 @@
FROM `tabGL Entry` gl
- /* Statistisches Konto (Debitoren/Kreditoren) */
- left join `tabParty Account` pa
- on gl.against = pa.parent
- and gl.company = pa.company
-
/* Kontonummer */
left join `tabAccount` acc
on gl.account = acc.name
- /* Gegenkonto-Nummer */
- left join `tabAccount` acc_against
- on gl.against = acc_against.name
-
- /* Statistische Kontonummer */
- left join `tabAccount` acc_pa
- on pa.account = acc_pa.name
-
- /* Statistische Gegenkonto-Nummer */
- left join `tabAccount` acc_against_pa
- on pa.account = acc_against_pa.name
-
WHERE gl.company = %(company)s
AND DATE(gl.posting_date) >= %(from_date)s
AND DATE(gl.posting_date) <= %(to_date)s
@@ -317,17 +323,26 @@
filters = json.loads(filters)
validate(filters)
+ company = filters.get('company')
+
+ fiscal_year = get_fiscal_year(date=filters.get('from_date'), company=company)
+ filters['fiscal_year_start'] = fiscal_year[1]
# set chart of accounts used
- coa = frappe.get_value('Company', filters.get('company'), 'chart_of_accounts')
+ coa = frappe.get_value('Company', company, 'chart_of_accounts')
filters['skr'] = '04' if 'SKR04' in coa else ('03' if 'SKR03' in coa else '')
+ datev_settings = frappe.get_doc('DATEV Settings', company)
+ filters['account_number_length'] = datev_settings.account_number_length
+ filters['temporary_against_account_number'] = datev_settings.temporary_against_account_number
+
transactions = get_transactions(filters)
account_names = get_account_names(filters)
customers = get_customers(filters)
suppliers = get_suppliers(filters)
- download_csv_files_as_zip([
+ zip_name = '{} DATEV.zip'.format(frappe.utils.datetime.date.today())
+ zip_and_download(zip_name, [
{
'file_name': 'EXTF_Buchungsstapel.csv',
'csv_data': get_datev_csv(transactions, filters, csv_class=Transactions)
diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py
index 9529923..59b878e 100644
--- a/erpnext/regional/report/datev/test_datev.py
+++ b/erpnext/regional/report/datev/test_datev.py
@@ -126,7 +126,8 @@
"doctype": "DATEV Settings",
"client": company.name,
"client_number": "12345",
- "consultant_number": "67890"
+ "consultant_number": "67890",
+ "temporary_against_account_number": "9999"
}).insert()
@@ -137,7 +138,8 @@
self.filters = {
"company": self.company.name,
"from_date": today(),
- "to_date": today()
+ "to_date": today(),
+ "temporary_against_account_number": "9999"
}
make_datev_settings(self.company)
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 282efe4..62faa30 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -151,6 +151,7 @@
{select_columns}
from `tab{doctype}`
where docstatus = 1 {where_conditions}
+ and is_opening = 'No'
order by posting_date desc
""".format(select_columns=self.select_columns, doctype=self.doctype,
where_conditions=conditions), self.filters, as_dict=1)
@@ -235,6 +236,7 @@
self.cgst_sgst_invoices = []
unidentified_gst_accounts = []
+ unidentified_gst_accounts_invoice = []
for parent, account, item_wise_tax_detail, tax_amount in self.tax_details:
if account in self.gst_accounts.cess_account:
self.invoice_cess.setdefault(parent, tax_amount)
@@ -250,19 +252,21 @@
if not (cgst_or_sgst or account in self.gst_accounts.igst_account):
if "gst" in account.lower() and account not in unidentified_gst_accounts:
unidentified_gst_accounts.append(account)
+ unidentified_gst_accounts_invoice.append(parent)
continue
for item_code, tax_amounts in item_wise_tax_detail.items():
tax_rate = tax_amounts[0]
- if cgst_or_sgst:
- tax_rate *= 2
- if parent not in self.cgst_sgst_invoices:
- self.cgst_sgst_invoices.append(parent)
+ if tax_rate:
+ if cgst_or_sgst:
+ tax_rate *= 2
+ if parent not in self.cgst_sgst_invoices:
+ self.cgst_sgst_invoices.append(parent)
- rate_based_dict = self.items_based_on_tax_rate\
- .setdefault(parent, {}).setdefault(tax_rate, [])
- if item_code not in rate_based_dict:
- rate_based_dict.append(item_code)
+ rate_based_dict = self.items_based_on_tax_rate\
+ .setdefault(parent, {}).setdefault(tax_rate, [])
+ if item_code not in rate_based_dict:
+ rate_based_dict.append(item_code)
except ValueError:
continue
if unidentified_gst_accounts:
@@ -271,7 +275,7 @@
# Build itemised tax for export invoices where tax table is blank
for invoice, items in iteritems(self.invoice_items):
- if invoice not in self.items_based_on_tax_rate \
+ if invoice not in self.items_based_on_tax_rate and invoice not in unidentified_gst_accounts_invoice \
and frappe.db.get_value(self.doctype, invoice, "export_type") == "Without Payment of Tax":
self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
diff --git a/erpnext/regional/report/irs_1099/irs_1099.js b/erpnext/regional/report/irs_1099/irs_1099.js
index 2d74652..070ff43 100644
--- a/erpnext/regional/report/irs_1099/irs_1099.js
+++ b/erpnext/regional/report/irs_1099/irs_1099.js
@@ -4,7 +4,7 @@
frappe.query_reports["IRS 1099"] = {
"filters": [
{
- "fieldname":"company",
+ "fieldname": "company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
@@ -13,7 +13,7 @@
"width": 80,
},
{
- "fieldname":"fiscal_year",
+ "fieldname": "fiscal_year",
"label": __("Fiscal Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
@@ -22,7 +22,7 @@
"width": 80,
},
{
- "fieldname":"supplier_group",
+ "fieldname": "supplier_group",
"label": __("Supplier Group"),
"fieldtype": "Link",
"options": "Supplier Group",
@@ -32,16 +32,16 @@
},
],
- onload: function(query_report) {
+ onload: function (query_report) {
query_report.page.add_inner_button(__("Print IRS 1099 Forms"), () => {
build_1099_print(query_report);
});
}
};
-function build_1099_print(query_report){
+function build_1099_print(query_report) {
let filters = JSON.stringify(query_report.get_values());
let w = window.open('/api/method/erpnext.regional.report.irs_1099.irs_1099.irs_1099_print?' +
- '&filters=' + encodeURIComponent(filters));
+ '&filters=' + encodeURIComponent(filters));
// w.print();
}
diff --git a/erpnext/regional/report/irs_1099/irs_1099.py b/erpnext/regional/report/irs_1099/irs_1099.py
index d3509e5..4e57ff7 100644
--- a/erpnext/regional/report/irs_1099/irs_1099.py
+++ b/erpnext/regional/report/irs_1099/irs_1099.py
@@ -1,32 +1,41 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import frappe
import json
-from frappe import _, _dict
-from frappe.utils import nowdate
-from frappe.utils.data import fmt_money
-from erpnext.accounts.utils import get_fiscal_year
+
from PyPDF2 import PdfFileWriter
+
+import frappe
+from erpnext.accounts.utils import get_fiscal_year
+from frappe import _
+from frappe.utils import cstr, nowdate
+from frappe.utils.data import fmt_money
+from frappe.utils.jinja import render_template
from frappe.utils.pdf import get_pdf
from frappe.utils.print_format import read_multi_pdf
-from frappe.utils.jinja import render_template
+
+IRS_1099_FORMS_FILE_EXTENSION = ".pdf"
def execute(filters=None):
- filters = filters if isinstance(filters, _dict) else _dict(filters)
-
+ filters = filters if isinstance(filters, frappe._dict) else frappe._dict(filters)
if not filters:
filters.setdefault('fiscal_year', get_fiscal_year(nowdate())[0])
filters.setdefault('company', frappe.db.get_default("company"))
- region = frappe.db.get_value("Company", fieldname = ["country"], filters = { "name": filters.company })
+ region = frappe.db.get_value("Company",
+ filters={"name": filters.company},
+ fieldname=["country"])
+
if region != 'United States':
- return [],[]
+ return [], []
data = []
columns = get_columns()
+ conditions = ""
+ if filters.supplier_group:
+ conditions += "AND s.supplier_group = %s" %frappe.db.escape(filters.get("supplier_group"))
+
data = frappe.db.sql("""
SELECT
s.supplier_group as "supplier_group",
@@ -34,20 +43,25 @@
s.tax_id as "tax_id",
SUM(gl.debit_in_account_currency) AS "payments"
FROM
- `tabGL Entry` gl INNER JOIN `tabSupplier` s
+ `tabGL Entry` gl
+ INNER JOIN `tabSupplier` s
WHERE
s.name = gl.party
- AND s.irs_1099 = 1
- AND gl.fiscal_year = %(fiscal_year)s
- AND gl.party_type = "Supplier"
-
+ AND s.irs_1099 = 1
+ AND gl.fiscal_year = %(fiscal_year)s
+ AND gl.party_type = "Supplier"
+ AND gl.company = %(company)s
+ {conditions}
+
GROUP BY
gl.party
ORDER BY
- gl.party DESC""", {"fiscal_year": filters.fiscal_year,
- "supplier_group": filters.supplier_group,
- "company": filters.company}, as_dict=True)
+ gl.party DESC""".format(conditions=conditions), {
+ "fiscal_year": filters.fiscal_year,
+ "company": filters.company
+ }, as_dict=True)
+
return columns, data
@@ -71,14 +85,13 @@
"fieldname": "tax_id",
"label": _("Tax ID"),
"fieldtype": "Data",
- "width": 120
+ "width": 200
},
{
-
"fieldname": "payments",
"label": _("Total Payments"),
"fieldtype": "Currency",
- "width": 120
+ "width": 200
}
]
@@ -88,23 +101,32 @@
if not filters:
frappe._dict({
"company": frappe.db.get_default("Company"),
- "fiscal_year": frappe.db.get_default("fiscal_year")})
+ "fiscal_year": frappe.db.get_default("Fiscal Year")
+ })
else:
filters = frappe._dict(json.loads(filters))
+
+ fiscal_year_doc = get_fiscal_year(fiscal_year=filters.fiscal_year, as_dict=True)
+ fiscal_year = cstr(fiscal_year_doc.year_start_date.year)
+
company_address = get_payer_address_html(filters.company)
company_tin = frappe.db.get_value("Company", filters.company, "tax_id")
+
columns, data = execute(filters)
template = frappe.get_doc("Print Format", "IRS 1099 Form").html
output = PdfFileWriter()
+
for row in data:
+ row["fiscal_year"] = fiscal_year
row["company"] = filters.company
row["company_tin"] = company_tin
row["payer_street_address"] = company_address
- row["recipient_street_address"], row["recipient_city_state"] = get_street_address_html("Supplier", row.supplier)
+ row["recipient_street_address"], row["recipient_city_state"] = get_street_address_html(
+ "Supplier", row.supplier)
row["payments"] = fmt_money(row["payments"], precision=0, currency="USD")
- frappe._dict(row)
pdf = get_pdf(render_template(template, row), output=output if output else None)
- frappe.local.response.filename = filters.fiscal_year + " " + filters.company + " IRS 1099 Forms"
+
+ frappe.local.response.filename = f"{filters.fiscal_year} {filters.company} IRS 1099 Forms{IRS_1099_FORMS_FILE_EXTENSION}"
frappe.local.response.filecontent = read_multi_pdf(output)
frappe.local.response.type = "download"
@@ -120,36 +142,45 @@
ORDER BY
address_type="Postal" DESC, address_type="Billing" DESC
LIMIT 1
- """, {"company": company}, as_dict=True)
+ """, {"company": company}, as_dict=True)
+
+ address_display = ""
if address_list:
company_address = address_list[0]["name"]
- return frappe.get_doc("Address", company_address).get_display()
- else:
- return ""
+ address_display = frappe.get_doc("Address", company_address).get_display()
+
+ return address_display
def get_street_address_html(party_type, party):
address_list = frappe.db.sql("""
SELECT
link.parent
- FROM `tabDynamic Link` link, `tabAddress` address
- WHERE link.parenttype = "Address"
- AND link.link_name = %(party)s
- ORDER BY address.address_type="Postal" DESC,
+ FROM
+ `tabDynamic Link` link,
+ `tabAddress` address
+ WHERE
+ link.parenttype = "Address"
+ AND link.link_name = %(party)s
+ ORDER BY
+ address.address_type="Postal" DESC,
address.address_type="Billing" DESC
LIMIT 1
- """, {"party": party}, as_dict=True)
+ """, {"party": party}, as_dict=True)
+
+ street_address = city_state = ""
if address_list:
supplier_address = address_list[0]["parent"]
doc = frappe.get_doc("Address", supplier_address)
+
if doc.address_line2:
- street = doc.address_line1 + "<br>\n" + doc.address_line2 + "<br>\n"
+ street_address = doc.address_line1 + "<br>\n" + doc.address_line2 + "<br>\n"
else:
- street = doc.address_line1 + "<br>\n"
- city = doc.city + ", " if doc.city else ""
- city = city + doc.state + " " if doc.state else city
- city = city + doc.pincode if doc.pincode else city
- city += "<br>\n"
- return street, city
- else:
- return "", ""
+ street_address = doc.address_line1 + "<br>\n"
+
+ city_state = doc.city + ", " if doc.city else ""
+ city_state = city_state + doc.state + " " if doc.state else city_state
+ city_state = city_state + doc.pincode if doc.pincode else city_state
+ city_state += "<br>\n"
+
+ return street_address, city_state
diff --git a/erpnext/config/__init__.py b/erpnext/regional/report/uae_vat_201/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/regional/report/uae_vat_201/__init__.py
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
new file mode 100644
index 0000000..daa6976
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
@@ -0,0 +1,239 @@
+# coding=utf-8
+from __future__ import unicode_literals
+
+import erpnext
+import frappe
+from unittest import TestCase
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse_account
+from erpnext.regional.report.uae_vat_201.uae_vat_201 import (
+ get_total_emiratewise,
+ get_tourist_tax_return_total,
+ get_tourist_tax_return_tax,
+ get_zero_rated_total,
+ get_exempt_total,
+ get_standard_rated_expenses_total,
+ get_standard_rated_expenses_tax,
+)
+
+test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
+
+class TestUaeVat201(TestCase):
+ def setUp(self):
+ frappe.set_user("Administrator")
+
+ frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company UAE VAT'")
+ frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company UAE VAT'")
+
+ make_company("_Test Company UAE VAT", "_TCUV")
+ set_vat_accounts()
+
+ make_customer()
+
+ make_supplier()
+
+ create_warehouse("_Test UAE VAT Supplier Warehouse", company="_Test Company UAE VAT")
+
+ make_item("_Test UAE VAT Item", properties = {"is_zero_rated": 0, "is_exempt": 0})
+ make_item("_Test UAE VAT Zero Rated Item", properties = {"is_zero_rated": 1, "is_exempt": 0})
+ make_item("_Test UAE VAT Exempt Item", properties = {"is_zero_rated": 0, "is_exempt": 1})
+
+ make_sales_invoices()
+
+ create_purchase_invoices()
+
+ def test_uae_vat_201_report(self):
+ filters = {"company": "_Test Company UAE VAT"}
+ total_emiratewise = get_total_emiratewise(filters)
+ amounts_by_emirate = {}
+ for data in total_emiratewise:
+ emirate, amount, vat = data
+ amounts_by_emirate[emirate] = {
+ "raw_amount": amount,
+ "raw_vat_amount": vat,
+ }
+ self.assertEqual(amounts_by_emirate["Sharjah"]["raw_amount"],100)
+ self.assertEqual(amounts_by_emirate["Sharjah"]["raw_vat_amount"],5)
+ self.assertEqual(amounts_by_emirate["Dubai"]["raw_amount"],200)
+ self.assertEqual(amounts_by_emirate["Dubai"]["raw_vat_amount"],10)
+ self.assertEqual(get_tourist_tax_return_total(filters),100)
+ self.assertEqual(get_tourist_tax_return_tax(filters),2)
+ self.assertEqual(get_zero_rated_total(filters),100)
+ self.assertEqual(get_exempt_total(filters),100)
+ self.assertEqual(get_standard_rated_expenses_total(filters),250)
+ self.assertEqual(get_standard_rated_expenses_tax(filters),1)
+
+def make_company(company_name, abbr):
+ if not frappe.db.exists("Company", company_name):
+ company = frappe.get_doc({
+ "doctype": "Company",
+ "company_name": company_name,
+ "abbr": abbr,
+ "default_currency": "AED",
+ "country": "United Arab Emirates",
+ "create_chart_of_accounts_based_on": "Standard Template",
+ })
+ company.insert()
+ else:
+ company = frappe.get_doc("Company", company_name)
+
+ company.create_default_warehouses()
+
+ if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": company.name}):
+ company.create_default_cost_center()
+
+ company.save()
+ return company
+
+def set_vat_accounts():
+ if not frappe.db.exists("UAE VAT Settings", "_Test Company UAE VAT"):
+ vat_accounts = frappe.get_all(
+ "Account",
+ fields=["name"],
+ filters = {
+ "company": "_Test Company UAE VAT",
+ "is_group": 0,
+ "account_type": "Tax"
+ }
+ )
+
+ uae_vat_accounts = []
+ for account in vat_accounts:
+ uae_vat_accounts.append({
+ "doctype": "UAE VAT Account",
+ "account": account.name
+ })
+
+ frappe.get_doc({
+ "company": "_Test Company UAE VAT",
+ "uae_vat_accounts": uae_vat_accounts,
+ "doctype": "UAE VAT Settings",
+ }).insert()
+
+def make_customer():
+ if not frappe.db.exists("Customer", "_Test UAE Customer"):
+ customer = frappe.get_doc({
+ "doctype": "Customer",
+ "customer_name": "_Test UAE Customer",
+ "customer_type": "Company",
+ })
+ customer.insert()
+ else:
+ customer = frappe.get_doc("Customer", "_Test UAE Customer")
+
+def make_supplier():
+ if not frappe.db.exists("Supplier", "_Test UAE Supplier"):
+ frappe.get_doc({
+ "supplier_group": "Local",
+ "supplier_name": "_Test UAE Supplier",
+ "supplier_type": "Individual",
+ "doctype": "Supplier",
+ }).insert()
+
+def create_warehouse(warehouse_name, properties=None, company=None):
+ if not company:
+ company = "_Test Company"
+
+ warehouse_id = erpnext.encode_company_abbr(warehouse_name, company)
+ if not frappe.db.exists("Warehouse", warehouse_id):
+ warehouse = frappe.new_doc("Warehouse")
+ warehouse.warehouse_name = warehouse_name
+ warehouse.parent_warehouse = "All Warehouses - _TCUV"
+ warehouse.company = company
+ warehouse.account = get_warehouse_account(warehouse_name, company)
+ if properties:
+ warehouse.update(properties)
+ warehouse.save()
+ return warehouse.name
+ else:
+ return warehouse_id
+
+def make_item(item_code, properties=None):
+ if frappe.db.exists("Item", item_code):
+ return frappe.get_doc("Item", item_code)
+
+ item = frappe.get_doc({
+ "doctype": "Item",
+ "item_code": item_code,
+ "item_name": item_code,
+ "description": item_code,
+ "item_group": "Products"
+ })
+
+ if properties:
+ item.update(properties)
+
+ item.insert()
+
+ return item
+
+def make_sales_invoices():
+ def make_sales_invoices_wrapper(emirate, item, tax = True, tourist_tax= False):
+ si = create_sales_invoice(
+ company="_Test Company UAE VAT",
+ customer = '_Test UAE Customer',
+ currency = 'AED',
+ warehouse = 'Finished Goods - _TCUV',
+ debit_to = 'Debtors - _TCUV',
+ income_account = 'Sales - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ cost_center = 'Main - _TCUV',
+ item = item,
+ do_not_save=1
+ )
+ si.vat_emirate = emirate
+ if tax:
+ si.append(
+ "taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "VAT 5% - _TCUV",
+ "cost_center": "Main - _TCUV",
+ "description": "VAT 5% @ 5.0",
+ "rate": 5.0
+ }
+ )
+ if tourist_tax:
+ si.tourist_tax_return = 2
+ si.submit()
+
+ #Define Item Names
+ uae_item = "_Test UAE VAT Item"
+ uae_exempt_item = "_Test UAE VAT Exempt Item"
+ uae_zero_rated_item = "_Test UAE VAT Zero Rated Item"
+
+ #Sales Invoice with standard rated expense in Dubai
+ make_sales_invoices_wrapper('Dubai', uae_item)
+ #Sales Invoice with standard rated expense in Sharjah
+ make_sales_invoices_wrapper('Sharjah', uae_item)
+ #Sales Invoice with Tourist Tax Return
+ make_sales_invoices_wrapper('Dubai', uae_item, True, True)
+ #Sales Invoice with Exempt Item
+ make_sales_invoices_wrapper('Sharjah', uae_exempt_item, False)
+ #Sales Invoice with Zero Rated Item
+ make_sales_invoices_wrapper('Sharjah', uae_zero_rated_item, False)
+
+def create_purchase_invoices():
+ pi = make_purchase_invoice(
+ company="_Test Company UAE VAT",
+ supplier = '_Test UAE Supplier',
+ supplier_warehouse = '_Test UAE VAT Supplier Warehouse - _TCUV',
+ warehouse = '_Test UAE VAT Supplier Warehouse - _TCUV',
+ currency = 'AED',
+ cost_center = 'Main - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ item = "_Test UAE VAT Item",
+ do_not_save=1,
+ uom = "Nos"
+ )
+ pi.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "VAT 5% - _TCUV",
+ "cost_center": "Main - _TCUV",
+ "description": "VAT 5% @ 5.0",
+ "rate": 5.0
+ })
+
+ pi.recoverable_standard_rated_expenses = 1
+
+ pi.submit()
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.html b/erpnext/regional/report/uae_vat_201/uae_vat_201.html
new file mode 100644
index 0000000..d9b9968
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.html
@@ -0,0 +1,77 @@
+{%
+ var report_columns = report.get_columns_for_print();
+ report_columns = report_columns.filter(col => !col.hidden);
+%}
+<style>
+ .print-format {
+ padding: 10mm;
+ font-size: 8.0pt !important;
+ font-family: Tahoma, sans-serif;
+ }
+</style>
+
+<h1 style="margin-top:0; text-align: center;">{%= __(report.report_name) %}</h1>
+
+<h3 style="margin-top:0; font-weight:500">{%= __("VAT on Sales and All Other Outputs") %}</h2>
+
+<table class="table table-bordered">
+
+ <thead>
+ <th style="width: 13">{%= report_columns[0].label %}</th>
+ <th style="width: {%= 100 - (report_columns.length - 1) * 13%}%">{%= report_columns[1].label %}</th>
+
+ {% for (let i=2; i<report_columns.length; i++) { %}
+ <th style="width: 13">{%= report_columns[i].label %}</th>
+ {% } %}
+ </thead>
+
+ <tbody>
+ {% for (let j=1; j<12; j++) { %}
+ {%
+ var row = data[j];
+ %}
+ <tr >
+ {% for (let i=0; i<report_columns.length; i++) { %}
+ <td >
+ {% const fieldname = report_columns[i].fieldname; %}
+ {% if (!is_null(row[fieldname])) { %}
+ {%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
+ {% } %}
+ </td>
+ {% } %}
+ </tr>
+ {% } %}
+ </tbody>
+</table>
+
+<h3 style="margin-top:0; font-weight:500">{%= __("VAT on Expenses and All Other Inputs") %}</h2>
+
+<table class="table table-bordered">
+ <thead>
+ <th style="width: 13">{%= report_columns[0].label %}</th>
+ <th style="width: {%= 100 - (report_columns.length - 1) * 13%}%">{%= report_columns[1].label %}</th>
+
+ {% for (let i=2; i<report_columns.length; i++) { %}
+ <th style="width: 13">{%= report_columns[i].label %}</th>
+ {% } %}
+ </thead>
+
+ <tbody>
+ {% for (let j=14; j<data.length; j++) { %}
+ {%
+ var row = data[j];
+ %}
+ <tr >
+ {% for (let i=0; i<report_columns.length; i++) { %}
+ <td >
+ {% const fieldname = report_columns[i].fieldname; %}
+ {% if (!is_null(row[fieldname])) { %}
+ {%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
+ {% } %}
+ </td>
+ {% } %}
+ </tr>
+ {% } %}
+ </tbody>
+
+</table>
\ No newline at end of file
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.js b/erpnext/regional/report/uae_vat_201/uae_vat_201.js
new file mode 100644
index 0000000..5957424
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["UAE VAT 201"] = {
+ "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(), -3),
+ },
+ {
+ "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.legend=='VAT on Sales and All Other Outputs' || data.legend=='VAT on Expenses and All Other Inputs')
+ && data.legend==value) {
+ value = $(`<span>${value}</span>`);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("<p></p>").parent().html();
+ }
+ return value;
+ },
+};
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.json b/erpnext/regional/report/uae_vat_201/uae_vat_201.json
new file mode 100644
index 0000000..8a88bcd
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.json
@@ -0,0 +1,22 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2020-09-10 08:51:02.298482",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-09-10 08:51:02.298482",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "UAE VAT 201",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "GL Entry",
+ "report_name": "UAE VAT 201",
+ "report_type": "Script Report",
+ "roles": []
+}
\ No newline at end of file
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
new file mode 100644
index 0000000..b061423
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
@@ -0,0 +1,339 @@
+# 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):
+ columns = get_columns()
+ data, emirates, amounts_by_emirate = get_data(filters)
+ return columns, data
+
+def get_columns():
+ """Creates a list of dictionaries that are used to generate column headers of the data table."""
+ return [
+ {
+ "fieldname": "no",
+ "label": _("No"),
+ "fieldtype": "Data",
+ "width": 50
+ },
+ {
+ "fieldname": "legend",
+ "label": _("Legend"),
+ "fieldtype": "Data",
+ "width": 300
+ },
+ {
+ "fieldname": "amount",
+ "label": _("Amount (AED)"),
+ "fieldtype": "Currency",
+ "width": 125,
+ },
+ {
+ "fieldname": "vat_amount",
+ "label": _("VAT Amount (AED)"),
+ "fieldtype": "Currency",
+ "width": 150,
+ }
+ ]
+
+def get_data(filters = None):
+ """Returns the list of dictionaries. Each dictionary is a row in the datatable and chart data."""
+ data = []
+ emirates, amounts_by_emirate = append_vat_on_sales(data, filters)
+ append_vat_on_expenses(data, filters)
+ return data, emirates, amounts_by_emirate
+
+def append_vat_on_sales(data, filters):
+ """Appends Sales and All Other Outputs."""
+ append_data(data, '', _('VAT on Sales and All Other Outputs'), '', '')
+
+ emirates, amounts_by_emirate = standard_rated_expenses_emiratewise(data, filters)
+
+ append_data(data, '2',
+ _('Tax Refunds provided to Tourists under the Tax Refunds for Tourists Scheme'),
+ frappe.format((-1) * get_tourist_tax_return_total(filters), 'Currency'),
+ frappe.format((-1) * get_tourist_tax_return_tax(filters), 'Currency'))
+
+ append_data(data, '3', _('Supplies subject to the reverse charge provision'),
+ frappe.format(get_reverse_charge_total(filters), 'Currency'),
+ frappe.format(get_reverse_charge_tax(filters), 'Currency'))
+
+ append_data(data, '4', _('Zero Rated'),
+ frappe.format(get_zero_rated_total(filters), 'Currency'), "-")
+
+ append_data(data, '5', _('Exempt Supplies'),
+ frappe.format(get_exempt_total(filters), 'Currency'),"-")
+
+ append_data(data, '', '', '', '')
+
+ return emirates, amounts_by_emirate
+
+def standard_rated_expenses_emiratewise(data, filters):
+ """Append emiratewise standard rated expenses and vat."""
+ total_emiratewise = get_total_emiratewise(filters)
+ emirates = get_emirates()
+ amounts_by_emirate = {}
+ for emirate, amount, vat in total_emiratewise:
+ amounts_by_emirate[emirate] = {
+ "legend": emirate,
+ "raw_amount": amount,
+ "raw_vat_amount": vat,
+ "amount": frappe.format(amount, 'Currency'),
+ "vat_amount": frappe.format(vat, 'Currency'),
+ }
+ amounts_by_emirate = append_emiratewise_expenses(data, emirates, amounts_by_emirate)
+ return emirates, amounts_by_emirate
+
+def append_emiratewise_expenses(data, emirates, amounts_by_emirate):
+ """Append emiratewise standard rated expenses and vat."""
+ for no, emirate in enumerate(emirates, 97):
+ if emirate in amounts_by_emirate:
+ amounts_by_emirate[emirate]["no"] = _('1{0}').format(chr(no))
+ amounts_by_emirate[emirate]["legend"] = _('Standard rated supplies in {0}').format(emirate)
+ data.append(amounts_by_emirate[emirate])
+ else:
+ append_data(data, _('1{0}').format(chr(no)),
+ _('Standard rated supplies in {0}').format(emirate),
+ frappe.format(0, 'Currency'), frappe.format(0, 'Currency'))
+ return amounts_by_emirate
+
+def append_vat_on_expenses(data, filters):
+ """Appends Expenses and All Other Inputs."""
+ append_data(data, '', _('VAT on Expenses and All Other Inputs'), '', '')
+ append_data(data, '9', _('Standard Rated Expenses'),
+ frappe.format(get_standard_rated_expenses_total(filters), 'Currency'),
+ frappe.format(get_standard_rated_expenses_tax(filters), 'Currency'))
+ append_data(data, '10', _('Supplies subject to the reverse charge provision'),
+ frappe.format(get_reverse_charge_recoverable_total(filters), 'Currency'),
+ frappe.format(get_reverse_charge_recoverable_tax(filters), 'Currency'))
+
+def append_data(data, no, legend, amount, vat_amount):
+ """Returns data with appended value."""
+ data.append({"no": no, "legend":legend, "amount": amount, "vat_amount": vat_amount})
+
+def get_total_emiratewise(filters):
+ """Returns Emiratewise Amount and Taxes."""
+ conditions = get_conditions(filters)
+ try:
+ return frappe.db.sql("""
+ select
+ s.vat_emirate as emirate, sum(i.base_amount) as total, sum(s.total_taxes_and_charges)
+ from
+ `tabSales Invoice Item` i inner join `tabSales Invoice` s
+ on
+ i.parent = s.name
+ where
+ s.docstatus = 1 and i.is_exempt != 1 and i.is_zero_rated != 1
+ {where_conditions}
+ group by
+ s.vat_emirate;
+ """.format(where_conditions=conditions), filters)
+ except (IndexError, TypeError):
+ return 0
+
+def get_emirates():
+ """Returns a List of emirates in the order that they are to be displayed."""
+ return [
+ 'Abu Dhabi',
+ 'Dubai',
+ 'Sharjah',
+ 'Ajman',
+ 'Umm Al Quwain',
+ 'Ras Al Khaimah',
+ 'Fujairah'
+ ]
+
+def get_filters(filters):
+ """The conditions to be used to filter data to calculate the total sale."""
+ query_filters = []
+ if filters.get("company"):
+ query_filters.append(["company", '=', filters['company']])
+ if filters.get("from_date"):
+ query_filters.append(["posting_date", '>=', filters['from_date']])
+ if filters.get("from_date"):
+ query_filters.append(["posting_date", '<=', filters['to_date']])
+ return query_filters
+
+def get_reverse_charge_total(filters):
+ """Returns the sum of the total of each Purchase invoice made."""
+ query_filters = get_filters(filters)
+ query_filters.append(['reverse_charge', '=', 'Y'])
+ query_filters.append(['docstatus', '=', 1])
+ try:
+ return frappe.db.get_all('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_reverse_charge_tax(filters):
+ """Returns the sum of the tax of each Purchase invoice made."""
+ conditions = get_conditions_join(filters)
+ return frappe.db.sql("""
+ select sum(debit) from
+ `tabPurchase Invoice` p inner join `tabGL Entry` gl
+ on
+ gl.voucher_no = p.name
+ where
+ p.reverse_charge = "Y"
+ and p.docstatus = 1
+ and gl.docstatus = 1
+ and account in (select account from `tabUAE VAT Account` where parent=%(company)s)
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+
+def get_reverse_charge_recoverable_total(filters):
+ """Returns the sum of the total of each Purchase invoice made with recoverable reverse charge."""
+ query_filters = get_filters(filters)
+ query_filters.append(['reverse_charge', '=', 'Y'])
+ query_filters.append(['recoverable_reverse_charge', '>', '0'])
+ query_filters.append(['docstatus', '=', 1])
+ try:
+ return frappe.db.get_all('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_reverse_charge_recoverable_tax(filters):
+ """Returns the sum of the tax of each Purchase invoice made."""
+ conditions = get_conditions_join(filters)
+ return frappe.db.sql("""
+ select
+ sum(debit * p.recoverable_reverse_charge / 100)
+ from
+ `tabPurchase Invoice` p inner join `tabGL Entry` gl
+ on
+ gl.voucher_no = p.name
+ where
+ p.reverse_charge = "Y"
+ and p.docstatus = 1
+ and p.recoverable_reverse_charge > 0
+ and gl.docstatus = 1
+ and account in (select account from `tabUAE VAT Account` where parent=%(company)s)
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+
+def get_conditions_join(filters):
+ """The conditions to be used to filter data to calculate the total vat."""
+ conditions = ""
+ for opts in (("company", " and p.company=%(company)s"),
+ ("from_date", " and p.posting_date>=%(from_date)s"),
+ ("to_date", " and p.posting_date<=%(to_date)s")):
+ if filters.get(opts[0]):
+ conditions += opts[1]
+ return conditions
+
+def get_standard_rated_expenses_total(filters):
+ """Returns the sum of the total of each Purchase invoice made with recoverable reverse charge."""
+ query_filters = get_filters(filters)
+ query_filters.append(['recoverable_standard_rated_expenses', '>', 0])
+ query_filters.append(['docstatus', '=', 1])
+ try:
+ return frappe.db.get_all('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_standard_rated_expenses_tax(filters):
+ """Returns the sum of the tax of each Purchase invoice made."""
+ query_filters = get_filters(filters)
+ query_filters.append(['recoverable_standard_rated_expenses', '>', 0])
+ query_filters.append(['docstatus', '=', 1])
+ try:
+ return frappe.db.get_all('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(recoverable_standard_rated_expenses)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_tourist_tax_return_total(filters):
+ """Returns the sum of the total of each Sales invoice with non zero tourist_tax_return."""
+ query_filters = get_filters(filters)
+ query_filters.append(['tourist_tax_return', '>', 0])
+ query_filters.append(['docstatus', '=', 1])
+ try:
+ return frappe.db.get_all('Sales Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_tourist_tax_return_tax(filters):
+ """Returns the sum of the tax of each Sales invoice with non zero tourist_tax_return."""
+ query_filters = get_filters(filters)
+ query_filters.append(['tourist_tax_return', '>', 0])
+ query_filters.append(['docstatus', '=', 1])
+ try:
+ return frappe.db.get_all('Sales Invoice',
+ filters = query_filters,
+ fields = ['sum(tourist_tax_return)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_zero_rated_total(filters):
+ """Returns the sum of each Sales Invoice Item Amount which is zero rated."""
+ conditions = get_conditions(filters)
+ try:
+ return frappe.db.sql("""
+ select
+ sum(i.base_amount) as total
+ from
+ `tabSales Invoice Item` i inner join `tabSales Invoice` s
+ on
+ i.parent = s.name
+ where
+ s.docstatus = 1 and i.is_zero_rated = 1
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+
+def get_exempt_total(filters):
+ """Returns the sum of each Sales Invoice Item Amount which is Vat Exempt."""
+ conditions = get_conditions(filters)
+ try:
+ return frappe.db.sql("""
+ select
+ sum(i.base_amount) as total
+ from
+ `tabSales Invoice Item` i inner join `tabSales Invoice` s
+ on
+ i.parent = s.name
+ where
+ s.docstatus = 1 and i.is_exempt = 1
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+ except (IndexError, TypeError):
+ return 0
+def get_conditions(filters):
+ """The conditions to be used to filter data to calculate the total sale."""
+ conditions = ""
+ for opts in (("company", " and company=%(company)s"),
+ ("from_date", " and posting_date>=%(from_date)s"),
+ ("to_date", " and posting_date<=%(to_date)s")):
+ if filters.get(opts[0]):
+ conditions += opts[1]
+ return conditions
diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py
index 250659e..68208ab 100644
--- a/erpnext/regional/united_arab_emirates/setup.py
+++ b/erpnext/regional/united_arab_emirates/setup.py
@@ -5,24 +5,33 @@
import frappe, os, json
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from frappe.permissions import add_permission, update_permission_property
from erpnext.setup.setup_wizard.operations.taxes_setup import create_sales_tax
+from erpnext.payroll.doctype.gratuity_rule.gratuity_rule import get_gratuity_rule
def setup(company=None, patch=True):
make_custom_fields()
add_print_formats()
+ add_custom_roles_for_reports()
+ add_permissions()
+ create_gratuity_rule()
if company:
create_sales_tax(company)
def make_custom_fields():
+ is_zero_rated = dict(fieldname='is_zero_rated', label='Is Zero Rated',
+ fieldtype='Check', fetch_from='item_code.is_zero_rated', insert_after='description',
+ print_hide=1)
+ is_exempt = dict(fieldname='is_exempt', label='Is Exempt',
+ fieldtype='Check', fetch_from='item_code.is_exempt', insert_after='is_zero_rated',
+ print_hide=1)
+
invoice_fields = [
dict(fieldname='vat_section', label='VAT Details', fieldtype='Section Break',
insert_after='group_same_items', print_hide=1, collapsible=1),
dict(fieldname='permit_no', label='Permit Number',
fieldtype='Data', insert_after='vat_section', print_hide=1),
- dict(fieldname='reverse_charge_applicable', label='Reverse Charge Applicable',
- fieldtype='Select', insert_after='permit_no', print_hide=1,
- options='Y\nN', default='N')
]
purchase_invoice_fields = [
@@ -31,7 +40,16 @@
fetch_from='company.tax_id', print_hide=1),
dict(fieldname='supplier_name_in_arabic', label='Supplier Name in Arabic',
fieldtype='Read Only', insert_after='supplier_name',
- fetch_from='supplier.supplier_name_in_arabic', print_hide=1)
+ fetch_from='supplier.supplier_name_in_arabic', print_hide=1),
+ dict(fieldname='recoverable_standard_rated_expenses', print_hide=1, default='0',
+ label='Recoverable Standard Rated Expenses (AED)', insert_after='permit_no',
+ fieldtype='Currency', ),
+ dict(fieldname='reverse_charge', label='Reverse Charge Applicable',
+ fieldtype='Select', insert_after='recoverable_standard_rated_expenses', print_hide=1,
+ options='Y\nN', default='N'),
+ dict(fieldname='recoverable_reverse_charge', label='Recoverable Reverse Charge (Percentage)',
+ insert_after='reverse_charge', fieldtype='Percent', print_hide=1,
+ depends_on="eval:doc.reverse_charge=='Y'", default='100.000'),
]
sales_invoice_fields = [
@@ -41,6 +59,11 @@
dict(fieldname='customer_name_in_arabic', label='Customer Name in Arabic',
fieldtype='Read Only', insert_after='customer_name',
fetch_from='customer.customer_name_in_arabic', print_hide=1),
+ dict(fieldname='vat_emirate', label='VAT Emirate', insert_after='permit_no', fieldtype='Select',
+ options='\nAbu Dhabi\nAjman\nDubai\nFujairah\nRas Al Khaimah\nSharjah\nUmm Al Quwain',
+ fetch_from='company_address.emirate'),
+ dict(fieldname='tourist_tax_return', label='Tax Refund provided to Tourists (AED)',
+ insert_after='vat_emirate', fieldtype='Currency', print_hide=1, default='0'),
]
invoice_item_fields = [
@@ -67,6 +90,12 @@
'Item': [
dict(fieldname='tax_code', label='Tax Code',
fieldtype='Data', insert_after='item_group'),
+ dict(fieldname='is_zero_rated', label='Is Zero Rated',
+ fieldtype='Check', insert_after='tax_code',
+ print_hide=1),
+ dict(fieldname='is_exempt', label='Is Exempt',
+ fieldtype='Check', insert_after='is_zero_rated',
+ print_hide=1)
],
'Customer': [
dict(fieldname='customer_name_in_arabic', label='Customer Name in Arabic',
@@ -76,13 +105,19 @@
dict(fieldname='supplier_name_in_arabic', label='Supplier Name in Arabic',
fieldtype='Data', insert_after='supplier_name'),
],
+ 'Address': [
+ dict(fieldname='emirate', label='Emirate', fieldtype='Select', insert_after='state',
+ options='\nAbu Dhabi\nAjman\nDubai\nFujairah\nRas Al Khaimah\nSharjah\nUmm Al Quwain')
+ ],
'Purchase Invoice': purchase_invoice_fields + invoice_fields,
'Purchase Order': purchase_invoice_fields + invoice_fields,
'Purchase Receipt': purchase_invoice_fields + invoice_fields,
'Sales Invoice': sales_invoice_fields + invoice_fields,
+ 'POS Invoice': sales_invoice_fields + invoice_fields,
'Sales Order': sales_invoice_fields + invoice_fields,
'Delivery Note': sales_invoice_fields + invoice_fields,
- 'Sales Invoice Item': invoice_item_fields + delivery_date_field,
+ 'Sales Invoice Item': invoice_item_fields + delivery_date_field + [is_zero_rated, is_exempt],
+ 'POS Invoice Item': invoice_item_fields + delivery_date_field + [is_zero_rated, is_exempt],
'Purchase Invoice Item': invoice_item_fields,
'Sales Order Item': invoice_item_fields,
'Delivery Note Item': invoice_item_fields,
@@ -101,3 +136,115 @@
frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where
name in('Simplified Tax Invoice', 'Detailed Tax Invoice', 'Tax Invoice') """)
+
+def add_custom_roles_for_reports():
+ """Add Access Control to UAE VAT 201."""
+ if not frappe.db.get_value('Custom Role', dict(report='UAE VAT 201')):
+ frappe.get_doc(dict(
+ doctype='Custom Role',
+ report='UAE VAT 201',
+ roles= [
+ dict(role='Accounts User'),
+ dict(role='Accounts Manager'),
+ dict(role='Auditor')
+ ]
+ )).insert()
+
+def add_permissions():
+ """Add Permissions for UAE VAT Settings and UAE VAT Account."""
+ for doctype in ('UAE VAT Settings', 'UAE VAT Account'):
+ add_permission(doctype, 'All', 0)
+ for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
+ add_permission(doctype, role, 0)
+ update_permission_property(doctype, role, 0, 'write', 1)
+ update_permission_property(doctype, role, 0, 'create', 1)
+
+def create_gratuity_rule():
+ rule_1 = rule_2 = rule_3 = None
+
+ # Rule Under Limited Contract
+ slabs = get_slab_for_limited_contract()
+ if not frappe.db.exists("Gratuity Rule", "Rule Under Limited Contract (UAE)"):
+ rule_1 = get_gratuity_rule("Rule Under Limited Contract (UAE)", slabs, calculate_gratuity_amount_based_on="Sum of all previous slabs")
+
+ # Rule Under Unlimited Contract on termination
+ slabs = get_slab_for_unlimited_contract_on_termination()
+ if not frappe.db.exists("Gratuity Rule", "Rule Under Unlimited Contract on termination (UAE)"):
+ rule_2 = get_gratuity_rule("Rule Under Unlimited Contract on termination (UAE)", slabs)
+
+ # Rule Under Unlimited Contract on resignation
+ slabs = get_slab_for_unlimited_contract_on_resignation()
+ if not frappe.db.exists("Gratuity Rule", "Rule Under Unlimited Contract on resignation (UAE)"):
+ rule_3 = get_gratuity_rule("Rule Under Unlimited Contract on resignation (UAE)", slabs)
+
+ #for applicable salary component user need to set this by its own
+ if rule_1:
+ rule_1.flags.ignore_mandatory = True
+ rule_1.save()
+ if rule_2:
+ rule_2.flags.ignore_mandatory = True
+ rule_2.save()
+ if rule_3:
+ rule_3.flags.ignore_mandatory = True
+ rule_3.save()
+
+
+def get_slab_for_limited_contract():
+ return [{
+ "from_year": 0,
+ "to_year":1,
+ "fraction_of_applicable_earnings": 0
+ },
+ {
+ "from_year": 1,
+ "to_year":5,
+ "fraction_of_applicable_earnings": 21/30
+ },
+ {
+ "from_year": 5,
+ "to_year":0,
+ "fraction_of_applicable_earnings": 1
+ }]
+
+def get_slab_for_unlimited_contract_on_termination():
+ return [{
+ "from_year": 0,
+ "to_year":1,
+ "fraction_of_applicable_earnings": 0
+ },
+ {
+ "from_year": 1,
+ "to_year":5,
+ "fraction_of_applicable_earnings": 21/30
+ },
+ {
+ "from_year": 5,
+ "to_year":0,
+ "fraction_of_applicable_earnings": 1
+ }]
+
+def get_slab_for_unlimited_contract_on_resignation():
+ fraction_1 = 1/3 * 21/30
+ fraction_2 = 2/3 * 21/30
+ fraction_3 = 21/30
+
+ return [{
+ "from_year": 0,
+ "to_year":1,
+ "fraction_of_applicable_earnings": 0
+ },
+ {
+ "from_year": 1,
+ "to_year":3,
+ "fraction_of_applicable_earnings": fraction_1
+ },
+ {
+ "from_year": 3,
+ "to_year":5,
+ "fraction_of_applicable_earnings": fraction_2
+ },
+ {
+ "from_year": 5,
+ "to_year":0,
+ "fraction_of_applicable_earnings": fraction_3
+ }]
diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py
index a0425f6..7d5fd6e 100644
--- a/erpnext/regional/united_arab_emirates/utils.py
+++ b/erpnext/regional/united_arab_emirates/utils.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt
+from frappe import _
+import erpnext
+from frappe.utils import flt, round_based_on_smallest_currency_fraction, money_in_words
from erpnext.controllers.taxes_and_totals import get_itemised_tax
from six import iteritems
@@ -26,4 +28,134 @@
row.tax_rate = flt(tax_rate, row.precision("tax_rate"))
row.tax_amount = flt((row.net_amount * tax_rate) / 100, row.precision("net_amount"))
- row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
\ No newline at end of file
+ row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
+
+def get_account_currency(account):
+ """Helper function to get account currency."""
+ if not account:
+ return
+ def generator():
+ account_currency, company = frappe.get_cached_value(
+ "Account",
+ account,
+ ["account_currency",
+ "company"]
+ )
+ if not account_currency:
+ account_currency = frappe.get_cached_value('Company', company, "default_currency")
+
+ return account_currency
+
+ return frappe.local_cache("account_currency", account, generator)
+
+def get_tax_accounts(company):
+ """Get the list of tax accounts for a specific company."""
+ tax_accounts_dict = frappe._dict()
+ tax_accounts_list = frappe.get_all("UAE VAT Account",
+ filters={"parent": company},
+ fields=["Account"]
+ )
+
+ if not tax_accounts_list and not frappe.flags.in_test:
+ frappe.throw(_('Please set Vat Accounts for Company: "{0}" in UAE VAT Settings').format(company))
+ for tax_account in tax_accounts_list:
+ for account, name in tax_account.items():
+ tax_accounts_dict[name] = name
+
+ return tax_accounts_dict
+
+def update_grand_total_for_rcm(doc, method):
+ """If the Reverse Charge is Applicable subtract the tax amount from the grand total and update in the form."""
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+
+ if country != 'United Arab Emirates':
+ return
+
+ if not doc.total_taxes_and_charges:
+ return
+
+ if doc.reverse_charge == 'Y':
+ tax_accounts = get_tax_accounts(doc.company)
+
+ base_vat_tax = 0
+ vat_tax = 0
+
+ for tax in doc.get('taxes'):
+ if tax.category not in ("Total", "Valuation and Total"):
+ continue
+
+ if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in tax_accounts:
+ base_vat_tax += tax.base_tax_amount_after_discount_amount
+ vat_tax += tax.tax_amount_after_discount_amount
+
+ doc.taxes_and_charges_added -= vat_tax
+ doc.total_taxes_and_charges -= vat_tax
+ doc.base_taxes_and_charges_added -= base_vat_tax
+ doc.base_total_taxes_and_charges -= base_vat_tax
+
+ update_totals(vat_tax, base_vat_tax, doc)
+
+def update_totals(vat_tax, base_vat_tax, doc):
+ """Update the grand total values in the form."""
+ doc.base_grand_total -= base_vat_tax
+ doc.grand_total -= vat_tax
+
+ if doc.meta.get_field("rounded_total"):
+
+ if doc.is_rounded_total_disabled():
+ doc.outstanding_amount = doc.grand_total
+
+ else:
+ doc.rounded_total = round_based_on_smallest_currency_fraction(doc.grand_total,
+ doc.currency, doc.precision("rounded_total"))
+ doc.rounding_adjustment = flt(doc.rounded_total - doc.grand_total,
+ doc.precision("rounding_adjustment"))
+ doc.outstanding_amount = doc.rounded_total or doc.grand_total
+
+ doc.in_words = money_in_words(doc.grand_total, doc.currency)
+ doc.base_in_words = money_in_words(doc.base_grand_total, erpnext.get_company_currency(doc.company))
+ doc.set_payment_schedule()
+
+def make_regional_gl_entries(gl_entries, doc):
+ """Hooked to make_regional_gl_entries in Purchase Invoice.It appends the region specific general ledger entries to the list of GL Entries."""
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+
+ if country != 'United Arab Emirates':
+ return gl_entries
+
+ if doc.reverse_charge == 'Y':
+ tax_accounts = get_tax_accounts(doc.company)
+ for tax in doc.get('taxes'):
+ if tax.category not in ("Total", "Valuation and Total"):
+ continue
+ gl_entries = make_gl_entry(tax, gl_entries, doc, tax_accounts)
+ return gl_entries
+
+def make_gl_entry(tax, gl_entries, doc, tax_accounts):
+ dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
+ if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in tax_accounts:
+ account_currency = get_account_currency(tax.account_head)
+
+ gl_entries.append(doc.get_gl_dict({
+ "account": tax.account_head,
+ "cost_center": tax.cost_center,
+ "posting_date": doc.posting_date,
+ "against": doc.supplier,
+ dr_or_cr: tax.base_tax_amount_after_discount_amount,
+ dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
+ if account_currency==doc.company_currency \
+ else tax.tax_amount_after_discount_amount
+ }, account_currency, item=tax
+ ))
+ return gl_entries
+
+
+def validate_returns(doc, method):
+ """Standard Rated expenses should not be set when Reverse Charge Applicable is set."""
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+ if country != 'United Arab Emirates':
+ return
+ if doc.reverse_charge == 'Y' and flt(doc.recoverable_standard_rated_expenses) != 0:
+ frappe.throw(_(
+ "Recoverable Standard Rated expenses should not be set when Reverse Charge Applicable is Y"
+ ))
diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py
index 2b0ecaf..24ab1cf 100644
--- a/erpnext/regional/united_states/setup.py
+++ b/erpnext/regional/united_states/setup.py
@@ -36,5 +36,4 @@
def add_print_formats():
frappe.reload_doc("regional", "print_format", "irs_1099_form")
- frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where
- name in('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 ad95010..513570e 100644
--- a/erpnext/regional/united_states/test_united_states.py
+++ b/erpnext/regional/united_states/test_united_states.py
@@ -26,7 +26,6 @@
make_payment_entry_to_irs_1099_supplier()
filters = frappe._dict({"fiscal_year": "_Test Fiscal Year 2016", "company": "_Test Company 1"})
columns, data = execute_1099_report(filters)
- print(columns, data)
expected_row = {'supplier': '_US 1099 Test Supplier',
'supplier_group': 'Services',
'payments': 100.0,
diff --git a/erpnext/selling/desk_page/retail/retail.json b/erpnext/selling/desk_page/retail/retail.json
deleted file mode 100644
index c4ddf26..0000000
--- a/erpnext/selling/desk_page/retail/retail.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Settings & Configurations",
- "links": "[\n {\n \"description\": \"Setup default values for POS Invoices\",\n \"label\": \"Point-of-Sale Profile\",\n \"name\": \"POS Profile\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"POS Settings\",\n \"name\": \"POS Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Loyalty Program",
- "links": "[\n {\n \"description\": \"To make Customer based incentive schemes.\",\n \"label\": \"Loyalty Program\",\n \"name\": \"Loyalty Program\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"To view logs of Loyalty Points assigned to a Customer.\",\n \"label\": \"Loyalty Point Entry\",\n \"name\": \"Loyalty Point Entry\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Opening & Closing",
- "links": "[\n {\n \"label\": \"POS Opening Entry\",\n \"name\": \"POS Opening Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"POS Closing Entry\",\n \"name\": \"POS Closing Entry\",\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Domains",
- "charts": [],
- "creation": "2020-03-02 17:18:32.505616",
- "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": "Retail",
- "modified": "2020-09-09 11:46:28.297435",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Retail",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "restrict_to_domain": "Retail",
- "shortcuts": [
- {
- "doc_view": "",
- "label": "Point Of Sale",
- "link_to": "point-of-sale",
- "type": "Page"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/selling/desk_page/selling/selling.json b/erpnext/selling/desk_page/selling/selling.json
deleted file mode 100644
index 4c09ee9..0000000
--- a/erpnext/selling/desk_page/selling/selling.json
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Selling",
- "links": "[\n {\n \"description\": \"Customer Database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"description\": \"Quotes to Leads or Customers.\",\n \"label\": \"Quotation\",\n \"name\": \"Quotation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"description\": \"Confirmed orders from Customers.\",\n \"label\": \"Sales Order\",\n \"name\": \"Sales Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"description\": \"Blanket Orders from Costumers.\",\n \"label\": \"Blanket Order\",\n \"name\": \"Blanket Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Manage Sales Partners.\",\n \"label\": \"Sales Partner\",\n \"name\": \"Sales Partner\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Items and Pricing",
- "links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Price List\"\n ],\n \"description\": \"Multiple Item prices.\",\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"onboard\": 1,\n \"route\": \"#Report/Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Price List master.\",\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Item Groups.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Bundle items at time of sale.\",\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying different promotional schemes.\",\n \"label\": \"Promotional Scheme\",\n \"name\": \"Promotional Scheme\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Rules for applying pricing and discount.\",\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for adding shipping costs.\",\n \"label\": \"Shipping Rule\",\n \"name\": \"Shipping Rule\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Define coupon codes.\",\n \"label\": \"Coupon Code\",\n \"name\": \"Coupon Code\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"description\": \"Default settings for selling transactions.\",\n \"label\": \"Selling Settings\",\n \"name\": \"Selling Settings\",\n \"settings\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for selling transactions.\",\n \"label\": \"Sales Taxes and Charges Template\",\n \"name\": \"Sales Taxes and Charges Template\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Track Leads by Lead Source.\",\n \"label\": \"Lead Source\",\n \"name\": \"Lead Source\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Addresses.\",\n \"label\": \"Address\",\n \"name\": \"Address\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Key Reports",
- "links": "[\n {\n \n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Analytics\",\n \"name\": \"Sales Analytics\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Order Analysis\",\n \"name\": \"Sales Order Analysis\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Sales Funnel\",\n \"name\": \"sales-funnel\",\n \"onboard\": 1,\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Order Trends\",\n \"name\": \"Sales Order Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Quotation\"\n ],\n \"doctype\": \"Quotation\",\n \"is_query_report\": true,\n \"label\": \"Quotation Trends\",\n \"name\": \"Quotation Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"icon\": \"fa fa-bar-chart\",\n \"is_query_report\": true,\n \"label\": \"Customer Acquisition and Loyalty\",\n \"name\": \"Customer Acquisition and Loyalty\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Inactive Customers\",\n \"name\": \"Inactive Customers\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Person-wise Transaction Summary\",\n \"name\": \"Sales Person-wise Transaction Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales History\",\n \"name\": \"Item-wise Sales History\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Other Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Customer Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"route_options\": {\n \"party_type\": \"Customer\"\n },\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Available Stock for Packing Items\",\n \"name\": \"Available Stock for Packing Items\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Pending SO Items For Purchase Request\",\n \"name\": \"Pending SO Items For Purchase Request\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Delivery Note\"\n ],\n \"doctype\": \"Delivery Note\",\n \"is_query_report\": true,\n \"label\": \"Delivery Note Trends\",\n \"name\": \"Delivery Note Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customers Without Any Sales Transactions\",\n \"name\": \"Customers Without Any Sales Transactions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Sales Order Trends",
- "label": "Sales Order Trends"
- }
- ],
- "charts_label": "Selling ",
- "creation": "2020-01-28 11:49:12.092882",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends_another_page": 0,
- "hide_custom": 1,
- "idx": 0,
- "is_standard": 1,
- "label": "Selling",
- "modified": "2020-08-15 10:12:53.131621",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Selling",
- "onboarding": "Selling",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Available",
- "label": "Item",
- "link_to": "Item",
- "stats_filter": "{\n \"disabled\":0\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} To Deliver",
- "label": "Sales Order",
- "link_to": "Sales Order",
- "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\":[\"in\", [\"To Deliver\", \"To Deliver and Bill\"]]\n}",
- "type": "DocType"
- },
- {
- "color": "#cef6d1",
- "format": "{} Open",
- "label": "Sales Analytics",
- "link_to": "Sales Analytics",
- "stats_filter": "{ \"Status\": \"Open\" }",
- "type": "Report"
- },
- {
- "label": "Sales Order Analysis",
- "link_to": "Sales Order Analysis",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Selling",
- "type": "Dashboard"
- }
- ],
- "shortcuts_label": "Quick Access"
-}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 557c715..7d5e84d 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -16,6 +16,8 @@
"customer_name",
"gender",
"customer_type",
+ "pan",
+ "tax_withholding_category",
"default_bank_account",
"lead_name",
"image",
@@ -34,9 +36,8 @@
"companies",
"currency_and_price_list",
"default_currency",
- "default_price_list",
"column_break_14",
- "language",
+ "default_price_list",
"address_contacts",
"address_html",
"website",
@@ -59,6 +60,7 @@
"column_break_45",
"market_segment",
"industry",
+ "language",
"is_frozen",
"column_break_38",
"loyalty_program",
@@ -479,13 +481,25 @@
"fieldname": "dn_required",
"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"
}
],
"icon": "fa fa-user",
"idx": 363,
"image_field": "image",
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-03-17 11:03:42.706907",
+ "modified": "2021-01-28 12:54:57.258959",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 1f955fc..c452594 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -58,6 +58,7 @@
self.set_loyalty_program()
self.check_customer_group_change()
self.validate_default_bank_account()
+ self.validate_internal_customer()
# set loyalty program tier
if frappe.db.exists('Customer', self.name):
@@ -82,6 +83,14 @@
if not is_company_account:
frappe.throw(_("{0} is not a company bank account").format(frappe.bold(self.default_bank_account)))
+ def validate_internal_customer(self):
+ internal_customer = frappe.db.get_value("Customer",
+ {"is_internal_customer": 1, "represents_company": self.represents_company, "name": ("!=", self.name)}, "name")
+
+ if internal_customer:
+ frappe.throw(_("Internal Customer for company {0} already exists").format(
+ frappe.bold(self.represents_company)))
+
def on_update(self):
self.validate_name_with_customer_group()
self.create_primary_contact()
@@ -117,7 +126,9 @@
'''If Customer created from Lead, update lead status to "Converted"
update Customer link in Quotation, Opportunity'''
if self.lead_name:
- frappe.db.set_value('Lead', self.lead_name, 'status', 'Converted', update_modified=False)
+ lead = frappe.get_doc('Lead', self.lead_name)
+ lead.status = 'Converted'
+ lead.save()
def create_lead_address_contact(self):
if self.lead_name:
@@ -132,7 +143,7 @@
address = frappe.get_doc('Address', address_name.get('name'))
if not address.has_link('Customer', self.name):
address.append('links', dict(link_doctype='Customer', link_name=self.name))
- address.save()
+ address.save(ignore_permissions=self.flags.ignore_permissions)
lead = frappe.db.get_value("Lead", self.lead_name, ["organization_lead", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True)
@@ -150,7 +161,7 @@
contact = frappe.get_doc('Contact', contact_name.get('name'))
if not contact.has_link('Customer', self.name):
contact.append('links', dict(link_doctype='Customer', link_name=self.name))
- contact.save()
+ contact.save(ignore_permissions=self.flags.ignore_permissions)
else:
lead.lead_name = lead.lead_name.lstrip().split(" ")
@@ -398,7 +409,7 @@
# form a list of emails and names to show to the user
credit_controller_users_formatted = [get_formatted_email(user).replace("<", "(").replace(">", ")") for user in credit_controller_users]
if not credit_controller_users_formatted:
- frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.".format(customer)))
+ frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.").format(customer))
message = """Please contact any of the following users to extend the credit limits for {0}:
<br><br><ul><li>{1}</li></ul>""".format(customer, '<li>'.join(credit_controller_users_formatted))
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 87fdaa3..7761aa7 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -54,7 +54,11 @@
details = get_party_details("_Test Customer")
for key, value in iteritems(to_check):
- self.assertEqual(value, details.get(key))
+ val = details.get(key)
+ if not val and not isinstance(val, list):
+ val = None
+
+ self.assertEqual(value, val)
def test_party_details_tax_category(self):
from erpnext.accounts.party import get_party_details
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 12f3260..5a0d9c9 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -7,7 +7,7 @@
frappe.ui.form.on('Quotation', {
setup: function(frm) {
frm.custom_make_buttons = {
- 'Sales Order': 'Make Sales Order'
+ 'Sales Order': 'Sales Order'
},
frm.set_query("quotation_to", function() {
@@ -116,7 +116,7 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"), "btn-default");
+ }, __("Get Items From"), "btn-default");
}
this.toggle_reqd_lead_customer();
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index 5b85187..3eba62b 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:08",
@@ -932,7 +933,7 @@
"is_submittable": 1,
"links": [],
"max_attachments": 1,
- "modified": "2020-07-26 17:46:19.951223",
+ "modified": "2020-10-30 13:58:59.212060",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 20ae19f..5da248c 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -19,13 +19,12 @@
self.indicator_color = 'blue'
self.indicator_title = 'Submitted'
if self.valid_till and getdate(self.valid_till) < getdate(nowdate()):
- self.indicator_color = 'darkgrey'
+ self.indicator_color = 'gray'
self.indicator_title = 'Expired'
def validate(self):
super(Quotation, self).validate()
self.set_status()
- self.update_opportunity()
self.validate_uom_is_integer("stock_uom", "qty")
self.validate_valid_till()
self.set_customer_name()
@@ -50,21 +49,20 @@
lead_name, company_name = frappe.db.get_value("Lead", self.party_name, ["lead_name", "company_name"])
self.customer_name = company_name or lead_name
- def update_opportunity(self):
+ def update_opportunity(self, status):
for opportunity in list(set([d.prevdoc_docname for d in self.get("items")])):
if opportunity:
- self.update_opportunity_status(opportunity)
+ self.update_opportunity_status(status, opportunity)
if self.opportunity:
- self.update_opportunity_status()
+ self.update_opportunity_status(status)
- def update_opportunity_status(self, opportunity=None):
+ def update_opportunity_status(self, status, opportunity=None):
if not opportunity:
opportunity = self.opportunity
opp = frappe.get_doc("Opportunity", opportunity)
- opp.status = None
- opp.set_status(update=True)
+ opp.set_status(status=status, update=True)
def declare_enquiry_lost(self, lost_reasons_list, detailed_reason=None):
if not self.has_sales_order():
@@ -82,7 +80,7 @@
else:
frappe.throw(_("Invalid lost reason {0}, please create a new lost reason").format(frappe.bold(reason.get('lost_reason'))))
- self.update_opportunity()
+ self.update_opportunity('Lost')
self.update_lead()
self.save()
@@ -95,7 +93,7 @@
self.company, self.base_grand_total, self)
#update enquiry status
- self.update_opportunity()
+ self.update_opportunity('Quotation')
self.update_lead()
def on_cancel(self):
@@ -105,7 +103,7 @@
#update enquiry status
self.set_status(update=True)
- self.update_opportunity()
+ self.update_opportunity('Open')
self.update_lead()
def print_other_charges(self,docname):
diff --git a/erpnext/selling/doctype/quotation/quotation_list.js b/erpnext/selling/doctype/quotation/quotation_list.js
index f425acf..b631685 100644
--- a/erpnext/selling/doctype/quotation/quotation_list.js
+++ b/erpnext/selling/doctype/quotation/quotation_list.js
@@ -20,9 +20,9 @@
} else if(doc.status==="Ordered") {
return [__("Ordered"), "green", "status,=,Ordered"];
} else if(doc.status==="Lost") {
- return [__("Lost"), "darkgrey", "status,=,Lost"];
+ return [__("Lost"), "gray", "status,=,Lost"];
} else if(doc.status==="Expired") {
- return [__("Expired"), "darkgrey", "status,=,Expired"];
+ return [__("Expired"), "gray", "status,=,Expired"];
}
}
};
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index b4c3d79..f0143f3 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -108,6 +108,10 @@
sales_order.transaction_date = nowdate()
sales_order.insert()
+ # Remove any unknown taxes if applied
+ sales_order.set('taxes', [])
+ sales_order.save()
+
self.assertEqual(sales_order.payment_schedule[0].payment_amount, 8906.00)
self.assertEqual(sales_order.payment_schedule[0].due_date, getdate(quotation.transaction_date))
self.assertEqual(sales_order.payment_schedule[1].payment_amount, 8906.00)
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation.js b/erpnext/selling/doctype/quotation/tests/test_quotation.js
index d69d799..ad942fe 100644
--- a/erpnext/selling/doctype/quotation/tests/test_quotation.js
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation.js
@@ -46,7 +46,7 @@
assert.ok(cur_frm.doc.items[0].rate == 200, "Price Changed Manually");
assert.equal(cur_frm.doc.total, 1000, "New Total Calculated");
- // Check Terms and Condtions
+ // Check Terms and Conditions
assert.ok(cur_frm.doc.tc_name == "Test Term 1", "Terms and Conditions Checked");
assert.ok(cur_frm.doc.payment_terms_template, "Payment Terms Template is correct");
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 59ae7b2..8b53902 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -47,6 +47,7 @@
"base_amount",
"base_net_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_43",
"valuation_rate",
@@ -634,12 +635,21 @@
"print_hide": 1,
"read_only": 1,
"report_hide": 1
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-19 20:48:43.222229",
+ "modified": "2021-02-23 01:13:54.670763",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.py b/erpnext/selling/doctype/quotation_item/quotation_item.py
index 966b542..7384871 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.py
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.py
@@ -5,8 +5,6 @@
import frappe
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
class QuotationItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 705dcb8..e3b41e6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -8,7 +8,7 @@
frm.custom_make_buttons = {
'Delivery Note': 'Delivery Note',
'Pick List': 'Pick List',
- 'Sales Invoice': 'Invoice',
+ 'Sales Invoice': 'Sales Invoice',
'Material Request': 'Material Request',
'Purchase Order': 'Purchase Order',
'Project': 'Project',
@@ -162,7 +162,7 @@
// sales invoice
if(flt(doc.per_billed, 6) < 100) {
- this.frm.add_custom_button(__('Invoice'), () => me.make_sales_invoice(), __('Create'));
+ this.frm.add_custom_button(__('Sales Invoice'), () => me.make_sales_invoice(), __('Create'));
}
// material request
@@ -171,8 +171,10 @@
this.frm.add_custom_button(__('Request for Raw Materials'), () => this.make_raw_material_request(), __('Create'));
}
- // make purchase order
+ // Make Purchase Order
+ if (!this.frm.doc.is_internal_customer) {
this.frm.add_custom_button(__('Purchase Order'), () => this.make_purchase_order(), __('Create'));
+ }
// maintenance
if(flt(doc.per_delivered, 2) < 100 && (order_is_maintenance || order_is_a_custom_sale)) {
@@ -181,7 +183,7 @@
}
// project
- if(flt(doc.per_delivered, 2) < 100 && (order_is_a_sale || order_is_a_custom_sale) && allow_delivery) {
+ if(flt(doc.per_delivered, 2) < 100) {
this.frm.add_custom_button(__('Project'), () => this.make_project(), __('Create'));
}
@@ -193,16 +195,15 @@
if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
let me = this;
- frappe.model.with_doc("Customer", me.frm.doc.customer, () => {
- let customer = frappe.model.get_doc("Customer", me.frm.doc.customer);
- let internal = customer.is_internal_customer;
- let disabled = customer.disabled;
- if (internal === 1 && disabled === 0) {
- me.frm.add_custom_button("Inter Company Order", function() {
- me.make_inter_company_order();
- }, __('Create'));
- }
- });
+ let internal = me.frm.doc.is_internal_customer;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Order" :
+ "Inter Company Purchase Order";
+
+ me.frm.add_custom_button(button_label, function() {
+ me.make_inter_company_order();
+ }, __('Create'));
+ }
}
}
// payment request
@@ -236,7 +237,7 @@
status: ["!=", "Lost"]
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
}
this.order_type(doc);
@@ -326,9 +327,8 @@
callback: function(r) {
if(r.message) {
frappe.msgprint({
- message: __('Work Orders Created: {0}',
- [r.message.map(function(d) {
- return repl('<a href="#Form/Work Order/%(name)s">%(name)s</a>', {name:d})
+ message: __('Work Orders Created: {0}', [r.message.map(function(d) {
+ return repl('<a href="/app/work-order/%(name)s">%(name)s</a>', {name:d})
}).join(', ')]),
indicator: 'green'
})
@@ -437,7 +437,7 @@
callback: function(r) {
if(r.message) {
frappe.msgprint(__('Material Request {0} submitted.',
- ['<a href="#Form/Material Request/'+r.message.name+'">' + r.message.name+ '</a>']));
+ ['<a href="/app/material-request/'+r.message.name+'">' + r.message.name+ '</a>']));
}
d.hide();
me.frm.reload_doc();
@@ -514,7 +514,7 @@
make_delivery_note: function() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
- frm: me.frm
+ frm: this.frm
})
},
@@ -554,19 +554,26 @@
},
make_purchase_order: function(){
+ let pending_items = this.frm.doc.items.some((item) =>{
+ let pending_qty = flt(item.stock_qty) - flt(item.ordered_qty);
+ return pending_qty > 0;
+ })
+ if(!pending_items){
+ frappe.throw({message: __("Purchase Order already created for all Sales Order items"), title: __("Note")});
+ }
+
var me = this;
var dialog = new frappe.ui.Dialog({
- title: __("For Supplier"),
+ title: __("Select Items"),
fields: [
- {"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
- "description": __("Leave the field empty to make purchase orders for all suppliers"),
- "get_query": function () {
- return {
- query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
- filters: {'parent': me.frm.doc.name}
- }
- }},
- {fieldname: 'items_for_po', fieldtype: 'Table', label: 'Select Items',
+ {
+ "fieldtype": "Check",
+ "label": __("Against Default Supplier"),
+ "fieldname": "against_default_supplier",
+ "default": 0
+ },
+ {
+ fieldname: 'items_for_po', fieldtype: 'Table', label: 'Select Items',
fields: [
{
fieldtype:'Data',
@@ -584,8 +591,8 @@
},
{
fieldtype:'Float',
- fieldname:'qty',
- label: __('Quantity'),
+ fieldname:'pending_qty',
+ label: __('Pending Qty'),
read_only: 1,
in_list_view:1
},
@@ -594,60 +601,97 @@
read_only:1,
fieldname:'uom',
label: __('UOM'),
+ in_list_view:1,
+ },
+ {
+ fieldtype:'Data',
+ fieldname:'supplier',
+ label: __('Supplier'),
+ read_only:1,
in_list_view:1
- }
- ],
- data: cur_frm.doc.items,
- get_data: function() {
- return cur_frm.doc.items
- }
- },
-
- {"fieldtype": "Button", "label": __('Create Purchase Order'), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
- ]
- });
-
- dialog.fields_dict.make_purchase_order.$input.click(function() {
- var args = dialog.get_values();
- let selected_items = dialog.fields_dict.items_for_po.grid.get_selected_children()
- if(selected_items.length == 0) {
- frappe.throw({message: 'Please select Item form Table', title: __('Message'), indicator:'blue'})
- }
- let selected_items_list = []
- for(let i in selected_items){
- selected_items_list.push(selected_items[i].item_code)
- }
- dialog.hide();
- return frappe.call({
- type: "GET",
- method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order",
- args: {
- "source_name": me.frm.doc.name,
- "for_supplier": args.supplier,
- "selected_items": selected_items_list
- },
- freeze: true,
- callback: function(r) {
- if(!r.exc) {
- // var args = dialog.get_values();
- if (args.supplier){
- var doc = frappe.model.sync(r.message);
- frappe.set_route("Form", r.message.doctype, r.message.name);
- }
- else{
- frappe.route_options = {
- "sales_order": me.frm.doc.name
- }
- frappe.set_route("List", "Purchase Order");
- }
- }
+ },
+ ]
}
- })
+ ],
+ primary_action_label: 'Create Purchase Order',
+ primary_action (args) {
+ if (!args) return;
+
+ let selected_items = dialog.fields_dict.items_for_po.grid.get_selected_children();
+ if(selected_items.length == 0) {
+ frappe.throw({message: 'Please select Items from the Table', title: __('Items Required'), indicator:'blue'})
+ }
+
+ dialog.hide();
+
+ var method = args.against_default_supplier ? "make_purchase_order_for_default_supplier" : "make_purchase_order"
+ return frappe.call({
+ method: "erpnext.selling.doctype.sales_order.sales_order." + method,
+ freeze: true,
+ freeze_message: __("Creating Purchase Order ..."),
+ args: {
+ "source_name": me.frm.doc.name,
+ "selected_items": selected_items
+ },
+ freeze: true,
+ callback: function(r) {
+ if(!r.exc) {
+ if (!args.against_default_supplier) {
+ frappe.model.sync(r.message);
+ frappe.set_route("Form", r.message.doctype, r.message.name);
+ }
+ else {
+ frappe.route_options = {
+ "sales_order": me.frm.doc.name
+ }
+ frappe.set_route("List", "Purchase Order");
+ }
+ }
+ }
+ })
+ }
});
- dialog.get_field("items_for_po").grid.only_sortable()
- dialog.get_field("items_for_po").refresh()
+
+ dialog.fields_dict["against_default_supplier"].df.onchange = () => set_po_items_data(dialog);
+
+ function set_po_items_data (dialog) {
+ var against_default_supplier = dialog.get_value("against_default_supplier");
+ var items_for_po = dialog.get_value("items_for_po");
+
+ if (against_default_supplier) {
+ let items_with_supplier = items_for_po.filter((item) => item.supplier)
+
+ dialog.fields_dict["items_for_po"].df.data = items_with_supplier;
+ dialog.get_field("items_for_po").refresh();
+ } else {
+ let po_items = [];
+ me.frm.doc.items.forEach(d => {
+ let pending_qty = (flt(d.stock_qty) - flt(d.ordered_qty)) / flt(d.conversion_factor);
+ if (pending_qty > 0) {
+ po_items.push({
+ "doctype": "Sales Order Item",
+ "name": d.name,
+ "item_name": d.item_name,
+ "item_code": d.item_code,
+ "pending_qty": pending_qty,
+ "uom": d.uom,
+ "supplier": d.supplier
+ });
+ }
+ });
+
+ dialog.fields_dict["items_for_po"].df.data = po_items;
+ dialog.get_field("items_for_po").refresh();
+ }
+ }
+
+ set_po_items_data(dialog);
+ dialog.get_field("items_for_po").grid.only_sortable();
+ dialog.get_field("items_for_po").refresh();
+ dialog.wrapper.find('.grid-heading-row .grid-row-check').click();
dialog.show();
},
+
hold_sales_order: function(){
var me = this;
var d = new frappe.ui.Dialog({
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index a68b738..0a5c665 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-06-18 12:39:59",
@@ -106,6 +107,8 @@
"tc_name",
"terms",
"more_info",
+ "is_internal_customer",
+ "represents_company",
"inter_company_order_reference",
"project",
"party_account_currency",
@@ -1102,7 +1105,8 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Inter Company Order Reference",
- "options": "Purchase Order"
+ "options": "Purchase Order",
+ "read_only": 1
},
{
"description": "Track this Sales Order against any Project",
@@ -1454,13 +1458,29 @@
"hide_seconds": 1,
"label": "Skip Delivery Note",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fetch_from": "customer.is_internal_customer",
+ "fieldname": "is_internal_customer",
+ "fieldtype": "Check",
+ "label": "Is Internal Customer",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "customer.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2020-07-31 14:13:17.962015",
+ "modified": "2021-01-20 23:40:39.929296",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
@@ -1534,7 +1554,7 @@
"sort_field": "modified",
"sort_order": "DESC",
"timeline_field": "customer",
- "title_field": "customer",
+ "title_field": "customer_name",
"track_changes": 1,
"track_seen": 1
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index f882898..e561291 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -5,7 +5,7 @@
import frappe
import json
import frappe.utils
-from frappe.utils import cstr, flt, getdate, cint, nowdate, add_days, get_link_to_form
+from frappe.utils import cstr, flt, getdate, cint, nowdate, add_days, get_link_to_form, strip_html
from frappe import _
from six import string_types
from frappe.model.utils import get_fetch_values
@@ -14,7 +14,6 @@
from frappe.desk.notifications import clear_doctype_notifications
from frappe.contacts.doctype.address.address import get_company_address
from erpnext.controllers.selling_controller import SellingController
-from frappe.automation.doctype.auto_repeat.auto_repeat import get_next_schedule_date
from erpnext.selling.doctype.customer.customer import check_credit_limit
from erpnext.stock.doctype.item.item import get_item_defaults
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
@@ -159,7 +158,6 @@
frappe.throw(_("Quotation {0} is cancelled").format(quotation))
doc.set_status(update=True)
- doc.update_opportunity()
def validate_drop_ship(self):
for d in self.get('items'):
@@ -182,6 +180,7 @@
update_coupon_code_count(self.coupon_code,'used')
def on_cancel(self):
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
super(SalesOrder, self).on_cancel()
# Cannot cancel closed SO
@@ -418,8 +417,7 @@
def on_recurring(self, reference_doc, auto_repeat_doc):
def _get_delivery_date(ref_doc_delivery_date, red_doc_transaction_date, transaction_date):
- delivery_date = get_next_schedule_date(ref_doc_delivery_date,
- auto_repeat_doc.frequency, auto_repeat_doc.start_date, cint(auto_repeat_doc.repeat_on_day))
+ delivery_date = auto_repeat_doc.get_next_schedule_date(schedule_date=ref_doc_delivery_date)
if delivery_date <= transaction_date:
delivery_date_diff = frappe.utils.date_diff(ref_doc_delivery_date, red_doc_transaction_date)
@@ -443,25 +441,19 @@
for item in self.items:
if item.ensure_delivery_based_on_produced_serial_no:
if item.item_code in normal_items:
- frappe.throw(_("Cannot ensure delivery by Serial No as \
- Item {0} is added with and without Ensure Delivery by \
- Serial No.").format(item.item_code))
+ frappe.throw(_("Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.").format(item.item_code))
if item.item_code not in reserved_items:
if not frappe.get_cached_value("Item", item.item_code, "has_serial_no"):
- frappe.throw(_("Item {0} has no Serial No. Only serilialized items \
- can have delivery based on Serial No").format(item.item_code))
+ frappe.throw(_("Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No").format(item.item_code))
if not frappe.db.exists("BOM", {"item": item.item_code, "is_active": 1}):
- frappe.throw(_("No active BOM found for item {0}. Delivery by \
- Serial No cannot be ensured").format(item.item_code))
+ frappe.throw(_("No active BOM found for item {0}. Delivery by Serial No cannot be ensured").format(item.item_code))
reserved_items.append(item.item_code)
else:
normal_items.append(item.item_code)
if not item.ensure_delivery_based_on_produced_serial_no and \
item.item_code in reserved_items:
- frappe.throw(_("Cannot ensure delivery by Serial No as \
- Item {0} is added with and without Ensure Delivery by \
- Serial No.").format(item.item_code))
+ frappe.throw(_("Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.").format(item.item_code))
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
@@ -785,7 +777,9 @@
return data
@frappe.whitelist()
-def make_purchase_order(source_name, for_supplier=None, selected_items=[], target_doc=None):
+def make_purchase_order_for_default_supplier(source_name, selected_items=None, target_doc=None):
+ if not selected_items: return
+
if isinstance(selected_items, string_types):
selected_items = json.loads(selected_items)
@@ -822,102 +816,133 @@
def update_item(source, target, source_parent):
target.schedule_date = source.delivery_date
- target.qty = flt(source.qty) - flt(source.ordered_qty)
- target.stock_qty = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.conversion_factor)
+ target.qty = flt(source.qty) - (flt(source.ordered_qty) / flt(source.conversion_factor))
+ target.stock_qty = (flt(source.stock_qty) - flt(source.ordered_qty))
target.project = source_parent.project
- suppliers =[]
- if for_supplier:
- suppliers.append(for_supplier)
- else:
- sales_order = frappe.get_doc("Sales Order", source_name)
- for item in sales_order.items:
- if item.supplier and item.supplier not in suppliers:
- suppliers.append(item.supplier)
+ suppliers = [item.get('supplier') for item in selected_items if item.get('supplier') and item.get('supplier')]
+ suppliers = list(set(suppliers))
+
+ items_to_map = [item.get('item_code') for item in selected_items if item.get('item_code') and item.get('item_code')]
+ items_to_map = list(set(items_to_map))
if not suppliers:
frappe.throw(_("Please set a Supplier against the Items to be considered in the Purchase Order."))
for supplier in suppliers:
- po =frappe.get_list("Purchase Order", filters={"sales_order":source_name, "supplier":supplier, "docstatus": ("<", "2")})
- if len(po) == 0:
- doc = get_mapped_doc("Sales Order", source_name, {
- "Sales Order": {
- "doctype": "Purchase Order",
- "field_no_map": [
- "address_display",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "contact_person",
- "taxes_and_charges"
- ],
- "validation": {
- "docstatus": ["=", 1]
- }
- },
- "Sales Order Item": {
- "doctype": "Purchase Order Item",
- "field_map": [
- ["name", "sales_order_item"],
- ["parent", "sales_order"],
- ["stock_uom", "stock_uom"],
- ["uom", "uom"],
- ["conversion_factor", "conversion_factor"],
- ["delivery_date", "schedule_date"]
- ],
- "field_no_map": [
- "rate",
- "price_list_rate",
- "item_tax_template"
- ],
- "postprocess": update_item,
- "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == supplier and doc.item_code in selected_items
+ doc = get_mapped_doc("Sales Order", source_name, {
+ "Sales Order": {
+ "doctype": "Purchase Order",
+ "field_no_map": [
+ "address_display",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "contact_person",
+ "taxes_and_charges",
+ "shipping_address",
+ "terms"
+ ],
+ "validation": {
+ "docstatus": ["=", 1]
}
- }, target_doc, set_missing_values)
- if not for_supplier:
- doc.insert()
- else:
- suppliers =[]
- if suppliers:
- if not for_supplier:
- frappe.db.commit()
- return doc
- else:
- frappe.msgprint(_("PO already created for all sales order items"))
+ },
+ "Sales Order Item": {
+ "doctype": "Purchase Order Item",
+ "field_map": [
+ ["name", "sales_order_item"],
+ ["parent", "sales_order"],
+ ["stock_uom", "stock_uom"],
+ ["uom", "uom"],
+ ["conversion_factor", "conversion_factor"],
+ ["delivery_date", "schedule_date"]
+ ],
+ "field_no_map": [
+ "rate",
+ "price_list_rate",
+ "item_tax_template",
+ "discount_percentage",
+ "discount_amount",
+ "pricing_rules"
+ ],
+ "postprocess": update_item,
+ "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.supplier == supplier and doc.item_code in items_to_map
+ }
+ }, target_doc, set_missing_values)
+ doc.insert()
+ frappe.db.commit()
+ return doc
@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def get_supplier(doctype, txt, searchfield, start, page_len, filters):
- supp_master_name = frappe.defaults.get_user_default("supp_master_name")
- if supp_master_name == "Supplier Name":
- fields = ["name", "supplier_group"]
- else:
- fields = ["name", "supplier_name", "supplier_group"]
- fields = ", ".join(fields)
+def make_purchase_order(source_name, selected_items=None, target_doc=None):
+ if not selected_items: return
- return frappe.db.sql("""select {field} from `tabSupplier`
- where docstatus < 2
- and ({key} like %(txt)s
- or supplier_name like %(txt)s)
- and name in (select supplier from `tabSales Order Item` where parent = %(parent)s)
- and name not in (select supplier from `tabPurchase Order` po inner join `tabPurchase Order Item` poi
- on po.name=poi.parent where po.docstatus<2 and poi.sales_order=%(parent)s)
- order by
- if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
- if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999),
- name, supplier_name
- limit %(start)s, %(page_len)s """.format(**{
- 'field': fields,
- 'key': frappe.db.escape(searchfield)
- }), {
- 'txt': "%%%s%%" % txt,
- '_txt': txt.replace("%", ""),
- 'start': start,
- 'page_len': page_len,
- 'parent': filters.get('parent')
- })
+ if isinstance(selected_items, string_types):
+ 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')]
+ items_to_map = list(set(items_to_map))
+
+ def set_missing_values(source, target):
+ target.supplier = ""
+ target.apply_discount_on = ""
+ target.additional_discount_percentage = 0.0
+ target.discount_amount = 0.0
+ target.inter_company_order_reference = ""
+ target.customer = ""
+ target.customer_name = ""
+ target.run_method("set_missing_values")
+ target.run_method("calculate_taxes_and_totals")
+
+ def update_item(source, target, source_parent):
+ target.schedule_date = source.delivery_date
+ target.qty = flt(source.qty) - (flt(source.ordered_qty) / flt(source.conversion_factor))
+ target.stock_qty = (flt(source.stock_qty) - flt(source.ordered_qty))
+ target.project = source_parent.project
+
+ # po = frappe.get_list("Purchase Order", filters={"sales_order":source_name, "supplier":supplier, "docstatus": ("<", "2")})
+ doc = get_mapped_doc("Sales Order", source_name, {
+ "Sales Order": {
+ "doctype": "Purchase Order",
+ "field_no_map": [
+ "address_display",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "contact_person",
+ "taxes_and_charges",
+ "shipping_address",
+ "terms"
+ ],
+ "validation": {
+ "docstatus": ["=", 1]
+ }
+ },
+ "Sales Order Item": {
+ "doctype": "Purchase Order Item",
+ "field_map": [
+ ["name", "sales_order_item"],
+ ["parent", "sales_order"],
+ ["stock_uom", "stock_uom"],
+ ["uom", "uom"],
+ ["conversion_factor", "conversion_factor"],
+ ["delivery_date", "schedule_date"]
+ ],
+ "field_no_map": [
+ "rate",
+ "price_list_rate",
+ "item_tax_template",
+ "discount_percentage",
+ "discount_amount",
+ "supplier",
+ "pricing_rules"
+ ],
+ "postprocess": update_item,
+ "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map
+ }
+ }, target_doc, set_missing_values)
+ return doc
@frappe.whitelist()
def make_work_orders(items, sales_order, company, project=None):
@@ -989,20 +1014,24 @@
doctype = 'Material Request',
transaction_date = nowdate(),
company = company,
- requested_by = frappe.session.user,
material_request_type = 'Purchase'
))
for item in raw_materials:
item_doc = frappe.get_cached_doc('Item', item.get('item_code'))
+
schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days))
- material_request.append('items', {
- 'item_code': item.get('item_code'),
- 'qty': item.get('quantity'),
- 'schedule_date': schedule_date,
- 'warehouse': item.get('warehouse'),
- 'sales_order': sales_order,
- 'project': project
+ row = material_request.append('items', {
+ 'item_code': item.get('item_code'),
+ 'qty': item.get('quantity'),
+ 'schedule_date': schedule_date,
+ 'warehouse': item.get('warehouse'),
+ 'sales_order': sales_order,
+ 'project': project
})
+
+ if not (strip_html(item.get("description")) and strip_html(item_doc.description)):
+ row.description = item_doc.item_name or item.get('item_code')
+
material_request.insert()
material_request.flags.ignore_permissions = 1
material_request.run_method("set_missing_values")
@@ -1058,4 +1087,4 @@
if not total_produced_qty and frappe.flags.in_patch: return
- frappe.db.set_value('Sales Order Item', sales_order_item, 'produced_qty', total_produced_qty)
\ No newline at end of file
+ frappe.db.set_value('Sales Order Item', sales_order_item, 'produced_qty', total_produced_qty)
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 735b071..0fdfb1b 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1,11 +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 frappe
import json
-from frappe.utils import flt, add_days, nowdate
-import frappe.permissions
import unittest
+import frappe
+import frappe.permissions
+from frappe.utils import flt, add_days, nowdate
+from frappe.core.doctype.user_permission.test_user_permission import create_user
from erpnext.selling.doctype.sales_order.sales_order \
import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -17,6 +18,18 @@
from erpnext.stock.doctype.item.test_item import make_item
class TestSalesOrder(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.unlink_setting = int(frappe.db.get_value("Accounts Settings", "Accounts Settings",
+ "unlink_advance_payment_on_cancelation_of_order"))
+
+ @classmethod
+ def tearDownClass(cls) -> None:
+ # reset config to previous state
+ frappe.db.set_value("Accounts Settings", "Accounts Settings",
+ "unlink_advance_payment_on_cancelation_of_order", cls.unlink_setting)
+
def tearDown(self):
frappe.set_user("Administrator")
@@ -89,6 +102,8 @@
self.assertEqual(len(si.get("items")), 1)
si.insert()
+ si.set('taxes', [])
+ si.save()
self.assertEqual(si.payment_schedule[0].payment_amount, 500.0)
self.assertEqual(si.payment_schedule[0].due_date, so.transaction_date)
@@ -323,6 +338,9 @@
create_dn_against_so(so.name, 4)
make_sales_invoice(so.name)
+ prev_total = so.get("base_total")
+ prev_total_in_words = so.get("base_in_words")
+
first_item_of_so = so.get("items")[0]
trans_item = json.dumps([
{'item_code' : first_item_of_so.item_code, 'rate' : first_item_of_so.rate, \
@@ -338,6 +356,12 @@
self.assertEqual(so.get("items")[-1].amount, 1400)
self.assertEqual(so.status, 'To Deliver and Bill')
+ updated_total = so.get("base_total")
+ updated_total_in_words = so.get("base_in_words")
+
+ self.assertEqual(updated_total, prev_total+1400)
+ self.assertNotEqual(updated_total_in_words, prev_total_in_words)
+
def test_update_child_removing_item(self):
so = make_sales_order(**{
"item_list": [{
@@ -402,13 +426,27 @@
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 2, 'docname': so.items[0].name}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
+ def test_update_child_with_precision(self):
+ from frappe.model.meta import get_field_precision
+ from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+
+ precision = get_field_precision(frappe.get_meta("Sales Order Item").get_field("rate"))
+
+ make_property_setter("Sales Order Item", "rate", "precision", 7, "Currency")
+ so = make_sales_order(item_code= "_Test Item", qty=4, rate=200.34664)
+
+ trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200.34669, 'qty' : 4, 'docname': so.items[0].name}])
+ update_child_qty_rate('Sales Order', trans_item, so.name)
+
+ so.reload()
+ self.assertEqual(so.items[0].rate, 200.34669)
+ make_property_setter("Sales Order Item", "rate", "precision", precision, "Currency")
+
def test_update_child_perm(self):
so = make_sales_order(item_code= "_Test Item", qty=4)
- user = 'test@example.com'
- test_user = frappe.get_doc('User', user)
- test_user.add_roles("Accounts User")
- frappe.set_user(user)
+ test_user = create_user("test_so_child_perms@example.com", "Accounts User")
+ frappe.set_user(test_user.name)
# update qty
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': so.items[0].name}])
@@ -417,9 +455,7 @@
# add new item
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 100, 'qty' : 2}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
- test_user.remove_roles("Accounts User")
- frappe.set_user("Administrator")
-
+
def test_update_child_qty_rate_with_workflow(self):
from frappe.model.workflow import apply_workflow
@@ -427,7 +463,6 @@
so = make_sales_order(item_code= "_Test Item", qty=1, rate=150, do_not_submit=1)
apply_workflow(so, 'Approve')
- frappe.set_user("Administrator")
user = 'test@example.com'
test_user = frappe.get_doc('User', user)
test_user.add_roles("Sales User", "Test Junior Approver")
@@ -488,34 +523,121 @@
so.reload()
self.assertEqual(so.packed_items[0].qty, 8)
- def test_warehouse_user(self):
- frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
- frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
- frappe.permissions.add_user_permission("Company", "_Test Company 1", "test2@example.com")
+ def test_update_child_with_tax_template(self):
+ """
+ Test Action: Create a SO with one item having its tax account head already in the SO.
+ Add the same item + new item with tax template via Update Items.
+ Expected result: First Item's tax row is updated. New tax row is added for second Item.
+ """
+ if not frappe.db.exists("Item", "Test Item with Tax"):
+ make_item("Test Item with Tax", {
+ 'is_stock_item': 1,
+ })
- test_user = frappe.get_doc("User", "test@example.com")
- test_user.add_roles("Sales User", "Stock User")
- test_user.remove_roles("Sales Manager")
+ if not frappe.db.exists("Item Tax Template", {"title": 'Test Update Items Template'}):
+ frappe.get_doc({
+ 'doctype': 'Item Tax Template',
+ 'title': 'Test Update Items Template',
+ 'company': '_Test Company',
+ 'taxes': [
+ {
+ 'tax_type': "_Test Account Service Tax - _TC",
+ 'tax_rate': 10,
+ }
+ ]
+ }).insert()
+
+ new_item_with_tax = frappe.get_doc("Item", "Test Item with Tax")
+
+ new_item_with_tax.append("taxes", {
+ "item_tax_template": "Test Update Items Template - _TC",
+ "valid_from": nowdate()
+ })
+ new_item_with_tax.save()
+
+ tax_template = "_Test Account Excise Duty @ 10 - _TC"
+ item = "_Test Item Home Desktop 100"
+ if not frappe.db.exists("Item Tax", {"parent":item, "item_tax_template":tax_template}):
+ item_doc = frappe.get_doc("Item", item)
+ item_doc.append("taxes", {
+ "item_tax_template": tax_template,
+ "valid_from": nowdate()
+ })
+ item_doc.save()
+ else:
+ # update valid from
+ frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = CURDATE()
+ where parent = %(item)s and item_tax_template = %(tax)s""",
+ {"item": item, "tax": tax_template})
+
+ so = make_sales_order(item_code=item, qty=1, do_not_save=1)
+
+ so.append("taxes", {
+ "account_head": "_Test Account Excise Duty - _TC",
+ "charge_type": "On Net Total",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Excise Duty",
+ "doctype": "Sales Taxes and Charges",
+ "rate": 10
+ })
+ so.insert()
+ so.submit()
+
+ self.assertEqual(so.taxes[0].tax_amount, 10)
+ self.assertEqual(so.taxes[0].total, 110)
+
+ old_stock_settings_value = frappe.db.get_single_value("Stock Settings", "default_warehouse")
+ frappe.db.set_value("Stock Settings", None, "default_warehouse", "_Test Warehouse - _TC")
+
+ items = json.dumps([
+ {'item_code' : item, 'rate' : 100, 'qty' : 1, 'docname': so.items[0].name},
+ {'item_code' : item, 'rate' : 200, 'qty' : 1}, # added item whose tax account head already exists in PO
+ {'item_code' : new_item_with_tax.name, 'rate' : 100, 'qty' : 1} # added item whose tax account head is missing in PO
+ ])
+ update_child_qty_rate('Sales Order', items, so.name)
+
+ so.reload()
+ self.assertEqual(so.taxes[0].tax_amount, 40)
+ self.assertEqual(so.taxes[0].total, 440)
+ self.assertEqual(so.taxes[1].account_head, "_Test Account Service Tax - _TC")
+ self.assertEqual(so.taxes[1].tax_amount, 40)
+ self.assertEqual(so.taxes[1].total, 480)
+
+ # teardown
+ frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = NULL
+ where parent = %(item)s and item_tax_template = %(tax)s""", {"item": item, "tax": tax_template})
+ so.cancel()
+ so.delete()
+ new_item_with_tax.delete()
+ frappe.get_doc("Item Tax Template", "Test Update Items Template - _TC").delete()
+ frappe.db.set_value("Stock Settings", None, "default_warehouse", old_stock_settings_value)
+
+ def test_warehouse_user(self):
+ test_user = create_user("test_so_warehouse_user@example.com", "Sales User", "Stock User")
test_user_2 = frappe.get_doc("User", "test2@example.com")
test_user_2.add_roles("Sales User", "Stock User")
test_user_2.remove_roles("Sales Manager")
- frappe.set_user("test@example.com")
+ frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", test_user.name)
+ frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", test_user_2.name)
+ frappe.permissions.add_user_permission("Company", "_Test Company 1", test_user_2.name)
- so = make_sales_order(company="_Test Company 1",
+ frappe.set_user(test_user.name)
+
+ so = make_sales_order(company="_Test Company 1", customer="_Test Customer 1",
warehouse="_Test Warehouse 2 - _TC1", do_not_save=True)
so.conversion_rate = 0.02
so.plc_conversion_rate = 0.02
self.assertRaises(frappe.PermissionError, so.insert)
- frappe.set_user("test2@example.com")
+ frappe.set_user(test_user_2.name)
so.insert()
frappe.set_user("Administrator")
- frappe.permissions.remove_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
- frappe.permissions.remove_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
- frappe.permissions.remove_user_permission("Company", "_Test Company 1", "test2@example.com")
+ frappe.permissions.remove_user_permission("Warehouse", "_Test Warehouse 1 - _TC", test_user.name)
+ frappe.permissions.remove_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", test_user_2.name)
+ frappe.permissions.remove_user_permission("Company", "_Test Company 1", test_user_2.name)
def test_block_delivery_note_against_cancelled_sales_order(self):
so = make_sales_order()
@@ -581,12 +703,12 @@
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
def test_drop_shipping(self):
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order
+ from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier, \
+ update_status as so_update_status
from erpnext.buying.doctype.purchase_order.purchase_order import update_status
- make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100)
+ # make items
po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "delivered_by_supplier": 1})
-
dn_item = make_item("_Test Regular Item", {"is_stock_item": 1})
so_items = [
@@ -608,80 +730,114 @@
]
if frappe.db.get_value("Item", "_Test Regular Item", "is_stock_item")==1:
- make_stock_entry(item="_Test Regular Item", target="_Test Warehouse - _TC", qty=10, rate=100)
+ make_stock_entry(item="_Test Regular Item", target="_Test Warehouse - _TC", qty=2, rate=100)
- #setuo existing qty from bin
- bin = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"},
- fields=["ordered_qty", "reserved_qty"])
-
- existing_ordered_qty = bin[0].ordered_qty if bin else 0.0
- existing_reserved_qty = bin[0].reserved_qty if bin else 0.0
-
- bin = frappe.get_all("Bin", filters={"item_code": dn_item.item_code,
- "warehouse": "_Test Warehouse - _TC"}, fields=["reserved_qty"])
-
- existing_reserved_qty_for_dn_item = bin[0].reserved_qty if bin else 0.0
-
- #create so, po and partial dn
+ #create so, po and dn
so = make_sales_order(item_list=so_items, do_not_submit=True)
so.submit()
- po = make_purchase_order(so.name, '_Test Supplier', selected_items=[so_items[0]['item_code']])
+ po = make_purchase_order_for_default_supplier(so.name, selected_items=[so_items[0]])
po.submit()
- dn = create_dn_against_so(so.name, delivered_qty=1)
+ dn = create_dn_against_so(so.name, delivered_qty=2)
self.assertEqual(so.customer, po.customer)
self.assertEqual(po.items[0].sales_order, so.name)
self.assertEqual(po.items[0].item_code, po_item.item_code)
self.assertEqual(dn.items[0].item_code, dn_item.item_code)
-
- #test ordered_qty and reserved_qty
- bin = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"},
- fields=["ordered_qty", "reserved_qty"])
-
- ordered_qty = bin[0].ordered_qty if bin else 0.0
- reserved_qty = bin[0].reserved_qty if bin else 0.0
-
- self.assertEqual(abs(flt(ordered_qty)), existing_ordered_qty)
- self.assertEqual(abs(flt(reserved_qty)), existing_reserved_qty)
-
- reserved_qty = frappe.db.get_value("Bin",
- {"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty")
-
- self.assertEqual(abs(flt(reserved_qty)), existing_reserved_qty_for_dn_item + 1)
-
#test po_item length
self.assertEqual(len(po.items), 1)
- #test per_delivered status
+ # test ordered_qty and reserved_qty for drop ship item
+ bin_po_item = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"},
+ fields=["ordered_qty", "reserved_qty"])
+
+ ordered_qty = bin_po_item[0].ordered_qty if bin_po_item else 0.0
+ reserved_qty = bin_po_item[0].reserved_qty if bin_po_item else 0.0
+
+ # drop ship PO should not impact bin, test the same
+ self.assertEqual(abs(flt(ordered_qty)), 0)
+ self.assertEqual(abs(flt(reserved_qty)), 0)
+
+ # test per_delivered status
update_status("Delivered", po.name)
- self.assertEqual(flt(frappe.db.get_value("Sales Order", so.name, "per_delivered"), 2), 75.00)
+ self.assertEqual(flt(frappe.db.get_value("Sales Order", so.name, "per_delivered"), 2), 100.00)
+ po.load_from_db()
- #test reserved qty after complete delivery
- dn = create_dn_against_so(so.name, delivered_qty=1)
- reserved_qty = frappe.db.get_value("Bin",
- {"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty")
-
- self.assertEqual(abs(flt(reserved_qty)), existing_reserved_qty_for_dn_item)
-
- #test after closing so
+ # test after closing so
so.db_set('status', "Closed")
so.update_reserved_qty()
- bin = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"},
+ # test ordered_qty and reserved_qty for drop ship item after closing so
+ bin_po_item = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"},
fields=["ordered_qty", "reserved_qty"])
- ordered_qty = bin[0].ordered_qty if bin else 0.0
- reserved_qty = bin[0].reserved_qty if bin else 0.0
+ ordered_qty = bin_po_item[0].ordered_qty if bin_po_item else 0.0
+ reserved_qty = bin_po_item[0].reserved_qty if bin_po_item else 0.0
- self.assertEqual(abs(flt(ordered_qty)), existing_ordered_qty)
- self.assertEqual(abs(flt(reserved_qty)), existing_reserved_qty)
+ self.assertEqual(abs(flt(ordered_qty)), 0)
+ self.assertEqual(abs(flt(reserved_qty)), 0)
- reserved_qty = frappe.db.get_value("Bin",
- {"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty")
+ # teardown
+ so_update_status("Draft", so.name)
+ dn.load_from_db()
+ dn.cancel()
+ po.cancel()
+ so.load_from_db()
+ so.cancel()
- self.assertEqual(abs(flt(reserved_qty)), existing_reserved_qty_for_dn_item)
+ def test_drop_shipping_partial_order(self):
+ from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier, \
+ update_status as so_update_status
+
+ # make items
+ po_item1 = make_item("_Test Item for Drop Shipping 1", {"is_stock_item": 1, "delivered_by_supplier": 1})
+ po_item2 = make_item("_Test Item for Drop Shipping 2", {"is_stock_item": 1, "delivered_by_supplier": 1})
+
+ so_items = [
+ {
+ "item_code": po_item1.item_code,
+ "warehouse": "",
+ "qty": 2,
+ "rate": 400,
+ "delivered_by_supplier": 1,
+ "supplier": '_Test Supplier'
+ },
+ {
+ "item_code": po_item2.item_code,
+ "warehouse": "",
+ "qty": 2,
+ "rate": 400,
+ "delivered_by_supplier": 1,
+ "supplier": '_Test Supplier'
+ }
+ ]
+
+ # create so and po
+ so = make_sales_order(item_list=so_items, do_not_submit=True)
+ so.submit()
+
+ # create po for only one item
+ po1 = make_purchase_order_for_default_supplier(so.name, selected_items=[so_items[0]])
+ po1.submit()
+
+ self.assertEqual(so.customer, po1.customer)
+ self.assertEqual(po1.items[0].sales_order, so.name)
+ self.assertEqual(po1.items[0].item_code, po_item1.item_code)
+ #test po item length
+ self.assertEqual(len(po1.items), 1)
+
+ # create po for remaining item
+ po2 = make_purchase_order_for_default_supplier(so.name, selected_items=[so_items[1]])
+ po2.submit()
+
+ # teardown
+ so_update_status("Draft", so.name)
+
+ po1.cancel()
+ po2.cancel()
+ so.load_from_db()
+ so.cancel()
def test_reserved_qty_for_closing_so(self):
bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"},
@@ -898,6 +1054,38 @@
self.assertRaises(frappe.LinkExistsError, so_doc.cancel)
+ def test_cancel_sales_order_after_cancel_payment_entry(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+ # make a sales order
+ so = make_sales_order()
+
+ # disable unlinking of payment entry
+ frappe.db.set_value("Accounts Settings", "Accounts Settings",
+ "unlink_advance_payment_on_cancelation_of_order", 0)
+
+ # create a payment entry against sales order
+ pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Bank - _TC")
+ pe.reference_no = "1"
+ pe.reference_date = nowdate()
+ pe.paid_from_account_currency = so.currency
+ pe.paid_to_account_currency = so.currency
+ pe.source_exchange_rate = 1
+ pe.target_exchange_rate = 1
+ pe.paid_amount = so.grand_total
+ pe.save(ignore_permissions=True)
+ pe.submit()
+
+ # Cancel payment entry
+ po_doc = frappe.get_doc("Payment Entry", pe.name)
+ po_doc.cancel()
+
+ # Cancel sales order
+ try:
+ so_doc = frappe.get_doc('Sales Order', so.name)
+ so_doc.cancel()
+ except Exception:
+ self.fail("Can not cancel sales order with linked cancelled payment entry")
+
def test_request_for_raw_materials(self):
item = make_item("_Test Finished Item", {"is_stock_item": 1,
"maintain_stock": 1,
@@ -975,6 +1163,7 @@
so.company = args.company or "_Test Company"
so.customer = args.customer or "_Test Customer"
so.currency = args.currency or "INR"
+ so.po_no = args.po_no or '12345'
if args.selling_price_list:
so.selling_price_list = args.selling_price_list
@@ -1055,4 +1244,4 @@
))
workflow.insert(ignore_permissions=True)
- return workflow
\ No newline at end of file
+ return workflow
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index eff17f8..1e5590e 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -46,6 +46,7 @@
"base_rate",
"base_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_24",
"net_rate",
@@ -214,7 +215,6 @@
"fieldtype": "Link",
"label": "UOM",
"options": "UOM",
- "print_hide": 0,
"reqd": 1
},
{
@@ -780,12 +780,21 @@
"fieldname": "manufacturing_section_section",
"fieldtype": "Section Break",
"label": "Manufacturing Section"
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-29 20:54:32.309460",
+ "modified": "2021-02-23 01:15:05.803091",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",
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 4a87a0c..27f303d 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
@@ -5,11 +5,9 @@
import frappe
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
class SalesOrderItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
def on_doctype_update():
frappe.db.add_index("Sales Order Item", ["item_code", "warehouse"])
\ No newline at end of file
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index dcbc074..2104c01 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -63,7 +63,7 @@
},
{
"default": "15",
- "description": "Auto close Opportunity after 15 days",
+ "description": "Auto close Opportunity after the no. of days mentioned above",
"fieldname": "close_opportunity_after_days",
"fieldtype": "Int",
"label": "Close Opportunity After Days"
@@ -80,18 +80,18 @@
{
"fieldname": "so_required",
"fieldtype": "Select",
- "label": "Sales Order Required for Sales Invoice & Delivery Note Creation",
+ "label": "Is Sales Order Required for Sales Invoice & Delivery Note Creation?",
"options": "No\nYes"
},
{
"fieldname": "dn_required",
"fieldtype": "Select",
- "label": "Delivery Note Required for Sales Invoice Creation",
+ "label": "Is Delivery Note Required for Sales Invoice Creation?",
"options": "No\nYes"
},
{
"default": "Each Transaction",
- "description": "How often should project and company be updated based on Sales Transactions.",
+ "description": "How often should Project and Company be updated based on Sales Transactions?",
"fieldname": "sales_update_frequency",
"fieldtype": "Select",
"label": "Sales Update Frequency",
@@ -108,38 +108,39 @@
"default": "0",
"fieldname": "editable_price_list_rate",
"fieldtype": "Check",
- "label": "Allow user to edit Price List Rate in transactions"
+ "label": "Allow User to Edit Price List Rate in Transactions"
},
{
"default": "0",
"fieldname": "allow_multiple_items",
"fieldtype": "Check",
- "label": "Allow Item to be added multiple times in a transaction"
+ "label": "Allow Item to Be Added Multiple Times in a Transaction"
},
{
"default": "0",
"fieldname": "allow_against_multiple_purchase_orders",
"fieldtype": "Check",
- "label": "Allow multiple Sales Orders against a Customer's Purchase Order"
+ "label": "Allow Multiple Sales Orders Against a Customer's Purchase Order"
},
{
"default": "0",
"fieldname": "validate_selling_price",
"fieldtype": "Check",
- "label": "Validate Selling Price for Item against Purchase Rate or Valuation Rate"
+ "label": "Validate Selling Price for Item Against Purchase Rate or Valuation Rate"
},
{
"default": "0",
"fieldname": "hide_tax_id",
"fieldtype": "Check",
- "label": "Hide Customer's Tax Id from Sales Transactions"
+ "label": "Hide Customer's Tax ID from Sales Transactions"
}
],
"icon": "fa fa-cog",
"idx": 1,
+ "index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-06-01 13:58:35.637858",
+ "modified": "2021-03-02 17:35:53.603607",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
@@ -156,5 +157,6 @@
}
],
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/onscan.js b/erpnext/selling/page/point_of_sale/onscan.js
deleted file mode 100644
index 428dc75..0000000
--- a/erpnext/selling/page/point_of_sale/onscan.js
+++ /dev/null
@@ -1 +0,0 @@
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t()):e.onScan=t()}(this,function(){var d={attachTo:function(e,t){if(void 0!==e.scannerDetectionData)throw new Error("onScan.js is already initialized for DOM element "+e);var n={onScan:function(e,t){},onScanError:function(e){},onKeyProcess:function(e,t){},onKeyDetect:function(e,t){},onPaste:function(e,t){},keyCodeMapper:function(e){return d.decodeKeyEvent(e)},onScanButtonLongPress:function(){},scanButtonKeyCode:!1,scanButtonLongPressTime:500,timeBeforeScanTest:100,avgTimeByChar:30,minLength:6,suffixKeyCodes:[9,13],prefixKeyCodes:[],ignoreIfFocusOn:!1,stopPropagation:!1,preventDefault:!1,captureEvents:!1,reactToKeydown:!0,reactToPaste:!1,singleScanQty:1};return t=this._mergeOptions(n,t),e.scannerDetectionData={options:t,vars:{firstCharTime:0,lastCharTime:0,accumulatedString:"",testTimer:!1,longPressTimeStart:0,longPressed:!1}},!0===t.reactToPaste&&e.addEventListener("paste",this._handlePaste,t.captureEvents),!1!==t.scanButtonKeyCode&&e.addEventListener("keyup",this._handleKeyUp,t.captureEvents),!0!==t.reactToKeydown&&!1===t.scanButtonKeyCode||e.addEventListener("keydown",this._handleKeyDown,t.captureEvents),this},detachFrom:function(e){e.scannerDetectionData.options.reactToPaste&&e.removeEventListener("paste",this._handlePaste),!1!==e.scannerDetectionData.options.scanButtonKeyCode&&e.removeEventListener("keyup",this._handleKeyUp),e.removeEventListener("keydown",this._handleKeyDown),e.scannerDetectionData=void 0},getOptions:function(e){return e.scannerDetectionData.options},setOptions:function(e,t){switch(e.scannerDetectionData.options.reactToPaste){case!0:!1===t.reactToPaste&&e.removeEventListener("paste",this._handlePaste);break;case!1:!0===t.reactToPaste&&e.addEventListener("paste",this._handlePaste)}switch(e.scannerDetectionData.options.scanButtonKeyCode){case!1:!1!==t.scanButtonKeyCode&&e.addEventListener("keyup",this._handleKeyUp);break;default:!1===t.scanButtonKeyCode&&e.removeEventListener("keyup",this._handleKeyUp)}return e.scannerDetectionData.options=this._mergeOptions(e.scannerDetectionData.options,t),this._reinitialize(e),this},decodeKeyEvent:function(e){var t=this._getNormalizedKeyNum(e);switch(!0){case 48<=t&&t<=90:case 106<=t&&t<=111:if(void 0!==e.key&&""!==e.key)return e.key;var n=String.fromCharCode(t);switch(e.shiftKey){case!1:n=n.toLowerCase();break;case!0:n=n.toUpperCase()}return n;case 96<=t&&t<=105:return t-96}return""},simulate:function(e,t){return this._reinitialize(e),Array.isArray(t)?t.forEach(function(e){var t={};"object"!=typeof e&&"function"!=typeof e||null===e?t.keyCode=parseInt(e):t=e;var n=new KeyboardEvent("keydown",t);document.dispatchEvent(n)}):this._validateScanCode(e,t),this},_reinitialize:function(e){var t=e.scannerDetectionData.vars;t.firstCharTime=0,t.lastCharTime=0,t.accumulatedString=""},_isFocusOnIgnoredElement:function(e){var t=e.scannerDetectionData.options.ignoreIfFocusOn;if(!t)return!1;var n=document.activeElement;if(Array.isArray(t)){for(var a=0;a<t.length;a++)if(!0===n.matches(t[a]))return!0}else if(n.matches(t))return!0;return!1},_validateScanCode:function(e,t){var n,a=e.scannerDetectionData,i=a.options,o=a.options.singleScanQty,r=a.vars.firstCharTime,s=a.vars.lastCharTime,c={};switch(!0){case t.length<i.minLength:c={message:"Receieved code is shorter then minimal length"};break;case s-r>t.length*i.avgTimeByChar:c={message:"Receieved code was not entered in time"};break;default:return i.onScan.call(e,t,o),n=new CustomEvent("scan",{detail:{scanCode:t,qty:o}}),e.dispatchEvent(n),d._reinitialize(e),!0}return c.scanCode=t,c.scanDuration=s-r,c.avgTimeByChar=i.avgTimeByChar,c.minLength=i.minLength,i.onScanError.call(e,c),n=new CustomEvent("scanError",{detail:c}),e.dispatchEvent(n),d._reinitialize(e),!1},_mergeOptions:function(e,t){var n,a={};for(n in e)Object.prototype.hasOwnProperty.call(e,n)&&(a[n]=e[n]);for(n in t)Object.prototype.hasOwnProperty.call(t,n)&&(a[n]=t[n]);return a},_getNormalizedKeyNum:function(e){return e.which||e.keyCode},_handleKeyDown:function(e){var t=d._getNormalizedKeyNum(e),n=this.scannerDetectionData.options,a=this.scannerDetectionData.vars,i=!1;if(!1!==n.onKeyDetect.call(this,t,e)&&!d._isFocusOnIgnoredElement(this))if(!1===n.scanButtonKeyCode||t!=n.scanButtonKeyCode){switch(!0){case a.firstCharTime&&-1!==n.suffixKeyCodes.indexOf(t):e.preventDefault(),e.stopImmediatePropagation(),i=!0;break;case!a.firstCharTime&&-1!==n.prefixKeyCodes.indexOf(t):e.preventDefault(),e.stopImmediatePropagation(),i=!1;break;default:var o=n.keyCodeMapper.call(this,e);if(null===o)return;a.accumulatedString+=o,n.preventDefault&&e.preventDefault(),n.stopPropagation&&e.stopImmediatePropagation(),i=!1}a.firstCharTime||(a.firstCharTime=Date.now()),a.lastCharTime=Date.now(),a.testTimer&&clearTimeout(a.testTimer),i?(d._validateScanCode(this,a.accumulatedString),a.testTimer=!1):a.testTimer=setTimeout(d._validateScanCode,n.timeBeforeScanTest,this,a.accumulatedString),n.onKeyProcess.call(this,o,e)}else a.longPressed||(a.longPressTimer=setTimeout(n.onScanButtonLongPress,n.scanButtonLongPressTime,this),a.longPressed=!0)},_handlePaste:function(e){if(!d._isFocusOnIgnoredElement(this)){e.preventDefault(),oOptions.stopPropagation&&e.stopImmediatePropagation();var t=(event.clipboardData||window.clipboardData).getData("text");this.scannerDetectionData.options.onPaste.call(this,t,event);var n=this.scannerDetectionData.vars;n.firstCharTime=0,n.lastCharTime=0,d._validateScanCode(this,t)}},_handleKeyUp:function(e){d._isFocusOnIgnoredElement(this)||d._getNormalizedKeyNum(e)==this.scannerDetectionData.options.scanButtonKeyCode&&(clearTimeout(this.scannerDetectionData.vars.longPressTimer),this.scannerDetectionData.vars.longPressed=!1)},isScanInProgressFor:function(e){return 0<e.scannerDetectionData.vars.firstCharTime}};return d});
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index 8d4ac78..e3405e0 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -1,7 +1,4 @@
-/* global Clusterize */
frappe.provide('erpnext.PointOfSale');
-{% include "erpnext/selling/page/point_of_sale/pos_controller.js" %}
-frappe.provide('erpnext.queries');
frappe.pages['point-of-sale'].on_page_load = function(wrapper) {
frappe.ui.make_app_page({
@@ -10,6 +7,16 @@
single_column: true
});
- wrapper.pos = new erpnext.PointOfSale.Controller(wrapper);
- window.cur_pos = wrapper.pos;
+ frappe.require('assets/js/point-of-sale.min.js', function() {
+ wrapper.pos = new erpnext.PointOfSale.Controller(wrapper);
+ window.cur_pos = wrapper.pos;
+ });
+};
+
+frappe.pages['point-of-sale'].refresh = function(wrapper) {
+ if (document.scannerDetectionData) {
+ onScan.detachFrom(document);
+ wrapper.pos.wrapper.html("");
+ wrapper.pos.check_opening_entry();
+ }
};
\ No newline at end of file
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 83bd71d..062cba1 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -11,54 +11,66 @@
from six import string_types
@frappe.whitelist()
-def get_items(start, page_length, price_list, item_group, search_value="", pos_profile=None):
+def get_items(start, page_length, price_list, item_group, pos_profile, search_value=""):
data = dict()
- warehouse = ""
+ result = []
- if pos_profile:
- warehouse = frappe.db.get_value('POS Profile', pos_profile, ['warehouse'])
+ allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
+ warehouse, hide_unavailable_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items'])
if not frappe.db.exists('Item Group', item_group):
item_group = get_root_of('Item Group')
if search_value:
data = search_serial_or_batch_or_barcode_number(search_value)
-
+
item_code = data.get("item_code") if data.get("item_code") else search_value
serial_no = data.get("serial_no") if data.get("serial_no") else ""
batch_no = data.get("batch_no") if data.get("batch_no") else ""
barcode = data.get("barcode") if data.get("barcode") else ""
- condition = get_conditions(item_code, serial_no, batch_no, barcode)
+ if data:
+ item_info = frappe.db.get_value(
+ "Item", data.get("item_code"),
+ ["name as item_code", "item_name", "description", "stock_uom", "image as item_image", "is_stock_item"]
+ , as_dict=1)
+ item_info.setdefault('serial_no', serial_no)
+ item_info.setdefault('batch_no', batch_no)
+ item_info.setdefault('barcode', barcode)
- if pos_profile:
- condition += get_item_group_condition(pos_profile)
+ return { 'items': [item_info] }
+
+ condition = get_conditions(item_code, serial_no, batch_no, barcode)
+ condition += get_item_group_condition(pos_profile)
lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt'])
- # locate function is used to sort by closest match from the beginning of the value
- result = []
+ bin_join_selection, bin_join_condition = "", ""
+ if hide_unavailable_items:
+ bin_join_selection = ", `tabBin` bin"
+ bin_join_condition = "AND bin.warehouse = %(warehouse)s AND bin.item_code = item.name AND bin.actual_qty > 0"
items_data = frappe.db.sql("""
SELECT
- name AS item_code,
- item_name,
- description,
- stock_uom,
- image AS item_image,
- idx AS idx,
- is_stock_item
+ item.name AS item_code,
+ item.item_name,
+ item.description,
+ item.stock_uom,
+ item.image AS item_image,
+ item.is_stock_item
FROM
- `tabItem`
+ `tabItem` item {bin_join_selection}
WHERE
- disabled = 0
- AND has_variants = 0
- AND is_sales_item = 1
- AND is_fixed_asset = 0
- AND item_group in (SELECT name FROM `tabItem Group` WHERE lft >= {lft} AND rgt <= {rgt})
- AND {condition}
+ item.disabled = 0
+ AND item.is_stock_item = 1
+ AND item.has_variants = 0
+ AND item.is_sales_item = 1
+ AND item.is_fixed_asset = 0
+ AND item.item_group in (SELECT name FROM `tabItem Group` WHERE lft >= {lft} AND rgt <= {rgt})
+ AND {condition}
+ {bin_join_condition}
ORDER BY
- name asc
+ item.name asc
LIMIT
{start}, {page_length}"""
.format(
@@ -66,8 +78,10 @@
page_length=page_length,
lft=lft,
rgt=rgt,
- condition=condition
- ), as_dict=1)
+ condition=condition,
+ bin_join_selection=bin_join_selection,
+ bin_join_condition=bin_join_condition
+ ), {'warehouse': warehouse}, as_dict=1)
if items_data:
items = [d.item_code for d in items_data]
@@ -82,46 +96,24 @@
for item in items_data:
item_code = item.item_code
item_price = item_prices.get(item_code) or {}
- item_stock_qty = get_stock_availability(item_code, warehouse)
-
- if not item_stock_qty:
- pass
+ if allow_negative_stock:
+ item_stock_qty = frappe.db.sql("""select ifnull(sum(actual_qty), 0) from `tabBin` where item_code = %s""", item_code)[0][0]
else:
- row = {}
- row.update(item)
- row.update({
- 'price_list_rate': item_price.get('price_list_rate'),
- 'currency': item_price.get('currency'),
- 'actual_qty': item_stock_qty,
- })
- result.append(row)
+ item_stock_qty = get_stock_availability(item_code, warehouse)
+
+ row = {}
+ row.update(item)
+ row.update({
+ 'price_list_rate': item_price.get('price_list_rate'),
+ 'currency': item_price.get('currency'),
+ 'actual_qty': item_stock_qty,
+ })
+ result.append(row)
res = {
'items': result
}
- if len(res['items']) == 1:
- res['items'][0].setdefault('serial_no', serial_no)
- res['items'][0].setdefault('batch_no', batch_no)
- res['items'][0].setdefault('barcode', barcode)
-
- return res
-
- if serial_no:
- res.update({
- 'serial_no': serial_no
- })
-
- if batch_no:
- res.update({
- 'batch_no': batch_no
- })
-
- if barcode:
- res.update({
- 'barcode': barcode
- })
-
return res
@frappe.whitelist()
@@ -145,16 +137,16 @@
def get_conditions(item_code, serial_no, batch_no, barcode):
if serial_no or batch_no or barcode:
- return "name = {0}".format(frappe.db.escape(item_code))
+ return "item.name = {0}".format(frappe.db.escape(item_code))
- return """(name like {item_code}
- or item_name like {item_code})""".format(item_code = frappe.db.escape('%' + item_code + '%'))
+ return """(item.name like {item_code}
+ or item.item_name like {item_code})""".format(item_code = frappe.db.escape('%' + item_code + '%'))
def get_item_group_condition(pos_profile):
cond = "and 1=1"
item_groups = get_item_groups(pos_profile)
if item_groups:
- cond = "and item_group in (%s)"%(', '.join(['%s']*len(item_groups)))
+ cond = "and item.item_group in (%s)"%(', '.join(['%s']*len(item_groups)))
return cond % tuple(item_groups)
@@ -238,13 +230,31 @@
frappe.db.set_value('Customer', customer, 'loyalty_program', value)
contact = frappe.get_cached_value('Customer', customer, 'customer_primary_contact')
+ if not contact:
+ contact = frappe.db.sql("""
+ SELECT parent FROM `tabDynamic Link`
+ WHERE
+ parenttype = 'Contact' AND
+ parentfield = 'links' AND
+ link_doctype = 'Customer' AND
+ link_name = %s
+ """, (customer), as_dict=1)
+ contact = contact[0].get('parent') if contact else None
- if contact:
- contact_doc = frappe.get_doc('Contact', contact)
- if fieldname == 'email_id':
- contact_doc.set('email_ids', [{ 'email_id': value, 'is_primary': 1}])
- frappe.db.set_value('Customer', customer, 'email_id', value)
- elif fieldname == 'mobile_no':
- contact_doc.set('phone_nos', [{ 'phone': value, 'is_primary_mobile_no': 1}])
- frappe.db.set_value('Customer', customer, 'mobile_no', value)
- contact_doc.save()
\ No newline at end of file
+ if not contact:
+ new_contact = frappe.new_doc('Contact')
+ new_contact.is_primary_contact = 1
+ new_contact.first_name = customer
+ new_contact.set('links', [{'link_doctype': 'Customer', 'link_name': customer}])
+ new_contact.save()
+ contact = new_contact.name
+ frappe.db.set_value('Customer', customer, 'customer_primary_contact', contact)
+
+ contact_doc = frappe.get_doc('Contact', contact)
+ if fieldname == 'email_id':
+ contact_doc.set('email_ids', [{ 'email_id': value, 'is_primary': 1}])
+ frappe.db.set_value('Customer', customer, 'email_id', value)
+ elif fieldname == 'mobile_no':
+ contact_doc.set('phone_nos', [{ 'phone': value, 'is_primary_mobile_no': 1}])
+ frappe.db.set_value('Customer', customer, 'mobile_no', value)
+ contact_doc.save()
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 5018254..9e3c9a5 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -1,46 +1,68 @@
-{% include "erpnext/selling/page/point_of_sale/onscan.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_item_selector.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_item_cart.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_item_details.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_payment.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_number_pad.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_past_order_list.js" %}
-{% include "erpnext/selling/page/point_of_sale/pos_past_order_summary.js" %}
-
erpnext.PointOfSale.Controller = class {
constructor(wrapper) {
this.wrapper = $(wrapper).find('.layout-main-section');
this.page = wrapper.page;
- this.load_assets();
+ this.check_opening_entry();
}
- load_assets() {
- // after loading assets first check if opening entry has been made
- frappe.require(['assets/erpnext/css/pos.css'], this.check_opening_entry.bind(this));
+ fetch_opening_entry() {
+ return frappe.call("erpnext.selling.page.point_of_sale.point_of_sale.check_opening_entry", { "user": frappe.session.user });
}
check_opening_entry() {
- return frappe.call("erpnext.selling.page.point_of_sale.point_of_sale.check_opening_entry", { "user": frappe.session.user })
- .then((r) => {
- if (r.message.length) {
- // assuming only one opening voucher is available for the current user
- this.prepare_app_defaults(r.message[0]);
- } else {
- this.create_opening_voucher();
- }
- });
+ this.fetch_opening_entry().then((r) => {
+ if (r.message.length) {
+ // assuming only one opening voucher is available for the current user
+ this.prepare_app_defaults(r.message[0]);
+ } else {
+ this.create_opening_voucher();
+ }
+ });
}
create_opening_voucher() {
+ const me = this;
const table_fields = [
- { fieldname: "mode_of_payment", fieldtype: "Link", in_list_view: 1, label: "Mode of Payment", options: "Mode of Payment", reqd: 1 },
- { fieldname: "opening_amount", fieldtype: "Currency", default: 0, in_list_view: 1, label: "Opening Amount",
- options: "company:company_currency" }
+ {
+ fieldname: "mode_of_payment", fieldtype: "Link",
+ in_list_view: 1, label: "Mode of Payment",
+ options: "Mode of Payment", reqd: 1
+ },
+ {
+ fieldname: "opening_amount", fieldtype: "Currency",
+ in_list_view: 1, label: "Opening Amount",
+ options: "company:company_currency",
+ change: function () {
+ dialog.fields_dict.balance_details.df.data.some(d => {
+ if (d.idx == this.doc.idx) {
+ d.opening_amount = this.value;
+ dialog.fields_dict.balance_details.grid.refresh();
+ return true;
+ }
+ });
+ }
+ }
];
-
+ const fetch_pos_payment_methods = () => {
+ const pos_profile = dialog.fields_dict.pos_profile.get_value();
+ if (!pos_profile) return;
+ frappe.db.get_doc("POS Profile", pos_profile).then(({ payments }) => {
+ dialog.fields_dict.balance_details.df.data = [];
+ payments.forEach(pay => {
+ const { mode_of_payment } = pay;
+ dialog.fields_dict.balance_details.df.data.push({ mode_of_payment, opening_amount: '0' });
+ });
+ dialog.fields_dict.balance_details.grid.refresh();
+ });
+ }
+ const pos_profile_query = {
+ query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
+ filters: { company: frappe.defaults.get_default('company') }
+ }
const dialog = new frappe.ui.Dialog({
title: __('Create POS Opening Entry'),
+ static: true,
fields: [
{
fieldtype: 'Link', label: __('Company'), default: frappe.defaults.get_default('company'),
@@ -49,20 +71,8 @@
{
fieldtype: 'Link', label: __('POS Profile'),
options: 'POS Profile', fieldname: 'pos_profile', reqd: 1,
- onchange: () => {
- const pos_profile = dialog.fields_dict.pos_profile.get_value();
-
- if (!pos_profile) return;
-
- frappe.db.get_doc("POS Profile", pos_profile).then(doc => {
- dialog.fields_dict.balance_details.df.data = [];
- doc.payments.forEach(pay => {
- const { mode_of_payment } = pay;
- dialog.fields_dict.balance_details.df.data.push({ mode_of_payment });
- });
- dialog.fields_dict.balance_details.grid.refresh();
- });
- }
+ get_query: () => pos_profile_query,
+ onchange: () => fetch_pos_payment_methods()
},
{
fieldname: "balance_details",
@@ -75,49 +85,45 @@
fields: table_fields
}
],
- primary_action: ({ company, pos_profile, balance_details }) => {
+ primary_action: async function({ company, pos_profile, balance_details }) {
if (!balance_details.length) {
frappe.show_alert({
message: __("Please add Mode of payments and opening balance details."),
indicator: 'red'
})
- frappe.utils.play_sound("error");
- return;
+ return frappe.utils.play_sound("error");
}
- frappe.dom.freeze();
- return frappe.call("erpnext.selling.page.point_of_sale.point_of_sale.create_opening_voucher",
- { pos_profile, company, balance_details })
- .then((r) => {
- frappe.dom.unfreeze();
- dialog.hide();
- if (r.message) {
- this.prepare_app_defaults(r.message);
- }
- })
+
+ // filter balance details for empty rows
+ balance_details = balance_details.filter(d => d.mode_of_payment);
+
+ const method = "erpnext.selling.page.point_of_sale.point_of_sale.create_opening_voucher";
+ const res = await frappe.call({ method, args: { pos_profile, company, balance_details }, freeze:true });
+ !res.exc && me.prepare_app_defaults(res.message);
+ dialog.hide();
},
primary_action_label: __('Submit')
});
dialog.show();
}
- prepare_app_defaults(data) {
+ async prepare_app_defaults(data) {
this.pos_opening = data.name;
this.company = data.company;
this.pos_profile = data.pos_profile;
this.pos_opening_time = data.period_start_date;
+ this.item_stock_map = {};
+ this.settings = {};
frappe.db.get_value('Stock Settings', undefined, 'allow_negative_stock').then(({ message }) => {
this.allow_negative_stock = flt(message.allow_negative_stock) || false;
});
frappe.db.get_doc("POS Profile", this.pos_profile).then((profile) => {
- this.customer_groups = profile.customer_groups.map(group => group.customer_group);
- this.cart.make_customer_selector();
+ Object.assign(this.settings, profile);
+ this.settings.customer_groups = profile.customer_groups.map(group => group.customer_group);
+ this.make_app();
});
-
- this.item_stock_map = {};
-
- this.make_app();
}
set_opening_entry_status() {
@@ -130,26 +136,18 @@
}
make_app() {
- return frappe.run_serially([
- () => frappe.dom.freeze(),
- () => {
- this.set_opening_entry_status();
- this.prepare_dom();
- this.prepare_components();
- this.prepare_menu();
- },
- () => this.make_new_invoice(),
- () => frappe.dom.unfreeze(),
- () => this.page.set_title(__('Point of Sale')),
- ]);
+ this.prepare_dom();
+ this.prepare_components();
+ this.prepare_menu();
+ this.make_new_invoice();
}
prepare_dom() {
- this.wrapper.append(`
- <div class="app grid grid-cols-10 pt-8 gap-6"></div>`
+ this.wrapper.append(
+ `<div class="point-of-sale-app"></div>`
);
- this.$components_wrapper = this.wrapper.find('.app');
+ this.$components_wrapper = this.wrapper.find('.point-of-sale-app');
}
prepare_components() {
@@ -162,26 +160,25 @@
}
prepare_menu() {
- var me = this;
this.page.clear_menu();
- this.page.add_menu_item(__("Form View"), function () {
- frappe.model.sync(me.frm.doc);
- frappe.set_route("Form", me.frm.doc.doctype, me.frm.doc.name);
- });
+ this.page.add_menu_item(__("Open Form View"), this.open_form_view.bind(this), false, 'Ctrl+F');
- this.page.add_menu_item(__("Toggle Recent Orders"), () => {
- const show = this.recent_order_list.$component.hasClass('d-none');
- this.toggle_recent_order_list(show);
- });
+ this.page.add_menu_item(__("Toggle Recent Orders"), this.toggle_recent_order.bind(this), false, 'Ctrl+O');
- this.page.add_menu_item(__("Save as Draft"), this.save_draft_invoice.bind(this));
+ this.page.add_menu_item(__("Save as Draft"), this.save_draft_invoice.bind(this), false, 'Ctrl+S');
- frappe.ui.keys.on("ctrl+s", this.save_draft_invoice.bind(this));
+ this.page.add_menu_item(__('Close the POS'), this.close_pos.bind(this), false, 'Shift+Ctrl+C');
+ }
- this.page.add_menu_item(__('Close the POS'), this.close_pos.bind(this));
+ open_form_view() {
+ frappe.model.sync(this.frm.doc);
+ frappe.set_route("Form", this.frm.doc.doctype, this.frm.doc.name);
+ }
- frappe.ui.keys.on("shift+ctrl+s", this.close_pos.bind(this));
+ toggle_recent_order() {
+ const show = this.recent_order_list.$component.is(':hidden');
+ this.toggle_recent_order_list(show);
}
save_draft_invoice() {
@@ -189,7 +186,7 @@
if (this.frm.doc.items.length == 0) {
frappe.show_alert({
- message:__("You must add atleast one item to save it as draft."),
+ message: __("You must add atleast one item to save it as draft."),
indicator:'red'
});
frappe.utils.play_sound("error");
@@ -198,8 +195,8 @@
this.frm.save(undefined, undefined, undefined, () => {
frappe.show_alert({
- message:__("There was an error saving the document."),
- indicator:'red'
+ message: __("There was an error saving the document."),
+ indicator: 'red'
});
frappe.utils.play_sound("error");
}).then(() => {
@@ -208,7 +205,7 @@
() => this.make_new_invoice(),
() => frappe.dom.unfreeze(),
]);
- })
+ });
}
close_pos() {
@@ -228,12 +225,11 @@
this.item_selector = new erpnext.PointOfSale.ItemSelector({
wrapper: this.$components_wrapper,
pos_profile: this.pos_profile,
+ settings: this.settings,
events: {
item_selected: args => this.on_cart_update(args),
- get_frm: () => this.frm || {},
-
- get_allowed_item_group: () => this.item_groups
+ get_frm: () => this.frm || {}
}
})
}
@@ -241,15 +237,14 @@
init_item_cart() {
this.cart = new erpnext.PointOfSale.ItemCart({
wrapper: this.$components_wrapper,
+ settings: this.settings,
events: {
get_frm: () => this.frm,
cart_item_clicked: (item_code, batch_no, uom) => {
- const item_row = this.frm.doc.items.find(
- i => i.item_code === item_code
- && i.uom === uom
- && (!batch_no || (batch_no && i.batch_no === batch_no))
- );
+ const search_field = batch_no ? 'batch_no' : 'item_code';
+ const search_value = batch_no || item_code;
+ const item_row = this.frm.doc.items.find(i => i[search_field] === search_value && i.uom === uom);
this.item_details.toggle_item_details_section(item_row);
},
@@ -263,9 +258,7 @@
this.customer_details = details;
// will add/remove LP payment method
this.payment.render_loyalty_points_payment_mode();
- },
-
- get_allowed_customer_group: () => this.customer_groups
+ }
}
})
}
@@ -273,6 +266,7 @@
init_item_details() {
this.item_details = new erpnext.PointOfSale.ItemDetails({
wrapper: this.$components_wrapper,
+ settings: this.settings,
events: {
get_frm: () => this.frm,
@@ -346,23 +340,22 @@
toggle_other_sections: (show) => {
if (show) {
- this.item_details.$component.hasClass('d-none') ? '' : this.item_details.$component.addClass('d-none');
- this.item_selector.$component.addClass('d-none');
+ this.item_details.$component.is(':visible') ? this.item_details.$component.css('display', 'none') : '';
+ this.item_selector.$component.css('display', 'none');
} else {
- this.item_selector.$component.removeClass('d-none');
+ this.item_selector.$component.css('display', 'flex');
}
},
submit_invoice: () => {
this.frm.savesubmit()
.then((r) => {
- // this.set_invoice_status();
this.toggle_components(false);
this.order_summary.toggle_component(true);
this.order_summary.load_summary_of(this.frm.doc, true);
frappe.show_alert({
indicator: 'green',
- message: __(`POS invoice ${r.doc.name} created succesfully`)
+ message: __('POS invoice {0} created succesfully', [r.doc.name])
});
});
}
@@ -379,7 +372,7 @@
this.order_summary.load_summary_of(doc);
});
},
- reset_summary: () => this.order_summary.show_summary_placeholder()
+ reset_summary: () => this.order_summary.toggle_summary_placeholder(true)
}
})
}
@@ -404,10 +397,16 @@
this.recent_order_list.toggle_component(false);
frappe.run_serially([
() => this.frm.refresh(name),
+ () => this.frm.call('reset_mode_of_payments'),
() => this.cart.load_invoice(),
() => this.item_selector.toggle_component(true)
]);
},
+ delete_order: (name) => {
+ frappe.model.delete_doc(this.frm.doc.doctype, name, () => {
+ this.recent_order_list.refresh_list();
+ });
+ },
new_order: () => {
frappe.run_serially([
() => frappe.dom.freeze(),
@@ -420,8 +419,6 @@
})
}
-
-
toggle_recent_order_list(show) {
this.toggle_components(!show);
this.recent_order_list.toggle_component(show);
@@ -438,10 +435,12 @@
make_new_invoice() {
return frappe.run_serially([
+ () => frappe.dom.freeze(),
() => this.make_sales_invoice_frm(),
() => this.set_pos_profile_data(),
() => this.set_pos_profile_status(),
() => this.cart.load_invoice(),
+ () => frappe.dom.unfreeze()
]);
}
@@ -495,53 +494,20 @@
if (this.pos_profile && !this.frm.doc.pos_profile) this.frm.doc.pos_profile = this.pos_profile;
if (!this.frm.doc.company) return;
- return new Promise(resolve => {
- return this.frm.call({
- doc: this.frm.doc,
- method: "set_missing_values",
- }).then((r) => {
- if(!r.exc) {
- if (!this.frm.doc.pos_profile) {
- frappe.dom.unfreeze();
- this.raise_exception_for_pos_profile();
- }
- this.frm.trigger("update_stock");
- this.frm.trigger('calculate_taxes_and_totals');
- if(this.frm.doc.taxes_and_charges) this.frm.script_manager.trigger("taxes_and_charges");
- frappe.model.set_default_values(this.frm.doc);
- if (r.message) {
- this.frm.pos_print_format = r.message.print_format || "";
- this.frm.meta.default_print_format = r.message.print_format || "";
- this.frm.allow_edit_rate = r.message.allow_edit_rate;
- this.frm.allow_edit_discount = r.message.allow_edit_discount;
- this.frm.doc.campaign = r.message.campaign;
- }
- }
- resolve();
- });
- });
- }
-
- raise_exception_for_pos_profile() {
- setTimeout(() => frappe.set_route('List', 'POS Profile'), 2000);
- frappe.throw(__("POS Profile is required to use Point-of-Sale"));
- }
-
- set_invoice_status() {
- const [status, indicator] = frappe.listview_settings["POS Invoice"].get_indicator(this.frm.doc);
- this.page.set_indicator(__(`${status}`), indicator);
+ return this.frm.trigger("set_pos_data");
}
set_pos_profile_status() {
- this.page.set_indicator(__(`${this.pos_profile}`), "blue");
+ this.page.set_indicator(this.pos_profile, "blue");
}
async on_cart_update(args) {
frappe.dom.freeze();
+ let item_row = undefined;
try {
let { field, value, item } = args;
const { item_code, batch_no, serial_no, uom } = item;
- let item_row = this.get_item_from_frm(item_code, batch_no, uom);
+ item_row = this.get_item_from_frm(item_code, batch_no, uom);
const item_selected_from_selector = field === 'qty' && value === "+1"
@@ -550,9 +516,11 @@
field === 'qty' && (value = flt(value));
- if (field === 'qty' && value > 0 && !this.allow_negative_stock)
- await this.check_stock_availability(item_row, value, this.frm.doc.set_warehouse);
-
+ if (['qty', 'conversion_factor'].includes(field) && value > 0 && !this.allow_negative_stock) {
+ const qty_needed = field === 'qty' ? value * item_row.conversion_factor : item_row.qty * value;
+ await this.check_stock_availability(item_row, qty_needed, this.frm.doc.set_warehouse);
+ }
+
if (this.is_current_item_being_edited(item_row) || item_selected_from_selector) {
await frappe.model.set_value(item_row.doctype, item_row.name, field, value);
this.update_cart_html(item_row);
@@ -568,11 +536,16 @@
frappe.utils.play_sound("error");
return;
}
+ if (!item_code) return;
+
item_selected_from_selector && (value = flt(value))
const args = { item_code, batch_no, [field]: value };
- if (serial_no) args['serial_no'] = serial_no;
+ if (serial_no) {
+ await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no);
+ args['serial_no'] = serial_no;
+ }
if (field === 'serial_no') args['qty'] = value.split(`\n`).length || 0;
@@ -585,18 +558,20 @@
this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
this.update_cart_html(item_row);
- }
+ }
+
} catch (error) {
console.log(error);
} finally {
frappe.dom.unfreeze();
+ return item_row;
}
}
get_item_from_frm(item_code, batch_no, uom) {
const has_batch_no = batch_no;
return this.frm.doc.items.find(
- i => i.item_code === item_code
+ i => i.item_code === item_code
&& (!has_batch_no || (has_batch_no && i.batch_no === batch_no))
&& (i.uom === uom)
);
@@ -625,7 +600,7 @@
const no_serial_selected = !item_row.serial_no;
const no_batch_selected = !item_row.batch_no;
- if ((serialized && no_serial_selected) || (batched && no_batch_selected) ||
+ if ((serialized && no_serial_selected) || (batched && no_batch_selected) ||
(serialized && batched && (no_batch_selected || no_serial_selected))) {
return true;
}
@@ -633,29 +608,46 @@
}
async trigger_new_item_events(item_row) {
- await this.frm.script_manager.trigger('item_code', item_row.doctype, item_row.name)
- await this.frm.script_manager.trigger('qty', item_row.doctype, item_row.name)
+ await this.frm.script_manager.trigger('item_code', item_row.doctype, item_row.name);
+ await this.frm.script_manager.trigger('qty', item_row.doctype, item_row.name);
}
async check_stock_availability(item_row, qty_needed, warehouse) {
const available_qty = (await this.get_available_stock(item_row.item_code, warehouse)).message;
frappe.dom.unfreeze();
+ const bold_item_code = item_row.item_code.bold();
+ const bold_warehouse = warehouse.bold();
+ const bold_available_qty = available_qty.toString().bold()
if (!(available_qty > 0)) {
frappe.model.clear_doc(item_row.doctype, item_row.name);
- frappe.throw(__(`Item Code: ${item_row.item_code.bold()} is not available under warehouse ${warehouse.bold()}.`))
+ frappe.throw({
+ title: __("Not Available"),
+ message: __('Item Code: {0} is not available under warehouse {1}.', [bold_item_code, bold_warehouse])
+ })
} else if (available_qty < qty_needed) {
frappe.show_alert({
- message: __(`Stock quantity not enough for Item Code: ${item_row.item_code.bold()} under warehouse ${warehouse.bold()}.
- Available quantity ${available_qty.toString().bold()}.`),
+ message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.', [bold_item_code, bold_warehouse, bold_available_qty]),
indicator: 'orange'
});
frappe.utils.play_sound("error");
- this.item_details.qty_control.set_value(flt(available_qty));
}
frappe.dom.freeze();
}
+ async check_serial_no_availablilty(item_code, warehouse, serial_no) {
+ const method = "erpnext.stock.doctype.serial_no.serial_no.get_pos_reserved_serial_nos";
+ const args = {filters: { item_code, warehouse }}
+ const res = await frappe.call({ method, args });
+
+ if (res.message.includes(serial_no)) {
+ frappe.throw({
+ title: __("Not Available"),
+ message: __('Serial No: {0} has already been transacted into another POS Invoice.', [serial_no.bold()])
+ });
+ }
+ }
+
get_available_stock(item_code, warehouse) {
const me = this;
return frappe.call({
@@ -689,14 +681,14 @@
frappe.dom.freeze();
const { doctype, name, current_item } = this.item_details;
- frappe.model.set_value(doctype, name, 'qty', 0);
-
- this.frm.script_manager.trigger('qty', doctype, name).then(() => {
- frappe.model.clear_doc(doctype, name);
- this.update_cart_html(current_item, true);
- this.item_details.toggle_item_details_section(undefined);
- frappe.dom.unfreeze();
- })
+ frappe.model.set_value(doctype, name, 'qty', 0)
+ .then(() => {
+ frappe.model.clear_doc(doctype, name);
+ this.update_cart_html(current_item, true);
+ this.item_details.toggle_item_details_section(undefined);
+ frappe.dom.unfreeze();
+ })
+ .catch(e => console.log(e));
}
-}
+};
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 724b60b..9ab9eef 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -1,12 +1,16 @@
erpnext.PointOfSale.ItemCart = class {
- constructor({ wrapper, events }) {
+ constructor({ wrapper, events, settings }) {
this.wrapper = wrapper;
this.events = events;
this.customer_info = undefined;
-
+ this.hide_images = settings.hide_images;
+ this.allowed_customer_groups = settings.customer_groups;
+ this.allow_rate_change = settings.allow_rate_change;
+ this.allow_discount_change = settings.allow_discount_change;
+
this.init_component();
}
-
+
init_component() {
this.prepare_dom();
this.init_child_components();
@@ -16,10 +20,10 @@
prepare_dom() {
this.wrapper.append(
- `<section class="col-span-4 flex flex-col shadow rounded item-cart bg-white mx-h-70 h-100"></section>`
+ `<section class="customer-cart-container"></section>`
)
- this.$component = this.wrapper.find('.item-cart');
+ this.$component = this.wrapper.find('.customer-cart-container');
}
init_child_components() {
@@ -29,32 +33,33 @@
init_customer_selector() {
this.$component.append(
- `<div class="customer-section rounded flex flex-col m-8 mb-0"></div>`
+ `<div class="customer-section"></div>`
)
this.$customer_section = this.$component.find('.customer-section');
+ this.make_customer_selector();
}
-
+
reset_customer_selector() {
const frm = this.events.get_frm();
frm.set_value('customer', '');
- this.$customer_section.removeClass('border pr-4 pl-4');
this.make_customer_selector();
this.customer_field.set_focus();
}
-
+
init_cart_components() {
this.$component.append(
- `<div class="cart-container flex flex-col items-center rounded flex-1 relative">
- <div class="absolute flex flex-col p-8 pt-0 w-full h-full">
- <div class="flex text-grey cart-header pt-2 pb-2 p-4 mt-2 mb-2 w-full f-shrink-0">
- <div class="flex-1">Item</div>
- <div class="mr-4">Qty</div>
- <div class="rate-list-header mr-1 text-right">Amount</div>
+ `<div class="cart-container">
+ <div class="abs-cart-container">
+ <div class="cart-label">Item Cart</div>
+ <div class="cart-header">
+ <div class="name-header">Item</div>
+ <div class="qty-header">Qty</div>
+ <div class="rate-amount-header">Amount</div>
</div>
- <div class="cart-items-section flex flex-col flex-1 scroll-y rounded w-full"></div>
- <div class="cart-totals-section flex flex-col w-full mt-4 f-shrink-0"></div>
- <div class="numpad-section flex flex-col mt-4 d-none w-full p-8 pt-0 pb-0 f-shrink-0"></div>
- </div>
+ <div class="cart-items-section"></div>
+ <div class="cart-totals-section"></div>
+ <div class="numpad-section"></div>
+ </div>
</div>`
);
this.$cart_container = this.$component.find('.cart-container');
@@ -70,54 +75,48 @@
this.make_no_items_placeholder();
}
-
+
make_no_items_placeholder() {
- this.$cart_header.addClass('d-none');
+ this.$cart_header.css('display', 'none');
this.$cart_items_wrapper.html(
- `<div class="no-item-wrapper flex items-center h-18">
- <div class="flex-1 text-center text-grey">No items in cart</div>
- </div>`
- )
- this.$cart_items_wrapper.addClass('mt-4 border-grey border-dashed');
+ `<div class="no-item-wrapper">No items in cart</div>`
+ );
+ }
+
+ get_discount_icon() {
+ return (
+ `<svg class="discount-icon" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M19 15.6213C19 15.2235 19.158 14.842 19.4393 14.5607L20.9393 13.0607C21.5251 12.4749 21.5251 11.5251 20.9393 10.9393L19.4393 9.43934C19.158 9.15804 19 8.7765 19 8.37868V6.5C19 5.67157 18.3284 5 17.5 5H15.6213C15.2235 5 14.842 4.84196 14.5607 4.56066L13.0607 3.06066C12.4749 2.47487 11.5251 2.47487 10.9393 3.06066L9.43934 4.56066C9.15804 4.84196 8.7765 5 8.37868 5H6.5C5.67157 5 5 5.67157 5 6.5V8.37868C5 8.7765 4.84196 9.15804 4.56066 9.43934L3.06066 10.9393C2.47487 11.5251 2.47487 12.4749 3.06066 13.0607L4.56066 14.5607C4.84196 14.842 5 15.2235 5 15.6213V17.5C5 18.3284 5.67157 19 6.5 19H8.37868C8.7765 19 9.15804 19.158 9.43934 19.4393L10.9393 20.9393C11.5251 21.5251 12.4749 21.5251 13.0607 20.9393L14.5607 19.4393C14.842 19.158 15.2235 19 15.6213 19H17.5C18.3284 19 19 18.3284 19 17.5V15.6213Z" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
+ <path d="M15 9L9 15" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
+ <path d="M10.5 9.5C10.5 10.0523 10.0523 10.5 9.5 10.5C8.94772 10.5 8.5 10.0523 8.5 9.5C8.5 8.94772 8.94772 8.5 9.5 8.5C10.0523 8.5 10.5 8.94772 10.5 9.5Z" fill="white" stroke-linecap="round" stroke-linejoin="round"/>
+ <path d="M15.5 14.5C15.5 15.0523 15.0523 15.5 14.5 15.5C13.9477 15.5 13.5 15.0523 13.5 14.5C13.5 13.9477 13.9477 13.5 14.5 13.5C15.0523 13.5 15.5 13.9477 15.5 14.5Z" fill="white" stroke-linecap="round" stroke-linejoin="round"/>
+ </svg>`
+ );
}
make_cart_totals_section() {
this.$totals_section = this.$component.find('.cart-totals-section');
this.$totals_section.append(
- `<div class="add-discount flex items-center pt-4 pb-4 pr-4 pl-4 text-grey pointer no-select d-none">
- + Add Discount
+ `<div class="add-discount-wrapper">
+ ${this.get_discount_icon()} Add Discount
</div>
- <div class="border border-grey rounded">
- <div class="net-total flex justify-between items-center h-16 pr-8 pl-8 border-b-grey">
- <div class="flex flex-col">
- <div class="text-md text-dark-grey text-bold">Net Total</div>
- </div>
- <div class="flex flex-col text-right">
- <div class="text-md text-dark-grey text-bold">0.00</div>
- </div>
- </div>
- <div class="taxes"></div>
- <div class="grand-total flex justify-between items-center h-16 pr-8 pl-8 border-b-grey">
- <div class="flex flex-col">
- <div class="text-md text-dark-grey text-bold">Grand Total</div>
- </div>
- <div class="flex flex-col text-right">
- <div class="text-md text-dark-grey text-bold">0.00</div>
- </div>
- </div>
- <div class="checkout-btn flex items-center justify-center h-16 pr-8 pl-8 text-center text-grey no-select pointer rounded-b text-md text-bold">
- Checkout
- </div>
- <div class="edit-cart-btn flex items-center justify-center h-16 pr-8 pl-8 text-center text-grey no-select pointer d-none text-md text-bold">
- Edit Cart
- </div>
- </div>`
+ <div class="net-total-container">
+ <div class="net-total-label">Net Total</div>
+ <div class="net-total-value">0.00</div>
+ </div>
+ <div class="taxes-container"></div>
+ <div class="grand-total-container">
+ <div>Grand Total</div>
+ <div>0.00</div>
+ </div>
+ <div class="checkout-btn">Checkout</div>
+ <div class="edit-cart-btn">Edit Cart</div>`
)
- this.$add_discount_elem = this.$component.find(".add-discount");
+ this.$add_discount_elem = this.$component.find(".add-discount-wrapper");
}
-
+
make_cart_numpad() {
this.$numpad_section = this.$component.find('.numpad-section');
@@ -137,39 +136,37 @@
[ '', '', '', 'col-span-2' ],
[ '', '', '', 'col-span-2' ],
[ '', '', '', 'col-span-2' ],
- [ '', '', '', 'col-span-2 text-bold text-danger' ]
+ [ '', '', '', 'col-span-2 remove-btn' ]
],
fieldnames_map: { 'Quantity': 'qty', 'Discount': 'discount_percentage' }
})
this.$numpad_section.prepend(
- `<div class="flex mb-2 justify-between">
+ `<div class="numpad-totals">
<span class="numpad-net-total"></span>
<span class="numpad-grand-total"></span>
</div>`
)
this.$numpad_section.append(
- `<div class="numpad-btn checkout-btn flex items-center justify-center h-16 pr-8 pl-8 bg-primary
- text-center text-white no-select pointer rounded text-md text-bold mt-4" data-button-value="checkout">
- Checkout
- </div>`
+ `<div class="numpad-btn checkout-btn" data-button-value="checkout">Checkout</div>`
)
}
-
+
bind_events() {
const me = this;
- this.$customer_section.on('click', '.add-remove-customer', function (e) {
- const customer_info_is_visible = me.$cart_container.hasClass('d-none');
- customer_info_is_visible ?
- me.toggle_customer_info(false) : me.reset_customer_selector();
+ this.$customer_section.on('click', '.reset-customer-btn', function () {
+ me.reset_customer_selector();
});
- this.$customer_section.on('click', '.customer-header', function(e) {
- // don't triggger the event if .add-remove-customer btn is clicked which is under .customer-header
- if ($(e.target).closest('.add-remove-customer').length) return;
+ this.$customer_section.on('click', '.close-details-btn', function () {
+ me.toggle_customer_info(false);
+ });
- const show = !me.$cart_container.hasClass('d-none');
+ this.$customer_section.on('click', '.customer-display', function(e) {
+ if ($(e.target).closest('.reset-customer-btn').length) return;
+
+ const show = me.$cart_container.is(':visible');
me.toggle_customer_info(show);
});
@@ -178,7 +175,7 @@
me.toggle_item_highlight(this);
- const payment_section_hidden = me.$totals_section.find('.edit-cart-btn').hasClass('d-none');
+ const payment_section_hidden = !me.$totals_section.find('.edit-cart-btn').is(':visible');
if (!payment_section_hidden) {
// payment section is visible
// edit cart first and then open item details section
@@ -193,23 +190,21 @@
});
this.$component.on('click', '.checkout-btn', function() {
- if (!$(this).hasClass('bg-primary')) return;
-
+ if ($(this).attr('style').indexOf('--blue-500') == -1) return;
+
me.events.checkout();
me.toggle_checkout_btn(false);
- me.$add_discount_elem.removeClass("d-none");
+ me.allow_discount_change && me.$add_discount_elem.removeClass("d-none");
});
this.$totals_section.on('click', '.edit-cart-btn', () => {
this.events.edit_cart();
this.toggle_checkout_btn(true);
-
- this.$add_discount_elem.addClass("d-none");
});
- this.$component.on('click', '.add-discount', () => {
- const can_edit_discount = this.$add_discount_elem.find('.edit-discount').length;
+ this.$component.on('click', '.add-discount-wrapper', () => {
+ const can_edit_discount = this.$add_discount_elem.find('.edit-discount-btn').length;
if(!this.discount_field || can_edit_discount) this.show_discount_control();
});
@@ -223,56 +218,85 @@
attach_shortcuts() {
for (let row of this.number_pad.keys) {
for (let btn of row) {
+ if (typeof btn !== 'string') continue; // do not make shortcuts for numbers
+
let shortcut_key = `ctrl+${frappe.scrub(String(btn))[0]}`;
if (btn === 'Delete') shortcut_key = 'ctrl+backspace';
if (btn === 'Remove') shortcut_key = 'shift+ctrl+backspace'
if (btn === '.') shortcut_key = 'ctrl+>';
// to account for fieldname map
- const fieldname = this.number_pad.fieldnames[btn] ? this.number_pad.fieldnames[btn] :
+ const fieldname = this.number_pad.fieldnames[btn] ? this.number_pad.fieldnames[btn] :
typeof btn === 'string' ? frappe.scrub(btn) : btn;
+ let shortcut_label = shortcut_key.split('+').map(frappe.utils.to_title_case).join('+');
+ shortcut_label = frappe.utils.is_mac() ? shortcut_label.replace('Ctrl', '⌘') : shortcut_label;
+ this.$numpad_section.find(`.numpad-btn[data-button-value="${fieldname}"]`).attr("title", shortcut_label);
+
frappe.ui.keys.on(`${shortcut_key}`, () => {
const cart_is_visible = this.$component.is(":visible");
if (cart_is_visible && this.item_is_selected && this.$numpad_section.is(":visible")) {
this.$numpad_section.find(`.numpad-btn[data-button-value="${fieldname}"]`).click();
- }
+ }
})
}
}
-
- frappe.ui.keys.on("ctrl+enter", () => {
- const cart_is_visible = this.$component.is(":visible");
- const payment_section_hidden = this.$totals_section.find('.edit-cart-btn').hasClass('d-none');
- if (cart_is_visible && payment_section_hidden) {
- this.$component.find(".checkout-btn").click();
+ const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
+ this.$component.find(".checkout-btn").attr("title", `${ctrl_label}+Enter`);
+ frappe.ui.keys.add_shortcut({
+ shortcut: "ctrl+enter",
+ action: () => this.$component.find(".checkout-btn").click(),
+ condition: () => this.$component.is(":visible") && !this.$totals_section.find('.edit-cart-btn').is(':visible'),
+ description: __("Checkout Order / Submit Order / New Order"),
+ ignore_inputs: true,
+ page: cur_page.page.page
+ });
+ this.$component.find(".edit-cart-btn").attr("title", `${ctrl_label}+E`);
+ frappe.ui.keys.on("ctrl+e", () => {
+ const item_cart_visible = this.$component.is(":visible");
+ const checkout_btn_invisible = !this.$totals_section.find('.checkout-btn').is('visible');
+ if (item_cart_visible && checkout_btn_invisible) {
+ this.$component.find(".edit-cart-btn").click();
+ }
+ });
+ this.$component.find(".add-discount-wrapper").attr("title", `${ctrl_label}+D`);
+ frappe.ui.keys.add_shortcut({
+ shortcut: "ctrl+d",
+ action: () => this.$component.find(".add-discount-wrapper").click(),
+ condition: () => this.$add_discount_elem.is(":visible"),
+ description: __("Add Order Discount"),
+ ignore_inputs: true,
+ page: cur_page.page.page
+ });
+ frappe.ui.keys.on("escape", () => {
+ const item_cart_visible = this.$component.is(":visible");
+ if (item_cart_visible && this.discount_field && this.discount_field.parent.is(":visible")) {
+ this.discount_field.set_value(0);
}
});
}
-
+
toggle_item_highlight(item) {
const $cart_item = $(item);
- const item_is_highlighted = $cart_item.hasClass("shadow");
+ const item_is_highlighted = $cart_item.attr("style") == "background-color:var(--gray-50);";
if (!item || item_is_highlighted) {
this.item_is_selected = false;
- this.$cart_container.find('.cart-item-wrapper').removeClass("shadow").css("opacity", "1");
+ this.$cart_container.find('.cart-item-wrapper').css("background-color", "");
} else {
- $cart_item.addClass("shadow");
+ $cart_item.css("background-color", "var(--gray-50)");
this.item_is_selected = true;
- this.$cart_container.find('.cart-item-wrapper').css("opacity", "1");
- this.$cart_container.find('.cart-item-wrapper').not(item).removeClass("shadow").css("opacity", "0.65");
+ this.$cart_container.find('.cart-item-wrapper').not(item).css("background-color", "");
}
- // highlight with inner shadow
- // $cart_item.addClass("shadow-inner bg-selected");
- // me.$cart_container.find('.cart-item-wrapper').not(this).removeClass("shadow-inner bg-selected");
}
make_customer_selector() {
- this.$customer_section.html(`<div class="customer-search-field flex flex-1 items-center"></div>`);
+ this.$customer_section.html(`
+ <div class="customer-field"></div>
+ `);
const me = this;
const query = { query: 'erpnext.controllers.queries.customer_query' };
- const allowed_customer_group = this.events.get_allowed_customer_group() || [];
+ const allowed_customer_group = this.allowed_customer_groups || [];
if (allowed_customer_group.length) {
query.filters = {
customer_group: ['in', allowed_customer_group]
@@ -302,12 +326,12 @@
}
},
},
- parent: this.$customer_section.find('.customer-search-field'),
+ parent: this.$customer_section.find('.customer-field'),
render_input: true,
});
this.customer_field.toggle_label(false);
}
-
+
fetch_customer_details(customer) {
if (customer) {
return new Promise((resolve) => {
@@ -341,10 +365,9 @@
}
show_discount_control() {
- this.$add_discount_elem.removeClass("pr-4 pl-4");
+ this.$add_discount_elem.css({ 'padding': '0px', 'border': 'none' });
this.$add_discount_elem.html(
- `<div class="add-dicount-field flex flex-1 items-center"></div>
- <div class="submit-field flex items-center"></div>`
+ `<div class="add-discount-field"></div>`
);
const me = this;
@@ -353,15 +376,24 @@
label: __('Discount'),
fieldtype: 'Data',
placeholder: __('Enter discount percentage.'),
+ input_class: 'input-xs',
onchange: function() {
- if (this.value || this.value == 0) {
- const frm = me.events.get_frm();
+ const frm = me.events.get_frm();
+ if (flt(this.value) != 0) {
frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', flt(this.value));
me.hide_discount_control(this.value);
+ } else {
+ frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', 0);
+ me.$add_discount_elem.css({
+ '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.discount_field = undefined;
}
},
},
- parent: this.$add_discount_elem.find('.add-dicount-field'),
+ parent: this.$add_discount_elem.find('.add-discount-field'),
render_input: true,
});
this.discount_field.toggle_label(false);
@@ -369,32 +401,38 @@
}
hide_discount_control(discount) {
- this.$add_discount_elem.addClass('pr-4 pl-4');
- this.$add_discount_elem.html(
- `<svg class="mr-2" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1"
- stroke-linecap="round" stroke-linejoin="round">
- <path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
- </svg>
- <div class="edit-discount p-1 pr-3 pl-3 text-dark-grey rounded w-fit bg-green-200 mb-2">
- ${String(discount).bold()}% off
- </div>
- `
- );
+ if (!discount) {
+ this.$add_discount_elem.css({ 'padding': '0px', 'border': 'none' });
+ this.$add_discount_elem.html(
+ `<div class="add-discount-field"></div>`
+ );
+ } else {
+ this.$add_discount_elem.css({
+ 'border': '1px dashed var(--dark-green-500)',
+ 'padding': 'var(--padding-sm) var(--padding-md)'
+ });
+ this.$add_discount_elem.html(
+ `<div class="edit-discount-btn">
+ ${this.get_discount_icon()} Additional ${String(discount).bold()}% discount applied
+ </div>`
+ );
+ }
}
-
+
update_customer_section() {
+ const me = this;
const { customer, email_id='', mobile_no='', image } = this.customer_info || {};
if (customer) {
- this.$customer_section.addClass('border pr-4 pl-4').html(
- `<div class="customer-details flex flex-col">
- <div class="customer-header flex items-center rounded h-18 pointer">
- ${get_customer_image()}
- <div class="customer-name flex flex-col flex-1 f-shrink-1 overflow-hidden whitespace-nowrap">
- <div class="text-md text-dark-grey text-bold">${customer}</div>
+ this.$customer_section.html(
+ `<div class="customer-details">
+ <div class="customer-display">
+ ${this.get_customer_image()}
+ <div class="customer-name-desc">
+ <div class="customer-name">${customer}</div>
${get_customer_description()}
</div>
- <div class="f-shrink-0 add-remove-customer flex items-center pointer" data-customer="${escape(customer)}">
+ <div class="reset-customer-btn" data-customer="${escape(customer)}">
<svg width="32" height="32" viewBox="0 0 14 14" fill="none">
<path d="M4.93764 4.93759L7.00003 6.99998M9.06243 9.06238L7.00003 6.99998M7.00003 6.99998L4.93764 9.06238L9.06243 4.93759" stroke="#8D99A6"/>
</svg>
@@ -409,157 +447,144 @@
function get_customer_description() {
if (!email_id && !mobile_no) {
- return `<div class="text-grey-200 italic">Click to add email / phone</div>`
+ return `<div class="customer-desc">Click to add email / phone</div>`;
} else if (email_id && !mobile_no) {
- return `<div class="text-grey">${email_id}</div>`
+ return `<div class="customer-desc">${email_id}</div>`;
} else if (mobile_no && !email_id) {
- return `<div class="text-grey">${mobile_no}</div>`
+ return `<div class="customer-desc">${mobile_no}</div>`;
} else {
- return `<div class="text-grey">${email_id} | ${mobile_no}</div>`
+ return `<div class="customer-desc">${email_id} - ${mobile_no}</div>`;
}
}
- function get_customer_image() {
- if (image) {
- return `<div class="icon flex items-center justify-center w-12 h-12 rounded bg-light-grey mr-4 text-grey-200">
- <img class="h-full" src="${image}" alt="${image}" style="object-fit: cover;">
- </div>`
- } else {
- return `<div class="icon flex items-center justify-center w-12 h-12 rounded bg-light-grey mr-4 text-grey-200 text-md">
- ${frappe.get_abbr(customer)}
- </div>`
- }
+ }
+
+ get_customer_image() {
+ const { customer, image } = this.customer_info || {};
+ if (image) {
+ return `<div class="customer-image"><img src="${image}" alt="${image}""></div>`;
+ } else {
+ return `<div class="customer-image customer-abbr">${frappe.get_abbr(customer)}</div>`;
}
}
-
+
update_totals_section(frm) {
if (!frm) frm = this.events.get_frm();
- this.render_net_total(frm.doc.base_net_total);
- this.render_grand_total(frm.doc.base_grand_total);
+ this.render_net_total(frm.doc.net_total);
+ const grand_total = cint(frappe.sys_defaults.disable_rounded_total) ? frm.doc.grand_total : frm.doc.rounded_total;
+ this.render_grand_total(grand_total);
- const taxes = frm.doc.taxes.map(t => { return { description: t.description, rate: t.rate }})
- this.render_taxes(frm.doc.base_total_taxes_and_charges, taxes);
+ const taxes = frm.doc.taxes.map(t => {
+ return {
+ description: t.description, rate: t.rate
+ };
+ });
+ this.render_taxes(frm.doc.total_taxes_and_charges, taxes);
}
-
+
render_net_total(value) {
const currency = this.events.get_frm().doc.currency;
- this.$totals_section.find('.net-total').html(
- `<div class="flex flex-col">
- <div class="text-md text-dark-grey text-bold">Net Total</div>
- </div>
- <div class="flex flex-col text-right">
- <div class="text-md text-dark-grey text-bold">${format_currency(value, currency)}</div>
- </div>`
+ this.$totals_section.find('.net-total-container').html(
+ `<div>Net Total</div><div>${format_currency(value, currency)}</div>`
)
- this.$numpad_section.find('.numpad-net-total').html(`Net Total: <span class="text-bold">${format_currency(value, currency)}</span>`)
+ this.$numpad_section.find('.numpad-net-total').html(
+ `<div>Net Total: <span>${format_currency(value, currency)}</span></div>`
+ );
}
-
+
render_grand_total(value) {
const currency = this.events.get_frm().doc.currency;
- this.$totals_section.find('.grand-total').html(
- `<div class="flex flex-col">
- <div class="text-md text-dark-grey text-bold">Grand Total</div>
- </div>
- <div class="flex flex-col text-right">
- <div class="text-md text-dark-grey text-bold">${format_currency(value, currency)}</div>
- </div>`
+ this.$totals_section.find('.grand-total-container').html(
+ `<div>Grand Total</div><div>${format_currency(value, currency)}</div>`
)
- this.$numpad_section.find('.numpad-grand-total').html(`Grand Total: <span class="text-bold">${format_currency(value, currency)}</span>`)
+ this.$numpad_section.find('.numpad-grand-total').html(
+ `<div>Grand Total: <span>${format_currency(value, currency)}</span></div>`
+ );
}
render_taxes(value, taxes) {
if (taxes.length) {
const currency = this.events.get_frm().doc.currency;
- this.$totals_section.find('.taxes').html(
- `<div class="flex items-center justify-between h-16 pr-8 pl-8 border-b-grey">
- <div class="flex">
- <div class="text-md text-dark-grey text-bold w-fit">Tax Charges</div>
- <div class="flex ml-6 text-dark-grey">
- ${
- taxes.map((t, i) => {
- let margin_left = '';
- if (i !== 0) margin_left = 'ml-2';
- return `<span class="border-grey p-1 pl-2 pr-2 rounded ${margin_left}">${t.description}</span>`
- }).join('')
- }
- </div>
- </div>
- <div class="flex flex-col text-right">
- <div class="text-md text-dark-grey text-bold">${format_currency(value, currency)}</div>
- </div>
- </div>`
- )
+ const taxes_html = taxes.map(t => {
+ const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`;
+ return `<div class="tax-row">
+ <div class="tax-label">${description}</div>
+ <div class="tax-value">${format_currency(value, currency)}</div>
+ </div>`;
+ }).join('');
+ this.$totals_section.find('.taxes-container').css('display', 'flex').html(taxes_html);
} else {
- this.$totals_section.find('.taxes').html('')
+ this.$totals_section.find('.taxes-container').css('display', 'none').html('');
}
}
get_cart_item({ item_code, batch_no, uom }) {
const batch_attr = `[data-batch-no="${escape(batch_no)}"]`;
const item_code_attr = `[data-item-code="${escape(item_code)}"]`;
- const uom_attr = `[data-uom=${escape(uom)}]`;
+ const uom_attr = `[data-uom="${escape(uom)}"]`;
- const item_selector = batch_no ?
+ const item_selector = batch_no ?
`.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`;
-
+
return this.$cart_items_wrapper.find(item_selector);
}
-
+
update_item_html(item, remove_item) {
const $item = this.get_cart_item(item);
if (remove_item) {
- $item && $item.remove();
+ $item && $item.next().remove() && $item.remove();
} else {
const { item_code, batch_no, uom } = item;
const search_field = batch_no ? 'batch_no' : 'item_code';
const search_value = batch_no || item_code;
const item_row = this.events.get_frm().doc.items.find(i => i[search_field] === search_value && i.uom === uom);
-
+
this.render_cart_item(item_row, $item);
}
- const no_of_cart_items = this.$cart_items_wrapper.children().length;
- no_of_cart_items > 0 && this.highlight_checkout_btn(no_of_cart_items > 0);
-
+ const no_of_cart_items = this.$cart_items_wrapper.find('.cart-item-wrapper').length;
+ this.highlight_checkout_btn(no_of_cart_items > 0);
+
this.update_empty_cart_section(no_of_cart_items);
}
-
+
render_cart_item(item_data, $item_to_update) {
const currency = this.events.get_frm().doc.currency;
const me = this;
-
+
if (!$item_to_update.length) {
this.$cart_items_wrapper.append(
- `<div class="cart-item-wrapper flex items-center h-18 pr-4 pl-4 rounded border-grey pointer no-select"
+ `<div class="cart-item-wrapper"
data-item-code="${escape(item_data.item_code)}" data-uom="${escape(item_data.uom)}"
data-batch-no="${escape(item_data.batch_no || '')}">
- </div>`
+ </div>
+ <div class="seperator"></div>`
)
$item_to_update = this.get_cart_item(item_data);
}
$item_to_update.html(
- `<div class="flex flex-col flex-1 f-shrink-1 overflow-hidden whitespace-nowrap">
- <div class="text-md text-dark-grey text-bold">
+ `${get_item_image_html()}
+ <div class="item-name-desc">
+ <div class="item-name">
${item_data.item_name}
</div>
${get_description_html()}
</div>
- ${get_rate_discount_html()}
- </div>`
+ ${get_rate_discount_html()}`
)
set_dynamic_rate_header_width();
this.scroll_to_item($item_to_update);
function set_dynamic_rate_header_width() {
- const rate_cols = Array.from(me.$cart_items_wrapper.find(".rate-col"));
- me.$cart_header.find(".rate-list-header").css("width", "");
- me.$cart_items_wrapper.find(".rate-col").css("width", "");
+ const rate_cols = Array.from(me.$cart_items_wrapper.find(".item-rate-amount"));
+ me.$cart_header.find(".rate-amount-header").css("width", "");
+ me.$cart_items_wrapper.find(".item-rate-amount").css("width", "");
let max_width = rate_cols.reduce((max_width, elm) => {
if ($(elm).width() > max_width)
max_width = $(elm).width();
@@ -569,30 +594,26 @@
max_width += 1;
if (max_width == 1) max_width = "";
- me.$cart_header.find(".rate-list-header").css("width", max_width);
- me.$cart_items_wrapper.find(".rate-col").css("width", max_width);
+ me.$cart_header.find(".rate-amount-header").css("width", max_width);
+ me.$cart_items_wrapper.find(".item-rate-amount").css("width", max_width);
}
-
+
function get_rate_discount_html() {
if (item_data.rate && item_data.amount && item_data.rate !== item_data.amount) {
return `
- <div class="flex f-shrink-0 ml-4 items-center">
- <div class="flex w-8 h-8 rounded bg-light-grey mr-4 items-center justify-center font-bold f-shrink-0">
- <span>${item_data.qty || 0}</span>
- </div>
- <div class="rate-col flex flex-col f-shrink-0 text-right">
- <div class="text-md text-dark-grey text-bold">${format_currency(item_data.amount, currency)}</div>
- <div class="text-md-0 text-dark-grey">${format_currency(item_data.rate, currency)}</div>
+ <div class="item-qty-rate">
+ <div class="item-qty"><span>${item_data.qty || 0}</span></div>
+ <div class="item-rate-amount">
+ <div class="item-rate">${format_currency(item_data.amount, currency)}</div>
+ <div class="item-amount">${format_currency(item_data.rate, currency)}</div>
</div>
</div>`
} else {
return `
- <div class="flex f-shrink-0 ml-4 text-right">
- <div class="flex w-8 h-8 rounded bg-light-grey mr-4 items-center justify-center font-bold f-shrink-0">
- <span>${item_data.qty || 0}</span>
- </div>
- <div class="rate-col flex flex-col f-shrink-0 text-right">
- <div class="text-md text-dark-grey text-bold">${format_currency(item_data.rate, currency)}</div>
+ <div class="item-qty-rate">
+ <div class="item-qty"><span>${item_data.qty || 0}</span></div>
+ <div class="item-rate-amount">
+ <div class="item-rate">${format_currency(item_data.rate, currency)}</div>
</div>
</div>`
}
@@ -608,10 +629,19 @@
}
}
item_data.description = frappe.ellipsis(item_data.description, 45);
- return `<div class="text-grey">${item_data.description}</div>`
+ return `<div class="item-desc">${item_data.description}</div>`;
}
return ``;
}
+
+ function get_item_image_html() {
+ const { image, item_name } = item_data;
+ if (image) {
+ return `<div class="item-image"><img src="${image}" alt="${image}""></div>`;
+ } else {
+ return `<div class="item-image item-abbr">${frappe.get_abbr(item_name)}</div>`;
+ }
+ }
}
scroll_to_item($item) {
@@ -619,52 +649,68 @@
const scrollTop = $item.offset().top - this.$cart_items_wrapper.offset().top + this.$cart_items_wrapper.scrollTop();
this.$cart_items_wrapper.animate({ scrollTop });
}
-
+
update_selector_value_in_cart_item(selector, value, item) {
const $item_to_update = this.get_cart_item(item);
- $item_to_update.attr(`data-${selector}`, value);
+ $item_to_update.attr(`data-${selector}`, escape(value));
}
toggle_checkout_btn(show_checkout) {
if (show_checkout) {
- this.$totals_section.find('.checkout-btn').removeClass('d-none');
- this.$totals_section.find('.edit-cart-btn').addClass('d-none');
+ this.$totals_section.find('.checkout-btn').css('display', 'flex');
+ this.$totals_section.find('.edit-cart-btn').css('display', 'none');
} else {
- this.$totals_section.find('.checkout-btn').addClass('d-none');
- this.$totals_section.find('.edit-cart-btn').removeClass('d-none');
+ this.$totals_section.find('.checkout-btn').css('display', 'none');
+ this.$totals_section.find('.edit-cart-btn').css('display', 'flex');
}
}
highlight_checkout_btn(toggle) {
- const has_primary_class = this.$totals_section.find('.checkout-btn').hasClass('bg-primary');
- if (toggle && !has_primary_class) {
- this.$totals_section.find('.checkout-btn').addClass('bg-primary text-white text-lg');
- } else if (!toggle && has_primary_class) {
- this.$totals_section.find('.checkout-btn').removeClass('bg-primary text-white text-lg');
+ if (toggle) {
+ this.$add_discount_elem.css('display', 'flex');
+ this.$cart_container.find('.checkout-btn').css({
+ 'background-color': 'var(--blue-500)'
+ });
+ } else {
+ this.$add_discount_elem.css('display', 'none');
+ this.$cart_container.find('.checkout-btn').css({
+ 'background-color': 'var(--blue-200)'
+ });
}
}
-
+
update_empty_cart_section(no_of_cart_items) {
const $no_item_element = this.$cart_items_wrapper.find('.no-item-wrapper');
// if cart has items and no item is present
- no_of_cart_items > 0 && $no_item_element && $no_item_element.remove()
- && this.$cart_items_wrapper.removeClass('mt-4 border-grey border-dashed') && this.$cart_header.removeClass('d-none');
+ no_of_cart_items > 0 && $no_item_element && $no_item_element.remove() && this.$cart_header.css('display', 'flex');
no_of_cart_items === 0 && !$no_item_element.length && this.make_no_items_placeholder();
}
-
+
on_numpad_event($btn) {
const current_action = $btn.attr('data-button-value');
const action_is_field_edit = ['qty', 'discount_percentage', 'rate'].includes(current_action);
-
- this.highlight_numpad_btn($btn, current_action);
+ const action_is_allowed = action_is_field_edit ? (
+ (current_action == 'rate' && this.allow_rate_change) ||
+ (current_action == 'discount_percentage' && this.allow_discount_change) ||
+ (current_action == 'qty')) : true;
const action_is_pressed_twice = this.prev_action === current_action;
const first_click_event = !this.prev_action;
const field_to_edit_changed = this.prev_action && this.prev_action != current_action;
if (action_is_field_edit) {
+ if (!action_is_allowed) {
+ const label = current_action == 'rate' ? 'Rate'.bold() : 'Discount'.bold();
+ const message = __('Editing {0} is not allowed as per POS Profile settings', [label]);
+ frappe.show_alert({
+ indicator: 'red',
+ message: message
+ });
+ frappe.utils.play_sound("error");
+ return;
+ }
if (first_click_event || field_to_edit_changed) {
this.prev_action = current_action;
@@ -672,7 +718,7 @@
this.prev_action = undefined;
}
this.numpad_value = '';
-
+
} else if (current_action === 'checkout') {
this.prev_action = undefined;
this.toggle_item_highlight();
@@ -698,7 +744,7 @@
frappe.utils.play_sound("error");
return;
}
-
+
if (flt(this.numpad_value) > 100 && this.prev_action === 'discount_percentage') {
frappe.show_alert({
message: __('Discount cannot be greater than 100%'),
@@ -708,40 +754,41 @@
this.numpad_value = current_action;
}
+ this.highlight_numpad_btn($btn, current_action);
this.events.numpad_event(this.numpad_value, this.prev_action);
}
-
+
highlight_numpad_btn($btn, curr_action) {
- const curr_action_is_highlighted = $btn.hasClass('shadow-inner');
+ const curr_action_is_highlighted = $btn.hasClass('highlighted-numpad-btn');
const curr_action_is_action = ['qty', 'discount_percentage', 'rate', 'done'].includes(curr_action);
if (!curr_action_is_highlighted) {
- $btn.addClass('shadow-inner bg-selected');
+ $btn.addClass('highlighted-numpad-btn');
}
if (this.prev_action === curr_action && curr_action_is_highlighted) {
// if Qty is pressed twice
- $btn.removeClass('shadow-inner bg-selected');
+ $btn.removeClass('highlighted-numpad-btn');
}
if (this.prev_action && this.prev_action !== curr_action && curr_action_is_action) {
// Order: Qty -> Rate then remove Qty highlight
const prev_btn = $(`[data-button-value='${this.prev_action}']`);
- prev_btn.removeClass('shadow-inner bg-selected');
+ prev_btn.removeClass('highlighted-numpad-btn');
}
if (!curr_action_is_action || curr_action === 'done') {
// if numbers are clicked
setTimeout(() => {
- $btn.removeClass('shadow-inner bg-selected');
- }, 100);
+ $btn.removeClass('highlighted-numpad-btn');
+ }, 200);
}
}
toggle_numpad(show) {
if (show) {
- this.$totals_section.addClass('d-none');
- this.$numpad_section.removeClass('d-none');
+ this.$totals_section.css('display', 'none');
+ this.$numpad_section.css('display', 'flex');
} else {
- this.$totals_section.removeClass('d-none');
- this.$numpad_section.addClass('d-none');
+ this.$totals_section.css('display', 'flex');
+ this.$numpad_section.css('display', 'none');
}
this.reset_numpad();
}
@@ -749,7 +796,7 @@
reset_numpad() {
this.numpad_value = '';
this.prev_action = undefined;
- this.$numpad_section.find('.shadow-inner').removeClass('shadow-inner bg-selected');
+ this.$numpad_section.find('.highlighted-numpad-btn').removeClass('highlighted-numpad-btn');
}
toggle_numpad_field_edit(fieldname) {
@@ -760,48 +807,56 @@
toggle_customer_info(show) {
if (show) {
- this.$cart_container.addClass('d-none')
- this.$customer_section.addClass('flex-1 scroll-y').removeClass('mb-0 border pr-4 pl-4')
- this.$customer_section.find('.icon').addClass('w-24 h-24 text-2xl').removeClass('w-12 h-12 text-md')
- this.$customer_section.find('.customer-header').removeClass('h-18');
- this.$customer_section.find('.customer-details').addClass('sticky z-100 bg-white');
+ const { customer } = this.customer_info || {};
- this.$customer_section.find('.customer-name').html(
- `<div class="text-md text-dark-grey text-bold">${this.customer_info.customer}</div>
- <div class="last-transacted-on text-grey-200"></div>`
- )
-
- this.$customer_section.find('.customer-details').append(
- `<div class="customer-form">
- <div class="text-grey mt-4 mb-6">CONTACT DETAILS</div>
- <div class="grid grid-cols-2 gap-4">
- <div class="email_id-field"></div>
- <div class="mobile_no-field"></div>
- <div class="loyalty_program-field"></div>
- <div class="loyalty_points-field"></div>
+ this.$cart_container.css('display', 'none');
+ this.$customer_section.css({
+ 'height': '100%',
+ 'padding-top': '0px'
+ });
+ this.$customer_section.find('.customer-details').html(
+ `<div class="header">
+ <div class="label">Contact Details</div>
+ <div class="close-details-btn">
+ <svg width="32" height="32" viewBox="0 0 14 14" fill="none">
+ <path d="M4.93764 4.93759L7.00003 6.99998M9.06243 9.06238L7.00003 6.99998M7.00003 6.99998L4.93764 9.06238L9.06243 4.93759" stroke="#8D99A6"/>
+ </svg>
</div>
- <div class="text-grey mt-4 mb-6">RECENT TRANSACTIONS</div>
- </div>`
- )
+ </div>
+ <div class="customer-display">
+ ${this.get_customer_image()}
+ <div class="customer-name-desc">
+ <div class="customer-name">${customer}</div>
+ <div class="customer-desc"></div>
+ </div>
+ </div>
+ <div class="customer-fields-container">
+ <div class="email_id-field"></div>
+ <div class="mobile_no-field"></div>
+ <div class="loyalty_program-field"></div>
+ <div class="loyalty_points-field"></div>
+ </div>
+ <div class="transactions-label">Recent Transactions</div>`
+ );
// transactions need to be in diff div from sticky elem for scrolling
- this.$customer_section.append(`<div class="customer-transactions flex-1 rounded"></div>`)
+ this.$customer_section.append(`<div class="customer-transactions"></div>`);
- this.render_customer_info_form();
+ this.render_customer_fields();
this.fetch_customer_transactions();
} else {
- this.$cart_container.removeClass('d-none');
- this.$customer_section.removeClass('flex-1 scroll-y').addClass('mb-0 border pr-4 pl-4');
- this.$customer_section.find('.icon').addClass('w-12 h-12 text-md').removeClass('w-24 h-24 text-2xl');
- this.$customer_section.find('.customer-header').addClass('h-18')
- this.$customer_section.find('.customer-details').removeClass('sticky z-100 bg-white');
+ this.$cart_container.css('display', 'flex');
+ this.$customer_section.css({
+ 'height': '',
+ 'padding-top': ''
+ });
this.update_customer_section();
}
}
- render_customer_info_form() {
- const $customer_form = this.$customer_section.find('.customer-form');
+ render_customer_fields() {
+ const $customer_form = this.$customer_section.find('.customer-fields-container');
const dfs = [{
fieldname: 'email_id',
@@ -823,7 +878,7 @@
},{
fieldname: 'loyalty_points',
label: __('Loyalty Points'),
- fieldtype: 'Int',
+ fieldtype: 'Data',
read_only: 1
}];
@@ -867,7 +922,7 @@
}
fetch_customer_transactions() {
- frappe.db.get_list('POS Invoice', {
+ frappe.db.get_list('POS Invoice', {
filters: { customer: this.customer_info.customer, docstatus: 1 },
fields: ['name', 'grand_total', 'status', 'posting_date', 'posting_time', 'currency'],
limit: 20
@@ -875,41 +930,45 @@
const transaction_container = this.$customer_section.find('.customer-transactions');
if (!res.length) {
- transaction_container.removeClass('flex-1 border rounded').html(
- `<div class="text-grey text-center">No recent transactions found</div>`
+ transaction_container.html(
+ `<div class="no-transactions-placeholder">No recent transactions found</div>`
)
return;
};
const elapsed_time = moment(res[0].posting_date+" "+res[0].posting_time).fromNow();
- this.$customer_section.find('.last-transacted-on').html(`Last transacted ${elapsed_time}`);
+ this.$customer_section.find('.customer-desc').html(`Last transacted ${elapsed_time}`);
res.forEach(invoice => {
const posting_datetime = moment(invoice.posting_date+" "+invoice.posting_time).format("Do MMMM, h:mma");
- let indicator_color = '';
-
- if (in_list(['Paid', 'Consolidated'], invoice.status)) (indicator_color = 'green');
- if (invoice.status === 'Draft') (indicator_color = 'red');
- if (invoice.status === 'Return') (indicator_color = 'grey');
+ let indicator_color = {
+ 'Paid': 'green',
+ 'Draft': 'red',
+ 'Return': 'gray',
+ 'Consolidated': 'blue'
+ };
transaction_container.append(
- `<div class="invoice-wrapper flex p-3 justify-between border-grey rounded pointer no-select" data-invoice-name="${escape(invoice.name)}">
- <div class="flex flex-col justify-end">
- <div class="text-dark-grey text-bold overflow-hidden whitespace-nowrap mb-2">${invoice.name}</div>
- <div class="flex items-center f-shrink-1 text-dark-grey overflow-hidden whitespace-nowrap">
- ${posting_datetime}
- </div>
+ `<div class="invoice-wrapper" data-invoice-name="${escape(invoice.name)}">
+ <div class="invoice-name-date">
+ <div class="invoice-name">${invoice.name}</div>
+ <div class="invoice-date">${posting_datetime}</div>
</div>
- <div class="flex flex-col text-right">
- <div class="f-shrink-0 text-md text-dark-grey text-bold ml-4">
+ <div class="invoice-total-status">
+ <div class="invoice-total">
${format_currency(invoice.grand_total, invoice.currency, 0) || 0}
</div>
- <div class="f-shrink-0 text-grey ml-4 text-bold indicator ${indicator_color}">${invoice.status}</div>
+ <div class="invoice-status">
+ <span class="indicator-pill whitespace-nowrap ${indicator_color[invoice.status]}">
+ <span>${invoice.status}</span>
+ </span>
+ </div>
</div>
- </div>`
+ </div>
+ <div class="seperator"></div>`
)
});
- })
+ });
}
load_invoice() {
@@ -917,8 +976,8 @@
this.fetch_customer_details(frm.doc.customer).then(() => {
this.events.customer_details_updated(this.customer_info);
this.update_customer_section();
- })
-
+ });
+
this.$cart_items_wrapper.html('');
if (frm.doc.items.length) {
frm.doc.items.forEach(item => {
@@ -932,20 +991,18 @@
this.update_totals_section(frm);
if(frm.doc.docstatus === 1) {
- this.$totals_section.find('.checkout-btn').addClass('d-none');
- this.$totals_section.find('.edit-cart-btn').addClass('d-none');
- this.$totals_section.find('.grand-total').removeClass('border-b-grey');
+ this.$totals_section.find('.checkout-btn').css('display', 'none');
+ this.$totals_section.find('.edit-cart-btn').css('display', 'none');
} else {
- this.$totals_section.find('.checkout-btn').removeClass('d-none');
- this.$totals_section.find('.edit-cart-btn').addClass('d-none');
- this.$totals_section.find('.grand-total').addClass('border-b-grey');
+ this.$totals_section.find('.checkout-btn').css('display', 'flex');
+ this.$totals_section.find('.edit-cart-btn').css('display', 'none');
}
this.toggle_component(true);
}
toggle_component(show) {
- show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
+ show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
}
-
+
}
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 3a5f89b..cb0a010 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_details.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_details.js
@@ -1,7 +1,9 @@
erpnext.PointOfSale.ItemDetails = class {
- constructor({ wrapper, events }) {
+ constructor({ wrapper, events, settings }) {
this.wrapper = wrapper;
this.events = events;
+ this.allow_rate_change = settings.allow_rate_change;
+ this.allow_discount_change = settings.allow_discount_change;
this.current_item = {};
this.init_component();
@@ -16,35 +18,36 @@
prepare_dom() {
this.wrapper.append(
- `<section class="col-span-4 flex shadow rounded item-details bg-white mx-h-70 h-100 d-none"></section>`
+ `<section class="item-details-container"></section>`
)
- this.$component = this.wrapper.find('.item-details');
+ this.$component = this.wrapper.find('.item-details-container');
}
init_child_components() {
this.$component.html(
- `<div class="details-container flex flex-col p-8 rounded w-full">
- <div class="flex justify-between mb-2">
- <div class="text-grey">ITEM DETAILS</div>
- <div class="close-btn text-grey hover-underline pointer no-select">Close</div>
+ `<div class="item-details-header">
+ <div class="label">Item Details</div>
+ <div class="close-btn">
+ <svg width="32" height="32" viewBox="0 0 14 14" fill="none">
+ <path d="M4.93764 4.93759L7.00003 6.99998M9.06243 9.06238L7.00003 6.99998M7.00003 6.99998L4.93764 9.06238L9.06243 4.93759" stroke="#8D99A6"/>
+ </svg>
</div>
- <div class="item-defaults flex">
- <div class="flex-1 flex flex-col justify-end mr-4 mb-2">
- <div class="item-name text-xl font-weight-450"></div>
- <div class="item-description text-md-0 text-grey-200"></div>
- <div class="item-price text-xl font-bold"></div>
- </div>
- <div class="item-image flex items-center justify-center w-46 h-46 bg-light-grey rounded ml-4 text-6xl text-grey-100"></div>
+ </div>
+ <div class="item-display">
+ <div class="item-name-desc-price">
+ <div class="item-name"></div>
+ <div class="item-desc"></div>
+ <div class="item-price"></div>
</div>
- <div class="discount-section flex items-center"></div>
- <div class="text-grey mt-4 mb-6">STOCK DETAILS</div>
- <div class="form-container grid grid-cols-2 row-gap-2 col-gap-4 grid-auto-row"></div>
- </div>`
+ <div class="item-image"></div>
+ </div>
+ <div class="discount-section"></div>
+ <div class="form-container"></div>`
)
this.$item_name = this.$component.find('.item-name');
- this.$item_description = this.$component.find('.item-description');
+ this.$item_description = this.$component.find('.item-desc');
this.$item_price = this.$component.find('.item-price');
this.$item_image = this.$component.find('.item-image');
this.$form_container = this.$component.find('.form-container');
@@ -52,7 +55,7 @@
}
toggle_item_details_section(item) {
- const { item_code, batch_no, uom } = this.current_item;
+ const { item_code, batch_no, uom } = this.current_item;
const item_code_is_same = item && item_code === item.item_code;
const batch_is_same = item && batch_no == item.batch_no;
const uom_is_same = item && uom === item.uom;
@@ -61,16 +64,16 @@
this.events.toggle_item_selector(this.item_has_changed);
this.toggle_component(this.item_has_changed);
-
+
if (this.item_has_changed) {
this.doctype = item.doctype;
this.item_meta = frappe.get_meta(this.doctype);
this.name = item.name;
this.item_row = item;
this.currency = this.events.get_frm().doc.currency;
-
+
this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom };
-
+
this.render_dom(item);
this.render_discount_dom(item);
this.render_form(item);
@@ -79,7 +82,7 @@
this.current_item = {};
}
}
-
+
validate_serial_batch_item() {
const doc = this.events.get_frm().doc;
const item_row = doc.items.find(item => item.name === this.name);
@@ -91,7 +94,7 @@
const no_serial_selected = !item_row.serial_no;
const no_batch_selected = !item_row.batch_no;
- if ((serialized && no_serial_selected) || (batched && no_batch_selected) ||
+ if ((serialized && no_serial_selected) || (batched && no_batch_selected) ||
(serialized && batched && (no_batch_selected || no_serial_selected))) {
frappe.show_alert({
@@ -102,40 +105,34 @@
this.events.remove_item_from_cart();
}
}
-
+
render_dom(item) {
- let { item_code ,item_name, description, image, price_list_rate } = item;
+ let { item_name, description, image, price_list_rate } = item;
function get_description_html() {
if (description) {
- description = description.indexOf('...') === -1 && description.length > 75 ? description.substr(0, 73) + '...' : description;
+ description = description.indexOf('...') === -1 && description.length > 140 ? description.substr(0, 139) + '...' : description;
return description;
}
return ``;
}
-
+
this.$item_name.html(item_name);
this.$item_description.html(get_description_html());
this.$item_price.html(format_currency(price_list_rate, this.currency));
if (image) {
- this.$item_image.html(
- `<img class="h-full" src="${image}" alt="${image}" style="object-fit: cover;">`
- );
+ this.$item_image.html(`<img src="${image}" alt="${image}">`);
} else {
- this.$item_image.html(frappe.get_abbr(item_code));
+ this.$item_image.html(`<div class="item-abbr">${frappe.get_abbr(item_name)}</div>`);
}
}
-
+
render_discount_dom(item) {
if (item.discount_percentage) {
this.$dicount_section.html(
- `<div class="text-grey line-through mr-4 text-md mb-2">
- ${format_currency(item.price_list_rate, this.currency)}
- </div>
- <div class="p-1 pr-3 pl-3 rounded w-fit text-bold bg-green-200 mb-2">
- ${item.discount_percentage}% off
- </div>`
+ `<div class="item-rate">${format_currency(item.price_list_rate, this.currency)}</div>
+ <div class="item-discount">${item.discount_percentage}% off</div>`
)
this.$item_price.html(format_currency(item.rate, this.currency));
} else {
@@ -149,18 +146,16 @@
fields_to_display.forEach((fieldname, idx) => {
this.$form_container.append(
- `<div class="">
- <div class="item_detail_field ${fieldname}-control" data-fieldname="${fieldname}"></div>
- </div>`
+ `<div class="${fieldname}-control" data-fieldname="${fieldname}"></div>`
)
const field_meta = this.item_meta.fields.find(df => df.fieldname === fieldname);
fieldname === 'discount_percentage' ? (field_meta.label = __('Discount (%)')) : '';
const me = this;
-
+
this[`${fieldname}_control`] = frappe.ui.form.make_control({
- df: {
- ...field_meta,
+ df: {
+ ...field_meta,
onchange: function() {
me.events.form_updated(me.doctype, me.name, fieldname, this.value);
}
@@ -177,7 +172,7 @@
}
get_form_fields(item) {
- const fields = ['qty', 'uom', 'rate', 'price_list_rate', 'discount_percentage', 'warehouse', 'actual_qty'];
+ const fields = ['qty', 'uom', 'rate', 'conversion_factor', 'discount_percentage', 'warehouse', 'actual_qty', 'price_list_rate'];
if (item.has_serial_no) fields.push('serial_no');
if (item.has_batch_no) fields.push('batch_no');
return fields;
@@ -185,39 +180,42 @@
make_auto_serial_selection_btn(item) {
if (item.has_serial_no) {
- this.$form_container.append(
- `<div class="grid-filler no-select"></div>`
- )
if (!item.has_batch_no) {
this.$form_container.append(
`<div class="grid-filler no-select"></div>`
- )
+ );
}
this.$form_container.append(
- `<div class="auto-fetch-btn bg-grey-100 border border-grey text-bold rounded pt-3 pb-3 pl-6 pr-8 text-grey pointer no-select mt-2"
- style="height: 3.3rem">
- Auto Fetch Serial Numbers
- </div>`
- )
- this.$form_container.find('.serial_no-control').find('textarea').css('height', '9rem');
- this.$form_container.find('.serial_no-control').parent().addClass('row-span-2');
+ `<div class="btn btn-sm btn-secondary auto-fetch-btn">Auto Fetch Serial Numbers</div>`
+ );
+ this.$form_container.find('.serial_no-control').find('textarea').css('height', '6rem');
}
}
-
+
bind_custom_control_change_event() {
const me = this;
if (this.rate_control) {
- this.rate_control.df.onchange = function() {
- if (this.value) {
- me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
- const item_row = frappe.get_doc(me.doctype, me.name);
- const doc = me.events.get_frm().doc;
+ if (this.allow_rate_change) {
+ this.rate_control.df.onchange = function() {
+ if (this.value || flt(this.value) === 0) {
+ me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
+ const item_row = frappe.get_doc(me.doctype, me.name);
+ const doc = me.events.get_frm().doc;
- me.$item_price.html(format_currency(item_row.rate, doc.currency));
- me.render_discount_dom(item_row);
- });
- }
+ me.$item_price.html(format_currency(item_row.rate, doc.currency));
+ me.render_discount_dom(item_row);
+ });
+ }
+ };
+ } else {
+ this.rate_control.df.read_only = 1;
}
+ this.rate_control.refresh();
+ }
+
+ if (this.discount_percentage_control && !this.allow_discount_change) {
+ this.discount_percentage_control.df.read_only = 1;
+ this.discount_percentage_control.refresh();
}
if (this.warehouse_control) {
@@ -234,24 +232,22 @@
})
} else if (available_qty === 0) {
me.warehouse_control.set_value('');
- frappe.throw(__(`Item Code: ${me.item_row.item_code.bold()} is not available under warehouse ${this.value.bold()}.`));
+ const bold_item_code = me.item_row.item_code.bold();
+ const bold_warehouse = this.value.bold();
+ frappe.throw(
+ __('Item Code: {0} is not available under warehouse {1}.', [bold_item_code, bold_warehouse])
+ );
}
me.actual_qty_control.set_value(available_qty);
});
}
}
- this.warehouse_control.refresh();
- }
-
- if (this.discount_percentage_control) {
- this.discount_percentage_control.df.onchange = function() {
- if (this.value) {
- me.events.form_updated(me.doctype, me.name, 'discount_percentage', this.value).then(() => {
- const item_row = frappe.get_doc(me.doctype, me.name);
- me.rate_control.set_value(item_row.rate);
- });
+ this.warehouse_control.df.get_query = () => {
+ return {
+ filters: { company: this.events.get_frm().doc.company }
}
- }
+ };
+ this.warehouse_control.refresh();
}
if (this.serial_no_control) {
@@ -270,7 +266,8 @@
query: 'erpnext.controllers.queries.get_batch_no',
filters: {
item_code: me.item_row.item_code,
- warehouse: me.item_row.warehouse
+ warehouse: me.item_row.warehouse,
+ posting_date: me.events.get_frm().doc.posting_date
}
}
};
@@ -287,16 +284,34 @@
me.events.set_value_in_current_cart_item('uom', this.value);
me.events.form_updated(me.doctype, me.name, 'uom', this.value);
me.current_item.uom = this.value;
+
+ const item_row = frappe.get_doc(me.doctype, me.name);
+ me.conversion_factor_control.df.read_only = (item_row.stock_uom == this.value);
+ me.conversion_factor_control.refresh();
}
}
+
+ frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
+ const field_control = this[`${fieldname}_control`];
+ const { item_code, batch_no, uom } = this.current_item;
+ const item_code_is_same = item_code === item_row.item_code;
+ const batch_is_same = batch_no == item_row.batch_no;
+ const uom_is_same = uom === item_row.uom;
+ const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false;
+
+ if (item_is_same && field_control && field_control.get_value() !== value) {
+ field_control.set_value(value);
+ cur_pos.update_cart_html(item_row);
+ }
+ });
}
-
+
async auto_update_batch_no() {
if (this.serial_no_control && this.batch_no_control) {
const selected_serial_nos = this.serial_no_control.get_value().split(`\n`).filter(s => s);
if (!selected_serial_nos.length) return;
- // find batch nos of the selected serial no
+ // find batch nos of the selected serial no
const serials_with_batch_no = await frappe.db.get_list("Serial No", {
filters: { 'name': ["in", selected_serial_nos]},
fields: ["batch_no", "name"]
@@ -311,7 +326,7 @@
const batch_serial_nos = batch_serial_map[batch_no].join(`\n`);
// eg. 10 selected serial no. -> 5 belongs to first batch other 5 belongs to second batch
const serial_nos_belongs_to_other_batch = selected_serial_nos.length !== batch_serial_map[batch_no].length;
-
+
const current_batch_no = this.batch_no_control.get_value();
current_batch_no != batch_no && await this.batch_no_control.set_value(batch_no);
@@ -326,7 +341,7 @@
this.events.clone_new_batch_item_in_frm(batch_serial_map, this.current_item);
}
}
-
+
bind_events() {
this.bind_auto_serial_fetch_event();
this.bind_fields_to_numpad_fields();
@@ -337,6 +352,7 @@
}
attach_shortcuts() {
+ this.wrapper.find('.close-btn').attr("title", "Esc");
frappe.ui.keys.on("escape", () => {
const item_details_visible = this.$component.is(":visible");
if (item_details_visible) {
@@ -355,18 +371,22 @@
}
});
}
-
+
bind_auto_serial_fetch_event() {
this.$form_container.on('click', '.auto-fetch-btn', () => {
- this.batch_no_control.set_value('');
+ this.batch_no_control && this.batch_no_control.set_value('');
let qty = this.qty_control.get_value();
+ let conversion_factor = this.conversion_factor_control.get_value();
+ let expiry_date = this.item_row.has_batch_no ? this.events.get_frm().doc.posting_date : "";
+
let numbers = frappe.call({
method: "erpnext.stock.doctype.serial_no.serial_no.auto_fetch_serial_number",
args: {
- qty,
+ qty: qty * conversion_factor,
item_code: this.current_item.item_code,
warehouse: this.warehouse_control.get_value() || '',
batch_nos: this.current_item.batch_no || '',
+ posting_date: expiry_date,
for_doctype: 'POS Invoice'
}
});
@@ -376,10 +396,14 @@
let records_length = auto_fetched_serial_numbers.length;
if (!records_length) {
const warehouse = this.warehouse_control.get_value().bold();
- frappe.msgprint(__(`Serial numbers unavailable for Item ${this.current_item.item_code.bold()}
- under warehouse ${warehouse}. Please try changing warehouse.`));
+ const item_code = this.current_item.item_code.bold();
+ frappe.msgprint(
+ __('Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.', [item_code, warehouse])
+ );
} else if (records_length < qty) {
- frappe.msgprint(`Fetched only ${records_length} available serial numbers.`);
+ frappe.msgprint(
+ __('Fetched only {0} available serial numbers.', [records_length])
+ );
this.qty_control.set_value(records_length);
}
numbers = auto_fetched_serial_numbers.join(`\n`);
@@ -389,6 +413,6 @@
}
toggle_component(show) {
- show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
+ show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
}
}
\ No newline at end of file
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 c87b845..e0d5b73 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -1,12 +1,17 @@
+import onScan from 'onscan.js';
+
erpnext.PointOfSale.ItemSelector = class {
- constructor({ frm, wrapper, events, pos_profile }) {
+ // eslint-disable-next-line no-unused-vars
+ constructor({ frm, wrapper, events, pos_profile, settings }) {
this.wrapper = wrapper;
this.events = events;
this.pos_profile = pos_profile;
-
+ this.hide_images = settings.hide_images;
+ this.auto_add_item = settings.auto_add_item_to_cart;
+
this.inti_component();
}
-
+
inti_component() {
this.prepare_dom();
this.make_search_bar();
@@ -17,29 +22,25 @@
prepare_dom() {
this.wrapper.append(
- `<section class="col-span-6 flex shadow rounded items-selector bg-white mx-h-70 h-100">
- <div class="flex flex-col rounded w-full scroll-y">
- <div class="filter-section flex p-8 pb-2 bg-white sticky z-100">
- <div class="search-field flex f-grow-3 mr-8 items-center text-grey"></div>
- <div class="item-group-field flex f-grow-1 items-center text-grey text-bold"></div>
- </div>
- <div class="flex flex-1 flex-col p-8 pt-2">
- <div class="text-grey mb-6">ALL ITEMS</div>
- <div class="items-container grid grid-cols-4 gap-8">
- </div>
- </div>
+ `<section class="items-selector">
+ <div class="filter-section">
+ <div class="label">All Items</div>
+ <div class="search-field"></div>
+ <div class="item-group-field"></div>
</div>
+ <div class="items-container"></div>
</section>`
);
-
+
this.$component = this.wrapper.find('.items-selector');
+ this.$items_container = this.$component.find('.items-container');
}
async load_items_data() {
if (!this.item_group) {
const res = await frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name");
this.parent_item_group = res.message.name;
- };
+ }
if (!this.price_list) {
const res = await frappe.db.get_value("POS Profile", this.pos_profile, "selling_price_list");
this.price_list = res.message.selling_price_list;
@@ -51,11 +52,12 @@
}
get_items({start = 0, page_length = 40, search_value=''}) {
- const price_list = this.events.get_frm().doc?.selling_price_list || this.price_list;
+ const doc = this.events.get_frm().doc;
+ const price_list = (doc && doc.selling_price_list) || this.price_list;
let { item_group, pos_profile } = this;
!item_group && (item_group = this.parent_item_group);
-
+
return frappe.call({
method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items",
freeze: true,
@@ -65,49 +67,52 @@
render_item_list(items) {
- this.$items_container = this.$component.find('.items-container');
this.$items_container.html('');
items.forEach(item => {
const item_html = this.get_item_html(item);
this.$items_container.append(item_html);
- })
+ });
}
get_item_html(item) {
+ const me = this;
+ // eslint-disable-next-line no-unused-vars
const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item;
- const indicator_color = actual_qty > 10 ? "green" : actual_qty !== 0 ? "orange" : "red";
+ const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
function get_item_image_html() {
- if (item_image) {
+ if (!me.hide_images && item_image) {
return `<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
- <img class="h-full" src="${item_image}" alt="${item_image}" style="object-fit: cover;">
- </div>`
+ <img class="h-full" src="${item_image}" alt="${frappe.get_abbr(item.item_name)}" style="object-fit: cover;">
+ </div>`;
} else {
- return `<div class="flex items-center justify-center h-32 bg-light-grey text-6xl text-grey-100">
- ${frappe.get_abbr(item.item_name)}
- </div>`
+ return `<div class="item-display abbr">${frappe.get_abbr(item.item_name)}</div>`;
}
}
return (
- `<div class="item-wrapper rounded shadow pointer no-select" data-item-code="${escape(item.item_code)}"
- data-serial-no="${escape(serial_no)}" data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
+ `<div class="item-wrapper"
+ data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
+ data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
title="Avaiable Qty: ${actual_qty}">
+
${get_item_image_html()}
- <div class="flex items-center pr-4 pl-4 h-10 justify-between">
- <div class="flex items-center f-shrink-1 text-dark-grey overflow-hidden whitespace-nowrap">
+
+ <div class="item-detail">
+ <div class="item-name">
<span class="indicator ${indicator_color}"></span>
${frappe.ellipsis(item.item_name, 18)}
</div>
- <div class="f-shrink-0 text-dark-grey text-bold ml-4">${format_currency(item.price_list_rate, item.currency, 0) || 0}</div>
+ <div class="item-rate">${format_currency(item.price_list_rate, item.currency, 0) || 0}</div>
</div>
</div>`
- )
+ );
}
make_search_bar() {
const me = this;
+ const doc = me.events.get_frm().doc;
this.$component.find('.search-field').html('');
this.$component.find('.item-group-field').html('');
@@ -115,7 +120,7 @@
df: {
label: __('Search'),
fieldtype: 'Data',
- placeholder: __('Search by item code, serial number, batch no or barcode')
+ placeholder: __('Search by item code, serial number or barcode')
},
parent: this.$component.find('.search-field'),
render_input: true,
@@ -135,9 +140,9 @@
return {
query: 'erpnext.selling.page.point_of_sale.point_of_sale.item_group_query',
filters: {
- pos_profile: me.events.get_frm().doc?.pos_profile
+ pos_profile: doc ? doc.pos_profile : ''
}
- }
+ };
},
},
parent: this.$component.find('.item-group-field'),
@@ -147,13 +152,18 @@
this.item_group_field.toggle_label(false);
}
+ set_search_value(value) {
+ $(this.search_field.$input[0]).val(value).trigger("input");
+ }
+
bind_events() {
const me = this;
+ window.onScan = onScan;
onScan.attachTo(document, {
onScan: (sScancode) => {
if (this.search_field && this.$component.is(':visible')) {
this.search_field.set_focus();
- $(this.search_field.$input[0]).val(sScancode).trigger("input");
+ this.set_search_value(sScancode);
this.barcode_scanned = true;
}
}
@@ -165,14 +175,15 @@
let batch_no = unescape($item.attr('data-batch-no'));
let serial_no = unescape($item.attr('data-serial-no'));
let uom = unescape($item.attr('data-uom'));
-
+
// escape(undefined) returns "undefined" then unescape returns "undefined"
batch_no = batch_no === "undefined" ? undefined : batch_no;
serial_no = serial_no === "undefined" ? undefined : serial_no;
uom = uom === "undefined" ? undefined : uom;
me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom }});
- })
+ me.set_search_value('');
+ });
this.search_field.$input.on('input', (e) => {
clearTimeout(this.last_search);
@@ -184,16 +195,26 @@
}
attach_shortcuts() {
- frappe.ui.keys.on("ctrl+i", () => {
- const selector_is_visible = this.$component.is(':visible');
- if (!selector_is_visible) return;
- this.search_field.set_focus();
+ const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
+ this.search_field.parent.attr("title", `${ctrl_label}+I`);
+ frappe.ui.keys.add_shortcut({
+ shortcut: "ctrl+i",
+ action: () => this.search_field.set_focus(),
+ condition: () => this.$component.is(':visible'),
+ description: __("Focus on search input"),
+ ignore_inputs: true,
+ page: cur_page.page.page
});
- frappe.ui.keys.on("ctrl+g", () => {
- const selector_is_visible = this.$component.is(':visible');
- if (!selector_is_visible) return;
- this.item_group_field.set_focus();
+ this.item_group_field.parent.attr("title", `${ctrl_label}+G`);
+ frappe.ui.keys.add_shortcut({
+ shortcut: "ctrl+g",
+ action: () => this.item_group_field.set_focus(),
+ condition: () => this.$component.is(':visible'),
+ description: __("Focus on Item Group filter"),
+ ignore_inputs: true,
+ page: cur_page.page.page
});
+
// for selecting the last filtered item on search
frappe.ui.keys.on("enter", () => {
const selector_is_visible = this.$component.is(':visible');
@@ -215,7 +236,7 @@
}
});
}
-
+
filter_items({ search_term='' }={}) {
if (search_term) {
search_term = search_term.toLowerCase();
@@ -226,40 +247,47 @@
const items = this.search_index[search_term];
this.items = items;
this.render_item_list(items);
+ this.auto_add_item && this.items.length == 1 && this.add_filtered_item_to_cart();
return;
}
}
this.get_items({ search_value: search_term })
.then(({ message }) => {
+ // eslint-disable-next-line no-unused-vars
const { items, serial_no, batch_no, barcode } = message;
if (search_term && !barcode) {
this.search_index[search_term] = items;
}
this.items = items;
this.render_item_list(items);
+ this.auto_add_item && this.items.length == 1 && this.add_filtered_item_to_cart();
});
}
-
+
+ add_filtered_item_to_cart() {
+ this.$items_container.find(".item-wrapper").click();
+ }
+
resize_selector(minimize) {
- minimize ?
- this.$component.find('.search-field').removeClass('mr-8') :
- this.$component.find('.search-field').addClass('mr-8');
-
- minimize ?
- this.$component.find('.filter-section').addClass('flex-col') :
- this.$component.find('.filter-section').removeClass('flex-col');
+ minimize ?
+ this.$component.find('.filter-section').css('grid-template-columns', 'repeat(1, minmax(0, 1fr))') :
+ this.$component.find('.filter-section').css('grid-template-columns', 'repeat(12, minmax(0, 1fr))');
minimize ?
- this.$component.removeClass('col-span-6').addClass('col-span-2') :
- this.$component.removeClass('col-span-2').addClass('col-span-6')
+ this.$component.find('.search-field').css('margin', 'var(--margin-sm) 0px') :
+ this.$component.find('.search-field').css('margin', '0px var(--margin-sm)');
minimize ?
- this.$items_container.removeClass('grid-cols-4').addClass('grid-cols-1') :
- this.$items_container.removeClass('grid-cols-1').addClass('grid-cols-4')
+ this.$component.css('grid-column', 'span 2 / span 2') :
+ this.$component.css('grid-column', 'span 6 / span 6');
+
+ minimize ?
+ this.$items_container.css('grid-template-columns', 'repeat(1, minmax(0, 1fr))') :
+ this.$items_container.css('grid-template-columns', 'repeat(4, minmax(0, 1fr))');
}
toggle_component(show) {
- show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
+ show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
}
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/pos_number_pad.js b/erpnext/selling/page/point_of_sale/pos_number_pad.js
index 4b8e841..962bcaf 100644
--- a/erpnext/selling/page/point_of_sale/pos_number_pad.js
+++ b/erpnext/selling/page/point_of_sale/pos_number_pad.js
@@ -22,17 +22,16 @@
return keys.reduce((a, row, i) => {
return a + row.reduce((a2, number, j) => {
const class_to_append = css_classes && css_classes[i] ? css_classes[i][j] : '';
- const fieldname = fieldnames && fieldnames[number] ?
+ const fieldname = fieldnames && fieldnames[number] ?
fieldnames[number] : typeof number === 'string' ? frappe.scrub(number) : number;
- return a2 + `<div class="numpad-btn pointer no-select rounded ${class_to_append}
- flex items-center justify-center h-16 text-md border-grey border" data-button-value="${fieldname}">${number}</div>`
- }, '')
+ return a2 + `<div class="numpad-btn ${class_to_append}" data-button-value="${fieldname}">${number}</div>`;
+ }, '');
}, '');
}
this.wrapper.html(
- `<div class="grid grid-cols-${cols} gap-4">
+ `<div class="numpad-container">
${get_keys()}
</div>`
)
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 9181ee8..ec39231 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
@@ -1,55 +1,51 @@
erpnext.PointOfSale.PastOrderList = class {
- constructor({ wrapper, events }) {
- this.wrapper = wrapper;
- this.events = events;
+ constructor({ wrapper, events }) {
+ this.wrapper = wrapper;
+ this.events = events;
- this.init_component();
- }
+ this.init_component();
+ }
- init_component() {
- this.prepare_dom();
- this.make_filter_section();
- this.bind_events();
- }
+ init_component() {
+ this.prepare_dom();
+ this.make_filter_section();
+ this.bind_events();
+ }
- prepare_dom() {
- this.wrapper.append(
- `<section class="col-span-4 flex flex-col shadow rounded past-order-list bg-white mx-h-70 h-100 d-none">
- <div class="flex flex-col rounded w-full scroll-y">
- <div class="filter-section flex flex-col p-8 pb-2 bg-white sticky z-100">
- <div class="search-field flex items-center text-grey"></div>
- <div class="status-field flex items-center text-grey text-bold"></div>
- </div>
- <div class="flex flex-1 flex-col p-8 pt-2">
- <div class="text-grey mb-6">RECENT ORDERS</div>
- <div class="invoices-container rounded border grid grid-cols-1"></div>
- </div>
- </div>
- </section>`
- )
+ prepare_dom() {
+ this.wrapper.append(
+ `<section class="past-order-list">
+ <div class="filter-section">
+ <div class="label">Recent Orders</div>
+ <div class="search-field"></div>
+ <div class="status-field"></div>
+ </div>
+ <div class="invoices-container"></div>
+ </section>`
+ );
- this.$component = this.wrapper.find('.past-order-list');
- this.$invoices_container = this.$component.find('.invoices-container');
- }
+ this.$component = this.wrapper.find('.past-order-list');
+ this.$invoices_container = this.$component.find('.invoices-container');
+ }
- bind_events() {
- this.search_field.$input.on('input', (e) => {
+ bind_events() {
+ this.search_field.$input.on('input', (e) => {
clearTimeout(this.last_search);
this.last_search = setTimeout(() => {
- const search_term = e.target.value;
- this.refresh_list(search_term, this.status_field.get_value());
+ const search_term = e.target.value;
+ this.refresh_list(search_term, this.status_field.get_value());
}, 300);
- });
- const me = this;
- this.$invoices_container.on('click', '.invoice-wrapper', function() {
- const invoice_name = unescape($(this).attr('data-invoice-name'));
+ });
+ const me = this;
+ this.$invoices_container.on('click', '.invoice-wrapper', function() {
+ const invoice_name = unescape($(this).attr('data-invoice-name'));
- me.events.open_invoice_data(invoice_name);
- })
- }
+ me.events.open_invoice_data(invoice_name);
+ });
+ }
- make_filter_section() {
- const me = this;
+ make_filter_section() {
+ const me = this;
this.search_field = frappe.ui.form.make_control({
df: {
label: __('Search'),
@@ -58,73 +54,70 @@
},
parent: this.$component.find('.search-field'),
render_input: true,
- });
+ });
this.status_field = frappe.ui.form.make_control({
df: {
label: __('Invoice Status'),
- fieldtype: 'Select',
+ fieldtype: 'Select',
options: `Draft\nPaid\nConsolidated\nReturn`,
- placeholder: __('Filter by invoice status'),
- onchange: function() {
- me.refresh_list(me.search_field.get_value(), this.value);
- }
+ placeholder: __('Filter by invoice status'),
+ onchange: function() {
+ if (me.$component.is(':visible')) me.refresh_list();
+ }
},
- parent: this.$component.find('.status-field'),
+ parent: this.$component.find('.status-field'),
render_input: true,
- });
- this.search_field.toggle_label(false);
- this.status_field.toggle_label(false);
- this.status_field.set_value('Paid');
- }
-
- toggle_component(show) {
- show ?
- this.$component.removeClass('d-none') && this.refresh_list() :
- this.$component.addClass('d-none');
- }
+ });
+ this.search_field.toggle_label(false);
+ this.status_field.toggle_label(false);
+ this.status_field.set_value('Draft');
+ }
- refresh_list() {
- frappe.dom.freeze();
- this.events.reset_summary();
- const search_term = this.search_field.get_value();
- const status = this.status_field.get_value();
+ refresh_list() {
+ frappe.dom.freeze();
+ this.events.reset_summary();
+ const search_term = this.search_field.get_value();
+ const status = this.status_field.get_value();
- this.$invoices_container.html('');
+ this.$invoices_container.html('');
- return frappe.call({
+ return frappe.call({
method: "erpnext.selling.page.point_of_sale.point_of_sale.get_past_order_list",
freeze: true,
- args: { search_term, status },
- callback: (response) => {
- frappe.dom.unfreeze();
- response.message.forEach(invoice => {
- const invoice_html = this.get_invoice_html(invoice);
- this.$invoices_container.append(invoice_html);
- });
- }
- });
- }
+ args: { search_term, status },
+ callback: (response) => {
+ frappe.dom.unfreeze();
+ response.message.forEach(invoice => {
+ const invoice_html = this.get_invoice_html(invoice);
+ this.$invoices_container.append(invoice_html);
+ });
+ }
+ });
+ }
- get_invoice_html(invoice) {
- const posting_datetime = moment(invoice.posting_date+" "+invoice.posting_time).format("Do MMMM, h:mma");
- return (
- `<div class="invoice-wrapper flex p-4 justify-between border-b-grey pointer no-select" data-invoice-name="${escape(invoice.name)}">
- <div class="flex flex-col justify-end">
- <div class="text-dark-grey text-bold overflow-hidden whitespace-nowrap mb-2">${invoice.name}</div>
- <div class="flex items-center">
- <div class="flex items-center f-shrink-1 text-dark-grey overflow-hidden whitespace-nowrap">
- <svg class="mr-2" width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
- <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
- </svg>
- ${invoice.customer}
- </div>
- </div>
- </div>
- <div class="flex flex-col text-right">
- <div class="f-shrink-0 text-lg text-dark-grey text-bold ml-4">${format_currency(invoice.grand_total, invoice.currency, 0) || 0}</div>
- <div class="f-shrink-0 text-grey ml-4">${posting_datetime}</div>
- </div>
- </div>`
- )
- }
-}
\ No newline at end of file
+ get_invoice_html(invoice) {
+ const posting_datetime = moment(invoice.posting_date+" "+invoice.posting_time).format("Do MMMM, h:mma");
+ return (
+ `<div class="invoice-wrapper" data-invoice-name="${escape(invoice.name)}">
+ <div class="invoice-name-date">
+ <div class="invoice-name">${invoice.name}</div>
+ <div class="invoice-date">
+ <svg class="mr-2" width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
+ <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
+ </svg>
+ ${invoice.customer}
+ </div>
+ </div>
+ <div class="invoice-total-status">
+ <div class="invoice-total">${format_currency(invoice.grand_total, invoice.currency, 0) || 0}</div>
+ <div class="invoice-date">${posting_datetime}</div>
+ </div>
+ </div>
+ <div class="seperator"></div>`
+ );
+ }
+
+ toggle_component(show) {
+ show ? this.$component.css('display', 'flex') && this.refresh_list() : this.$component.css('display', 'none');
+ }
+};
\ No newline at end of file
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 30e0918..b10a9e3 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
@@ -1,456 +1,397 @@
erpnext.PointOfSale.PastOrderSummary = class {
- constructor({ wrapper, events }) {
- this.wrapper = wrapper;
- this.events = events;
+ constructor({ wrapper, events }) {
+ this.wrapper = wrapper;
+ this.events = events;
- this.init_component();
- }
+ this.init_component();
+ }
- init_component() {
- this.prepare_dom();
- this.init_child_components();
- this.bind_events();
- this.attach_shortcuts();
- }
+ init_component() {
+ this.prepare_dom();
+ this.init_email_print_dialog();
+ this.bind_events();
+ this.attach_shortcuts();
+ }
- prepare_dom() {
- this.wrapper.append(
- `<section class="col-span-6 flex flex-col items-center shadow rounded past-order-summary bg-white mx-h-70 h-100 d-none">
- <div class="no-summary-placeholder flex flex-1 items-center justify-center p-16">
- <div class="no-item-wrapper flex items-center h-18 pr-4 pl-4">
- <div class="flex-1 text-center text-grey">Select an invoice to load summary data</div>
- </div>
- </div>
- <div class="summary-wrapper d-none flex-1 w-66 text-dark-grey relative">
- <div class="summary-container absolute flex flex-col pt-16 pb-16 pr-8 pl-8 w-full h-full"></div>
- </div>
- </section>`
- )
+ prepare_dom() {
+ this.wrapper.append(
+ `<section class="past-order-summary">
+ <div class="no-summary-placeholder">
+ Select an invoice to load summary data
+ </div>
+ <div class="invoice-summary-wrapper">
+ <div class="abs-container">
+ <div class="upper-section"></div>
+ <div class="label">Items</div>
+ <div class="items-container summary-container"></div>
+ <div class="label">Totals</div>
+ <div class="totals-container summary-container"></div>
+ <div class="label">Payments</div>
+ <div class="payments-container summary-container"></div>
+ <div class="summary-btns"></div>
+ </div>
+ </div>
+ </section>`
+ );
- this.$component = this.wrapper.find('.past-order-summary');
- this.$summary_wrapper = this.$component.find('.summary-wrapper');
- this.$summary_container = this.$component.find('.summary-container');
- }
+ this.$component = this.wrapper.find('.past-order-summary');
+ this.$summary_wrapper = this.$component.find('.invoice-summary-wrapper');
+ this.$summary_container = this.$component.find('.abs-container');
+ this.$upper_section = this.$summary_container.find('.upper-section');
+ this.$items_container = this.$summary_container.find('.items-container');
+ this.$totals_container = this.$summary_container.find('.totals-container');
+ this.$payment_container = this.$summary_container.find('.payments-container');
+ this.$summary_btns = this.$summary_container.find('.summary-btns');
+ }
- init_child_components() {
- this.init_upper_section();
- this.init_items_summary();
- this.init_totals_summary();
- this.init_payments_summary();
- this.init_summary_buttons();
- this.init_email_print_dialog();
- }
+ init_email_print_dialog() {
+ const email_dialog = new frappe.ui.Dialog({
+ title: 'Email Receipt',
+ fields: [
+ {fieldname: 'email_id', fieldtype: 'Data', options: 'Email', label: 'Email ID'},
+ // {fieldname:'remarks', fieldtype:'Text', label:'Remarks (if any)'}
+ ],
+ primary_action: () => {
+ this.send_email();
+ },
+ primary_action_label: __('Send'),
+ });
+ this.email_dialog = email_dialog;
- init_upper_section() {
- this.$summary_container.append(
- `<div class="flex upper-section justify-between w-full h-24"></div>`
- );
+ const print_dialog = new frappe.ui.Dialog({
+ title: 'Print Receipt',
+ fields: [
+ {fieldname: 'print', fieldtype: 'Data', label: 'Print Preview'}
+ ],
+ primary_action: () => {
+ this.print_receipt();
+ },
+ primary_action_label: __('Print'),
+ });
+ this.print_dialog = print_dialog;
+ }
- this.$upper_section = this.$summary_container.find('.upper-section');
- }
+ get_upper_section_html(doc) {
+ const { status } = doc;
+ let indicator_color = '';
- init_items_summary() {
- this.$summary_container.append(
- `<div class="flex flex-col flex-1 mt-6 w-full scroll-y">
- <div class="text-grey mb-4 sticky bg-white">ITEMS</div>
- <div class="items-summary-container border rounded flex flex-col w-full"></div>
- </div>`
- )
+ in_list(['Paid', 'Consolidated'], status) && (indicator_color = 'green');
+ status === 'Draft' && (indicator_color = 'red');
+ status === 'Return' && (indicator_color = 'grey');
- this.$items_summary_container = this.$summary_container.find('.items-summary-container');
- }
+ return `<div class="left-section">
+ <div class="customer-name">${doc.customer}</div>
+ <div class="customer-email">${this.customer_email}</div>
+ <div class="cashier">Sold by: ${doc.owner}</div>
+ </div>
+ <div class="right-section">
+ <div class="paid-amount">${format_currency(doc.paid_amount, doc.currency)}</div>
+ <div class="invoice-name">${doc.name}</div>
+ <span class="indicator-pill whitespace-nowrap ${indicator_color}"><span>${doc.status}</span></span>
+ </div>`;
+ }
- init_totals_summary() {
- this.$summary_container.append(
- `<div class="flex flex-col mt-6 w-full f-shrink-0">
- <div class="text-grey mb-4">TOTALS</div>
- <div class="summary-totals-container border rounded flex flex-col w-full"></div>
- </div>`
- )
+ get_item_html(doc, item_data) {
+ return `<div class="item-row-wrapper">
+ <div class="item-name">${item_data.item_name}</div>
+ <div class="item-qty">${item_data.qty || 0}</div>
+ <div class="item-rate-disc">${get_rate_discount_html()}</div>
+ </div>`;
- this.$totals_summary_container = this.$summary_container.find('.summary-totals-container');
- }
+ function get_rate_discount_html() {
+ if (item_data.rate && item_data.price_list_rate && item_data.rate !== item_data.price_list_rate) {
+ return `<span class="item-disc">(${item_data.discount_percentage}% off)</span>
+ <div class="item-rate">${format_currency(item_data.rate, doc.currency)}</div>`;
+ } else {
+ return `<div class="item-rate">${format_currency(item_data.price_list_rate || item_data.rate, doc.currency)}</div>`;
+ }
+ }
+ }
- init_payments_summary() {
- this.$summary_container.append(
- `<div class="flex flex-col mt-6 w-full f-shrink-0">
- <div class="text-grey mb-4">PAYMENTS</div>
- <div class="payments-summary-container border rounded flex flex-col w-full mb-4"></div>
- </div>`
- )
+ get_discount_html(doc) {
+ if (doc.discount_amount) {
+ return `<div class="summary-row-wrapper">
+ <div>Discount (${doc.additional_discount_percentage} %)</div>
+ <div>${format_currency(doc.discount_amount, doc.currency)}</div>
+ </div>`;
+ } else {
+ return ``;
+ }
+ }
- this.$payment_summary_container = this.$summary_container.find('.payments-summary-container');
- }
+ get_net_total_html(doc) {
+ return `<div class="summary-row-wrapper">
+ <div>Net Total</div>
+ <div>${format_currency(doc.net_total, doc.currency)}</div>
+ </div>`;
+ }
- init_summary_buttons() {
- this.$summary_container.append(
- `<div class="summary-btns flex summary-btns justify-between w-full f-shrink-0"></div>`
- )
+ get_taxes_html(doc) {
+ if (!doc.taxes.length) return '';
- this.$summary_btns = this.$summary_container.find('.summary-btns');
- }
+ let taxes_html = doc.taxes.map(t => {
+ const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`;
+ return `
+ <div class="tax-row">
+ <div class="tax-label">${description}</div>
+ <div class="tax-value">${format_currency(t.tax_amount_after_discount_amount, doc.currency)}</div>
+ </div>
+ `;
+ }).join('');
- init_email_print_dialog() {
- const email_dialog = new frappe.ui.Dialog({
- title: 'Email Receipt',
- fields: [
- {fieldname:'email_id', fieldtype:'Data', options: 'Email', label:'Email ID'},
- // {fieldname:'remarks', fieldtype:'Text', label:'Remarks (if any)'}
- ],
- primary_action: () => {
- this.send_email();
- },
- primary_action_label: __('Send'),
- });
- this.email_dialog = email_dialog;
+ return `<div class="taxes-wrapper">${taxes_html}</div>`;
+ }
- const print_dialog = new frappe.ui.Dialog({
- title: 'Print Receipt',
- fields: [
- {fieldname:'print', fieldtype:'Data', label:'Print Preview'}
- ],
- primary_action: () => {
- const frm = this.events.get_frm();
- frm.doc = this.doc;
- frm.print_preview.lang_code = frm.doc.language;
- frm.print_preview.printit(true);
- },
- primary_action_label: __('Print'),
- });
- this.print_dialog = print_dialog;
- }
+ get_grand_total_html(doc) {
+ return `<div class="summary-row-wrapper grand-total">
+ <div>Grand Total</div>
+ <div>${format_currency(doc.grand_total, doc.currency)}</div>
+ </div>`;
+ }
- get_upper_section_html(doc) {
- const { status } = doc; let indicator_color = '';
+ get_payment_html(doc, payment) {
+ return `<div class="summary-row-wrapper payments">
+ <div>${payment.mode_of_payment}</div>
+ <div>${format_currency(payment.amount, doc.currency)}</div>
+ </div>`;
+ }
- in_list(['Paid', 'Consolidated'], status) && (indicator_color = 'green');
- status === 'Draft' && (indicator_color = 'red');
- status === 'Return' && (indicator_color = 'grey');
+ bind_events() {
+ this.$summary_container.on('click', '.return-btn', () => {
+ this.events.process_return(this.doc.name);
+ this.toggle_component(false);
+ this.$component.find('.no-summary-placeholder').css('display', 'flex');
+ this.$summary_wrapper.css('display', 'none');
+ });
- return `<div class="flex flex-col items-start justify-end pr-4">
- <div class="text-lg text-bold pt-2">${doc.customer}</div>
- <div class="text-grey">${this.customer_email}</div>
- <div class="text-grey mt-auto">Sold by: ${doc.owner}</div>
- </div>
- <div class="flex flex-col flex-1 items-end justify-between">
- <div class="text-2-5xl text-bold">${format_currency(doc.paid_amount, doc.currency)}</div>
- <div class="flex justify-between">
- <div class="text-grey mr-4">${doc.name}</div>
- <div class="text-grey text-bold indicator ${indicator_color}">${doc.status}</div>
- </div>
- </div>`
- }
+ this.$summary_container.on('click', '.edit-btn', () => {
+ this.events.edit_order(this.doc.name);
+ this.toggle_component(false);
+ this.$component.find('.no-summary-placeholder').css('display', 'flex');
+ this.$summary_wrapper.css('display', 'none');
+ });
- get_discount_html(doc) {
- if (doc.discount_amount) {
- return `<div class="total-summary-wrapper flex items-center h-12 pr-4 pl-4 pointer border-b-grey no-select">
- <div class="flex f-shrink-1 items-center">
- <div class="text-md-0 text-dark-grey text-bold overflow-hidden whitespace-nowrap mr-2">
- Discount
- </div>
- <span class="text-grey">(${doc.additional_discount_percentage} %)</span>
- </div>
- <div class="flex flex-col f-shrink-0 ml-auto text-right">
- <div class="text-md-0 text-dark-grey text-bold">${format_currency(doc.discount_amount, doc.currency)}</div>
- </div>
- </div>`;
- } else {
- return ``;
- }
- }
+ this.$summary_container.on('click', '.delete-btn', () => {
+ this.events.delete_order(this.doc.name);
+ this.show_summary_placeholder();
+ });
- get_net_total_html(doc) {
- return `<div class="total-summary-wrapper flex items-center h-12 pr-4 pl-4 pointer border-b-grey no-select">
- <div class="flex f-shrink-1 items-center">
- <div class="text-md-0 text-dark-grey text-bold overflow-hidden whitespace-nowrap">
- Net Total
- </div>
- </div>
- <div class="flex flex-col f-shrink-0 ml-auto text-right">
- <div class="text-md-0 text-dark-grey text-bold">${format_currency(doc.net_total, doc.currency)}</div>
- </div>
- </div>`
- }
+ this.$summary_container.on('click', '.new-btn', () => {
+ this.events.new_order();
+ this.toggle_component(false);
+ this.$component.find('.no-summary-placeholder').css('display', 'flex');
+ this.$summary_wrapper.css('display', 'none');
+ });
- get_taxes_html(doc) {
- return `<div class="total-summary-wrapper flex items-center justify-between h-12 pr-4 pl-4 border-b-grey">
- <div class="flex">
- <div class="text-md-0 text-dark-grey text-bold w-fit">Tax Charges</div>
- <div class="flex ml-6 text-dark-grey">
- ${
- doc.taxes.map((t, i) => {
- let margin_left = '';
- if (i !== 0) margin_left = 'ml-2';
- return `<span class="pl-2 pr-2 ${margin_left}">${t.description} @${t.rate}%</span>`
- }).join('')
- }
- </div>
- </div>
- <div class="flex flex-col text-right">
- <div class="text-md-0 text-dark-grey text-bold">${format_currency(doc.base_total_taxes_and_charges, doc.currency)}</div>
- </div>
- </div>`
- }
+ this.$summary_container.on('click', '.email-btn', () => {
+ this.email_dialog.fields_dict.email_id.set_value(this.customer_email);
+ this.email_dialog.show();
+ });
- get_grand_total_html(doc) {
- return `<div class="total-summary-wrapper flex items-center h-12 pr-4 pl-4 pointer border-b-grey no-select">
- <div class="flex f-shrink-1 items-center">
- <div class="text-md-0 text-dark-grey text-bold overflow-hidden whitespace-nowrap">
- Grand Total
- </div>
- </div>
- <div class="flex flex-col f-shrink-0 ml-auto text-right">
- <div class="text-md-0 text-dark-grey text-bold">${format_currency(doc.grand_total, doc.currency)}</div>
- </div>
- </div>`
- }
+ this.$summary_container.on('click', '.print-btn', () => {
+ this.print_receipt();
+ });
+ }
- get_item_html(doc, item_data) {
- return `<div class="item-summary-wrapper flex items-center h-12 pr-4 pl-4 border-b-grey pointer no-select">
- <div class="flex w-6 h-6 rounded bg-light-grey mr-4 items-center justify-center font-bold f-shrink-0">
- <span>${item_data.qty || 0}</span>
- </div>
- <div class="flex flex-col f-shrink-1">
- <div class="text-md text-dark-grey text-bold overflow-hidden whitespace-nowrap">
- ${item_data.item_name}
- </div>
- </div>
- <div class="flex f-shrink-0 ml-auto text-right">
- ${get_rate_discount_html()}
- </div>
- </div>`
+ print_receipt() {
+ const frm = this.events.get_frm();
+ frappe.utils.print(
+ frm.doctype,
+ frm.docname,
+ frm.pos_print_format,
+ frm.doc.letter_head,
+ frm.doc.language || frappe.boot.lang
+ );
+ }
- function get_rate_discount_html() {
- if (item_data.rate && item_data.price_list_rate && item_data.rate !== item_data.price_list_rate) {
- return `<span class="text-grey mr-2">(${item_data.discount_percentage}% off)</span>
- <div class="text-md-0 text-dark-grey text-bold">${format_currency(item_data.rate, doc.currency)}</div>`
- } else {
- return `<div class="text-md-0 text-dark-grey text-bold">${format_currency(item_data.price_list_rate || item_data.rate, doc.currency)}</div>`
- }
- }
- }
+ attach_shortcuts() {
+ const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
+ this.$summary_container.find('.print-btn').attr("title", `${ctrl_label}+P`);
+ frappe.ui.keys.add_shortcut({
+ shortcut: "ctrl+p",
+ action: () => this.$summary_container.find('.print-btn').click(),
+ condition: () => this.$component.is(':visible') && this.$summary_container.find('.print-btn').is(":visible"),
+ description: __("Print Receipt"),
+ page: cur_page.page.page
+ });
+ this.$summary_container.find('.new-btn').attr("title", `${ctrl_label}+Enter`);
+ frappe.ui.keys.on("ctrl+enter", () => {
+ const summary_is_visible = this.$component.is(":visible");
+ if (summary_is_visible && this.$summary_container.find('.new-btn').is(":visible")) {
+ this.$summary_container.find('.new-btn').click();
+ }
+ });
+ this.$summary_container.find('.edit-btn').attr("title", `${ctrl_label}+E`);
+ frappe.ui.keys.add_shortcut({
+ shortcut: "ctrl+e",
+ action: () => this.$summary_container.find('.edit-btn').click(),
+ condition: () => this.$component.is(':visible') && this.$summary_container.find('.edit-btn').is(":visible"),
+ description: __("Edit Receipt"),
+ page: cur_page.page.page
+ });
+ }
- get_payment_html(doc, payment) {
- return `<div class="payment-summary-wrapper flex items-center h-12 pr-4 pl-4 pointer border-b-grey no-select">
- <div class="flex f-shrink-1 items-center">
- <div class="text-md-0 text-dark-grey text-bold overflow-hidden whitespace-nowrap">
- ${payment.mode_of_payment}
- </div>
- </div>
- <div class="flex flex-col f-shrink-0 ml-auto text-right">
- <div class="text-md-0 text-dark-grey text-bold">${format_currency(payment.amount, doc.currency)}</div>
- </div>
- </div>`
- }
+ send_email() {
+ const frm = this.events.get_frm();
+ const recipients = this.email_dialog.get_values().recipients;
+ const doc = this.doc || frm.doc;
+ const print_format = frm.pos_print_format;
- bind_events() {
- this.$summary_container.on('click', '.return-btn', () => {
- this.events.process_return(this.doc.name);
- this.toggle_component(false);
- this.$component.find('.no-summary-placeholder').removeClass('d-none');
- this.$summary_wrapper.addClass('d-none');
- });
+ frappe.call({
+ method: "frappe.core.doctype.communication.email.make",
+ args: {
+ recipients: recipients,
+ subject: __(frm.meta.name) + ': ' + doc.name,
+ doctype: doc.doctype,
+ name: doc.name,
+ send_email: 1,
+ print_format,
+ sender_full_name: frappe.user.full_name(),
+ _lang: doc.language
+ },
+ callback: r => {
+ if (!r.exc) {
+ frappe.utils.play_sound("email");
+ if (r.message["emails_not_sent_to"]) {
+ frappe.msgprint(__(
+ "Email not sent to {0} (unsubscribed / disabled)",
+ [ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]
+ ));
+ } else {
+ frappe.show_alert({
+ message: __('Email sent successfully.'),
+ indicator: 'green'
+ });
+ }
+ this.email_dialog.hide();
+ } else {
+ frappe.msgprint(__("There were errors while sending email. Please try again."));
+ }
+ }
+ });
+ }
- this.$summary_container.on('click', '.edit-btn', () => {
- this.events.edit_order(this.doc.name);
- this.toggle_component(false);
- this.$component.find('.no-summary-placeholder').removeClass('d-none');
- this.$summary_wrapper.addClass('d-none');
- });
+ add_summary_btns(map) {
+ this.$summary_btns.html('');
+ map.forEach(m => {
+ if (m.condition) {
+ m.visible_btns.forEach(b => {
+ const class_name = b.split(' ')[0].toLowerCase();
+ this.$summary_btns.append(
+ `<div class="summary-btn btn btn-default ${class_name}-btn">${b}</div>`
+ );
+ });
+ }
+ });
+ this.$summary_btns.children().last().removeClass('mr-4');
+ }
- this.$summary_container.on('click', '.new-btn', () => {
- this.events.new_order();
- this.toggle_component(false);
- this.$component.find('.no-summary-placeholder').removeClass('d-none');
- this.$summary_wrapper.addClass('d-none');
- });
+ toggle_summary_placeholder(show) {
+ if (show) {
+ this.$summary_wrapper.css('display', 'none');
+ this.$component.find('.no-summary-placeholder').css('display', 'flex');
+ } else {
+ this.$summary_wrapper.css('display', 'flex');
+ this.$component.find('.no-summary-placeholder').css('display', 'none');
+ }
+ }
- this.$summary_container.on('click', '.email-btn', () => {
- this.email_dialog.fields_dict.email_id.set_value(this.customer_email);
- this.email_dialog.show();
- });
+ get_condition_btn_map(after_submission) {
+ if (after_submission)
+ return [{ condition: true, visible_btns: ['Print Receipt', 'Email Receipt', 'New Order'] }];
- this.$summary_container.on('click', '.print-btn', () => {
- // this.print_dialog.show();
- const frm = this.events.get_frm();
- frm.doc = this.doc;
- frm.print_preview.lang_code = frm.doc.language;
- frm.print_preview.printit(true);
- });
- }
+ return [
+ { condition: this.doc.docstatus === 0, visible_btns: ['Edit Order', 'Delete Order'] },
+ { condition: !this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt', 'Return']},
+ { condition: this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt']}
+ ];
+ }
- attach_shortcuts() {
- frappe.ui.keys.on("ctrl+p", () => {
- const print_btn_visible = this.$summary_container.find('.print-btn').is(":visible");
- const summary_visible = this.$component.is(":visible");
- if (!summary_visible || !print_btn_visible) return;
+ load_summary_of(doc, after_submission=false) {
+ after_submission ?
+ this.$component.css('grid-column', 'span 10 / span 10') :
+ this.$component.css('grid-column', 'span 6 / span 6');
- this.$summary_container.find('.print-btn').click();
- });
- }
+ this.toggle_summary_placeholder(false);
- toggle_component(show) {
- show ?
- this.$component.removeClass('d-none') :
- this.$component.addClass('d-none');
- }
+ this.doc = doc;
- send_email() {
- const frm = this.events.get_frm();
- const recipients = this.email_dialog.get_values().recipients;
- const doc = this.doc || frm.doc;
- const print_format = frm.pos_print_format;
+ this.attach_document_info(doc);
- frappe.call({
- method:"frappe.core.doctype.communication.email.make",
- args: {
- recipients: recipients,
- subject: __(frm.meta.name) + ': ' + doc.name,
- doctype: doc.doctype,
- name: doc.name,
- send_email: 1,
- print_format,
- sender_full_name: frappe.user.full_name(),
- _lang : doc.language
- },
- callback: r => {
- if(!r.exc) {
- frappe.utils.play_sound("email");
- if(r.message["emails_not_sent_to"]) {
- frappe.msgprint(__("Email not sent to {0} (unsubscribed / disabled)",
- [ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) );
- } else {
- frappe.show_alert({
- message: __('Email sent successfully.'),
- indicator: 'green'
- });
- }
- this.email_dialog.hide();
- } else {
- frappe.msgprint(__("There were errors while sending email. Please try again."));
- }
- }
- });
- }
+ this.attach_items_info(doc);
- add_summary_btns(map) {
- this.$summary_btns.html('');
- map.forEach(m => {
- if (m.condition) {
- m.visible_btns.forEach(b => {
- const class_name = b.split(' ')[0].toLowerCase();
- this.$summary_btns.append(
- `<div class="${class_name}-btn border rounded h-14 flex flex-1 items-center mr-4 justify-center text-md text-bold no-select pointer">
- ${b}
- </div>`
- )
- });
- }
- });
- this.$summary_btns.children().last().removeClass('mr-4');
- }
+ this.attach_totals_info(doc);
- show_summary_placeholder() {
- this.$summary_wrapper.addClass("d-none");
- this.$component.find('.no-summary-placeholder').removeClass('d-none');
- }
+ this.attach_payments_info(doc);
- switch_to_post_submit_summary() {
- // switch to full width view
- this.$component.removeClass('col-span-6').addClass('col-span-10');
- this.$summary_wrapper.removeClass('w-66').addClass('w-40');
+ const condition_btns_map = this.get_condition_btn_map(after_submission);
- // switch place holder with summary container
- this.$component.find('.no-summary-placeholder').addClass('d-none');
- this.$summary_wrapper.removeClass('d-none');
- }
+ this.add_summary_btns(condition_btns_map);
+ }
- switch_to_recent_invoice_summary() {
- // switch full width view with 60% view
- this.$component.removeClass('col-span-10').addClass('col-span-6');
- this.$summary_wrapper.removeClass('w-40').addClass('w-66');
+ attach_document_info(doc) {
+ frappe.db.get_value('Customer', this.doc.customer, 'email_id').then(({ message }) => {
+ this.customer_email = message.email_id || '';
+ const upper_section_dom = this.get_upper_section_html(doc);
+ this.$upper_section.html(upper_section_dom);
+ });
+ }
- // switch place holder with summary container
- this.$component.find('.no-summary-placeholder').addClass('d-none');
- this.$summary_wrapper.removeClass('d-none');
- }
+ attach_items_info(doc) {
+ this.$items_container.html('');
+ doc.items.forEach(item => {
+ const item_dom = this.get_item_html(doc, item);
+ this.$items_container.append(item_dom);
+ this.set_dynamic_rate_header_width();
+ });
+ }
- get_condition_btn_map(after_submission) {
- if (after_submission)
- return [{ condition: true, visible_btns: ['Print Receipt', 'Email Receipt', 'New Order'] }];
+ set_dynamic_rate_header_width() {
+ const rate_cols = Array.from(this.$items_container.find(".item-rate-disc"));
+ this.$items_container.find(".item-rate-disc").css("width", "");
+ let max_width = rate_cols.reduce((max_width, elm) => {
+ if ($(elm).width() > max_width)
+ max_width = $(elm).width();
+ return max_width;
+ }, 0);
- return [
- { condition: this.doc.docstatus === 0, visible_btns: ['Edit Order'] },
- { condition: !this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt', 'Return']},
- { condition: this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt']}
- ];
- }
+ max_width += 1;
+ if (max_width == 1) max_width = "";
- load_summary_of(doc, after_submission=false) {
- this.$summary_wrapper.removeClass("d-none");
+ this.$items_container.find(".item-rate-disc").css("width", max_width);
+ }
- after_submission ?
- this.switch_to_post_submit_summary() : this.switch_to_recent_invoice_summary();
+ attach_payments_info(doc) {
+ this.$payment_container.html('');
+ doc.payments.forEach(p => {
+ if (p.amount) {
+ const payment_dom = this.get_payment_html(doc, p);
+ this.$payment_container.append(payment_dom);
+ }
+ });
+ if (doc.redeem_loyalty_points && doc.loyalty_amount) {
+ const payment_dom = this.get_payment_html(doc, {
+ mode_of_payment: 'Loyalty Points',
+ amount: doc.loyalty_amount,
+ });
+ this.$payment_container.append(payment_dom);
+ }
+ }
- this.doc = doc;
+ attach_totals_info(doc) {
+ this.$totals_container.html('');
- this.attach_basic_info(doc);
+ const net_total_dom = this.get_net_total_html(doc);
+ const taxes_dom = this.get_taxes_html(doc);
+ const discount_dom = this.get_discount_html(doc);
+ const grand_total_dom = this.get_grand_total_html(doc);
+ this.$totals_container.append(net_total_dom);
+ this.$totals_container.append(taxes_dom);
+ this.$totals_container.append(discount_dom);
+ this.$totals_container.append(grand_total_dom);
+ }
- this.attach_items_info(doc);
-
- this.attach_totals_info(doc);
-
- this.attach_payments_info(doc);
-
- const condition_btns_map = this.get_condition_btn_map(after_submission);
-
- this.add_summary_btns(condition_btns_map);
- }
-
- attach_basic_info(doc) {
- frappe.db.get_value('Customer', this.doc.customer, 'email_id').then(({ message }) => {
- this.customer_email = message.email_id || '';
- const upper_section_dom = this.get_upper_section_html(doc);
- this.$upper_section.html(upper_section_dom);
- });
- }
-
- attach_items_info(doc) {
- this.$items_summary_container.html('');
- doc.items.forEach(item => {
- const item_dom = this.get_item_html(doc, item);
- this.$items_summary_container.append(item_dom);
- });
- }
-
- attach_payments_info(doc) {
- this.$payment_summary_container.html('');
- doc.payments.forEach(p => {
- if (p.amount) {
- const payment_dom = this.get_payment_html(doc, p);
- this.$payment_summary_container.append(payment_dom);
- }
- });
- if (doc.redeem_loyalty_points && doc.loyalty_amount) {
- const payment_dom = this.get_payment_html(doc, {
- mode_of_payment: 'Loyalty Points',
- amount: doc.loyalty_amount,
- });
- this.$payment_summary_container.append(payment_dom);
- }
- }
-
- attach_totals_info(doc) {
- this.$totals_summary_container.html('');
-
- const discount_dom = this.get_discount_html(doc);
- const net_total_dom = this.get_net_total_html(doc);
- const taxes_dom = this.get_taxes_html(doc);
- const grand_total_dom = this.get_grand_total_html(doc);
- this.$totals_summary_container.append(discount_dom);
- this.$totals_summary_container.append(net_total_dom);
- this.$totals_summary_container.append(taxes_dom);
- this.$totals_summary_container.append(grand_total_dom);
- }
-
-}
\ No newline at end of file
+ toggle_component(show) {
+ show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
+ }
+};
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 7f0cabe..22a279d 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -1,5 +1,4 @@
-{% include "erpnext/selling/page/point_of_sale/pos_number_pad.js" %}
-
+/* eslint-disable no-unused-vars */
erpnext.PointOfSale.Payment = class {
constructor({ events, wrapper }) {
this.wrapper = wrapper;
@@ -9,47 +8,37 @@
}
init_component() {
- this.prepare_dom();
- this.initialize_numpad();
+ this.prepare_dom();
+ this.initialize_numpad();
this.bind_events();
this.attach_shortcuts();
-
+
}
prepare_dom() {
this.wrapper.append(
- `<section class="col-span-6 flex shadow rounded payment-section bg-white mx-h-70 h-100 d-none">
- <div class="flex flex-col p-16 pt-8 pb-8 w-full">
- <div class="text-grey mb-6 payment-section no-select pointer">
- PAYMENT METHOD<span class="octicon octicon-chevron-down collapse-indicator"></span>
+ `<section class="payment-container">
+ <div class="section-label payment-section">Payment Method</div>
+ <div class="payment-modes"></div>
+ <div class="fields-numpad-container">
+ <div class="fields-section">
+ <div class="section-label">Additional Information</div>
+ <div class="invoice-fields"></div>
</div>
- <div class="payment-modes flex flex-wrap"></div>
- <div class="invoice-details-section"></div>
- <div class="flex mt-auto justify-center w-full">
- <div class="flex flex-col justify-center flex-1 ml-4">
- <div class="flex w-full">
- <div class="totals-remarks items-end justify-end flex flex-1">
- <div class="remarks text-md-0 text-grey mr-auto"></div>
- <div class="totals flex justify-end pt-4"></div>
- </div>
- <div class="number-pad w-40 mb-4 ml-8 d-none"></div>
- </div>
- <div class="flex items-center justify-center mt-4 submit-order h-16 w-full rounded bg-primary text-md text-white no-select pointer text-bold">
- Complete Order
- </div>
- <div class="order-time flex items-center justify-end mt-2 pt-2 pb-2 w-full text-md-0 text-grey no-select pointer d-none"></div>
- </div>
- </div>
- </div>
- </section>`
- )
- this.$component = this.wrapper.find('.payment-section');
+ <div class="number-pad"></div>
+ </div>
+ <div class="totals-section">
+ <div class="totals"></div>
+ </div>
+ <div class="submit-order-btn">Complete Order</div>
+ </section>`
+ );
+ this.$component = this.wrapper.find('.payment-container');
this.$payment_modes = this.$component.find('.payment-modes');
- this.$totals_remarks = this.$component.find('.totals-remarks');
+ this.$totals_section = this.$component.find('.totals-section');
this.$totals = this.$component.find('.totals');
- this.$remarks = this.$component.find('.remarks');
this.$numpad = this.$component.find('.number-pad');
- this.$invoice_details_section = this.$component.find('.invoice-details-section');
+ this.$invoice_fields_section = this.$component.find('.fields-section');
}
make_invoice_fields_control() {
@@ -57,13 +46,8 @@
const fields = doc.invoice_fields;
if (!fields.length) return;
- this.$invoice_details_section.html(
- `<div class="text-grey pb-6 mt-2 pointer no-select">
- ADDITIONAL INFORMATION<span class="octicon octicon-chevron-down collapse-indicator"></span>
- </div>
- <div class="invoice-fields grid grid-cols-2 gap-4 mb-6 d-none"></div>`
- );
- this.$invoice_fields = this.$invoice_details_section.find('.invoice-fields');
+ this.$invoice_fields = this.$invoice_fields_section.find('.invoice-fields');
+ this.$invoice_fields.html('');
const frm = this.events.get_frm();
fields.forEach(df => {
@@ -71,8 +55,10 @@
`<div class="invoice_detail_field ${df.fieldname}-field" data-fieldname="${df.fieldname}"></div>`
);
let df_events = {
- onchange: function() { frm.set_value(this.df.fieldname, this.value); }
- }
+ onchange: function() {
+ frm.set_value(this.df.fieldname, this.value);
+ }
+ };
if (df.fieldtype == "Button") {
df_events = {
click: function() {
@@ -80,11 +66,11 @@
frm.script_manager.trigger(df.fieldname, frm.doc.doctype, frm.doc.docname);
}
}
- }
+ };
}
this[`${df.fieldname}_field`] = frappe.ui.form.make_control({
- df: {
+ df: {
...df,
...df_events
},
@@ -92,7 +78,7 @@
render_input: true,
});
this[`${df.fieldname}_field`].set_value(frm.doc[df.fieldname]);
- })
+ });
});
}
@@ -112,13 +98,12 @@
[ 7, 8, 9 ],
[ '.', 0, 'Delete' ]
],
- })
+ });
this.numpad_value = '';
}
on_numpad_clicked($btn) {
- const me = this;
const button_value = $btn.attr('data-button-value');
highlight_numpad_btn($btn);
@@ -127,9 +112,9 @@
this.selected_mode.set_value(this.numpad_value);
function highlight_numpad_btn($btn) {
- $btn.addClass('shadow-inner bg-selected');
+ $btn.addClass('shadow-base-inner bg-selected');
setTimeout(() => {
- $btn.removeClass('shadow-inner bg-selected');
+ $btn.removeClass('shadow-base-inner bg-selected');
}, 100);
}
}
@@ -142,13 +127,16 @@
// if clicked element doesn't have .mode-of-payment class then return
if (!$(e.target).is(mode_clicked)) return;
+ const scrollLeft = mode_clicked.offset().left - me.$payment_modes.offset().left + me.$payment_modes.scrollLeft();
+ me.$payment_modes.animate({ scrollLeft });
+
const mode = mode_clicked.attr('data-mode');
// hide all control fields and shortcuts
- $(`.mode-of-payment-control`).addClass('d-none');
- $(`.cash-shortcuts`).addClass('d-none');
- me.$payment_modes.find(`.pay-amount`).removeClass('d-none');
- me.$payment_modes.find(`.loyalty-amount-name`).addClass('d-none');
+ $(`.mode-of-payment-control`).css('display', 'none');
+ $(`.cash-shortcuts`).css('display', 'none');
+ me.$payment_modes.find(`.pay-amount`).css('display', 'inline');
+ me.$payment_modes.find(`.loyalty-amount-name`).css('display', 'none');
// remove highlight from all mode-of-payments
$('.mode-of-payment').removeClass('border-primary');
@@ -157,55 +145,60 @@
// clicked one is selected then unselect it
mode_clicked.removeClass('border-primary');
me.selected_mode = '';
- me.toggle_numpad(false);
} else {
// clicked one is not selected then select it
mode_clicked.addClass('border-primary');
- mode_clicked.find('.mode-of-payment-control').removeClass('d-none');
- mode_clicked.find('.cash-shortcuts').removeClass('d-none');
- me.$payment_modes.find(`.${mode}-amount`).addClass('d-none');
- me.$payment_modes.find(`.${mode}-name`).removeClass('d-none');
- me.toggle_numpad(true);
+ mode_clicked.find('.mode-of-payment-control').css('display', 'flex');
+ mode_clicked.find('.cash-shortcuts').css('display', 'grid');
+ me.$payment_modes.find(`.${mode}-amount`).css('display', 'none');
+ me.$payment_modes.find(`.${mode}-name`).css('display', 'inline');
me.selected_mode = me[`${mode}_control`];
- const doc = me.events.get_frm().doc;
- me.selected_mode?.$input?.get(0).focus();
- !me.selected_mode?.get_value() ? me.selected_mode?.set_value(doc.grand_total - doc.paid_amount) : '';
+ me.selected_mode && me.selected_mode.$input.get(0).focus();
+ me.auto_set_remaining_amount();
}
- })
+ });
- this.$payment_modes.on('click', '.shortcut', function(e) {
+ frappe.ui.form.on('POS Invoice', 'contact_mobile', (frm) => {
+ const contact = frm.doc.contact_mobile;
+ const request_button = $(this.request_for_payment_field.$input[0]);
+ if (contact) {
+ request_button.removeClass('btn-default').addClass('btn-primary');
+ } else {
+ request_button.removeClass('btn-primary').addClass('btn-default');
+ }
+ });
+
+ this.setup_listener_for_payments();
+
+ this.$payment_modes.on('click', '.shortcut', () => {
const value = $(this).attr('data-value');
me.selected_mode.set_value(value);
- })
+ });
- // this.$totals_remarks.on('click', '.remarks', () => {
- // this.toggle_remarks_control();
- // })
-
- this.$component.on('click', '.submit-order', () => {
+ this.$component.on('click', '.submit-order-btn', () => {
const doc = this.events.get_frm().doc;
const paid_amount = doc.paid_amount;
const items = doc.items;
if (paid_amount == 0 || !items.length) {
- const message = items.length ? __("You cannot submit the order without payment.") : __("You cannot submit empty order.")
+ const message = items.length ? __("You cannot submit the order without payment.") : __("You cannot submit empty order.");
frappe.show_alert({ message, indicator: "orange" });
frappe.utils.play_sound("error");
return;
}
this.events.submit_invoice();
- })
+ });
frappe.ui.form.on('POS Invoice', 'paid_amount', (frm) => {
this.update_totals_section(frm.doc);
// need to re calculate cash shortcuts after discount is applied
- const is_cash_shortcuts_invisible = this.$payment_modes.find('.cash-shortcuts').hasClass('d-none');
+ const is_cash_shortcuts_invisible = !this.$payment_modes.find('.cash-shortcuts').is(':visible');
this.attach_cash_shortcuts(frm.doc);
- !is_cash_shortcuts_invisible && this.$payment_modes.find('.cash-shortcuts').removeClass('d-none');
- })
+ !is_cash_shortcuts_invisible && this.$payment_modes.find('.cash-shortcuts').css('display', 'grid');
+ });
frappe.ui.form.on('POS Invoice', 'loyalty_amount', (frm) => {
const formatted_currency = format_currency(frm.doc.loyalty_amount, frm.doc.currency);
@@ -215,63 +208,88 @@
frappe.ui.form.on("Sales Invoice Payment", "amount", (frm, cdt, cdn) => {
// for setting correct amount after loyalty points are redeemed
const default_mop = locals[cdt][cdn];
- const mode = default_mop.mode_of_payment.replace(' ', '_').toLowerCase();
+ const mode = default_mop.mode_of_payment.replace(/ +/g, "_").toLowerCase();
if (this[`${mode}_control`] && this[`${mode}_control`].get_value() != default_mop.amount) {
this[`${mode}_control`].set_value(default_mop.amount);
}
});
+ }
- this.$component.on('click', '.invoice-details-section', function(e) {
- if ($(e.target).closest('.invoice-fields').length) return;
+ setup_listener_for_payments() {
+ frappe.realtime.on("process_phone_payment", (data) => {
+ const doc = this.events.get_frm().doc;
+ const { response, amount, success, failure_message } = data;
+ let message, title;
- me.$payment_modes.addClass('d-none');
- me.$invoice_fields.toggleClass("d-none");
- me.toggle_numpad(false);
+ if (success) {
+ title = __("Payment Received");
+ const grand_total = cint(frappe.sys_defaults.disable_rounded_total) ? doc.grand_total : doc.rounded_total;
+ if (amount >= grand_total) {
+ frappe.dom.unfreeze();
+ message = __("Payment of {0} received successfully.", [format_currency(amount, doc.currency, 0)]);
+ this.events.submit_invoice();
+ cur_frm.reload_doc();
+
+ } else {
+ message = __("Payment of {0} received successfully. Waiting for other requests to complete...", [format_currency(amount, doc.currency, 0)]);
+ }
+ } else if (failure_message) {
+ message = failure_message;
+ title = __("Payment Failed");
+ }
+
+ frappe.msgprint({ "message": message, "title": title });
});
- this.$component.on('click', '.payment-section', () => {
- this.$invoice_fields.addClass("d-none");
- this.$payment_modes.toggleClass('d-none');
- this.toggle_numpad(true);
- })
+ }
+
+ auto_set_remaining_amount() {
+ const doc = this.events.get_frm().doc;
+ const grand_total = cint(frappe.sys_defaults.disable_rounded_total) ? doc.grand_total : doc.rounded_total;
+ const remaining_amount = grand_total - doc.paid_amount;
+ const current_value = this.selected_mode ? this.selected_mode.get_value() : undefined;
+ if (!current_value && remaining_amount > 0 && this.selected_mode) {
+ this.selected_mode.set_value(remaining_amount);
+ }
}
attach_shortcuts() {
+ const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
+ this.$component.find('.submit-order-btn').attr("title", `${ctrl_label}+Enter`);
frappe.ui.keys.on("ctrl+enter", () => {
const payment_is_visible = this.$component.is(":visible");
const active_mode = this.$payment_modes.find(".border-primary");
if (payment_is_visible && active_mode.length) {
- this.$component.find('.submit-order').click();
+ this.$component.find('.submit-order-btn').click();
}
});
- frappe.ui.keys.on("tab", () => {
- const payment_is_visible = this.$component.is(":visible");
- const mode_of_payments = Array.from(this.$payment_modes.find(".mode-of-payment")).map(m => $(m).attr("data-mode"));
- let active_mode = this.$payment_modes.find(".border-primary");
- active_mode = active_mode.length ? active_mode.attr("data-mode") : undefined;
+ frappe.ui.keys.add_shortcut({
+ shortcut: "tab",
+ action: () => {
+ const payment_is_visible = this.$component.is(":visible");
+ let active_mode = this.$payment_modes.find(".border-primary");
+ active_mode = active_mode.length ? active_mode.attr("data-mode") : undefined;
- if (!active_mode) return;
+ if (!active_mode) return;
- const mode_index = mode_of_payments.indexOf(active_mode);
- const next_mode_index = (mode_index + 1) % mode_of_payments.length;
- const next_mode_to_be_clicked = this.$payment_modes.find(`.mode-of-payment[data-mode="${mode_of_payments[next_mode_index]}"]`);
+ const mode_of_payments = Array.from(this.$payment_modes.find(".mode-of-payment")).map(m => $(m).attr("data-mode"));
+ const mode_index = mode_of_payments.indexOf(active_mode);
+ const next_mode_index = (mode_index + 1) % mode_of_payments.length;
+ const next_mode_to_be_clicked = this.$payment_modes.find(`.mode-of-payment[data-mode="${mode_of_payments[next_mode_index]}"]`);
- if (payment_is_visible && mode_index != next_mode_index) {
- next_mode_to_be_clicked.click();
- }
+ if (payment_is_visible && mode_index != next_mode_index) {
+ next_mode_to_be_clicked.click();
+ }
+ },
+ condition: () => this.$component.is(':visible') && this.$payment_modes.find(".border-primary").length,
+ description: __("Switch Between Payment Modes"),
+ ignore_inputs: true,
+ page: cur_page.page.page
});
}
- toggle_numpad(show) {
- if (show) {
- this.$numpad.removeClass('d-none');
- this.$remarks.addClass('d-none');
- this.$totals_remarks.addClass('w-60 justify-center').removeClass('justify-end w-full');
- } else {
- this.$numpad.addClass('d-none');
- this.$remarks.removeClass('d-none');
- this.$totals_remarks.removeClass('w-60 justify-center').addClass('justify-end w-full');
- }
+ toggle_numpad() {
+ // pass
}
render_payment_section() {
@@ -303,7 +321,7 @@
fieldtype: 'Data',
onchange: function() {}
},
- parent: this.$totals_remarks.find(`.remarks`),
+ parent: this.$totals_section.find(`.remarks`),
render_input: true,
});
this[`remark_control`].set_value('');
@@ -315,40 +333,39 @@
const payments = doc.payments;
const currency = doc.currency;
- this.$payment_modes.html(
- `${
- payments.map((p, i) => {
- const mode = p.mode_of_payment.replace(' ', '_').toLowerCase();
+ this.$payment_modes.html(`${
+ payments.map((p, i) => {
+ const mode = p.mode_of_payment.replace(/ +/g, "_").toLowerCase();
const payment_type = p.type;
const margin = i % 2 === 0 ? 'pr-2' : 'pl-2';
const amount = p.amount > 0 ? format_currency(p.amount, currency) : '';
- return (
- `<div class="w-half ${margin} bg-white">
- <div class="mode-of-payment rounded border border-grey text-grey text-md
- mb-4 p-8 pt-4 pb-4 no-select pointer" data-mode="${mode}" data-payment-type="${payment_type}">
+ return (`
+ <div class="payment-mode-wrapper">
+ <div class="mode-of-payment" data-mode="${mode}" data-payment-type="${payment_type}">
${p.mode_of_payment}
- <div class="${mode}-amount pay-amount inline float-right text-bold">${amount}</div>
- <div class="${mode} mode-of-payment-control mt-4 flex flex-1 items-center d-none"></div>
+ <div class="${mode}-amount pay-amount">${amount}</div>
+ <div class="${mode} mode-of-payment-control"></div>
</div>
- </div>`
- )
- }).join('')
- }`
- )
+ </div>
+ `);
+ }).join('')
+ }`);
payments.forEach(p => {
- const mode = p.mode_of_payment.replace(' ', '_').toLowerCase();
+ const mode = p.mode_of_payment.replace(/ +/g, "_").toLowerCase();
const me = this;
this[`${mode}_control`] = frappe.ui.form.make_control({
df: {
- label: __(`${p.mode_of_payment}`),
+ label: p.mode_of_payment,
fieldtype: 'Currency',
- placeholder: __(`Enter ${p.mode_of_payment} amount.`),
+ placeholder: __('Enter {0} amount.', [p.mode_of_payment]),
onchange: function() {
- if (this.value || this.value == 0) {
- frappe.model.set_value(p.doctype, p.name, 'amount', flt(this.value))
- .then(() => me.update_totals_section());
+ const current_value = frappe.model.get_value(p.doctype, p.name, 'amount');
+ if (current_value != this.value) {
+ frappe.model
+ .set_value(p.doctype, p.name, 'amount', flt(this.value))
+ .then(() => me.update_totals_section())
const formatted_currency = format_currency(this.value, currency);
me.$payment_modes.find(`.${mode}-amount`).html(formatted_currency);
@@ -366,31 +383,26 @@
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) {
- const grand_total = doc.grand_total;
+ const grand_total = cint(frappe.sys_defaults.disable_rounded_total) ? doc.grand_total : doc.rounded_total;
const currency = doc.currency;
const shortcuts = this.get_cash_shortcuts(flt(grand_total));
this.$payment_modes.find('.cash-shortcuts').remove();
- this.$payment_modes.find('[data-payment-type="Cash"]').find('.mode-of-payment-control').after(
- `<div class="cash-shortcuts grid grid-cols-3 gap-2 flex-1 text-center text-md-0 mb-2 d-none">
- ${
- shortcuts.map(s => {
- return `<div class="shortcut rounded bg-light-grey text-dark-grey pt-2 pb-2 no-select pointer" data-value="${s}">
- ${format_currency(s, currency)}
- </div>`
- }).join('')
- }
- </div>`
- )
+ let shortcuts_html = shortcuts.map(s => {
+ return `<div class="shortcut" data-value="${s}">${format_currency(s, currency, 0)}</div>`;
+ }).join('');
+
+ this.$payment_modes.find('[data-payment-type="Cash"]').find('.mode-of-payment-control')
+ .after(`<div class="cash-shortcuts">${shortcuts_html}</div>`);
}
get_cash_shortcuts(grand_total) {
@@ -402,13 +414,13 @@
const get_nearest = (amount, x) => {
let nearest_x = Math.ceil((amount / x)) * x;
return nearest_x === amount ? nearest_x + x : nearest_x;
- }
+ };
return steps.reduce((finalArr, x) => {
let nearest_x = get_nearest(grand_total, x);
nearest_x = finalArr.indexOf(nearest_x) != -1 ? nearest_x + x : nearest_x;
return [...finalArr, nearest_x];
- }, []);
+ }, []);
}
render_loyalty_points_payment_mode() {
@@ -417,38 +429,37 @@
const { loyalty_program, loyalty_points, conversion_factor } = this.events.get_customer_details();
this.$payment_modes.find(`.mode-of-payment[data-mode="loyalty-amount"]`).parent().remove();
-
+
if (!loyalty_program) return;
let description, read_only, max_redeemable_amount;
if (!loyalty_points) {
- description = __(`You don't have enough points to redeem.`);
+ description = __("You don't have enough points to redeem.");
read_only = true;
} else {
- max_redeemable_amount = flt(flt(loyalty_points) * flt(conversion_factor), precision("loyalty_amount", doc))
- description = __(`You can redeem upto ${format_currency(max_redeemable_amount)}.`);
+ max_redeemable_amount = flt(flt(loyalty_points) * flt(conversion_factor), precision("loyalty_amount", doc));
+ description = __("You can redeem upto {0}.", [format_currency(max_redeemable_amount)]);
read_only = false;
}
const margin = this.$payment_modes.children().length % 2 === 0 ? 'pr-2' : 'pl-2';
const amount = doc.loyalty_amount > 0 ? format_currency(doc.loyalty_amount, doc.currency) : '';
this.$payment_modes.append(
- `<div class="w-half ${margin} bg-white">
- <div class="mode-of-payment rounded border border-grey text-grey text-md
- mb-4 p-8 pt-4 pb-4 no-select pointer" data-mode="loyalty-amount" data-payment-type="loyalty-amount">
+ `<div class="payment-mode-wrapper">
+ <div class="mode-of-payment" data-mode="loyalty-amount" data-payment-type="loyalty-amount">
Redeem Loyalty Points
- <div class="loyalty-amount-amount pay-amount inline float-right text-bold">${amount}</div>
- <div class="loyalty-amount-name inline float-right text-bold text-md-0 d-none">${loyalty_program}</div>
- <div class="loyalty-amount mode-of-payment-control mt-4 flex flex-1 items-center d-none"></div>
+ <div class="loyalty-amount-amount pay-amount">${amount}</div>
+ <div class="loyalty-amount-name">${loyalty_program}</div>
+ <div class="loyalty-amount mode-of-payment-control"></div>
</div>
</div>`
- )
+ );
this['loyalty-amount_control'] = frappe.ui.form.make_control({
df: {
- label: __('Redeem Loyalty Points'),
+ label: __("Redeem Loyalty Points"),
fieldtype: 'Currency',
- placeholder: __(`Enter amount to be redeemed.`),
+ placeholder: __("Enter amount to be redeemed."),
options: 'company:currency',
read_only,
onchange: async function() {
@@ -456,7 +467,7 @@
if (this.value > max_redeemable_amount) {
frappe.show_alert({
- message: __(`You cannot redeem more than ${format_currency(max_redeemable_amount)}.`),
+ message: __("You cannot redeem more than {0}.", [format_currency(max_redeemable_amount)]),
indicator: "red"
});
frappe.utils.play_sound("submit");
@@ -484,30 +495,37 @@
`<div class="w-full pr-2">
<div class="add-mode-of-payment w-half text-grey mb-4 no-select pointer">+ Add Payment Method</div>
</div>`
- )
+ );
}
update_totals_section(doc) {
if (!doc) doc = this.events.get_frm().doc;
const paid_amount = doc.paid_amount;
- const remaining = doc.grand_total - doc.paid_amount;
+ const grand_total = cint(frappe.sys_defaults.disable_rounded_total) ? doc.grand_total : doc.rounded_total;
+ const remaining = grand_total - doc.paid_amount;
const change = doc.change_amount || remaining <= 0 ? -1 * remaining : undefined;
- const currency = doc.currency
+ const currency = doc.currency;
const label = change ? __('Change') : __('To Be Paid');
this.$totals.html(
- `<div>
- <div class="pr-8 border-r-grey">Paid Amount</div>
- <div class="pr-8 border-r-grey text-bold text-2xl">${format_currency(paid_amount, currency)}</div>
+ `<div class="col">
+ <div class="total-label">Grand Total</div>
+ <div class="value">${format_currency(grand_total, currency)}</div>
</div>
- <div>
- <div class="pl-8">${label}</div>
- <div class="pl-8 text-green-400 text-bold text-2xl">${format_currency(change || remaining, currency)}</div>
+ <div class="seperator-y"></div>
+ <div class="col">
+ <div class="total-label">Paid Amount</div>
+ <div class="value">${format_currency(paid_amount, currency)}</div>
+ </div>
+ <div class="seperator-y"></div>
+ <div class="col">
+ <div class="total-label">${label}</div>
+ <div class="value">${format_currency(change || remaining, currency)}</div>
</div>`
- )
+ );
}
toggle_component(show) {
- show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
- }
- }
\ No newline at end of file
+ show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
+ }
+};
\ No newline at end of file
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 c716aa9..8473276 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
@@ -10,8 +10,8 @@
def execute(filters=None):
filters = frappe._dict(filters or {})
if filters.from_date > filters.to_date:
- frappe.throw(_('From Date cannot be greater than To Date'))
-
+ frappe.throw(_("From Date cannot be greater than To Date"))
+
columns = get_columns(filters)
data = get_data(filters)
@@ -148,14 +148,16 @@
company_list.append(filters.get("company"))
customer_details = get_customer_details()
+ item_details = get_item_details()
sales_order_records = get_sales_order_details(company_list, filters)
for record in sales_order_records:
customer_record = customer_details.get(record.customer)
+ item_record = item_details.get(record.item_code)
row = {
"item_code": record.item_code,
- "item_name": record.item_name,
- "item_group": record.item_group,
+ "item_name": item_record.item_name,
+ "item_group": item_record.item_group,
"description": record.description,
"quantity": record.qty,
"uom": record.uom,
@@ -196,8 +198,8 @@
return conditions
def get_customer_details():
- details = frappe.get_all('Customer',
- fields=['name', 'customer_name', "customer_group"])
+ details = frappe.get_all("Customer",
+ fields=["name", "customer_name", "customer_group"])
customer_details = {}
for d in details:
customer_details.setdefault(d.name, frappe._dict({
@@ -206,15 +208,25 @@
}))
return customer_details
+def get_item_details():
+ details = frappe.db.get_all("Item",
+ fields=["item_code", "item_name", "item_group"])
+ item_details = {}
+ for d in details:
+ item_details.setdefault(d.item_code, frappe._dict({
+ "item_name": d.item_name,
+ "item_group": d.item_group
+ }))
+ return item_details
+
def get_sales_order_details(company_list, filters):
conditions = get_conditions(filters)
return frappe.db.sql("""
SELECT
- so_item.item_code, so_item.item_name, so_item.item_group,
- so_item.description, so_item.qty, so_item.uom,
- so_item.base_rate, so_item.base_amount, so.name,
- so.transaction_date, so.customer, so.territory,
+ so_item.item_code, so_item.description, so_item.qty,
+ so_item.uom, so_item.base_rate, so_item.base_amount,
+ so.name, so.transaction_date, so.customer,so.territory,
so.project, so_item.delivered_qty,
so_item.billed_amt, so.company
FROM
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js
index 0e565a3..9089b53 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.js
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.js
@@ -74,67 +74,71 @@
return Object.assign(options, {
checkboxColumn: true,
events: {
- onCheckRow: function(data) {
+ onCheckRow: function (data) {
+ if (!data) return;
+ const data_doctype = $(
+ data[2].html
+ )[0].attributes.getNamedItem("data-doctype").value;
+ const tree_type = frappe.query_report.filters[0].value;
+ if (data_doctype != tree_type) return;
+
row_name = data[2].content;
length = data.length;
- var tree_type = frappe.query_report.filters[0].value;
-
- if(tree_type == "Customer") {
- row_values = data.slice(4,length-1).map(function (column) {
- return column.content;
- })
+ if (tree_type == "Customer") {
+ row_values = data
+ .slice(4, length - 1)
+ .map(function (column) {
+ return column.content;
+ });
} else if (tree_type == "Item") {
- row_values = data.slice(5,length-1).map(function (column) {
- return column.content;
- })
- }
- else {
- row_values = data.slice(3,length-1).map(function (column) {
- return column.content;
- })
+ row_values = data
+ .slice(5, length - 1)
+ .map(function (column) {
+ return column.content;
+ });
+ } else {
+ row_values = data
+ .slice(3, length - 1)
+ .map(function (column) {
+ return column.content;
+ });
}
entry = {
- 'name':row_name,
- 'values':row_values
- }
+ name: row_name,
+ values: row_values,
+ };
let raw_data = frappe.query_report.chart.data;
let new_datasets = raw_data.datasets;
- var found = false;
-
- for(var i=0; i < new_datasets.length;i++){
- if(new_datasets[i].name == row_name){
- found = true;
- new_datasets.splice(i,1);
- break;
+ let element_found = new_datasets.some((element, index, array)=>{
+ if(element.name == row_name){
+ array.splice(index, 1)
+ return true
}
- }
+ return false
+ })
- if(!found){
+ if (!element_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)
+ datasets: new_datasets,
+ };
+ chart_options = {
+ data: new_data,
+ type: "line",
+ };
+ frappe.query_report.render_chart(chart_options);
frappe.query_report.raw_chart_data = new_data;
},
- }
- })
+ },
+ });
},
}
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 002cfe4..0428573 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -42,16 +42,6 @@
me.frm.set_query('customer_address', erpnext.queries.address_query);
me.frm.set_query('shipping_address_name', erpnext.queries.address_query);
- if(this.frm.fields_dict.taxes_and_charges) {
- this.frm.set_query("taxes_and_charges", function() {
- return {
- filters: [
- ['Sales Taxes and Charges Template', 'company', '=', me.frm.doc.company],
- ['Sales Taxes and Charges Template', 'docstatus', '!=', 2]
- ]
- }
- });
- }
if(this.frm.fields_dict.selling_price_list) {
this.frm.set_query("selling_price_list", function() {
@@ -137,20 +127,6 @@
this.set_dynamic_labels();
},
- price_list_rate: function(doc, cdt, cdn) {
- var item = frappe.get_doc(cdt, cdn);
- frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
-
- // check if child doctype is Sales Order Item/Qutation Item and calculate the rate
- if(in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "POS Invoice Item"]), cdt)
- this.apply_pricing_rule_on_item(item);
- else
- item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0),
- precision("rate", item));
-
- this.calculate_taxes_and_totals();
- },
-
discount_percentage: function(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
item.discount_amount = 0.0;
@@ -363,26 +339,6 @@
refresh_field('product_bundle_help');
},
- margin_rate_or_amount: function(doc, cdt, cdn) {
- // calculated the revised total margin and rate on margin rate changes
- var item = locals[cdt][cdn];
- this.apply_pricing_rule_on_item(item)
- this.calculate_taxes_and_totals();
- cur_frm.refresh_fields();
- },
-
- margin_type: function(doc, cdt, cdn){
- // calculate the revised total margin and rate on margin type changes
- var item = locals[cdt][cdn];
- if(!item.margin_type) {
- frappe.model.set_value(cdt, cdn, "margin_rate_or_amount", 0);
- } else {
- this.apply_pricing_rule_on_item(item, doc,cdt, cdn)
- this.calculate_taxes_and_totals();
- cur_frm.refresh_fields();
- }
- },
-
company_address: function() {
var me = this;
if(this.frm.doc.company_address) {
@@ -409,6 +365,10 @@
}
},
+ batch_no: function(doc, cdt, cdn) {
+ this._super(doc, cdt, cdn);
+ },
+
qty: function(doc, cdt, cdn) {
this._super(doc, cdt, cdn);
@@ -479,7 +439,7 @@
$.each(frm.doc["items"] || [], function(i, row) {
if(r.message) {
frappe.model.set_value(row.doctype, row.name, "cost_center", r.message);
- frappe.msgprint(__("Cost Center For Item with Item Code '"+row.item_name+"' has been Changed to "+ r.message));
+ frappe.msgprint(__("Cost Center For Item with Item Code {0} has been Changed to {1}", [row.item_name, r.message]));
}
})
}
diff --git a/erpnext/selling/workspace/retail/retail.json b/erpnext/selling/workspace/retail/retail.json
new file mode 100644
index 0000000..e20f834
--- /dev/null
+++ b/erpnext/selling/workspace/retail/retail.json
@@ -0,0 +1,114 @@
+{
+ "category": "Domains",
+ "charts": [],
+ "creation": "2020-03-02 17:18:32.505616",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "retail",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Retail",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings & Configurations",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Point-of-Sale Profile",
+ "link_to": "POS Profile",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "POS Settings",
+ "link_to": "POS Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loyalty Program",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loyalty Program",
+ "link_to": "Loyalty Program",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Loyalty Point Entry",
+ "link_to": "Loyalty Point Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Opening & Closing",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "POS Opening Entry",
+ "link_to": "POS Opening Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "POS Closing Entry",
+ "link_to": "POS Closing Entry",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:36.758038",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Retail",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "restrict_to_domain": "Retail",
+ "shortcuts": [
+ {
+ "doc_view": "",
+ "label": "Point Of Sale",
+ "link_to": "point-of-sale",
+ "type": "Page"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/selling/workspace/selling/selling.json b/erpnext/selling/workspace/selling/selling.json
new file mode 100644
index 0000000..879034a
--- /dev/null
+++ b/erpnext/selling/workspace/selling/selling.json
@@ -0,0 +1,563 @@
+{
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Sales Order Trends",
+ "label": "Sales Order Trends"
+ }
+ ],
+ "charts_label": "Selling ",
+ "creation": "2020-01-28 11:49:12.092882",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 1,
+ "icon": "sell",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Selling",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Selling",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer",
+ "link_to": "Customer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Customer",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quotation",
+ "link_to": "Quotation",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Customer",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Order",
+ "link_to": "Sales Order",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Customer",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Invoice",
+ "link_to": "Sales Invoice",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Customer",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Blanket Order",
+ "link_to": "Blanket Order",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Partner",
+ "link_to": "Sales Partner",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Customer",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Person",
+ "link_to": "Sales Person",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Items and Pricing",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item",
+ "link_to": "Item",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Price List",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Price",
+ "link_to": "Item Price",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Price List",
+ "link_to": "Price List",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Group",
+ "link_to": "Item Group",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Product Bundle",
+ "link_to": "Product Bundle",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Promotional Scheme",
+ "link_to": "Promotional Scheme",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Pricing Rule",
+ "link_to": "Pricing Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shipping Rule",
+ "link_to": "Shipping Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Coupon Code",
+ "link_to": "Coupon Code",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Selling Settings",
+ "link_to": "Selling Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Terms and Conditions Template",
+ "link_to": "Terms and Conditions",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Taxes and Charges Template",
+ "link_to": "Sales Taxes and Charges Template",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lead Source",
+ "link_to": "Lead Source",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer Group",
+ "link_to": "Customer Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Contact",
+ "link_to": "Contact",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Address",
+ "link_to": "Address",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Territory",
+ "link_to": "Territory",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Campaign",
+ "link_to": "Campaign",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Key Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Analytics",
+ "link_to": "Sales Analytics",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Order Analysis",
+ "link_to": "Sales Order Analysis",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Funnel",
+ "link_to": "sales-funnel",
+ "link_type": "Page",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Order Trends",
+ "link_to": "Sales Order Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Quotation",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Quotation Trends",
+ "link_to": "Quotation Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Acquisition and Loyalty",
+ "link_to": "Customer Acquisition and Loyalty",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Inactive Customers",
+ "link_to": "Inactive Customers",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Person-wise Transaction Summary",
+ "link_to": "Sales Person-wise Transaction Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item-wise Sales History",
+ "link_to": "Item-wise Sales History",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Other Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Lead",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Lead Details",
+ "link_to": "Lead Details",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Address",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Addresses And Contacts",
+ "link_to": "Address And Contacts",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Available Stock for Packing Items",
+ "link_to": "Available Stock for Packing Items",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Pending SO Items For Purchase Request",
+ "link_to": "Pending SO Items For Purchase Request",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Delivery Note",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Delivery Note Trends",
+ "link_to": "Delivery Note Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Invoice Trends",
+ "link_to": "Sales Invoice Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Credit Balance",
+ "link_to": "Customer Credit Balance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customers Without Any Sales Transactions",
+ "link_to": "Customers Without Any Sales Transactions",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Partners Commission",
+ "link_to": "Sales Partners Commission",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Territory Target Variance Based On Item Group",
+ "link_to": "Territory Target Variance Based On Item Group",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Person Target Variance Based On Item Group",
+ "link_to": "Sales Person Target Variance Based On Item Group",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Partner Target Variance Based On Item Group",
+ "link_to": "Sales Partner Target Variance based on Item Group",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:35.971277",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Selling",
+ "onboarding": "Selling",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Grey",
+ "format": "{} Available",
+ "label": "Item",
+ "link_to": "Item",
+ "stats_filter": "{\n \"disabled\":0\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} To Deliver",
+ "label": "Sales Order",
+ "link_to": "Sales Order",
+ "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\":[\"in\", [\"To Deliver\", \"To Deliver and Bill\"]]\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "format": "{} Open",
+ "label": "Sales Analytics",
+ "link_to": "Sales Analytics",
+ "stats_filter": "{ \"Status\": \"Open\" }",
+ "type": "Report"
+ },
+ {
+ "label": "Sales Order Analysis",
+ "link_to": "Sales Order Analysis",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Selling",
+ "type": "Dashboard"
+ }
+ ],
+ "shortcuts_label": "Quick Access"
+}
\ No newline at end of file
diff --git a/erpnext/setup/desk_page/home/home.json b/erpnext/setup/desk_page/home/home.json
deleted file mode 100644
index 63cd5c5..0000000
--- a/erpnext/setup/desk_page/home/home.json
+++ /dev/null
@@ -1,99 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Healthcare",
- "links": "[\n {\n \"label\": \"Patient\",\n \"name\": \"Patient\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Diagnosis\",\n \"name\": \"Diagnosis\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Agriculture",
- "links": "[\n {\n \"label\": \"Crop\",\n \"name\": \"Crop\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Crop Cycle\",\n \"name\": \"Crop Cycle\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fertilizer\",\n \"name\": \"Fertilizer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Education",
- "links": "[\n {\n \"label\": \"Student\",\n \"name\": \"Student\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course\",\n \"name\": \"Course\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Instructor\",\n \"name\": \"Instructor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Room\",\n \"name\": \"Room\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Non Profit",
- "links": "[\n {\n \"description\": \"Member information.\",\n \"label\": \"Member\",\n \"name\": \"Member\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Volunteer information.\",\n \"label\": \"Volunteer\",\n \"name\": \"Volunteer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Chapter information.\",\n \"label\": \"Chapter\",\n \"name\": \"Chapter\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Donor information.\",\n \"label\": \"Donor\",\n \"name\": \"Donor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Stock",
- "links": "[\n {\n \"label\": \"Warehouse\",\n \"name\": \"Warehouse\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Brand\",\n \"name\": \"Brand\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Unit of Measure (UOM)\",\n \"name\": \"UOM\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Stock Reconciliation\",\n \"name\": \"Stock Reconciliation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Human Resources",
- "links": "[\n {\n \"label\": \"Employee\",\n \"name\": \"Employee\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Attendance Tool\",\n \"name\": \"Employee Attendance Tool\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Structure\",\n \"name\": \"Salary Structure\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "CRM",
- "links": "[\n {\n \"description\": \"Database of potential customers.\",\n \"label\": \"Lead\",\n \"name\": \"Lead\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Accounting",
- "links": "[\n {\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Company (not Customer or Supplier) master.\",\n \"label\": \"Company\",\n \"name\": \"Company\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of financial accounts.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Accounts\",\n \"name\": \"Account\",\n \"onboard\": 1,\n \"route\": \"#Tree/Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Create Opening Sales and Purchase Invoices\",\n \"label\": \"Opening Invoice Creation Tool\",\n \"name\": \"Opening Invoice Creation Tool\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Data Import and Settings",
- "links": "[\n {\n \"description\": \"Import Data from CSV / Excel files.\",\n \"icon\": \"octicon octicon-cloud-upload\",\n \"label\": \"Import Data\",\n \"name\": \"Data Import\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Import Chart Of Accounts from CSV / Excel files\",\n \"labe\": \"Chart Of Accounts Importer\",\n \"label\": \"Chart of Accounts Importer\",\n \"name\": \"Chart of Accounts Importer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Letter Heads for print templates.\",\n \"label\": \"Letter Head\",\n \"name\": \"Letter Head\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add / Manage Email Accounts.\",\n \"label\": \"Email Account\",\n \"name\": \"Email Account\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [],
- "creation": "2020-01-23 13:46:38.833076",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
- "docstatus": 0,
- "doctype": "Desk Page",
- "extends_another_page": 0,
- "idx": 0,
- "is_standard": 1,
- "label": "Home",
- "modified": "2020-05-11 10:20:37.358701",
- "modified_by": "Administrator",
- "module": "Setup",
- "name": "Home",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 1,
- "shortcuts": [
- {
- "label": "Item",
- "link_to": "Item",
- "type": "DocType"
- },
- {
- "label": "Customer",
- "link_to": "Customer",
- "type": "DocType"
- },
- {
- "label": "Supplier",
- "link_to": "Supplier",
- "type": "DocType"
- },
- {
- "label": "Sales Invoice",
- "link_to": "Sales Invoice",
- "type": "DocType"
- },
- {
- "label": "Dashboard",
- "link_to": "dashboard",
- "type": "Page"
- },
- {
- "label": "Leaderboard",
- "link_to": "leaderboard",
- "type": "Page"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index f882db6..c041d26 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -90,29 +90,41 @@
frm.toggle_enable("default_currency", (frm.doc.__onload &&
!frm.doc.__onload.transactions_exist));
- frm.add_custom_button(__('Create Tax Template'), function() {
- frm.trigger("make_default_tax_template");
- });
+ if (frm.has_perm('write')) {
+ frm.add_custom_button(__('Create Tax Template'), function() {
+ frm.trigger("make_default_tax_template");
+ });
+ }
- frm.add_custom_button(__('Cost Centers'), function() {
- frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name})
- }, __("View"));
+ if (frappe.perm.has_perm("Cost Center", 0, 'read')) {
+ frm.add_custom_button(__('Cost Centers'), function() {
+ frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name});
+ }, __("View"));
+ }
- frm.add_custom_button(__('Chart of Accounts'), function() {
- frappe.set_route('Tree', 'Account', {'company': frm.doc.name})
- }, __("View"));
+ if (frappe.perm.has_perm("Account", 0, 'read')) {
+ frm.add_custom_button(__('Chart of Accounts'), function() {
+ frappe.set_route('Tree', 'Account', {'company': frm.doc.name});
+ }, __("View"));
+ }
- frm.add_custom_button(__('Sales Tax Template'), function() {
- frappe.set_route('List', 'Sales Taxes and Charges Template', {'company': frm.doc.name});
- }, __("View"));
+ if (frappe.perm.has_perm("Sales Taxes and Charges Template", 0, 'read')) {
+ frm.add_custom_button(__('Sales Tax Template'), function() {
+ frappe.set_route('List', 'Sales Taxes and Charges Template', {'company': frm.doc.name});
+ }, __("View"));
+ }
- frm.add_custom_button(__('Purchase Tax Template'), function() {
- frappe.set_route('List', 'Purchase Taxes and Charges Template', {'company': frm.doc.name});
- }, __("View"));
+ if (frappe.perm.has_perm("Purchase Taxes and Charges Template", 0, 'read')) {
+ frm.add_custom_button(__('Purchase Tax Template'), function() {
+ frappe.set_route('List', 'Purchase Taxes and Charges Template', {'company': frm.doc.name});
+ }, __("View"));
+ }
- frm.add_custom_button(__('Default Tax Template'), function() {
- frm.trigger("make_default_tax_template");
- }, __('Create'));
+ if (frm.has_perm('write')) {
+ frm.add_custom_button(__('Default Tax Template'), function() {
+ frm.trigger("make_default_tax_template");
+ }, __('Create'));
+ }
}
erpnext.company.set_chart_of_accounts_options(frm.doc);
@@ -128,7 +140,7 @@
doc: frm.doc,
freeze: true,
callback: function() {
- frappe.msgprint(__("Default tax templates for sales and purchase are created."));
+ frappe.msgprint(__("Default tax templates for sales, purchase and items are created."));
}
})
},
@@ -262,7 +274,8 @@
["default_employee_advance_account", {"root_type": "Asset"}],
["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
- ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}]
+ ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
+ ["unrealized_profit_loss_account", {"root_type": "Liability"}]
], function(i, v) {
erpnext.company.set_custom_query(frm, v);
});
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 4a26a71..56f60df 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -46,10 +46,9 @@
"round_off_account",
"round_off_cost_center",
"write_off_account",
- "discount_allowed_account",
- "discount_received_account",
"exchange_gain_loss_account",
"unrealized_exchange_gain_loss_account",
+ "unrealized_profit_loss_account",
"column_break0",
"allow_account_creation_against_child_company",
"default_payable_account",
@@ -346,18 +345,6 @@
"options": "Account"
},
{
- "fieldname": "discount_allowed_account",
- "fieldtype": "Link",
- "label": "Discount Allowed Account",
- "options": "Account"
- },
- {
- "fieldname": "discount_received_account",
- "fieldtype": "Link",
- "label": "Discount Received Account",
- "options": "Account"
- },
- {
"fieldname": "exchange_gain_loss_account",
"fieldtype": "Link",
"label": "Exchange Gain / Loss Account",
@@ -738,8 +725,14 @@
{
"fieldname": "default_in_transit_warehouse",
"fieldtype": "Link",
- "label": "Default In Transit Warehouse",
+ "label": "Default In-Transit Warehouse",
"options": "Warehouse"
+ },
+ {
+ "fieldname": "unrealized_profit_loss_account",
+ "fieldtype": "Link",
+ "label": "Unrealized Profit / Loss Account",
+ "options": "Account"
}
],
"icon": "fa fa-building",
@@ -747,7 +740,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
- "modified": "2020-08-06 00:38:08.311216",
+ "modified": "2021-02-16 15:53:37.167589",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
@@ -808,4 +801,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 8e707fe..433851c 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -75,7 +75,7 @@
def validate_default_accounts(self):
accounts = [
- ["Default Bank Account", "default_bank_account"], ["Default Cash Account", "default_cash_account"],
+ ["Default Bank Account", "default_bank_account"], ["Default Cash Account", "default_cash_account"],
["Default Receivable Account", "default_receivable_account"], ["Default Payable Account", "default_payable_account"],
["Default Expense Account", "default_expense_account"], ["Default Income Account", "default_income_account"],
["Stock Received But Not Billed Account", "stock_received_but_not_billed"], ["Stock Adjustment Account", "stock_adjustment_account"],
@@ -89,8 +89,9 @@
frappe.throw(_("Account {0} does not belong to company: {1}").format(self.get(account[1]), self.name))
if get_account_currency(self.get(account[1])) != self.default_currency:
- frappe.throw(_("""{0} currency must be same as company's default currency.
- Please select another account""").format(frappe.bold(account[0])))
+ error_message = _("{0} currency must be same as company's default currency. Please select another account.") \
+ .format(frappe.bold(account[0]))
+ frappe.throw(error_message)
def validate_currency(self):
if self.is_new():
@@ -389,8 +390,10 @@
frappe.db.sql("delete from tabDepartment where company=%s", self.name)
frappe.db.sql("delete from `tabTax Withholding Account` where company=%s", self.name)
+ # delete tax templates
frappe.db.sql("delete from `tabSales Taxes and Charges Template` where company=%s", self.name)
frappe.db.sql("delete from `tabPurchase Taxes and Charges Template` where company=%s", self.name)
+ frappe.db.sql("delete from `tabItem Tax Template` where company=%s", self.name)
@frappe.whitelist()
def enqueue_replace_abbr(company, old, new):
@@ -442,7 +445,7 @@
module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(company_doc.country))
frappe.get_attr(module_name)(company_doc, False)
except Exception as e:
- frappe.log_error(str(e), frappe.get_traceback())
+ frappe.log_error()
frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country)))
diff --git a/erpnext/setup/doctype/company/company_list.js b/erpnext/setup/doctype/company/company_list.js
index 0172865..1d1184f 100644
--- a/erpnext/setup/doctype/company/company_list.js
+++ b/erpnext/setup/doctype/company/company_list.js
@@ -1,10 +1,5 @@
frappe.listview_settings['Company'] = {
- onload: () => {
- frappe.breadcrumbs.add({
- type: 'Custom',
- module: __('Accounts'),
- label: __('Accounts'),
- route: '#modules/Accounts'
- });
- }
-}
\ No newline at end of file
+ onload() {
+ frappe.breadcrumbs.add('Accounts');
+ },
+};
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index c94831e..0df4c87 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -27,7 +27,8 @@
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
"Party Account", "Employee", "Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template", "POS Profile", "BOM",
- "Company", "Bank Account"):
+ "Company", "Bank Account", "Item Tax Template", "Mode Of Payment",
+ "Item Default", "Customer", "Supplier", "GST Account"):
delete_for_doctype(doctype, company_name)
# reset company values
diff --git a/erpnext/setup/doctype/company/test_records.json b/erpnext/setup/doctype/company/test_records.json
index 2130241..9e55702 100644
--- a/erpnext/setup/doctype/company/test_records.json
+++ b/erpnext/setup/doctype/company/test_records.json
@@ -7,7 +7,8 @@
"doctype": "Company",
"domain": "Manufacturing",
"chart_of_accounts": "Standard",
- "default_holiday_list": "_Test Holiday List"
+ "default_holiday_list": "_Test Holiday List",
+ "enable_perpetual_inventory": 0
},
{
"abbr": "_TC1",
@@ -17,7 +18,8 @@
"doctype": "Company",
"domain": "Retail",
"chart_of_accounts": "Standard",
- "default_holiday_list": "_Test Holiday List"
+ "default_holiday_list": "_Test Holiday List",
+ "enable_perpetual_inventory": 0
},
{
"abbr": "_TC2",
@@ -27,7 +29,8 @@
"doctype": "Company",
"domain": "Retail",
"chart_of_accounts": "Standard",
- "default_holiday_list": "_Test Holiday List"
+ "default_holiday_list": "_Test Holiday List",
+ "enable_perpetual_inventory": 0
},
{
"abbr": "_TC3",
@@ -38,7 +41,8 @@
"doctype": "Company",
"domain": "Manufacturing",
"chart_of_accounts": "Standard",
- "default_holiday_list": "_Test Holiday List"
+ "default_holiday_list": "_Test Holiday List",
+ "enable_perpetual_inventory": 0
},
{
"abbr": "_TC4",
@@ -50,7 +54,8 @@
"doctype": "Company",
"domain": "Manufacturing",
"chart_of_accounts": "Standard",
- "default_holiday_list": "_Test Holiday List"
+ "default_holiday_list": "_Test Holiday List",
+ "enable_perpetual_inventory": 0
},
{
"abbr": "_TC5",
@@ -61,7 +66,8 @@
"doctype": "Company",
"domain": "Manufacturing",
"chart_of_accounts": "Standard",
- "default_holiday_list": "_Test Holiday List"
+ "default_holiday_list": "_Test Holiday List",
+ "enable_perpetual_inventory": 0
},
{
"abbr": "TCP1",
diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json
index 10f9bd0..0e2ed9e 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.json
+++ b/erpnext/setup/doctype/customer_group/customer_group.json
@@ -139,7 +139,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
- "modified": "2020-03-18 18:10:13.048492",
+ "modified": "2021-02-08 17:01:52.162202",
"modified_by": "Administrator",
"module": "Setup",
"name": "Customer Group",
@@ -189,6 +189,15 @@
"permlevel": 1,
"read": 1,
"role": "Sales Manager"
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "report": 1,
+ "role": "Customer",
+ "select": 1,
+ "share": 1
}
],
"search_fields": "parent_customer_group",
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index b30bd78..cbb4c7c 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -48,12 +48,8 @@
recipients = list(filter(lambda r: r in valid_users,
self.recipient_list.split("\n")))
- original_user = frappe.session.user
-
if recipients:
for user_id in recipients:
- frappe.set_user(user_id)
- frappe.set_user_lang(user_id)
msg_for_this_recipient = self.get_msg_html()
if msg_for_this_recipient:
frappe.sendmail(
@@ -64,9 +60,6 @@
reference_name = self.name,
unsubscribe_message = _("Unsubscribe from this Email Digest"))
- frappe.set_user(original_user)
- frappe.set_user_lang(original_user)
-
def get_msg_html(self):
"""Build email digest content"""
frappe.flags.ignore_account_permission = True
diff --git a/erpnext/setup/doctype/item_group/item_group.js b/erpnext/setup/doctype/item_group/item_group.js
index 9892dc3..1413cb2 100644
--- a/erpnext/setup/doctype/item_group/item_group.js
+++ b/erpnext/setup/doctype/item_group/item_group.js
@@ -61,6 +61,19 @@
frappe.set_route("List", "Item", {"item_group": frm.doc.name});
});
}
+
+ frappe.model.with_doctype('Item', () => {
+ const item_meta = frappe.get_meta('Item');
+
+ const valid_fields = item_meta.fields.filter(
+ df => ['Link', 'Table MultiSelect'].includes(df.fieldtype) && !df.hidden
+ ).map(df => ({ label: df.label, value: df.fieldname }));
+
+ const field = frappe.meta.get_docfield("Website Filter Field", "fieldname", frm.docname);
+ field.fieldtype = 'Select';
+ field.options = valid_fields;
+ frm.fields_dict.filter_fields.grid.refresh();
+ });
},
set_root_readonly: function(frm) {
diff --git a/erpnext/setup/doctype/item_group/item_group.json b/erpnext/setup/doctype/item_group/item_group.json
index 004421d..3e0680f 100644
--- a/erpnext/setup/doctype/item_group/item_group.json
+++ b/erpnext/setup/doctype/item_group/item_group.json
@@ -24,8 +24,12 @@
"route",
"weightage",
"slideshow",
+ "website_title",
"description",
"website_specifications",
+ "website_filters_section",
+ "filter_fields",
+ "filter_attributes",
"lft",
"rgt",
"old_parent"
@@ -180,6 +184,28 @@
"options": "Item Group",
"print_hide": 1,
"report_hide": 1
+ },
+ {
+ "fieldname": "website_filters_section",
+ "fieldtype": "Section Break",
+ "label": "Website Filters"
+ },
+ {
+ "fieldname": "filter_fields",
+ "fieldtype": "Table",
+ "label": "Item Fields",
+ "options": "Website Filter Field"
+ },
+ {
+ "fieldname": "filter_attributes",
+ "fieldtype": "Table",
+ "label": "Attributes",
+ "options": "Website Attribute"
+ },
+ {
+ "fieldname": "website_title",
+ "fieldtype": "Data",
+ "label": "Title"
}
],
"icon": "fa fa-sitemap",
@@ -188,7 +214,7 @@
"is_tree": 1,
"links": [],
"max_attachments": 3,
- "modified": "2020-03-18 18:10:34.383363",
+ "modified": "2021-02-18 13:40:30.049650",
"modified_by": "Administrator",
"module": "Setup",
"name": "Item Group",
@@ -245,6 +271,15 @@
"read": 1,
"report": 1,
"role": "Accounts User"
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "report": 1,
+ "role": "All",
+ "select": 1,
+ "share": 1
}
],
"search_fields": "parent_item_group",
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 4377840..bff806d 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -13,13 +13,16 @@
from erpnext.shopping_cart.product_info import set_product_info_for_website
from erpnext.utilities.product import get_qty_in_stock
from six.moves.urllib.parse import quote
+from erpnext.shopping_cart.product_query import ProductQuery
+from erpnext.shopping_cart.filters import ProductFiltersBuilder
class ItemGroup(NestedSet, WebsiteGenerator):
nsm_parent_field = 'parent_item_group'
website = frappe._dict(
condition_field = "show_in_website",
template = "templates/generators/item_group.html",
- no_cache = 1
+ no_cache = 1,
+ no_breadcrumbs = 1
)
def autoname(self):
@@ -70,18 +73,58 @@
context.page_length = cint(frappe.db.get_single_value('Products Settings', 'products_per_page')) or 6
context.search_link = '/product_search'
- start = int(frappe.form_dict.start or 0)
- if start < 0:
+ if frappe.form_dict:
+ search = frappe.form_dict.search
+ field_filters = frappe.parse_json(frappe.form_dict.field_filters)
+ attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
+ start = frappe.parse_json(frappe.form_dict.start)
+ else:
+ search = None
+ attribute_filters = None
+ field_filters = {}
start = 0
+
+ if not field_filters:
+ field_filters = {}
+
+ # Ensure the query remains within current item group
+ field_filters['item_group'] = self.name
+
+ engine = ProductQuery()
+ context.items = engine.query(attribute_filters, field_filters, search, start)
+
+ filter_engine = ProductFiltersBuilder(self.name)
+
+ context.field_filters = filter_engine.get_field_filters()
+ context.attribute_filters = filter_engine.get_attribute_fitlers()
+
context.update({
- "items": get_product_list_for_group(product_group = self.name, start=start,
- limit=context.page_length + 1, search=frappe.form_dict.get("search")),
"parents": get_parent_item_groups(self.parent_item_group),
"title": self.name
})
if self.slideshow:
- context.update(get_slideshow(self))
+ values = {
+ 'show_indicators': 1,
+ 'show_controls': 0,
+ 'rounded': 1,
+ 'slider_name': self.slideshow
+ }
+ slideshow = frappe.get_doc("Website Slideshow", self.slideshow)
+ slides = slideshow.get({"doctype":"Website Slideshow Item"})
+ for index, slide in enumerate(slides):
+ values[f"slide_{index + 1}_image"] = slide.image
+ values[f"slide_{index + 1}_title"] = slide.heading
+ values[f"slide_{index + 1}_subtitle"] = slide.description
+ values[f"slide_{index + 1}_theme"] = slide.theme or "Light"
+ values[f"slide_{index + 1}_content_align"] = slide.content_align or "Centre"
+ values[f"slide_{index + 1}_primary_action_label"] = slide.label
+ values[f"slide_{index + 1}_primary_action"] = slide.url
+
+ context.slideshow = values
+
+ context.breadcrumbs = 0
+ context.title = self.website_title or self.name
return context
diff --git a/erpnext/setup/doctype/item_group/test_records.json b/erpnext/setup/doctype/item_group/test_records.json
index 7115964..146da87 100644
--- a/erpnext/setup/doctype/item_group/test_records.json
+++ b/erpnext/setup/doctype/item_group/test_records.json
@@ -79,13 +79,13 @@
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 10",
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
"tax_category": ""
},
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 12",
+ "item_tax_template": "_Test Account Excise Duty @ 12 - _TC",
"tax_category": "_Test Tax Category 1"
}
]
@@ -99,7 +99,7 @@
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 15",
+ "item_tax_template": "_Test Account Excise Duty @ 15 - _TC",
"tax_category": ""
}
]
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index abff973..2ea0bc0 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -10,6 +10,7 @@
from frappe.model.document import Document
from frappe.model.naming import parse_naming_series
from frappe.permissions import get_doctypes_with_read
+from frappe.core.doctype.doctype.doctype import validate_series
class NamingSeriesNotSetError(frappe.ValidationError): pass
@@ -126,7 +127,7 @@
dt = frappe.get_doc("DocType", self.select_doc_for_series)
options = self.scrub_options_list(self.set_options.split("\n"))
for series in options:
- dt.validate_series(series)
+ validate_series(dt, series)
for i in sr:
if i[0]:
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
diff --git a/erpnext/setup/doctype/sales_person/sales_person.js b/erpnext/setup/doctype/sales_person/sales_person.js
index 8f7593d..b71a92f 100644
--- a/erpnext/setup/doctype/sales_person/sales_person.js
+++ b/erpnext/setup/doctype/sales_person/sales_person.js
@@ -5,8 +5,7 @@
refresh: function(frm) {
if(frm.doc.__onload && frm.doc.__onload.dashboard_info) {
var info = frm.doc.__onload.dashboard_info;
- frm.dashboard.add_indicator(__('Total Contribution Amount: {0}',
- [format_currency(info.allocated_amount, info.currency)]), 'blue');
+ frm.dashboard.add_indicator(__('Total Contribution Amount: {0}', [format_currency(info.allocated_amount, info.currency)]), 'blue');
}
},
diff --git a/erpnext/setup/doctype/territory/territory.json b/erpnext/setup/doctype/territory/territory.json
index aa8e048..a25bda0 100644
--- a/erpnext/setup/doctype/territory/territory.json
+++ b/erpnext/setup/doctype/territory/territory.json
@@ -123,7 +123,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
- "modified": "2020-03-18 18:11:36.623555",
+ "modified": "2021-02-08 17:10:03.767426",
"modified_by": "Administrator",
"module": "Setup",
"name": "Territory",
@@ -166,6 +166,15 @@
{
"read": 1,
"role": "Maintenance User"
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "report": 1,
+ "role": "Customer",
+ "select": 1,
+ "share": 1
}
],
"search_fields": "parent_territory,territory_manager",
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 2225fe1..82f191d 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -28,6 +28,7 @@
create_default_energy_point_rules()
add_company_to_session_defaults()
add_standard_navbar_items()
+ add_app_name()
frappe.db.commit()
@@ -141,13 +142,15 @@
}
]
- current_nabvar_items = navbar_settings.help_dropdown
+ current_navbar_items = navbar_settings.help_dropdown
navbar_settings.set('help_dropdown', [])
for item in erpnext_navbar_items:
- navbar_settings.append('help_dropdown', item)
+ current_labels = [item.get('item_label') for item in current_navbar_items]
+ if not item.get('item_label') in current_labels:
+ navbar_settings.append('help_dropdown', item)
- for item in current_nabvar_items:
+ for item in current_navbar_items:
navbar_settings.append('help_dropdown', {
'item_label': item.item_label,
'item_type': item.item_type,
@@ -158,3 +161,6 @@
})
navbar_settings.save()
+
+def add_app_name():
+ frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
diff --git a/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html b/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html
index 5808ce7..7166ba3 100644
--- a/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html
+++ b/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html
@@ -21,7 +21,6 @@
<h3>{%= __("Next Steps") %}</h3>
<ul class="list-unstyled">
<li><a class="text-muted" href="#">{%= __("Go to the Desktop and start using ERPNext") %}</a></li>
- <li><a class="text-muted" href="#modules/Learn">{%= __("View a list of all the help videos") %}</a></li>
<li><a class="text-muted" href="https://erpnext.com/docs/user" target="_blank">{%= __("Read the ERPNext Manual") %}</a></li>
<li><a class="text-muted" href="https://discuss.erpnext.com" target="_blank">{%= __("Community Forum") %}</a></li>
</ul>
diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json
index 19318df..beddaee 100644
--- a/erpnext/setup/setup_wizard/data/country_wise_tax.json
+++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json
@@ -60,14 +60,10 @@
},
"Australia": {
- "Australia GST1": {
+ "Australia GST": {
"account_name": "GST 10%",
"tax_rate": 10.00,
"default": 1
- },
- "Australia GST 2%": {
- "account_name": "GST 2%",
- "tax_rate": 2
}
},
@@ -648,10 +644,19 @@
},
"Italy": {
- "Italy Tax": {
- "account_name": "VAT",
- "tax_rate": 22.00
- }
+ "Italy VAT 22%": {
+ "account_name": "IVA 22%",
+ "tax_rate": 22.00,
+ "default": 1
+ },
+ "Italy VAT 10%":{
+ "account_name": "IVA 10%",
+ "tax_rate": 10.00
+ },
+ "Italy VAT 4%":{
+ "account_name": "IVA 4%",
+ "tax_rate": 4.00
+ }
},
"Ivory Coast": {
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 72ed002..5053c6a 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -195,6 +195,7 @@
{'doctype': "Party Type", "party_type": "Member", "account_type": "Receivable"},
{'doctype': "Party Type", "party_type": "Shareholder", "account_type": "Payable"},
{'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")},
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index e66fa76..c3c1593 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -29,6 +29,7 @@
try:
if accounts:
make_sales_and_purchase_tax_templates(accounts, template_name)
+ make_item_tax_templates(accounts, template_name)
except frappe.NameError:
if frappe.message_log: frappe.message_log.pop()
except RootNotEditable:
@@ -84,6 +85,27 @@
doc = frappe.get_doc(purchase_tax_template)
doc.insert(ignore_permissions=True)
+def make_item_tax_templates(accounts, template_name=None):
+ if not template_name:
+ template_name = accounts[0].name
+
+ item_tax_template = {
+ "doctype": "Item Tax Template",
+ "title": template_name,
+ "company": accounts[0].company,
+ 'taxes': []
+ }
+
+
+ for account in accounts:
+ item_tax_template['taxes'].append({
+ "tax_type": account.name,
+ "tax_rate": account.tax_rate
+ })
+
+ # Items
+ frappe.get_doc(copy.deepcopy(item_tax_template)).insert(ignore_permissions=True)
+
def get_tax_account_group(company):
tax_group = frappe.db.get_value("Account",
{"account_name": "Duties and Taxes", "is_group": 1, "company": company})
diff --git a/erpnext/setup/desk_page/erpnext_settings/erpnext_settings.json b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
similarity index 77%
rename from erpnext/setup/desk_page/erpnext_settings/erpnext_settings.json
rename to erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
index 253d711..014f409 100644
--- a/erpnext/setup/desk_page/erpnext_settings/erpnext_settings.json
+++ b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
@@ -1,18 +1,20 @@
{
- "cards": [],
"category": "Modules",
"charts": [],
"creation": "2020-03-12 14:47:51.166455",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
- "doctype": "Desk Page",
+ "doctype": "Workspace",
"extends": "Settings",
"extends_another_page": 1,
+ "hide_custom": 0,
+ "icon": "settings",
"idx": 0,
"is_standard": 1,
"label": "ERPNext Settings",
- "modified": "2020-04-01 11:28:51.400851",
+ "links": [],
+ "modified": "2020-12-01 13:38:37.759596",
"modified_by": "Administrator",
"module": "Setup",
"name": "ERPNext Settings",
@@ -21,89 +23,89 @@
"pin_to_top": 0,
"shortcuts": [
{
- "icon": "octicon octicon-rocket",
+ "icon": "project",
"label": "Projects Settings",
"link_to": "Projects Settings",
"type": "DocType"
},
{
- "icon": "octicon octicon-repo",
+ "icon": "accounting",
"label": "Accounts Settings",
"link_to": "Accounts Settings",
"type": "DocType"
},
{
- "icon": "octicon octicon-package",
+ "icon": "stock",
"label": "Stock Settings",
"link_to": "Stock Settings",
"type": "DocType"
},
{
- "icon": "octicon octicon-organization",
+ "icon": "hr",
"label": "HR Settings",
"link_to": "HR Settings",
"type": "DocType"
},
{
- "icon": "octicon octicon-tag",
+ "icon": "sell",
"label": "Selling Settings",
"link_to": "Selling Settings",
"type": "DocType"
},
{
- "icon": "octicon octicon-briefcase",
+ "icon": "buying",
"label": "Buying Settings",
"link_to": "Buying Settings",
"type": "DocType"
},
{
- "icon": "fa fa-life-ring",
+ "icon": "support",
"label": "Support Settings",
"link_to": "Support Settings",
"type": "DocType"
},
{
- "icon": "fa fa-shopping-cart",
+ "icon": "retail",
"label": "Shopping Cart Settings",
"link_to": "Shopping Cart Settings",
"type": "DocType"
},
{
- "icon": "fa fa-globe",
+ "icon": "website",
"label": "Portal Settings",
"link_to": "Portal Settings",
"type": "DocType"
},
{
- "icon": "octicon octicon-tools",
+ "icon": "organization",
"label": "Manufacturing Settings",
"link_to": "Manufacturing Settings",
"restrict_to_domain": "Manufacturing",
"type": "DocType"
},
{
- "icon": "octicon octicon-mortar-board",
+ "icon": "education",
"label": "Education Settings",
"link_to": "Education Settings",
"restrict_to_domain": "Education",
"type": "DocType"
},
{
- "icon": "fa fa-bed",
+ "icon": "organization",
"label": "Hotel Settings",
"link_to": "Hotel Settings",
"restrict_to_domain": "Hospitality",
"type": "DocType"
},
{
- "icon": "fa fa-heartbeat",
+ "icon": "non-profit",
"label": "Healthcare Settings",
"link_to": "Healthcare Settings",
"restrict_to_domain": "Healthcare",
"type": "DocType"
},
{
- "icon": "fa fa-cog",
+ "icon": "setting",
"label": "Domain Settings",
"link_to": "Domain Settings",
"type": "DocType"
diff --git a/erpnext/setup/workspace/home/home.json b/erpnext/setup/workspace/home/home.json
new file mode 100644
index 0000000..305456b
--- /dev/null
+++ b/erpnext/setup/workspace/home/home.json
@@ -0,0 +1,455 @@
+{
+ "category": "Modules",
+ "charts": [],
+ "creation": "2020-01-23 13:46:38.833076",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "getting-started",
+ "idx": 0,
+ "is_default": 0,
+ "is_standard": 1,
+ "label": "Home",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Accounting",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chart of Accounts",
+ "link_to": "Account",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Company",
+ "link_to": "Company",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer",
+ "link_to": "Customer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Supplier",
+ "link_to": "Supplier",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item",
+ "link_to": "Item",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Warehouse",
+ "link_to": "Warehouse",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Brand",
+ "link_to": "Brand",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Unit of Measure (UOM)",
+ "link_to": "UOM",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Reconciliation",
+ "link_to": "Stock Reconciliation",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Human Resources",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee",
+ "link_to": "Employee",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Employee",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Employee Attendance Tool",
+ "link_to": "Employee Attendance Tool",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Salary Structure",
+ "link_to": "Salary Structure",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "CRM",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Lead",
+ "link_to": "Lead",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customer Group",
+ "link_to": "Customer Group",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Territory",
+ "link_to": "Territory",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Data Import and Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Import Data",
+ "link_to": "Data Import",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Opening Invoice Creation Tool",
+ "link_to": "Opening Invoice Creation Tool",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chart of Accounts Importer",
+ "link_to": "Chart of Accounts Importer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Letter Head",
+ "link_to": "Letter Head",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Email Account",
+ "link_to": "Email Account",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Healthcare",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Patient",
+ "link_to": "Patient",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Diagnosis",
+ "link_to": "Diagnosis",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Education",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student",
+ "link_to": "Student",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Instructor",
+ "link_to": "Instructor",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course",
+ "link_to": "Course",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Room",
+ "link_to": "Room",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Non Profit",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Donor",
+ "link_to": "Donor",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Member",
+ "link_to": "Member",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Volunteer",
+ "link_to": "Volunteer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Chapter",
+ "link_to": "Chapter",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Agriculture",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Location",
+ "link_to": "Location",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Crop",
+ "link_to": "Crop",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Crop Cycle",
+ "link_to": "Crop Cycle",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fertilizer",
+ "link_to": "Fertilizer",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ }
+ ],
+ "modified": "2021-03-16 15:59:58.416154",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Home",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 1,
+ "shortcuts": [
+ {
+ "label": "Item",
+ "link_to": "Item",
+ "type": "DocType"
+ },
+ {
+ "label": "Customer",
+ "link_to": "Customer",
+ "type": "DocType"
+ },
+ {
+ "label": "Supplier",
+ "link_to": "Supplier",
+ "type": "DocType"
+ },
+ {
+ "label": "Sales Invoice",
+ "link_to": "Sales Invoice",
+ "type": "DocType"
+ },
+ {
+ "label": "Leaderboard",
+ "link_to": "leaderboard",
+ "type": "Page"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 0ccc025..681d161 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -42,15 +42,31 @@
return {
"doc": decorate_quotation_doc(doc),
- "shipping_addresses": [{"name": address.name, "title": address.address_title, "display": address.display}
- for address in addresses if address.address_type == "Shipping"],
- "billing_addresses": [{"name": address.name, "title": address.address_title, "display": address.display}
- for address in addresses if address.address_type == "Billing"],
+ "shipping_addresses": get_shipping_addresses(party),
+ "billing_addresses": get_billing_addresses(party),
"shipping_rules": get_applicable_shipping_rules(party),
"cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
}
@frappe.whitelist()
+def get_shipping_addresses(party=None):
+ if not party:
+ party = get_party()
+ addresses = get_address_docs(party=party)
+ return [{"name": address.name, "title": address.address_title, "display": address.display}
+ for address in addresses if address.address_type == "Shipping"
+ ]
+
+@frappe.whitelist()
+def get_billing_addresses(party=None):
+ if not party:
+ party = get_party()
+ addresses = get_address_docs(party=party)
+ return [{"name": address.name, "title": address.address_title, "display": address.display}
+ for address in addresses if address.address_type == "Billing"
+ ]
+
+@frappe.whitelist()
def place_order():
quotation = _get_cart_quotation()
cart_settings = frappe.db.get_value("Shopping Cart Settings", None,
@@ -180,6 +196,13 @@
lead_doc.update(lead)
lead_doc.set('lead_owner', '')
+ if not frappe.db.exists('Lead Source', 'Product Inquiry'):
+ frappe.get_doc({
+ 'doctype': 'Lead Source',
+ 'source_name' : 'Product Inquiry'
+ }).insert(ignore_permissions=True)
+ lead_doc.set('source', 'Product Inquiry')
+
try:
lead_doc.save(ignore_permissions=True)
except frappe.exceptions.DuplicateEntryError:
@@ -203,27 +226,33 @@
@frappe.whitelist()
def update_cart_address(address_type, address_name):
quotation = _get_cart_quotation()
- address_display = get_address_display(frappe.get_doc("Address", address_name).as_dict())
+ address_doc = frappe.get_doc("Address", address_name).as_dict()
+ address_display = get_address_display(address_doc)
if address_type.lower() == "billing":
quotation.customer_address = address_name
quotation.address_display = address_display
quotation.shipping_address_name == quotation.shipping_address_name or address_name
+ address_doc = next((doc for doc in get_billing_addresses() if doc["name"] == address_name), None)
elif address_type.lower() == "shipping":
quotation.shipping_address_name = address_name
quotation.shipping_address = address_display
quotation.customer_address == quotation.customer_address or address_name
-
+ address_doc = next((doc for doc in get_shipping_addresses() if doc["name"] == address_name), None)
apply_cart_settings(quotation=quotation)
quotation.flags.ignore_permissions = True
quotation.save()
context = get_cart_quotation(quotation)
+ context['address'] = address_doc
+
return {
"taxes": frappe.render_template("templates/includes/order/order_taxes.html",
context),
- }
+ "address": frappe.render_template("templates/includes/cart/address_card.html",
+ context)
+ }
def guess_territory():
territory = None
@@ -345,7 +374,7 @@
selling_price_list = None
# check if default customer price list exists
- if party_name:
+ if party_name and frappe.db.exists("Customer", party_name):
selling_price_list = get_default_price_list(frappe.get_doc("Customer", party_name))
# check default price list in shopping cart
@@ -433,6 +462,9 @@
return customer
def get_debtors_account(cart_settings):
+ if not cart_settings.payment_gateway_account:
+ frappe.throw(_("Payment Gateway Account not set"), _("Mandatory"))
+
payment_gateway_account_currency = \
frappe.get_doc("Payment Gateway Account", cart_settings.payment_gateway_account).currency
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.js b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.js
index 21fa4c3..b38828e 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.js
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.js
@@ -7,6 +7,22 @@
frm.fields_dict.quotation_series.df.options = frm.doc.__onload.quotation_series;
frm.refresh_field("quotation_series");
}
+
+ frm.set_query('payment_gateway_account', function() {
+ return { 'filters': { 'payment_channel': "Email" } };
+ });
+ },
+ refresh: function(frm) {
+ if (frm.doc.enabled) {
+ frm.get_field('store_page_docs').$wrapper.removeClass('hide-control').html(
+ `<div>${__("Follow these steps to create a landing page for your store")}:
+ <a href="https://docs.erpnext.com/docs/user/manual/en/website/store-landing-page"
+ style="color: var(--gray-600)">
+ docs/store-landing-page
+ </a>
+ </div>`
+ );
+ }
},
enabled: function(frm) {
if (frm.doc.enabled === 1) {
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
index 9d61e7d..7a4bb20 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
@@ -7,6 +7,7 @@
"engine": "InnoDB",
"field_order": [
"enabled",
+ "store_page_docs",
"display_settings",
"show_attachments",
"show_price",
@@ -25,10 +26,10 @@
"quotation_series",
"section_break_8",
"enable_checkout",
- "payment_success_url",
- "column_break_11",
"save_quotations_as_draft",
- "payment_gateway_account"
+ "column_break_11",
+ "payment_gateway_account",
+ "payment_success_url"
],
"fields": [
{
@@ -142,10 +143,12 @@
},
{
"default": "Orders",
+ "depends_on": "enable_checkout",
"description": "After payment completion redirect user to selected page.",
"fieldname": "payment_success_url",
"fieldtype": "Select",
"label": "Payment Success Url",
+ "mandatory_depends_on": "enable_checkout",
"options": "\nOrders\nInvoices\nMy Account"
},
{
@@ -153,9 +156,11 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "enable_checkout",
"fieldname": "payment_gateway_account",
"fieldtype": "Link",
"label": "Payment Gateway Account",
+ "mandatory_depends_on": "enable_checkout",
"options": "Payment Gateway Account"
},
{
@@ -174,13 +179,18 @@
"fieldname": "save_quotations_as_draft",
"fieldtype": "Check",
"label": "Save Quotations as Draft"
+ },
+ {
+ "depends_on": "doc.enabled",
+ "fieldname": "store_page_docs",
+ "fieldtype": "HTML"
}
],
"icon": "fa fa-shopping-cart",
"idx": 1,
"issingle": 1,
"links": [],
- "modified": "2020-09-24 16:28:07.192525",
+ "modified": "2021-03-02 17:34:57.642565",
"modified_by": "Administrator",
"module": "Shopping Cart",
"name": "Shopping Cart Settings",
@@ -197,5 +207,6 @@
}
],
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/shopping_cart/filters.py b/erpnext/shopping_cart/filters.py
new file mode 100644
index 0000000..6c63d87
--- /dev/null
+++ b/erpnext/shopping_cart/filters.py
@@ -0,0 +1,82 @@
+# 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:
+ def __init__(self, item_group=None):
+ if not item_group or item_group == "Products Settings":
+ self.doc = frappe.get_doc("Products Settings")
+ else:
+ self.doc = frappe.get_doc("Item Group", item_group)
+
+ self.item_group = item_group
+
+ def get_field_filters(self):
+ filter_fields = [row.fieldname for row in self.doc.filter_fields]
+
+ meta = frappe.get_meta('Item')
+ fields = [df for df in meta.fields if df.fieldname in filter_fields]
+
+ filter_data = []
+ for df in fields:
+ filters = {}
+ if df.fieldtype == "Link":
+ if self.item_group:
+ filters['item_group'] = self.item_group
+
+ values = frappe.get_all("Item", fields=[df.fieldname], filters=filters, distinct="True", pluck=df.fieldname)
+ else:
+ doctype = df.get_link_doctype()
+
+ # apply enable/disable/show_in_website filter
+ meta = frappe.get_meta(doctype)
+
+ if meta.has_field('enabled'):
+ filters['enabled'] = 1
+ if meta.has_field('disabled'):
+ filters['disabled'] = 0
+ if meta.has_field('show_in_website'):
+ filters['show_in_website'] = 1
+
+ values = [d.name for d in frappe.get_all(doctype, filters)]
+
+ # Remove None
+ values = values.remove(None) if None in values else values
+ if values:
+ filter_data.append([df, values])
+
+ return filter_data
+
+ def get_attribute_fitlers(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 = []
+
+ for attr_doc in attribute_docs:
+ selected_attributes = []
+ for attr in attr_doc.item_attribute_values:
+ filters= [
+ ["Item Variant Attribute", "attribute", "=", attr.parent],
+ ["Item Variant Attribute", "attribute_value", "=", attr.attribute_value]
+ ]
+ if self.item_group:
+ filters.append(["item_group", "=", self.item_group])
+
+ if frappe.db.get_all("Item", filters, limit=1):
+ selected_attributes.append(attr)
+
+ if selected_attributes:
+ valid_attributes.append(
+ _dict(
+ item_attribute_values=selected_attributes,
+ name=attr_doc.name
+ )
+ )
+
+ return valid_attributes
diff --git a/erpnext/shopping_cart/product_query.py b/erpnext/shopping_cart/product_query.py
new file mode 100644
index 0000000..36d446e
--- /dev/null
+++ b/erpnext/shopping_cart/product_query.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+from erpnext.shopping_cart.product_info import get_product_info_for_website
+
+class ProductQuery:
+ """Query engine for product listing
+
+ Attributes:
+ cart_settings (Document): Settings for Cart
+ fields (list): Fields to fetch in query
+ filters (TYPE): Description
+ or_filters (list): Description
+ page_length (Int): Length of page for the query
+ settings (Document): Products Settings DocType
+ filters (list)
+ or_filters (list)
+ """
+
+ def __init__(self):
+ self.settings = frappe.get_doc("Products Settings")
+ self.cart_settings = frappe.get_doc("Shopping Cart Settings")
+ self.page_length = self.settings.products_per_page or 20
+ self.fields = ['name', 'item_name', 'item_code', 'website_image', 'variant_of', 'has_variants', 'item_group', 'image', 'web_long_description', 'description', 'route']
+ self.filters = []
+ self.or_filters = [['show_in_website', '=', 1]]
+ if not self.settings.get('hide_variants'):
+ self.or_filters.append(['show_variant_in_website', '=', 1])
+
+ def query(self, attributes=None, fields=None, search_term=None, start=0):
+ """Summary
+
+ Args:
+ attributes (dict, optional): Item Attribute filters
+ fields (dict, optional): Field level filters
+ search_term (str, optional): Search term to lookup
+ start (int, optional): Page start
+
+ Returns:
+ list: List of results with set fields
+ """
+ if fields: self.build_fields_filters(fields)
+ if search_term: self.build_search_filters(search_term)
+
+ result = []
+
+ if attributes:
+ all_items = []
+ for attribute, values in attributes.items():
+ if not isinstance(values, list):
+ values = [values]
+
+ items = frappe.get_all(
+ "Item",
+ fields=self.fields,
+ filters=[
+ *self.filters,
+ ["Item Variant Attribute", "attribute", "=", attribute],
+ ["Item Variant Attribute", "attribute_value", "in", values],
+ ],
+ or_filters=self.or_filters,
+ start=start,
+ limit=self.page_length
+ )
+
+ items_dict = {item.name: item for item in items}
+ # TODO: Replace Variants by their parent templates
+
+ all_items.append(set(items_dict.keys()))
+
+ result = [items_dict.get(item) for item in list(set.intersection(*all_items))]
+ else:
+ result = frappe.get_all("Item", fields=self.fields, filters=self.filters, or_filters=self.or_filters, start=start, limit=self.page_length)
+
+ for item in result:
+ product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
+ if product_info:
+ item.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
+
+ return result
+
+ def build_fields_filters(self, filters):
+ """Build filters for field values
+
+ Args:
+ filters (dict): Filters
+ """
+ for field, values in filters.items():
+ if not values:
+ continue
+
+ if isinstance(values, list):
+ # If value is a list use `IN` query
+ self.filters.append([field, 'IN', values])
+ else:
+ # `=` will be faster than `IN` for most cases
+ self.filters.append([field, '=', values])
+
+ def build_search_filters(self, search_term):
+ """Query search term in specified fields
+
+ Args:
+ search_term (str): Search candidate
+ """
+ # Default fields to search from
+ default_fields = {'name', 'item_name', 'description', 'item_group'}
+
+ # Get meta search fields
+ meta = frappe.get_meta("Item")
+ meta_fields = set(meta.get_search_fields())
+
+ # Join the meta fields and default fields set
+ search_fields = default_fields.union(meta_fields)
+ try:
+ if frappe.db.count('Item', cache=True) > 50000:
+ search_fields.remove('description')
+ except KeyError:
+ pass
+
+ # Build or filters for query
+ search = '%{}%'.format(search_term)
+ self.or_filters += [[field, 'like', search] for field in search_fields]
diff --git a/erpnext/shopping_cart/search.py b/erpnext/shopping_cart/search.py
new file mode 100644
index 0000000..63e9fe1
--- /dev/null
+++ b/erpnext/shopping_cart/search.py
@@ -0,0 +1,126 @@
+import frappe
+from frappe.search.full_text_search import FullTextSearch
+from whoosh.fields import TEXT, ID, KEYWORD, Schema
+from frappe.utils import strip_html_tags
+from whoosh.qparser import MultifieldParser, FieldsPlugin, WildcardPlugin
+from whoosh.analysis import StemmingAnalyzer
+from whoosh.query import Prefix
+
+INDEX_NAME = "products"
+
+class ProductSearch(FullTextSearch):
+ """ Wrapper for WebsiteSearch """
+
+ def get_schema(self):
+ return Schema(
+ title=TEXT(stored=True, field_boost=1.5),
+ name=ID(stored=True),
+ path=ID(stored=True),
+ content=TEXT(stored=True, analyzer=StemmingAnalyzer()),
+ keywords=KEYWORD(stored=True, scorable=True, commas=True),
+ )
+
+ def get_id(self):
+ return "name"
+
+ def get_items_to_index(self):
+ """Get all routes to be indexed, this includes the static pages
+ in www/ and routes from published documents
+
+ Returns:
+ self (object): FullTextSearch Instance
+ """
+ items = get_all_published_items()
+ documents = [self.get_document_to_index(item) for item in items]
+ return documents
+
+ def get_document_to_index(self, item):
+ try:
+ item = frappe.get_doc("Item", item)
+ title = item.item_name
+ keywords = [item.item_group]
+
+ if item.brand:
+ keywords.append(item.brand)
+
+ if item.website_image_alt:
+ keywords.append(item.website_image_alt)
+
+ if item.has_variants and item.variant_based_on == "Item Attribute":
+ keywords = keywords + [attr.attribute for attr in item.attributes]
+
+ if item.web_long_description:
+ content = strip_html_tags(item.web_long_description)
+ elif item.description:
+ content = strip_html_tags(item.description)
+
+ return frappe._dict(
+ title=title,
+ name=item.name,
+ path=item.route,
+ content=content,
+ keywords=", ".join(keywords),
+ )
+ except Exception:
+ pass
+
+ def search(self, text, scope=None, limit=20):
+ """Search from the current index
+
+ Args:
+ text (str): String to search for
+ scope (str, optional): Scope to limit the search. Defaults to None.
+ limit (int, optional): Limit number of search results. Defaults to 20.
+
+ Returns:
+ [List(_dict)]: Search results
+ """
+ ix = self.get_index()
+
+ results = None
+ out = []
+
+ with ix.searcher() as searcher:
+ parser = MultifieldParser(["title", "content", "keywords"], ix.schema)
+ parser.remove_plugin_class(FieldsPlugin)
+ parser.remove_plugin_class(WildcardPlugin)
+ query = parser.parse(text)
+
+ filter_scoped = None
+ if scope:
+ filter_scoped = Prefix(self.id, scope)
+ results = searcher.search(query, limit=limit, filter=filter_scoped)
+
+ for r in results:
+ out.append(self.parse_result(r))
+
+ return out
+
+ def parse_result(self, result):
+ title_highlights = result.highlights("title")
+ content_highlights = result.highlights("content")
+ keyword_highlights = result.highlights("keywords")
+
+ return frappe._dict(
+ title=result["title"],
+ path=result["path"],
+ keywords=result["keywords"],
+ title_highlights=title_highlights,
+ content_highlights=content_highlights,
+ keyword_highlights=keyword_highlights,
+ )
+
+def get_all_published_items():
+ return frappe.get_all("Item", filters={"variant_of": "", "show_in_website": 1},pluck="name")
+
+def update_index_for_path(path):
+ search = ProductSearch(INDEX_NAME)
+ return search.update_index_by_name(path)
+
+def remove_document_from_index(path):
+ search = ProductSearch(INDEX_NAME)
+ return search.remove_document_from_index(path)
+
+def build_index_for_all_routes():
+ search = ProductSearch(INDEX_NAME)
+ return search.build()
\ No newline at end of file
diff --git a/erpnext/config/__init__.py b/erpnext/shopping_cart/web_template/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/shopping_cart/web_template/__init__.py
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/shopping_cart/web_template/hero_slider/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/shopping_cart/web_template/hero_slider/__init__.py
diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
new file mode 100644
index 0000000..1b39534
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
@@ -0,0 +1,85 @@
+{%- 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-left': align == 'Left',
+}) -%}
+
+{%- set heading_class = resolve_class({
+ 'text-white': theme == 'Dark',
+ '': theme == 'Light',
+}) -%}
+<div class="carousel-item {{ 'active' if index=='1' else ''}}" style="height: 450px;">
+ <img class="d-block h-100 w-100" style="object-fit: cover;" src="{{ image }}" alt="{{ title }}">
+ {%- if title or subtitle -%}
+ <div class="carousel-body container d-flex {{ align_class }}">
+ <div class="carousel-content align-self-center">
+ {%- if title -%}<h1 class="{{ heading_class }}">{{ title }}</h1>{%- endif -%}
+ {%- if subtitle -%}<p class="text-muted mt-2">{{ subtitle }}</p>{%- endif -%}
+ {%- if action -%}
+ <a href="{{ action }}" class="btn btn-primary mt-3">
+ {{ label }}
+ </a>
+ {%- endif -%}
+ </div>
+ </div>
+ {%- endif -%}
+</div>
+{%- endmacro -%}
+
+<div id="{{ slider_name }}" class="section-carousel carousel slide" data-ride="carousel">
+ {%- if show_indicators -%}
+ <ol class="carousel-indicators">
+ {%- for index in ['1', '2', '3', '4', '5'] -%}
+ {%- if values['slide_' + index + '_image'] -%}
+ <li data-target="#{{ slider_name }}" data-slide-to="{{ frappe.utils.cint(index) - 1 }}" class="{{ 'active' if index=='1' else ''}}"></li>
+ {%- endif -%}
+ {%- endfor -%}
+ </ol>
+ {%- endif -%}
+ <div class="carousel-inner {{ resolve_class({'rounded-carousel': rounded }) }}">
+ {%- for index in ['1', '2', '3', '4', '5'] -%}
+ {%- set image = values['slide_' + index + '_image'] -%}
+ {%- set title = values['slide_' + index + '_title'] -%}
+ {%- set subtitle = values['slide_' + index + '_subtitle'] -%}
+ {%- set primary_action = values['slide_' + index + '_primary_action'] -%}
+ {%- set primary_action_label = values['slide_' + index + '_primary_action_label'] -%}
+ {%- set align = values['slide_' + index + '_content_align'] -%}
+ {%- set theme = values['slide_' + index + '_theme'] -%}
+
+ {%- if image -%}
+ {{ slide(image, title, subtitle, primary_action, primary_action_label, index, align, theme) }}
+ {%- endif -%}
+
+ {%- endfor -%}
+ </div>
+ {%- if show_controls -%}
+ <a class="carousel-control-prev" href="#{{ slider_name }}" role="button" data-slide="prev">
+ <div class="carousel-control">
+ <svg class="mr-1" width="20" height="20" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M11.625 3.75L6.375 9L11.625 14.25" stroke="#4C5A67" stroke-linecap="round" stroke-linejoin="round"/>
+ </svg>
+ </div>
+ <span class="sr-only">Previous</span>
+ </a>
+ <a class="carousel-control-next" href="#{{ slider_name }}" role="button" data-slide="next">
+ <div class="carousel-control">
+ <svg class="ml-1" width="20" height="20" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M6.375 14.25L11.625 9L6.375 3.75" stroke="#4C5A67" stroke-linecap="round" stroke-linejoin="round"/>
+ </svg>
+ </div>
+ <span class="sr-only">Next</span>
+ </a>
+ {%- endif -%}
+</div>
+
+<script type="text/javascript">
+ $('.carousel').carousel({
+ interval: false,
+ pause: "hover",
+ wrap: true
+ })
+</script>
+
+<style>
+</style>
\ No newline at end of file
diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.json b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.json
new file mode 100644
index 0000000..04fb1d2
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.json
@@ -0,0 +1,284 @@
+{
+ "creation": "2020-11-17 15:21:51.207221",
+ "docstatus": 0,
+ "doctype": "Web Template",
+ "fields": [
+ {
+ "fieldname": "slider_name",
+ "fieldtype": "Data",
+ "label": "Slider Name",
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "show_indicators",
+ "fieldtype": "Check",
+ "label": "Show Indicators",
+ "reqd": 0
+ },
+ {
+ "default": "1",
+ "fieldname": "show_controls",
+ "fieldtype": "Check",
+ "label": "Show Controls",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1",
+ "fieldtype": "Section Break",
+ "label": "Slide 1",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_image",
+ "fieldtype": "Attach Image",
+ "label": "Image",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_subtitle",
+ "fieldtype": "Small Text",
+ "label": "Subtitle",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_primary_action_label",
+ "fieldtype": "Data",
+ "label": "Primary Action Label",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_primary_action",
+ "fieldtype": "Data",
+ "label": "Primary Action",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_content_align",
+ "fieldtype": "Select",
+ "label": "Content Align",
+ "options": "Left\nCentre\nRight",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_1_theme",
+ "fieldtype": "Select",
+ "label": "Slide Theme",
+ "options": "Dark\nLight",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2",
+ "fieldtype": "Section Break",
+ "label": "Slide 2",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2_image",
+ "fieldtype": "Attach Image",
+ "label": "Image ",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2_title",
+ "fieldtype": "Data",
+ "label": "Title ",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2_subtitle",
+ "fieldtype": "Small Text",
+ "label": "Subtitle ",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2_primary_action_label",
+ "fieldtype": "Data",
+ "label": "Primary Action Label ",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2_primary_action",
+ "fieldtype": "Data",
+ "label": "Primary Action ",
+ "reqd": 0
+ },
+ {
+ "default": "Left",
+ "fieldname": "slide_2_content_align",
+ "fieldtype": "Select",
+ "label": "Content Align",
+ "options": "Left\nCentre\nRight",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_2_theme",
+ "fieldtype": "Select",
+ "label": "Slide Theme",
+ "options": "Dark\nLight",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3",
+ "fieldtype": "Section Break",
+ "label": "Slide 3",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_image",
+ "fieldtype": "Attach Image",
+ "label": "Image",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_subtitle",
+ "fieldtype": "Small Text",
+ "label": "Subtitle",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_primary_action_label",
+ "fieldtype": "Data",
+ "label": "Primary Action Label",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_primary_action",
+ "fieldtype": "Data",
+ "label": "Primary Action",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_content_align",
+ "fieldtype": "Select",
+ "label": "Content Align",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_3_theme",
+ "fieldtype": "Select",
+ "label": "Slide Theme",
+ "options": "Dark\nLight",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4",
+ "fieldtype": "Section Break",
+ "label": "Slide 4",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_image",
+ "fieldtype": "Attach Image",
+ "label": "Image",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_subtitle",
+ "fieldtype": "Small Text",
+ "label": "Subtitle",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_primary_action_label",
+ "fieldtype": "Data",
+ "label": "Primary Action Label",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_primary_action",
+ "fieldtype": "Data",
+ "label": "Primary Action",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_content_align",
+ "fieldtype": "Select",
+ "label": "Content Align",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_4_theme",
+ "fieldtype": "Select",
+ "label": "Slide Theme",
+ "options": "Dark\nLight",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5",
+ "fieldtype": "Section Break",
+ "label": "Slide 5",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_image",
+ "fieldtype": "Attach Image",
+ "label": "Image",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_subtitle",
+ "fieldtype": "Small Text",
+ "label": "Subtitle",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_primary_action_label",
+ "fieldtype": "Data",
+ "label": "Primary Action Label",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_primary_action",
+ "fieldtype": "Data",
+ "label": "Primary Action",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_content_align",
+ "fieldtype": "Select",
+ "label": "Content Align",
+ "reqd": 0
+ },
+ {
+ "fieldname": "slide_5_theme",
+ "fieldtype": "Select",
+ "label": "Slide Theme",
+ "options": "Dark\nLight",
+ "reqd": 0
+ }
+ ],
+ "idx": 2,
+ "modified": "2020-12-29 12:30:02.794994",
+ "modified_by": "Administrator",
+ "module": "Shopping Cart",
+ "name": "Hero Slider",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "type": "Section"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/shopping_cart/web_template/item_card_group/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/shopping_cart/web_template/item_card_group/__init__.py
diff --git a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html b/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
new file mode 100644
index 0000000..890ae50
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
@@ -0,0 +1,38 @@
+{% from "erpnext/templates/includes/macros.html" import item_card, item_card_body %}
+
+<div class="section-with-cards item-card-group-section">
+ <div class="item-group-header d-flex justify-content-between">
+ <div class="title-section">
+ {%- if title -%}
+ <h2 class="section-title">{{ title }}</h2>
+ {%- endif -%}
+ {%- if subtitle -%}
+ <p class="section-description">{{ subtitle }}</p>
+ {%- endif -%}
+ </div>
+ <div class="primary-action-section">
+ {%- if primary_action -%}
+ <a href="{{ action }}" class="btn btn-primary pull-right">
+ {{ primary_action_label }}
+ </a>
+ {%- endif -%}
+ </div>
+ </div>
+
+ <div class="row">
+ {%- for index in ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] -%}
+ {%- set item = values['card_' + index + '_item'] -%}
+ {%- if item -%}
+ {%- set item = frappe.get_doc("Item", item) -%}
+ {{ item_card(
+ item.item_name, item.image, item.route, item.description,
+ None, item.item_group, values['card_' + index + '_featured'],
+ True, "Center"
+ ) }}
+ {%- endif -%}
+ {%- endfor -%}
+ </div>
+</div>
+
+<style>
+</style>
\ No newline at end of file
diff --git a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.json b/erpnext/shopping_cart/web_template/item_card_group/item_card_group.json
new file mode 100644
index 0000000..ad087b0
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/item_card_group/item_card_group.json
@@ -0,0 +1,273 @@
+{
+ "__unsaved": 1,
+ "creation": "2020-11-17 15:35:05.285322",
+ "docstatus": 0,
+ "doctype": "Web Template",
+ "fields": [
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 1
+ },
+ {
+ "fieldname": "subtitle",
+ "fieldtype": "Data",
+ "label": "Subtitle",
+ "reqd": 0
+ },
+ {
+ "__unsaved": 1,
+ "fieldname": "primary_action_label",
+ "fieldtype": "Data",
+ "label": "Primary Action Label",
+ "reqd": 0
+ },
+ {
+ "__islocal": 1,
+ "__unsaved": 1,
+ "fieldname": "primary_action",
+ "fieldtype": "Data",
+ "label": "Primary Action",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_1",
+ "fieldtype": "Section Break",
+ "label": "Card 1",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_1_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_1_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_2",
+ "fieldtype": "Section Break",
+ "label": "Card 2",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_2_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_2_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_3",
+ "fieldtype": "Section Break",
+ "label": "Card 3",
+ "options": "",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_3_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_3_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_4",
+ "fieldtype": "Section Break",
+ "label": "Card 4",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_4_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_4_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_5",
+ "fieldtype": "Section Break",
+ "label": "Card 5",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_5_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_5_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_6",
+ "fieldtype": "Section Break",
+ "label": "Card 6",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_6_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_6_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_7",
+ "fieldtype": "Section Break",
+ "label": "Card 7",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_7_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_7_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_8",
+ "fieldtype": "Section Break",
+ "label": "Card 8",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_8_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_8_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_9",
+ "fieldtype": "Section Break",
+ "label": "Card 9",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_9_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_9_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_10",
+ "fieldtype": "Section Break",
+ "label": "Card 10",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_10_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_10_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_11",
+ "fieldtype": "Section Break",
+ "label": "Card 11",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_11_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_11_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_12",
+ "fieldtype": "Section Break",
+ "label": "Card 12",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_12_item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "fieldname": "card_12_featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "reqd": 0
+ }
+ ],
+ "idx": 0,
+ "modified": "2020-11-19 18:48:52.633045",
+ "modified_by": "Administrator",
+ "module": "Shopping Cart",
+ "name": "Item Card Group",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "type": "Section"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/shopping_cart/web_template/product_card/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/shopping_cart/web_template/product_card/__init__.py
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/shopping_cart/web_template/product_card/product_card.html
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/shopping_cart/web_template/product_card/product_card.html
diff --git a/erpnext/shopping_cart/web_template/product_card/product_card.json b/erpnext/shopping_cart/web_template/product_card/product_card.json
new file mode 100644
index 0000000..1059c1b
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/product_card/product_card.json
@@ -0,0 +1,33 @@
+{
+ "__unsaved": 1,
+ "creation": "2020-11-17 15:28:47.809342",
+ "docstatus": 0,
+ "doctype": "Web Template",
+ "fields": [
+ {
+ "__unsaved": 1,
+ "fieldname": "item",
+ "fieldtype": "Link",
+ "label": "Item",
+ "options": "Item",
+ "reqd": 0
+ },
+ {
+ "__unsaved": 1,
+ "fieldname": "featured",
+ "fieldtype": "Check",
+ "label": "Featured",
+ "options": "",
+ "reqd": 0
+ }
+ ],
+ "idx": 0,
+ "modified": "2020-11-17 15:33:34.982515",
+ "modified_by": "Administrator",
+ "module": "Shopping Cart",
+ "name": "Product Card",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "type": "Component"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/shopping_cart/web_template/product_category_cards/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/shopping_cart/web_template/product_category_cards/__init__.py
diff --git a/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.html b/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.html
new file mode 100644
index 0000000..06b76af
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.html
@@ -0,0 +1,40 @@
+{%- macro card(title, image, url, text_primary=False) -%}
+{%- set align_class = resolve_class({
+ 'text-right': text_primary,
+ 'text-centre': align == 'Center',
+ 'text-left': align == 'Left',
+}) -%}
+<div class="card h-100">
+ {% if image %}
+ <img class="card-img-top" src="{{ image }}" alt="{{ title }}">
+ {% endif %}
+ <div class="card-body text-center text-muted small">
+ {{ title or '' }}
+ </div>
+ <a href="{{ url or '#' }}" class="stretched-link"></a>
+</div>
+{%- endmacro -%}
+
+<div class="section-with-cards product-category-section">
+ {%- if title -%}
+ <h2 class="section-title">{{ title }}</h2>
+ {%- endif -%}
+ {%- if subtitle -%}
+ <p class="section-description">{{ subtitle }}</p>
+ {%- endif -%}
+ <!-- {%- set card_size = card_size or 'Small' -%} -->
+ <div class="{{ resolve_class({'mt-6': title}) }}">
+ <div class="card-grid">
+ {%- for index in ['1', '2', '3', '4', '5', '6', '7', '8'] -%}
+ {%- set category = values['category_' + index] -%}
+ {%- if category -%}
+ {%- set category = frappe.get_doc("Item Group", category) -%}
+ {{ card(category.name, category.image, category.route) }}
+ {%- endif -%}
+ {%- endfor -%}
+ </div>
+ </div>
+</div>
+
+<style>
+</style>
diff --git a/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.json b/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.json
new file mode 100644
index 0000000..ba5f63b
--- /dev/null
+++ b/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.json
@@ -0,0 +1,85 @@
+{
+ "__unsaved": 1,
+ "creation": "2020-11-17 15:25:50.855934",
+ "docstatus": 0,
+ "doctype": "Web Template",
+ "fields": [
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 1
+ },
+ {
+ "fieldname": "subtitle",
+ "fieldtype": "Data",
+ "label": "Subtitle",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_1",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_2",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_3",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_4",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_5",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_6",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_7",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ },
+ {
+ "fieldname": "category_8",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 0
+ }
+ ],
+ "idx": 0,
+ "modified": "2020-11-18 17:26:28.726260",
+ "modified_by": "Administrator",
+ "module": "Shopping Cart",
+ "name": "Product Category Cards",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "type": "Section"
+}
\ No newline at end of file
diff --git a/erpnext/startup/filters.py b/erpnext/startup/filters.py
index a99e49b..ec07329 100644
--- a/erpnext/startup/filters.py
+++ b/erpnext/startup/filters.py
@@ -2,13 +2,13 @@
import frappe
def get_filters_config():
- filters_config = {
+ filters_config = {
"fiscal year": {
"label": "Fiscal Year",
"get_field": "erpnext.accounts.utils.get_fiscal_year_filter_field",
"valid_for_fieldtypes": ["Date", "Datetime", "DateRange"],
"depends_on": "company",
}
- }
+ }
- return filters_config
\ No newline at end of file
+ return filters_config
\ No newline at end of file
diff --git a/erpnext/startup/leaderboard.py b/erpnext/startup/leaderboard.py
index ef238f1..8819a55 100644
--- a/erpnext/startup/leaderboard.py
+++ b/erpnext/startup/leaderboard.py
@@ -12,6 +12,7 @@
{'fieldname': 'outstanding_amount', 'fieldtype': 'Currency'}
],
"method": "erpnext.startup.leaderboard.get_all_customers",
+ "icon": "customer"
},
"Item": {
"fields": [
@@ -23,6 +24,7 @@
{'fieldname': 'available_stock_value', 'fieldtype': 'Currency'}
],
"method": "erpnext.startup.leaderboard.get_all_items",
+ "icon": "stock"
},
"Supplier": {
"fields": [
@@ -31,6 +33,7 @@
{'fieldname': 'outstanding_amount', 'fieldtype': 'Currency'}
],
"method": "erpnext.startup.leaderboard.get_all_suppliers",
+ "icon": "buying"
},
"Sales Partner": {
"fields": [
@@ -38,12 +41,14 @@
{'fieldname': 'total_commission', 'fieldtype': 'Currency'}
],
"method": "erpnext.startup.leaderboard.get_all_sales_partner",
+ "icon": "hr"
},
"Sales Person": {
"fields": [
{'fieldname': 'total_sales_amount', 'fieldtype': 'Currency'}
],
"method": "erpnext.startup.leaderboard.get_all_sales_person",
+ "icon": "customer"
}
}
diff --git a/erpnext/stock/__init__.py b/erpnext/stock/__init__.py
index 8d64efe..283f7d5 100644
--- a/erpnext/stock/__init__.py
+++ b/erpnext/stock/__init__.py
@@ -38,7 +38,7 @@
frappe.flags.warehouse_account_map[company] = warehouse_account
else:
frappe.flags.warehouse_account_map = warehouse_account
-
+
return frappe.flags.warehouse_account_map.get(company) or frappe.flags.warehouse_account_map
def get_warehouse_account(warehouse, warehouse_account=None):
@@ -65,9 +65,13 @@
account = get_company_default_inventory_account(warehouse.company)
if not account and warehouse.company:
+ account = frappe.db.get_value('Account',
+ {'account_type': 'Stock', 'is_group': 0, 'company': warehouse.company}, 'name')
+
+ if not account and warehouse.company and not warehouse.is_group:
frappe.throw(_("Please set Account in Warehouse {0} or Default Inventory Account in Company {1}")
.format(warehouse.name, warehouse.company))
return account
def get_company_default_inventory_account(company):
- return frappe.get_cached_value('Company', company, 'default_inventory_account')
+ return frappe.get_cached_value('Company', company, 'default_inventory_account')
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index 9bd03d4..95cb92b 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -24,6 +24,16 @@
handle_move_add($(this), "Add")
});
+ this.content.on('click', '.btn-edit', function() {
+ let item = unescape($(this).attr('data-item'));
+ let warehouse = unescape($(this).attr('data-warehouse'));
+ let company = unescape($(this).attr('data-company'));
+ frappe.db.get_value('Putaway Rule',
+ {'item_code': item, 'warehouse': warehouse, 'company': company}, 'name', (r) => {
+ frappe.set_route("Form", "Putaway Rule", r.name);
+ });
+ });
+
function handle_move_add(element, action) {
let item = unescape(element.attr('data-item'));
let warehouse = unescape(element.attr('data-warehouse'));
@@ -59,7 +69,7 @@
// more
this.content.find('.btn-more').on('click', function() {
- me.start += 20;
+ me.start += me.page_length;
me.refresh();
});
@@ -69,33 +79,43 @@
this.before_refresh();
}
+ let args = {
+ item_code: this.item_code,
+ warehouse: this.warehouse,
+ parent_warehouse: this.parent_warehouse,
+ item_group: this.item_group,
+ company: this.company,
+ start: this.start,
+ sort_by: this.sort_by,
+ sort_order: this.sort_order
+ };
+
var me = this;
frappe.call({
- method: 'erpnext.stock.dashboard.item_dashboard.get_data',
- args: {
- item_code: this.item_code,
- warehouse: this.warehouse,
- item_group: this.item_group,
- start: this.start,
- sort_by: this.sort_by,
- sort_order: this.sort_order,
- },
+ method: this.method,
+ args: args,
callback: function(r) {
me.render(r.message);
}
});
},
render: function(data) {
- if(this.start===0) {
+ if (this.start===0) {
this.max_count = 0;
this.result.empty();
}
- var context = this.get_item_dashboard_data(data, this.max_count, true);
+ let context = "";
+ if (this.page_name === "warehouse-capacity-summary") {
+ context = this.get_capacity_dashboard_data(data);
+ } else {
+ context = this.get_item_dashboard_data(data, this.max_count, true);
+ }
+
this.max_count = this.max_count;
// show more button
- if(data && data.length===21) {
+ if (data && data.length===(this.page_length + 1)) {
this.content.find('.more').removeClass('hidden');
// remove the last element
@@ -106,12 +126,17 @@
// If not any stock in any warehouses provide a message to end user
if (context.data.length > 0) {
- $(frappe.render_template('item_dashboard_list', context)).appendTo(this.result);
+ this.content.find('.result').css('text-align', 'unset');
+ $(frappe.render_template(this.template, context)).appendTo(this.result);
} else {
- var message = __("Currently no stock available in any warehouse");
- $(`<span class='text-muted small'> ${message} </span>`).appendTo(this.result);
+ var message = __("No Stock Available Currently");
+ this.content.find('.result').css('text-align', 'center');
+
+ $(`<div class='text-muted' style='margin: 20px 5px;'>
+ ${message} </div>`).appendTo(this.result);
}
},
+
get_item_dashboard_data: function(data, max_count, show_item) {
if(!max_count) max_count = 0;
if(!data) data = [];
@@ -128,8 +153,8 @@
d.total_reserved, max_count);
});
- var can_write = 0;
- if(frappe.boot.user.can_write.indexOf("Stock Entry")>=0){
+ let can_write = 0;
+ if (frappe.boot.user.can_write.indexOf("Stock Entry") >= 0) {
can_write = 1;
}
@@ -138,9 +163,27 @@
max_count: max_count,
can_write:can_write,
show_item: show_item || false
+ };
+ },
+
+ get_capacity_dashboard_data: function(data) {
+ if (!data) data = [];
+
+ data.forEach(function(d) {
+ d.color = d.percent_occupied >=80 ? "#f8814f" : "#2490ef";
+ });
+
+ let can_write = 0;
+ if (frappe.boot.user.can_write.indexOf("Putaway Rule") >= 0) {
+ can_write = 1;
}
+
+ return {
+ data: data,
+ can_write: can_write,
+ };
}
-})
+});
erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) {
var dialog = new frappe.ui.Dialog({
@@ -198,7 +241,7 @@
freeze: true,
callback: function(r) {
frappe.show_alert(__('Stock Entry {0} created',
- ['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
+ ['<a href="/app/stock-entry/'+r.message.name+'">' + r.message.name+ '</a>']));
dialog.hide();
callback(r);
},
diff --git a/erpnext/stock/dashboard/item_dashboard_list.html b/erpnext/stock/dashboard/item_dashboard_list.html
index e1914ed..0c10be4 100644
--- a/erpnext/stock/dashboard/item_dashboard_list.html
+++ b/erpnext/stock/dashboard/item_dashboard_list.html
@@ -1,10 +1,10 @@
{% for d in data %}
<div class="dashboard-list-item">
<div class="row">
- <div class="col-sm-3 small" style="margin-top: 8px;">
+ <div class="col-sm-3" style="margin-top: 8px;">
<a data-type="warehouse" data-name="{{ d.warehouse }}">{{ d.warehouse }}</a>
</div>
- <div class="col-sm-3 small" style="margin-top: 8px;">
+ <div class="col-sm-3" style="margin-top: 8px;">
{% if show_item %}
<a data-type="item"
data-name="{{ d.item_code }}">{{ d.item_code }}
@@ -12,7 +12,7 @@
</a>
{% endif %}
</div>
- <div class="col-sm-4 small">
+ <div class="col-sm-4">
<span class="inline-graph">
<span class="inline-graph-half" title="{{ __("Reserved Qty") }}">
<span class="inline-graph-count">{{ d.total_reserved }}</span>
@@ -40,7 +40,7 @@
</span>
</div>
{% if can_write %}
- <div class="col-sm-2 text-right" style="margin-top: 8px;">
+ <div class="col-sm-2 text-right" style="margin: var(--margin-sm) 0;">
{% if d.actual_qty %}
<button class="btn btn-default btn-xs btn-move"
data-disable_quick_entry="{{ d.disable_quick_entry }}"
diff --git a/erpnext/stock/dashboard/warehouse_capacity_dashboard.py b/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
new file mode 100644
index 0000000..ab573e5
--- /dev/null
+++ b/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
@@ -0,0 +1,69 @@
+from __future__ import unicode_literals
+
+import frappe
+from frappe.model.db_query import DatabaseQuery
+from frappe.utils import nowdate
+from frappe.utils import flt
+from erpnext.stock.utils import get_stock_balance
+
+@frappe.whitelist()
+def get_data(item_code=None, warehouse=None, parent_warehouse=None,
+ company=None, start=0, sort_by="stock_capacity", sort_order="desc"):
+ """Return data to render the warehouse capacity dashboard."""
+ filters = get_filters(item_code, warehouse, parent_warehouse, company)
+
+ no_permission, filters = get_warehouse_filter_based_on_permissions(filters)
+ if no_permission:
+ return []
+
+ capacity_data = get_warehouse_capacity_data(filters, start)
+
+ asc_desc = -1 if sort_order == "desc" else 1
+ capacity_data = sorted(capacity_data, key = lambda i: (i[sort_by] * asc_desc))
+
+ return capacity_data
+
+def get_filters(item_code=None, warehouse=None, parent_warehouse=None,
+ company=None):
+ filters = [['disable', '=', 0]]
+ if item_code:
+ filters.append(['item_code', '=', item_code])
+ if warehouse:
+ filters.append(['warehouse', '=', warehouse])
+ if company:
+ filters.append(['company', '=', company])
+ if parent_warehouse:
+ lft, rgt = frappe.db.get_value("Warehouse", parent_warehouse, ["lft", "rgt"])
+ warehouses = frappe.db.sql_list("""
+ select name from `tabWarehouse`
+ where lft >=%s and rgt<=%s
+ """, (lft, rgt))
+ filters.append(['warehouse', 'in', warehouses])
+ return filters
+
+def get_warehouse_filter_based_on_permissions(filters):
+ try:
+ # check if user has any restrictions based on user permissions on warehouse
+ if DatabaseQuery('Warehouse', user=frappe.session.user).build_match_conditions():
+ filters.append(['warehouse', 'in', [w.name for w in frappe.get_list('Warehouse')]])
+ return False, filters
+ except frappe.PermissionError:
+ # user does not have access on warehouse
+ return True, []
+
+def get_warehouse_capacity_data(filters, start):
+ capacity_data = frappe.db.get_all('Putaway Rule',
+ fields=['item_code', 'warehouse','stock_capacity', 'company'],
+ filters=filters,
+ limit_start=start,
+ limit_page_length='11'
+ )
+
+ for entry in capacity_data:
+ balance_qty = get_stock_balance(entry.item_code, entry.warehouse, nowdate()) or 0
+ entry.update({
+ 'actual_qty': balance_qty,
+ 'percent_occupied': flt((flt(balance_qty) / flt(entry.stock_capacity)) * 100, 0)
+ })
+
+ return capacity_data
\ No newline at end of file
diff --git a/erpnext/stock/desk_page/stock/stock.json b/erpnext/stock/desk_page/stock/stock.json
deleted file mode 100644
index 2fba5fa..0000000
--- a/erpnext/stock/desk_page/stock/stock.json
+++ /dev/null
@@ -1,124 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Items and Pricing",
- "links": "[\n {\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shipping Rule\",\n \"name\": \"Shipping Rule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Item Alternative\",\n \"name\": \"Item Alternative\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Item Manufacturer\",\n \"name\": \"Item Manufacturer\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Stock Transactions",
- "links": "[\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Entry\",\n \"name\": \"Stock Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"label\": \"Delivery Note\",\n \"name\": \"Delivery Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Receipt\",\n \"name\": \"Purchase Receipt\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Pick List\",\n \"name\": \"Pick List\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Delivery Trip\",\n \"name\": \"Delivery Trip\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Stock Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Stock Ledger Entry\",\n \"is_query_report\": true,\n \"label\": \"Stock Ledger\",\n \"name\": \"Stock Ledger\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Stock Ledger Entry\",\n \"is_query_report\": true,\n \"label\": \"Stock Balance\",\n \"name\": \"Stock Balance\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Stock Projected Qty\",\n \"name\": \"Stock Projected Qty\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Summary\",\n \"name\": \"stock-balance\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Stock Ageing\",\n \"name\": \"Stock Ageing\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Item Price Stock\",\n \"name\": \"Item Price Stock\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"label\": \"Stock Settings\",\n \"name\": \"Stock Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Warehouse\",\n \"name\": \"Warehouse\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Unit of Measure (UOM)\",\n \"name\": \"UOM\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Item Variant Settings\",\n \"name\": \"Item Variant Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Brand\",\n \"name\": \"Brand\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Item Attribute\",\n \"name\": \"Item Attribute\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Serial No and Batch",
- "links": "[\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Serial No\",\n \"name\": \"Serial No\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Batch\",\n \"name\": \"Batch\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Installation Note\",\n \"name\": \"Installation Note\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Serial No\"\n ],\n \"doctype\": \"Serial No\",\n \"label\": \"Serial No Service Contract Expiry\",\n \"name\": \"Serial No Service Contract Expiry\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Serial No\"\n ],\n \"doctype\": \"Serial No\",\n \"label\": \"Serial No Status\",\n \"name\": \"Serial No Status\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Serial No\"\n ],\n \"doctype\": \"Serial No\",\n \"label\": \"Serial No Warranty Expiry\",\n \"name\": \"Serial No Warranty Expiry\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Tools",
- "links": "[\n {\n \"label\": \"Stock Reconciliation\",\n \"name\": \"Stock Reconciliation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Landed Cost Voucher\",\n \"name\": \"Landed Cost Voucher\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Packing Slip\",\n \"name\": \"Packing Slip\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quality Inspection\",\n \"name\": \"Quality Inspection\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quality Inspection Template\",\n \"name\": \"Quality Inspection Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quick Stock Balance\",\n \"name\": \"Quick Stock Balance\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Key Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Item Price\"\n ],\n \"doctype\": \"Item Price\",\n \"is_query_report\": false,\n \"label\": \"Item-wise Price List Rate\",\n \"name\": \"Item-wise Price List Rate\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Stock Entry\"\n ],\n \"doctype\": \"Stock Entry\",\n \"is_query_report\": true,\n \"label\": \"Stock Analytics\",\n \"name\": \"Stock Analytics\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Stock Qty vs Serial No Count\",\n \"name\": \"Stock Qty vs Serial No Count\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Delivery Note\"\n ],\n \"doctype\": \"Delivery Note\",\n \"is_query_report\": true,\n \"label\": \"Delivery Note Trends\",\n \"name\": \"Delivery Note Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Receipt\"\n ],\n \"doctype\": \"Purchase Receipt\",\n \"is_query_report\": true,\n \"label\": \"Purchase Receipt Trends\",\n \"name\": \"Purchase Receipt Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Order Analysis\",\n \"name\": \"Sales Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Order\"\n ],\n \"doctype\": \"Purchase Order\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Analysis\",\n \"name\": \"Purchase Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Bin\"\n ],\n \"doctype\": \"Bin\",\n \"is_query_report\": true,\n \"label\": \"Item Shortage Report\",\n \"name\": \"Item Shortage Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Batch\"\n ],\n \"doctype\": \"Batch\",\n \"is_query_report\": true,\n \"label\": \"Batch-Wise Balance History\",\n \"name\": \"Batch-Wise Balance History\",\n \"type\": \"report\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Other Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Material Request\"\n ],\n \"doctype\": \"Material Request\",\n \"is_query_report\": true,\n \"label\": \"Requested Items To Be Transferred\",\n \"name\": \"Requested Items To Be Transferred\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Stock Ledger Entry\"\n ],\n \"doctype\": \"Stock Ledger Entry\",\n \"is_query_report\": true,\n \"label\": \"Batch Item Expiry Status\",\n \"name\": \"Batch Item Expiry Status\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Price List\"\n ],\n \"doctype\": \"Price List\",\n \"is_query_report\": true,\n \"label\": \"Item Prices\",\n \"name\": \"Item Prices\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Itemwise Recommended Reorder Level\",\n \"name\": \"Itemwise Recommended Reorder Level\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Item Variant Details\",\n \"name\": \"Item Variant Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Order\"\n ],\n \"doctype\": \"Purchase Order\",\n \"is_query_report\": true,\n \"label\": \"Subcontracted Raw Materials To Be Transferred\",\n \"name\": \"Subcontracted Raw Materials To Be Transferred\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Order\"\n ],\n \"doctype\": \"Purchase Order\",\n \"is_query_report\": true,\n \"label\": \"Subcontracted Item To Be Received\",\n \"name\": \"Subcontracted Item To Be Received\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Stock Ledger Entry\"\n ],\n \"doctype\": \"Stock Ledger Entry\",\n \"is_query_report\": true,\n \"label\": \"Stock and Account Value Comparison\",\n \"name\": \"Stock and Account Value Comparison\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "cards_label": "Masters & Reports",
- "category": "Modules",
- "charts": [
- {
- "chart_name": "Warehouse wise Stock Value"
- }
- ],
- "creation": "2020-03-02 15:43:10.096528",
- "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": "Stock",
- "modified": "2020-08-11 17:29:32.626067",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Stock",
- "onboarding": "Stock",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#cef6d1",
- "format": "{} Available",
- "label": "Item",
- "link_to": "Item",
- "stats_filter": "{\n \"disabled\" : 0\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} Pending",
- "label": "Material Request",
- "link_to": "Material Request",
- "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Pending\"\n}",
- "type": "DocType"
- },
- {
- "label": "Stock Entry",
- "link_to": "Stock Entry",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} To Bill",
- "label": "Purchase Receipt",
- "link_to": "Purchase Receipt",
- "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Bill\"\n}",
- "type": "DocType"
- },
- {
- "color": "#ffe8cd",
- "format": "{} To Bill",
- "label": "Delivery Note",
- "link_to": "Delivery Note",
- "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Bill\"\n}",
- "type": "DocType"
- },
- {
- "label": "Stock Ledger",
- "link_to": "Stock Ledger",
- "type": "Report"
- },
- {
- "label": "Stock Balance",
- "link_to": "Stock Balance",
- "type": "Report"
- },
- {
- "label": "Dashboard",
- "link_to": "Stock",
- "type": "Dashboard"
- }
- ],
- "shortcuts_label": "Quick Access"
-}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/batch/batch.js b/erpnext/stock/doctype/batch/batch.js
index e2ea7f9..3b07e4e 100644
--- a/erpnext/stock/doctype/batch/batch.js
+++ b/erpnext/stock/doctype/batch/batch.js
@@ -47,8 +47,7 @@
return;
}
- var section = frm.dashboard.add_section(`<h5 style="margin-top: 0px;">
- ${ __("Stock Levels") }</a></h5>`);
+ const section = frm.dashboard.add_section('', __("Stock Levels"));
// sort by qty
r.message.sort(function(a, b) { a.qty > b.qty ? 1 : -1 });
@@ -103,7 +102,7 @@
},
callback: (r) => {
frappe.show_alert(__('Stock Entry {0} created',
- ['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
+ ['<a href="/app/stock-entry/'+r.message.name+'">' + r.message.name+ '</a>']));
frm.refresh();
},
});
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index c8424f1..8fdda56 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -93,7 +93,7 @@
if create_new_batch:
if batch_number_series:
- self.batch_id = make_autoname(batch_number_series)
+ self.batch_id = make_autoname(batch_number_series, doc=self)
elif batch_uses_naming_series():
self.batch_id = self.get_name_from_naming_series()
else:
diff --git a/erpnext/stock/doctype/batch/batch_list.js b/erpnext/stock/doctype/batch/batch_list.js
index d4f74c3..0de9fd0 100644
--- a/erpnext/stock/doctype/batch/batch_list.js
+++ b/erpnext/stock/doctype/batch/batch_list.js
@@ -2,9 +2,9 @@
add_fields: ["item", "expiry_date", "batch_qty", "disabled"],
get_indicator: (doc) => {
if (doc.disabled) {
- return [__("Disabled"), "darkgrey", "disabled,=,1"];
+ return [__("Disabled"), "gray", "disabled,=,1"];
} else if (!doc.batch_qty) {
- return [__("Empty"), "darkgrey", "batch_qty,=,0|disabled,=,0"];
+ return [__("Empty"), "gray", "batch_qty,=,0|disabled,=,0"];
} else if (doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
return [__("Expired"), "red", "expiry_date,not in,|expiry_date,<=,Today|batch_qty,>,0|disabled,=,0"]
} else {
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 1fce504..cbd272d 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -8,13 +8,10 @@
from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
from frappe.utils import cint, flt
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.stock.get_item_details import get_item_details
class TestBatch(unittest.TestCase):
-
- def setUp(self):
- set_perpetual_inventory(0)
-
def test_item_has_batch_enabled(self):
self.assertRaises(ValidationError, frappe.get_doc({
"doctype": "Batch",
@@ -187,7 +184,7 @@
stock_entry.cancel()
current_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
self.assertEqual(current_batch_qty, existing_batch_qty)
-
+
@classmethod
def make_new_batch_and_entry(cls, item_name, batch_name, warehouse):
'''Make a new stock entry for given target warehouse and batch name of item'''
@@ -256,3 +253,84 @@
batch.insert()
return batch
+
+ def test_batch_wise_item_price(self):
+ if not frappe.db.get_value('Item', '_Test Batch Price Item'):
+ frappe.get_doc({
+ 'doctype': 'Item',
+ 'is_stock_item': 1,
+ 'item_code': '_Test Batch Price Item',
+ 'item_group': 'Products',
+ 'has_batch_no': 1,
+ 'create_new_batch': 1
+ }).insert(ignore_permissions=True)
+
+ batch1 = create_batch('_Test Batch Price Item', 200, 1)
+ batch2 = create_batch('_Test Batch Price Item', 300, 1)
+ batch3 = create_batch('_Test Batch Price Item', 400, 0)
+
+ args = frappe._dict({
+ "item_code": "_Test Batch Price Item",
+ "company": "_Test Company with perpetual inventory",
+ "price_list": "_Test Price List",
+ "currency": "_Test Currency",
+ "doctype": "Sales Invoice",
+ "conversion_rate": 1,
+ "price_list_currency": "_Test Currency",
+ "plc_conversion_rate": 1,
+ "customer": "_Test Customer",
+ "name": None
+ })
+
+ #test price for batch1
+ args.update({'batch_no': batch1})
+ details = get_item_details(args)
+ self.assertEqual(details.get('price_list_rate'), 200)
+
+ #test price for batch2
+ args.update({'batch_no': batch2})
+ details = get_item_details(args)
+ self.assertEqual(details.get('price_list_rate'), 300)
+
+ #test price for batch3
+ args.update({'batch_no': batch3})
+ details = get_item_details(args)
+ self.assertEqual(details.get('price_list_rate'), 400)
+
+def create_batch(item_code, rate, create_item_price_for_batch):
+ pi = make_purchase_invoice(company="_Test Company",
+ warehouse= "Stores - _TC", cost_center = "Main - _TC", update_stock=1,
+ expense_account ="_Test Account Cost for Goods Sold - _TC", item_code=item_code)
+
+ batch = frappe.db.get_value('Batch', {'item': item_code, 'reference_name': pi.name})
+
+ if not create_item_price_for_batch:
+ create_price_list_for_batch(item_code, None, rate)
+ else:
+ create_price_list_for_batch(item_code, batch, rate)
+
+ return batch
+
+def create_price_list_for_batch(item_code, batch, rate):
+ frappe.get_doc({
+ 'doctype': 'Item Price',
+ 'item_code': '_Test Batch Price Item',
+ 'price_list': '_Test Price List',
+ 'batch_no': batch,
+ 'price_list_rate': rate
+ }).insert()
+
+def make_new_batch(**args):
+ args = frappe._dict(args)
+
+ try:
+ batch = frappe.get_doc({
+ "doctype": "Batch",
+ "batch_id": args.batch_id,
+ "item": args.item_code,
+ }).insert()
+
+ except frappe.DuplicateEntryError:
+ batch = frappe.get_doc("Batch", args.batch_id)
+
+ return batch
\ No newline at end of file
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 7acdec7..0514bd2 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -18,20 +18,31 @@
self.update_qty(args)
if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
- from erpnext.stock.stock_ledger import update_entries_after
+ from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
if not args.get("posting_date"):
args["posting_date"] = nowdate()
+ if args.get("is_cancelled") and via_landed_cost_voucher:
+ return
+
+ # Reposts only current voucher SL Entries
+ # Updates valuation rate, stock value, stock queue for current transaction
update_entries_after({
"item_code": self.item_code,
"warehouse": self.warehouse,
"posting_date": args.get("posting_date"),
"posting_time": args.get("posting_time"),
+ "voucher_type": args.get("voucher_type"),
"voucher_no": args.get("voucher_no"),
- "sle_id": args.sle_id
+ "sle_id": args.name,
+ "creation": args.creation
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
+ # update qty in future ale and Validate negative qty
+ update_qty_in_future_sle(args, allow_negative_stock)
+
+
def update_qty(self, args):
# update the stock values (for current quantities)
if args.get("voucher_type")=="Stock Reconciliation":
@@ -43,7 +54,7 @@
self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty"))
self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty"))
self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty"))
-
+
self.set_projected_qty()
self.db_update()
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 19d0bec..334bdea 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -7,14 +7,16 @@
frappe.provide("erpnext.stock");
frappe.provide("erpnext.stock.delivery_note");
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Delivery Note", {
setup: function(frm) {
frm.custom_make_buttons = {
'Packing Slip': 'Packing Slip',
'Installation Note': 'Installation Note',
- 'Sales Invoice': 'Invoice',
+ 'Sales Invoice': 'Sales Invoice',
'Stock Entry': 'Return',
+ 'Shipment': 'Shipment'
},
frm.set_indicator_formatter('item_code',
function(doc) {
@@ -75,7 +77,7 @@
}
});
-
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
print_without_amount: function(frm) {
@@ -93,13 +95,19 @@
frm.page.set_inner_btn_group_as_primary(__('Create'));
}
- if (frm.doc.docstatus === 1 && frm.doc.is_internal_customer && !frm.doc.inter_company_reference) {
- frm.add_custom_button(__('Purchase Receipt'), function() {
- frappe.model.open_mapped_doc({
- method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt',
- frm: frm,
- })
- }, __('Create'));
+ if (frm.doc.docstatus == 1 && !frm.doc.inter_company_reference) {
+ let internal = me.frm.doc.is_internal_customer;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Receipt" :
+ "Inter Company Purchase Receipt";
+
+ me.frm.add_custom_button(button_label, function() {
+ frappe.model.open_mapped_doc({
+ method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt',
+ frm: frm,
+ });
+ }, __('Create'));
+ }
}
}
});
@@ -151,11 +159,16 @@
project: me.frm.doc.project || undefined,
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
}
}
if (!doc.is_return && doc.status!="Closed") {
+ if(doc.docstatus == 1) {
+ this.frm.add_custom_button(__('Shipment'), function() {
+ me.make_shipment() }, __('Create'));
+ }
+
if(flt(doc.per_installed, 2) < 100 && doc.docstatus==1)
this.frm.add_custom_button(__('Installation Note'), function() {
me.make_installation_note() }, __('Create'));
@@ -220,6 +233,13 @@
}
},
+ make_shipment: function() {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.delivery_note.delivery_note.make_shipment",
+ frm: this.frm
+ })
+ },
+
make_sales_invoice: function() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
@@ -283,15 +303,6 @@
}
})
},
-
- to_warehouse: function() {
- let packed_items_table = this.frm.doc["packed_items"];
- this.autofill_warehouse(this.frm.doc["items"], "target_warehouse", this.frm.doc.to_warehouse);
- if (packed_items_table && packed_items_table.length) {
- this.autofill_warehouse(packed_items_table, "target_warehouse", this.frm.doc.to_warehouse);
- }
- }
-
});
$.extend(cur_frm.cscript, new erpnext.stock.DeliveryNoteController({frm: cur_frm}));
@@ -305,6 +316,7 @@
company: function(frm) {
frm.trigger("unhide_account_head");
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
unhide_account_head: function(frm) {
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index ea385c8..f595aad 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:09",
@@ -52,7 +53,7 @@
"sec_warehouse",
"set_warehouse",
"col_break_warehouse",
- "to_warehouse",
+ "set_target_warehouse",
"items_section",
"scan_barcode",
"items",
@@ -116,6 +117,7 @@
"source",
"column_break5",
"is_internal_customer",
+ "represents_company",
"inter_company_reference",
"per_billed",
"customer_group",
@@ -132,6 +134,7 @@
"per_installed",
"installation_status",
"column_break_89",
+ "per_returned",
"excise_page",
"instructions",
"subscription_section",
@@ -413,7 +416,8 @@
{
"fieldname": "company_address_display",
"fieldtype": "Small Text",
- "label": "Company Address"
+ "label": "Company Address",
+ "read_only": 1
},
{
"collapsible": 1,
@@ -500,18 +504,6 @@
"fieldtype": "Column Break"
},
{
- "description": "Required only for sample item.",
- "fieldname": "to_warehouse",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "To Warehouse",
- "no_copy": 1,
- "oldfieldname": "to_warehouse",
- "oldfieldtype": "Link",
- "options": "Warehouse",
- "print_hide": 1
- },
- {
"fieldname": "items_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
@@ -1097,7 +1089,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nTo Bill\nCompleted\nCancelled\nClosed",
+ "options": "\nDraft\nTo Bill\nCompleted\nReturn Issued\nCancelled\nClosed",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
@@ -1249,13 +1241,43 @@
"fieldtype": "Link",
"label": "Inter Company Reference",
"options": "Purchase Receipt"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "per_returned",
+ "fieldtype": "Percent",
+ "label": "% Returned",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.is_internal_customer",
+ "fieldname": "set_target_warehouse",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Set Target Warehouse",
+ "no_copy": 1,
+ "oldfieldname": "to_warehouse",
+ "oldfieldtype": "Link",
+ "options": "Warehouse",
+ "print_hide": 1
+ },
+ {
+ "description": "Company which internal customer represents.",
+ "fetch_from": "customer.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
+ "read_only": 1
}
],
"icon": "fa fa-truck",
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-03 23:18:47.739997",
+ "modified": "2020-12-26 17:07:59.194403",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index d04cf78..3544390 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -55,7 +55,7 @@
'no_allowance': 1
}]
if cint(self.is_return):
- self.status_updater.append({
+ self.status_updater.extend([{
'source_dt': 'Delivery Note Item',
'target_dt': 'Sales Order Item',
'join_field': 'so_detail',
@@ -69,9 +69,21 @@
where name=`tabDelivery Note Item`.parent and is_return=1)""",
'second_source_extra_cond': """ and exists (select name from `tabSales Invoice`
where name=`tabSales Invoice Item`.parent and is_return=1 and update_stock=1)"""
- })
+ },
+ {
+ 'source_dt': 'Delivery Note Item',
+ 'target_dt': 'Delivery Note Item',
+ 'join_field': 'dn_detail',
+ 'target_field': 'returned_qty',
+ 'target_parent_dt': 'Delivery Note',
+ 'target_parent_field': 'per_returned',
+ 'target_ref_field': 'stock_qty',
+ 'source_field': '-1 * stock_qty',
+ 'percent_join_field_parent': 'return_against'
+ }
+ ])
- def before_print(self):
+ def before_print(self, settings=None):
def toggle_print_hide(meta, fieldname):
df = meta.get_field(fieldname)
if self.get("print_without_amount"):
@@ -205,6 +217,7 @@
# because updating reserved qty in bin depends upon updated delivered qty in SO
self.update_stock_ledger()
self.make_gl_entries()
+ self.repost_future_sle_and_gle()
def on_cancel(self):
super(DeliveryNote, self).on_cancel()
@@ -222,7 +235,8 @@
self.cancel_packing_slips()
self.make_gl_entries_on_cancel()
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+ self.repost_future_sle_and_gle()
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
def check_credit_limit(self):
from erpnext.selling.doctype.customer.customer import check_credit_limit
@@ -569,6 +583,70 @@
return doclist
+@frappe.whitelist()
+def make_shipment(source_name, target_doc=None):
+ def postprocess(source, target):
+ user = frappe.db.get_value("User", frappe.session.user, ['email', 'full_name', 'phone', 'mobile_no'], as_dict=1)
+ target.pickup_contact_email = user.email
+ pickup_contact_display = '{}'.format(user.full_name)
+ if user:
+ if user.email:
+ pickup_contact_display += '<br>' + user.email
+ if user.phone:
+ pickup_contact_display += '<br>' + user.phone
+ if user.mobile_no and not user.phone:
+ pickup_contact_display += '<br>' + user.mobile_no
+ target.pickup_contact = pickup_contact_display
+
+ # As we are using session user details in the pickup_contact then pickup_contact_person will be session user
+ target.pickup_contact_person = frappe.session.user
+
+ contact = frappe.db.get_value("Contact", source.contact_person, ['email_id', 'phone', 'mobile_no'], as_dict=1)
+ delivery_contact_display = '{}'.format(source.contact_display)
+ if contact:
+ if contact.email_id:
+ delivery_contact_display += '<br>' + contact.email_id
+ if contact.phone:
+ delivery_contact_display += '<br>' + contact.phone
+ if contact.mobile_no and not contact.phone:
+ delivery_contact_display += '<br>' + contact.mobile_no
+ target.delivery_contact = delivery_contact_display
+
+ if source.shipping_address_name:
+ target.delivery_address_name = source.shipping_address_name
+ target.delivery_address = source.shipping_address
+ elif source.customer_address:
+ target.delivery_address_name = source.customer_address
+ target.delivery_address = source.address_display
+
+ doclist = get_mapped_doc("Delivery Note", source_name, {
+ "Delivery Note": {
+ "doctype": "Shipment",
+ "field_map": {
+ "grand_total": "value_of_goods",
+ "company": "pickup_company",
+ "company_address": "pickup_address_name",
+ "company_address_display": "pickup_address",
+ "customer": "delivery_customer",
+ "contact_person": "delivery_contact_name",
+ "contact_email": "delivery_contact_email"
+ },
+ "validation": {
+ "docstatus": ["=", 1]
+ }
+ },
+ "Delivery Note Item": {
+ "doctype": "Shipment Delivery Note",
+ "field_map": {
+ "name": "prevdoc_detail_docname",
+ "parent": "prevdoc_docname",
+ "parenttype": "prevdoc_doctype",
+ "base_amount": "grand_total"
+ }
+ }
+ }, target_doc, postprocess)
+
+ return doclist
@frappe.whitelist()
def make_sales_return(source_name, target_doc=None):
@@ -586,7 +664,8 @@
return make_inter_company_transaction("Delivery Note", source_name, target_doc)
def make_inter_company_transaction(doctype, source_name, target_doc=None):
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_transaction, get_inter_company_details
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (validate_inter_company_transaction,
+ get_inter_company_details, update_address, update_taxes, set_purchase_references)
if doctype == 'Delivery Note':
source_doc = frappe.get_doc(doctype, source_name)
@@ -604,6 +683,7 @@
def set_missing_values(source, target):
target.run_method("set_missing_values")
+ set_purchase_references(target)
if target.doctype == 'Purchase Receipt':
master_doctype = 'Purchase Taxes and Charges Template'
@@ -619,21 +699,35 @@
if target_doc.doctype == 'Purchase Receipt':
target_doc.company = details.get("company")
target_doc.supplier = details.get("party")
- target_doc.supplier_address = source_doc.company_address
- target_doc.shipping_address = source_doc.shipping_address_name or source_doc.customer_address
target_doc.buying_price_list = source_doc.selling_price_list
target_doc.is_internal_supplier = 1
target_doc.inter_company_reference = source_doc.name
+
+ # Invert the address on target doc creation
+ update_address(target_doc, 'supplier_address', 'address_display', source_doc.company_address)
+ update_address(target_doc, 'shipping_address', 'shipping_address_display', source_doc.customer_address)
+
+ update_taxes(target_doc, party=target_doc.supplier, party_type='Supplier', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.supplier_address,
+ company_address=target_doc.shipping_address)
else:
target_doc.company = details.get("company")
target_doc.customer = details.get("party")
target_doc.company_address = source_doc.supplier_address
- target_doc.shipping_address_name = source_doc.shipping_address
target_doc.selling_price_list = source_doc.buying_price_list
target_doc.is_internal_customer = 1
target_doc.inter_company_reference = source_doc.name
- doclist = get_mapped_doc(doctype, source_name, {
+ # Invert the address on target doc creation
+ update_address(target_doc, 'company_address', 'company_address_display', source_doc.supplier_address)
+ update_address(target_doc, 'shipping_address_name', 'shipping_address', source_doc.shipping_address)
+ update_address(target_doc, 'customer_address', 'address_display', source_doc.shipping_address)
+
+ update_taxes(target_doc, party=target_doc.customer, party_type='Customer', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.customer_address,
+ company_address=target_doc.company_address, shipping_address_name=target_doc.shipping_address_name)
+
+ doclist = get_mapped_doc(doctype, source_name, {
doctype: {
"doctype": target_doctype,
"postprocess": update_details,
@@ -644,7 +738,10 @@
doctype +" Item": {
"doctype": target_doctype + " Item",
"field_map": {
- source_document_warehouse_field: target_document_warehouse_field
+ source_document_warehouse_field: target_document_warehouse_field,
+ 'name': 'delivery_note_item',
+ 'batch_no': 'batch_no',
+ 'serial_no': 'serial_no'
},
"field_no_map": [
"warehouse"
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
index beeb9eb..47684d5 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
@@ -19,7 +19,7 @@
},
{
'label': _('Reference'),
- 'items': ['Sales Order', 'Quality Inspection']
+ 'items': ['Sales Order', 'Shipment', 'Quality Inspection']
},
{
'label': _('Returns'),
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
index 0ae7c37..f08125b 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
@@ -3,12 +3,14 @@
"transporter_name", "grand_total", "is_return", "status", "currency"],
get_indicator: function(doc) {
if(cint(doc.is_return)==1) {
- return [__("Return"), "darkgrey", "is_return,=,Yes"];
+ return [__("Return"), "gray", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
+ } else if (flt(doc.per_returned, 2) === 100) {
+ return [__("Return Issued"), "grey", "per_returned,=,100"];
} else if (flt(doc.per_billed, 2) < 100) {
return [__("To Bill"), "orange", "per_billed,<,100"];
- } else if (flt(doc.per_billed, 2) == 100) {
+ } else if (flt(doc.per_billed, 2) === 100) {
return [__("Completed"), "green", "per_billed,=,100"];
}
},
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 4b04a0a..d39b229 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -10,8 +10,7 @@
from frappe.utils import cint, nowdate, nowtime, cstr, add_days, flt, today
from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.accounts.utils import get_balance_on
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
- import get_gl_entries, set_perpetual_inventory
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice, make_delivery_trip
from erpnext.stock.doctype.stock_entry.test_stock_entry \
import make_stock_entry, make_serialized_item, get_qty_after_transaction
@@ -24,9 +23,6 @@
from erpnext.stock.doctype.item.test_item import create_item
class TestDeliveryNote(unittest.TestCase):
- def setUp(self):
- set_perpetual_inventory(0)
-
def test_over_billing_against_dn(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
@@ -43,7 +39,6 @@
def test_delivery_note_no_gl_entry(self):
company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(0, company)
make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
stock_queue = json.loads(get_previous_sle({
@@ -57,7 +52,7 @@
sle = frappe.get_doc("Stock Ledger Entry", {"voucher_type": "Delivery Note", "voucher_no": dn.name})
- self.assertEqual(sle.stock_value_difference, -1*stock_queue[0][1])
+ self.assertEqual(sle.stock_value_difference, flt(-1*stock_queue[0][1], 2))
self.assertFalse(get_gl_entries("Delivery Note", dn.name))
@@ -206,7 +201,7 @@
for field, value in field_values.items():
self.assertEqual(cstr(serial_no.get(field)), value)
- def test_sales_return_for_non_bundled_items(self):
+ def test_sales_return_for_non_bundled_items_partial(self):
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
make_stock_entry(item_code="_Test Item", target="Stores - TCP1", qty=50, basic_rate=100)
@@ -225,7 +220,10 @@
# return entry
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-2, rate=500,
- company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
+ company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1",
+ cost_center="Main - TCP1", do_not_submit=1)
+ dn1.items[0].dn_detail = dn.items[0].name
+ dn1.submit()
actual_qty_2 = get_qty_after_transaction(warehouse="Stores - TCP1")
@@ -243,6 +241,70 @@
self.assertEqual(gle_warehouse_amount, stock_value_difference)
+ # hack because new_doc isn't considering is_return portion of status_updater
+ returned = frappe.get_doc("Delivery Note", dn1.name)
+ returned.update_prevdoc_status()
+ dn.load_from_db()
+
+ # Check if Original DN updated
+ self.assertEqual(dn.items[0].returned_qty, 2)
+ self.assertEqual(dn.per_returned, 40)
+
+ from erpnext.controllers.sales_and_purchase_return import make_return_doc
+ return_dn_2 = make_return_doc("Delivery Note", dn.name)
+
+ # Check if unreturned amount is mapped in 2nd return
+ self.assertEqual(return_dn_2.items[0].qty, -3)
+
+ si = make_sales_invoice(dn.name)
+ si.submit()
+
+ self.assertEqual(si.items[0].qty, 3)
+
+ dn.load_from_db()
+ # DN should be completed on billing all unreturned amount
+ self.assertEqual(dn.items[0].billed_amt, 1500)
+ self.assertEqual(dn.per_billed, 100)
+ self.assertEqual(dn.status, 'Completed')
+
+ si.load_from_db()
+ si.cancel()
+
+ dn.load_from_db()
+ self.assertEqual(dn.per_billed, 0)
+
+ dn1.cancel()
+ dn.cancel()
+
+ def test_sales_return_for_non_bundled_items_full(self):
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
+
+ make_item("Box", {'is_stock_item': 1})
+
+ make_stock_entry(item_code="Box", target="Stores - TCP1", qty=10, basic_rate=100)
+
+ dn = create_delivery_note(item_code="Box", qty=5, rate=500, warehouse="Stores - TCP1", company=company,
+ expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
+
+ #return entry
+ dn1 = create_delivery_note(item_code="Box", is_return=1, return_against=dn.name, qty=-5, rate=500,
+ company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1",
+ cost_center="Main - TCP1", do_not_submit=1)
+ dn1.items[0].dn_detail = dn.items[0].name
+ dn1.submit()
+
+ # hack because new_doc isn't considering is_return portion of status_updater
+ returned = frappe.get_doc("Delivery Note", dn1.name)
+ returned.update_prevdoc_status()
+ dn.load_from_db()
+
+ # Check if Original DN updated
+ self.assertEqual(dn.items[0].returned_qty, 5)
+ self.assertEqual(dn.per_returned, 100)
+ self.assertEqual(dn.status, 'Return Issued')
+
def test_return_single_item_from_bundled_items(self):
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
@@ -427,7 +489,10 @@
def test_closed_delivery_note(self):
from erpnext.stock.doctype.delivery_note.delivery_note import update_delivery_note_status
- dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1", do_not_submit=True)
+ make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
+
+ dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1',
+ cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1", do_not_submit=True)
dn.submit()
@@ -442,9 +507,15 @@
self.assertEqual(dn.status, "To Bill")
self.assertEqual(dn.per_billed, 0)
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(dn.po_no, so.po_no)
+
si = make_sales_invoice(dn.name)
si.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(dn.po_no, si.po_no)
+
dn.load_from_db()
self.assertEqual(dn.get("items")[0].billed_amt, 200)
self.assertEqual(dn.per_billed, 100)
@@ -461,16 +532,25 @@
si.insert()
si.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(so.po_no, si.po_no)
+
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
dn1 = make_delivery_note(so.name)
dn1.get("items")[0].qty = 2
dn1.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(so.po_no, dn1.po_no)
+
dn2 = make_delivery_note(so.name)
dn2.get("items")[0].qty = 3
dn2.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(so.po_no, dn2.po_no)
+
dn1.load_from_db()
self.assertEqual(dn1.get("items")[0].billed_amt, 200)
self.assertEqual(dn1.per_billed, 100)
@@ -492,9 +572,15 @@
dn1.get("items")[0].qty = 2
dn1.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(dn1.po_no, so.po_no)
+
si1 = make_sales_invoice(dn1.name)
si1.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(dn1.po_no, si1.po_no)
+
dn1.load_from_db()
self.assertEqual(dn1.per_billed, 100)
@@ -502,10 +588,16 @@
si2.get("items")[0].qty = 4
si2.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(si2.po_no, so.po_no)
+
dn2 = make_delivery_note(so.name)
dn2.get("items")[0].qty = 5
dn2.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(dn2.po_no, so.po_no)
+
dn1.load_from_db()
self.assertEqual(dn1.get("items")[0].billed_amt, 200)
self.assertEqual(dn1.per_billed, 100)
@@ -525,9 +617,15 @@
si = make_sales_invoice(so.name)
si.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(so.po_no, si.po_no)
+
dn = make_delivery_note(si.name)
dn.submit()
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(dn.po_no, si.po_no)
+
self.assertEqual(dn.get("items")[0].billed_amt, 1000)
self.assertEqual(dn.per_billed, 100)
self.assertEqual(dn.status, "Completed")
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 3d57f47..b05090a 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-04-22 13:15:44",
"doctype": "DocType",
@@ -24,7 +25,10 @@
"col_break2",
"uom",
"conversion_factor",
+ "stock_qty_sec_break",
"stock_qty",
+ "stock_qty_col_break",
+ "returned_qty",
"section_break_17",
"price_list_rate",
"base_price_list_rate",
@@ -43,6 +47,7 @@
"base_rate",
"base_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_25",
"net_rate",
@@ -52,6 +57,7 @@
"base_net_rate",
"base_net_amount",
"billed_amt",
+ "incoming_rate",
"item_weight_details",
"weight_per_unit",
"total_weight",
@@ -211,7 +217,7 @@
{
"fieldname": "stock_qty",
"fieldtype": "Float",
- "label": "Qty as per Stock UOM",
+ "label": "Qty in Stock UOM",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
@@ -453,7 +459,7 @@
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "From Warehouse",
+ "label": "Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
@@ -462,11 +468,12 @@
"width": "100px"
},
{
+ "depends_on": "eval:parent.is_internal_customer",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "label": "Customer Warehouse (Optional)",
+ "label": "Target Warehouse",
"no_copy": 1,
"options": "Warehouse",
"print_hide": 1
@@ -715,12 +722,44 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "stock_qty_sec_break",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "stock_qty_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "returned_qty",
+ "fieldname": "returned_qty",
+ "fieldtype": "Float",
+ "label": "Returned Qty in Stock UOM"
+ },
+ {
+ "fieldname": "incoming_rate",
+ "fieldtype": "Currency",
+ "label": "Incoming Rate",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-07-20 12:25:06.177894",
+ "modified": "2021-02-23 01:04:08.588104",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
index aaca802..5030595 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
@@ -5,8 +5,6 @@
import frappe
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
class DeliveryNoteItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index faeeb57..2079cf8 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -81,11 +81,11 @@
}, __('Create'));
}
- frm.page.set_inner_btn_group_as_primary(__('Create'));
+ // frm.page.set_inner_btn_group_as_primary(__('Create'));
}
if (frm.doc.variant_of) {
frm.set_intro(__('This Item is a Variant of {0} (Template).',
- [`<a href="#Form/Item/${frm.doc.variant_of}">${frm.doc.variant_of}</a>`]), true);
+ [`<a href="/app/item/${frm.doc.variant_of}" onclick="location.reload()">${frm.doc.variant_of}</a>`]), true);
}
if (frappe.defaults.get_default("item_naming_by")!="Naming Series" || frm.doc.variant_of) {
@@ -380,11 +380,13 @@
// Show Stock Levels only if is_stock_item
if (frm.doc.is_stock_item) {
frappe.require('assets/js/item-dashboard.min.js', function() {
- var section = frm.dashboard.add_section('<h5 style="margin-top: 0px;">\
- <a href="#stock-balance">' + __("Stock Levels") + '</a></h5>');
+ const section = frm.dashboard.add_section('', __("Stock Levels"));
erpnext.item.item_dashboard = new erpnext.stock.ItemDashboard({
parent: section,
- item_code: frm.doc.name
+ item_code: frm.doc.name,
+ page_length: 20,
+ method: 'erpnext.stock.dashboard.item_dashboard.get_data',
+ template: 'item_dashboard_list'
});
erpnext.item.item_dashboard.refresh();
});
@@ -650,7 +652,7 @@
if (r.message) {
var variant = r.message;
frappe.msgprint_dialog = frappe.msgprint(__("Item Variant {0} already exists with same attributes",
- [repl('<a href="#Form/Item/%(item_encoded)s" class="strong variant-click">%(item)s</a>', {
+ [repl('<a href="/app/item/%(item_encoded)s" class="strong variant-click">%(item)s</a>', {
item_encoded: encodeURIComponent(variant),
item: variant
})]
@@ -715,6 +717,18 @@
.on('focus', function(e) {
$(e.target).val('').trigger('input');
})
+ .on("awesomplete-open", () => {
+ let modal = field.$input.parents('.modal-dialog')[0];
+ if (modal) {
+ $(modal).removeClass("modal-dialog-scrollable");
+ }
+ })
+ .on("awesomplete-close", () => {
+ let modal = field.$input.parents('.modal-dialog')[0];
+ if (modal) {
+ $(modal).addClass("modal-dialog-scrollable");
+ }
+ });
});
},
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index d07b3dc..6fed9ef 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -106,9 +106,9 @@
"item_tax_section_break",
"taxes",
"inspection_criteria",
+ "quality_inspection_template",
"inspection_required_before_purchase",
"inspection_required_before_delivery",
- "quality_inspection_template",
"manufacturing",
"default_bom",
"is_sub_contracted_item",
@@ -521,8 +521,7 @@
"fieldname": "has_variants",
"fieldtype": "Check",
"in_standard_filter": 1,
- "label": "Has Variants",
- "no_copy": 1
+ "label": "Has Variants"
},
{
"default": "Item Attribute",
@@ -538,7 +537,6 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Attributes",
- "no_copy": 1,
"options": "Item Variant Attribute"
},
{
@@ -814,7 +812,6 @@
"label": "Inspection Required before Delivery"
},
{
- "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)",
"fieldname": "quality_inspection_template",
"fieldtype": "Link",
"label": "Quality Inspection Template",
@@ -1057,6 +1054,7 @@
"read_only": 1
},
{
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"fieldname": "website_image_alt",
"fieldtype": "Data",
"label": "Image Description"
@@ -1069,7 +1067,7 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 1,
- "modified": "2020-08-07 14:24:58.384992",
+ "modified": "2021-03-18 14:04:38.575519",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
@@ -1121,6 +1119,15 @@
{
"read": 1,
"role": "Manufacturing User"
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "report": 1,
+ "role": "All",
+ "select": 1,
+ "share": 1
}
],
"quick_entry": 1,
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index d22fda8..7b7d2da 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -177,7 +177,7 @@
if not self.valuation_rate and self.standard_rate:
self.valuation_rate = self.standard_rate
- if not self.valuation_rate:
+ if not self.valuation_rate and not self.is_customer_provided_item:
frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered"))
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -317,6 +317,7 @@
context.search_link = '/product_search'
context.parents = get_parent_item_groups(self.item_group)
+ context.body_class = "product-page"
self.set_variant_context(context)
self.set_attribute_context(context)
@@ -577,8 +578,9 @@
# if barcode is getting updated , the row name has to reset.
# Delete previous old row doc and re-enter row as if new to reset name in db.
item_barcode.set("__islocal", True)
+ item_barcode_entry_name = item_barcode.name
item_barcode.name = None
- frappe.delete_doc("Item Barcode", item_barcode.name)
+ frappe.delete_doc("Item Barcode", item_barcode_entry_name)
def validate_warehouse_for_reorder(self):
'''Validate Reorder level table for duplicate and conditional mandatory'''
@@ -671,13 +673,14 @@
if not records: return
document = _("Stock Reconciliation") if len(records) == 1 else _("Stock Reconciliations")
- msg = _("The items {0} and {1} are present in the following {2} : <br>"
- .format(frappe.bold(old_name), frappe.bold(new_name), document))
+ msg = _("The items {0} and {1} are present in the following {2} : ").format(
+ frappe.bold(old_name), frappe.bold(new_name), document)
+ msg += '<br>'
msg += ', '.join([get_link_to_form("Stock Reconciliation", d.parent) for d in records]) + "<br><br>"
- msg += _("Note: To merge the items, create a separate Stock Reconciliation for the old item {0}"
- .format(frappe.bold(old_name)))
+ msg += _("Note: To merge the items, create a separate Stock Reconciliation for the old item {0}").format(
+ frappe.bold(old_name))
frappe.throw(_(msg), title=_("Merge not allowed"))
@@ -859,7 +862,7 @@
rows = ''
for docname, attr_list in not_included.items():
- link = "<a href='#Form/Item/{0}'>{0}</a>".format(frappe.bold(_(docname)))
+ link = "<a href='/app/Form/Item/{0}'>{0}</a>".format(frappe.bold(_(docname)))
rows += table_row(link, body(attr_list))
error_description = _('The following deleted attributes exist in Variants but not in the Template. You can either delete the Variants or keep the attribute(s) in template.')
@@ -970,23 +973,26 @@
frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(field))))
def check_if_linked_document_exists(self, field):
- linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "Purchase Receipt Item",
+ linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Receipt Item",
"Purchase Invoice Item", "Stock Entry Detail", "Stock Reconciliation Item"]
# For "Is Stock Item", following doctypes is important
# because reserved_qty, ordered_qty and requested_qty updated from these doctypes
if field == "is_stock_item":
- linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item"]
+ linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item", "Product Bundle"]
for doctype in linked_doctypes:
+ filters={"item_code": self.name, "docstatus": 1}
+
+ if doctype == "Product Bundle":
+ filters={"new_item_code": self.name}
+
if doctype in ("Purchase Invoice Item", "Sales Invoice Item",):
# If Invoice has Stock impact, only then consider it.
if self.stock_ledger_created():
return True
- elif frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}) or \
- frappe.db.get_value("Production Order",
- filters={"production_item": self.name, "docstatus": 1}):
+ elif frappe.db.get_value(doctype, filters):
return True
def validate_auto_reorder_enabled_in_stock_settings(self):
@@ -1189,8 +1195,7 @@
if item_code:
item_cache = ItemVariantsCacheManager(item_code)
- item_cache.clear_cache()
-
+ item_cache.rebuild_cache()
def check_stock_uom_with_bin(item, stock_uom):
if stock_uom == frappe.db.get_value("Item", item, "stock_uom"):
diff --git a/erpnext/stock/doctype/item/item_dashboard.py b/erpnext/stock/doctype/item/item_dashboard.py
index dd4676a..b3e4796 100644
--- a/erpnext/stock/doctype/item/item_dashboard.py
+++ b/erpnext/stock/doctype/item/item_dashboard.py
@@ -32,16 +32,16 @@
'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
},
{
+ 'label': _('Manufacture'),
+ 'items': ['Production Plan', 'Work Order', 'Item Manufacturer']
+ },
+ {
'label': _('Traceability'),
'items': ['Serial No', 'Batch']
},
{
'label': _('Move'),
'items': ['Stock Entry']
- },
- {
- 'label': _('Manufacture'),
- 'items': ['Production Plan', 'Work Order', 'Item Manufacturer']
}
]
}
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index cbd5e33..36d0de1 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -104,41 +104,41 @@
def test_item_tax_template(self):
expected_item_tax_template = [
{"item_code": "_Test Item With Item Tax Template", "tax_category": "",
- "item_tax_template": "_Test Account Excise Duty @ 10"},
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC"},
{"item_code": "_Test Item With Item Tax Template", "tax_category": "_Test Tax Category 1",
- "item_tax_template": "_Test Account Excise Duty @ 12"},
+ "item_tax_template": "_Test Account Excise Duty @ 12 - _TC"},
{"item_code": "_Test Item With Item Tax Template", "tax_category": "_Test Tax Category 2",
"item_tax_template": None},
{"item_code": "_Test Item Inherit Group Item Tax Template 1", "tax_category": "",
- "item_tax_template": "_Test Account Excise Duty @ 10"},
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC"},
{"item_code": "_Test Item Inherit Group Item Tax Template 1", "tax_category": "_Test Tax Category 1",
- "item_tax_template": "_Test Account Excise Duty @ 12"},
+ "item_tax_template": "_Test Account Excise Duty @ 12 - _TC"},
{"item_code": "_Test Item Inherit Group Item Tax Template 1", "tax_category": "_Test Tax Category 2",
"item_tax_template": None},
{"item_code": "_Test Item Inherit Group Item Tax Template 2", "tax_category": "",
- "item_tax_template": "_Test Account Excise Duty @ 15"},
+ "item_tax_template": "_Test Account Excise Duty @ 15 - _TC"},
{"item_code": "_Test Item Inherit Group Item Tax Template 2", "tax_category": "_Test Tax Category 1",
- "item_tax_template": "_Test Account Excise Duty @ 12"},
+ "item_tax_template": "_Test Account Excise Duty @ 12 - _TC"},
{"item_code": "_Test Item Inherit Group Item Tax Template 2", "tax_category": "_Test Tax Category 2",
"item_tax_template": None},
{"item_code": "_Test Item Override Group Item Tax Template", "tax_category": "",
- "item_tax_template": "_Test Account Excise Duty @ 20"},
+ "item_tax_template": "_Test Account Excise Duty @ 20 - _TC"},
{"item_code": "_Test Item Override Group Item Tax Template", "tax_category": "_Test Tax Category 1",
- "item_tax_template": "_Test Item Tax Template 1"},
+ "item_tax_template": "_Test Item Tax Template 1 - _TC"},
{"item_code": "_Test Item Override Group Item Tax Template", "tax_category": "_Test Tax Category 2",
"item_tax_template": None},
]
expected_item_tax_map = {
None: {},
- "_Test Account Excise Duty @ 10": {"_Test Account Excise Duty - _TC": 10},
- "_Test Account Excise Duty @ 12": {"_Test Account Excise Duty - _TC": 12},
- "_Test Account Excise Duty @ 15": {"_Test Account Excise Duty - _TC": 15},
- "_Test Account Excise Duty @ 20": {"_Test Account Excise Duty - _TC": 20},
- "_Test Item Tax Template 1": {"_Test Account Excise Duty - _TC": 5, "_Test Account Education Cess - _TC": 10,
+ "_Test Account Excise Duty @ 10 - _TC": {"_Test Account Excise Duty - _TC": 10},
+ "_Test Account Excise Duty @ 12 - _TC": {"_Test Account Excise Duty - _TC": 12},
+ "_Test Account Excise Duty @ 15 - _TC": {"_Test Account Excise Duty - _TC": 15},
+ "_Test Account Excise Duty @ 20 - _TC": {"_Test Account Excise Duty - _TC": 20},
+ "_Test Item Tax Template 1 - _TC": {"_Test Account Excise Duty - _TC": 5, "_Test Account Education Cess - _TC": 10,
"_Test Account S&H Education Cess - _TC": 15}
}
@@ -471,7 +471,7 @@
item_doc = frappe.get_doc('Item', item_code)
new_barcode = item_doc.append('barcodes')
new_barcode.update(barcode_properties_list[0])
- self.assertRaises(frappe.DuplicateEntryError, item_doc.save)
+ self.assertRaises(frappe.UniqueValidationError, item_doc.save)
# Add invalid barcode - should cause InvalidBarcode
item_doc = frappe.get_doc('Item', item_code)
diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json
index 9ca887c..909c4ee 100644
--- a/erpnext/stock/doctype/item/test_records.json
+++ b/erpnext/stock/doctype/item/test_records.json
@@ -92,7 +92,7 @@
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 10"
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC"
}
],
"stock_uom": "_Test UOM 1"
@@ -370,12 +370,12 @@
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 10"
+ "item_tax_template": "_Test Account Excise Duty @ 10 - _TC"
},
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 12",
+ "item_tax_template": "_Test Account Excise Duty @ 12 - _TC",
"tax_category": "_Test Tax Category 1"
}
]
@@ -449,14 +449,24 @@
{
"doctype": "Item Tax",
"parentfield": "taxes",
- "item_tax_template": "_Test Account Excise Duty @ 20"
+ "item_tax_template": "_Test Account Excise Duty @ 20 - _TC"
},
{
"doctype": "Item Tax",
"parentfield": "taxes",
"tax_category": "_Test Tax Category 1",
- "item_tax_template": "_Test Item Tax Template 1"
+ "item_tax_template": "_Test Item Tax Template 1 - _TC"
}
]
+ },
+ {
+ "description": "_Test",
+ "doctype": "Item",
+ "is_stock_item": 1,
+ "item_code": "138-CMS Shoe",
+ "item_group": "_Test Item Group",
+ "item_name": "138-CMS Shoe",
+ "stock_uom": "_Test UOM",
+ "gst_hsn_code": "999800"
}
]
diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
index f045e4f..d5700fe 100644
--- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
@@ -12,11 +12,9 @@
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt, make_rm_stock_entry
import unittest
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestItemAlternative(unittest.TestCase):
def setUp(self):
- set_perpetual_inventory(0)
make_items()
def test_alternative_item_for_subcontract_rm(self):
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.json b/erpnext/stock/doctype/item_attribute/item_attribute.json
index 2fbff4e..5c46789 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.json
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.json
@@ -1,357 +1,97 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:attribute_name",
- "beta": 0,
- "creation": "2014-09-26 03:49:54.899170",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:attribute_name",
+ "creation": "2014-09-26 03:49:54.899170",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "attribute_name",
+ "numeric_values",
+ "section_break_4",
+ "from_range",
+ "increment",
+ "column_break_8",
+ "to_range",
+ "section_break_5",
+ "item_attribute_values"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "attribute_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": "Attribute 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,
+ "fieldname": "attribute_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Attribute Name",
+ "reqd": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "numeric_values",
- "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": "Numeric Values",
- "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": "numeric_values",
+ "fieldtype": "Check",
+ "label": "Numeric Values"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "numeric_values",
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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
- },
+ "depends_on": "numeric_values",
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "from_range",
- "fieldtype": "Float",
- "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 Range",
- "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": "from_range",
+ "fieldtype": "Float",
+ "label": "From Range"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "increment",
- "fieldtype": "Float",
- "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": "Increment",
- "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": "increment",
+ "fieldtype": "Float",
+ "label": "Increment"
+ },
{
- "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,
- "depends_on": "",
- "fieldname": "to_range",
- "fieldtype": "Float",
- "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 Range",
- "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": "to_range",
+ "fieldtype": "Float",
+ "label": "To Range"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: !doc.numeric_values",
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval: !doc.numeric_values",
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "item_attribute_values",
- "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": "Item Attribute Values",
- "length": 0,
- "no_copy": 0,
- "options": "Item Attribute Value",
- "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": "item_attribute_values",
+ "fieldtype": "Table",
+ "label": "Item Attribute Values",
+ "options": "Item Attribute Value"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-edit",
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-01 13:17:46.524806",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Attribute",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-edit",
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-10-02 12:03:02.359202",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Attribute",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Item Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Item Manager",
+ "share": 1,
"write": 1
}
- ],
- "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
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py
index 2f75bbd..3764738 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.py
@@ -5,6 +5,7 @@
import frappe
from frappe.model.document import Document
from frappe import _
+from frappe.utils import flt
from erpnext.controllers.item_variant import (validate_is_incremental,
validate_item_attribute_value, InvalidItemAttributeValueError)
@@ -28,9 +29,18 @@
'''Validate that if there are existing items with attributes, they are valid'''
attributes_list = [d.attribute_value for d in self.item_attribute_values]
- for item in frappe.db.sql('''select i.name, iva.attribute_value as value
- from `tabItem Variant Attribute` iva, `tabItem` i where iva.attribute = %s
- and iva.parent = i.name and i.has_variants = 0''', self.name, as_dict=1):
+ # Get Item Variant Attribute details of variant items
+ items = frappe.db.sql("""
+ select
+ i.name, iva.attribute_value as value
+ from
+ `tabItem Variant Attribute` iva, `tabItem` i
+ where
+ iva.attribute = %(attribute)s
+ and iva.parent = i.name and
+ i.variant_of is not null and i.variant_of != ''""", {"attribute" : self.name}, as_dict=1)
+
+ for item in items:
if self.numeric_values:
validate_is_incremental(self, self.name, item.value, item.name)
else:
@@ -42,7 +52,7 @@
if self.from_range is None or self.to_range is None:
frappe.throw(_("Please specify from/to range"))
- elif self.from_range >= self.to_range:
+ elif flt(self.from_range) >= flt(self.to_range):
frappe.throw(_("From Range has to be less than To Range"))
if not self.increment:
diff --git a/erpnext/stock/doctype/item_attribute/test_records.json b/erpnext/stock/doctype/item_attribute/test_records.json
index d346979..6aa6ffd 100644
--- a/erpnext/stock/doctype/item_attribute/test_records.json
+++ b/erpnext/stock/doctype/item_attribute/test_records.json
@@ -4,10 +4,12 @@
"attribute_name": "Test Size",
"priority": 1,
"item_attribute_values": [
+ {"attribute_value": "Extra Small", "abbr": "XSL"},
{"attribute_value": "Small", "abbr": "S"},
{"attribute_value": "Medium", "abbr": "M"},
{"attribute_value": "Large", "abbr": "L"},
- {"attribute_value": "Extra Small", "abbr": "XSL"}
+ {"attribute_value": "Extra Large", "abbr": "XL"},
+ {"attribute_value": "2XL", "abbr": "2XL"}
]
},
{
diff --git a/erpnext/stock/doctype/item_price/item_price.js b/erpnext/stock/doctype/item_price/item_price.js
index 2729f4b..12cf6cf 100644
--- a/erpnext/stock/doctype/item_price/item_price.js
+++ b/erpnext/stock/doctype/item_price/item_price.js
@@ -14,6 +14,14 @@
frm.add_fetch("item_code", "stock_uom", "uom");
frm.set_df_property("bulk_import_help", "options",
- '<a href="#data-import-tool/Item Price">' + __("Import in Bulk") + '</a>');
+ '<a href="/app/data-import-tool/Item Price">' + __("Import in Bulk") + '</a>');
+
+ frm.set_query('batch_no', function() {
+ return {
+ filters: {
+ 'item': frm.doc.item_code
+ }
+ };
+ });
}
});
diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json
index 5f62381..83177b3 100644
--- a/erpnext/stock/doctype/item_price/item_price.json
+++ b/erpnext/stock/doctype/item_price/item_price.json
@@ -18,6 +18,7 @@
"price_list",
"customer",
"supplier",
+ "batch_no",
"column_break_3",
"buying",
"selling",
@@ -47,31 +48,41 @@
"oldfieldtype": "Select",
"options": "Item",
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "uom",
"fieldtype": "Link",
"label": "UOM",
- "options": "UOM"
+ "options": "UOM",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"description": "Quantity that must be bought or sold per UOM",
"fieldname": "packing_unit",
"fieldtype": "Int",
- "label": "Packing Unit"
+ "label": "Packing Unit",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_17",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "item_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Item Name",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fetch_from": "item_code.brand",
@@ -79,19 +90,25 @@
"fieldtype": "Read Only",
"in_list_view": 1,
"label": "Brand",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "item_description",
"fieldtype": "Text",
"label": "Item Description",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "price_list_details",
"fieldtype": "Section Break",
"label": "Price List",
- "options": "fa fa-tags"
+ "options": "fa fa-tags",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "price_list",
@@ -100,7 +117,9 @@
"in_standard_filter": 1,
"label": "Price List",
"options": "Price List",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -108,37 +127,49 @@
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
- "options": "Customer"
+ "options": "Customer",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"depends_on": "eval:doc.buying == 1",
"fieldname": "supplier",
"fieldtype": "Link",
"label": "Supplier",
- "options": "Supplier"
+ "options": "Supplier",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_3",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "buying",
"fieldtype": "Check",
"label": "Buying",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "selling",
"fieldtype": "Check",
"label": "Selling",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "item_details",
"fieldtype": "Section Break",
- "options": "fa fa-tag"
+ "options": "fa fa-tag",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"bold": 1,
@@ -146,11 +177,15 @@
"fieldtype": "Link",
"label": "Currency",
"options": "Currency",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_br_1",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "price_list_rate",
@@ -162,53 +197,80 @@
"oldfieldname": "ref_rate",
"oldfieldtype": "Currency",
"options": "currency",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_15",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "Today",
"fieldname": "valid_from",
"fieldtype": "Date",
- "label": "Valid From"
+ "label": "Valid From",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "lead_time_days",
"fieldtype": "Int",
- "label": "Lead Time in days"
+ "label": "Lead Time in days",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "column_break_18",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto"
+ "label": "Valid Upto",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_24",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "note",
"fieldtype": "Text",
- "label": "Note"
+ "label": "Note",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "reference",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Reference"
+ "label": "Reference",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "batch_no",
+ "fieldtype": "Link",
+ "label": "Batch No",
+ "options": "Batch",
+ "show_days": 1,
+ "show_seconds": 1
}
],
"icon": "fa fa-flag",
"idx": 1,
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-07-06 22:31:32.943475",
+ "modified": "2020-12-08 18:12:15.395772",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Price",
diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py
index 8e39eb5..e82a19b 100644
--- a/erpnext/stock/doctype/item_price/item_price.py
+++ b/erpnext/stock/doctype/item_price/item_price.py
@@ -4,14 +4,13 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-
-
-class ItemPriceDuplicateItem(frappe.ValidationError): pass
-
-
from frappe.model.document import Document
+class ItemPriceDuplicateItem(frappe.ValidationError):
+ pass
+
+
class ItemPrice(Document):
def validate(self):
@@ -23,7 +22,7 @@
def validate_item(self):
if not frappe.db.exists("Item", self.item_code):
- frappe.throw(_("Item {0} not found").format(self.item_code))
+ frappe.throw(_("Item {0} not found.").format(self.item_code))
def validate_dates(self):
if self.valid_from and self.valid_upto:
@@ -38,38 +37,46 @@
if not price_list_details:
link = frappe.utils.get_link_to_form('Price List', self.price_list)
- frappe.throw("The price list {0} does not exists or disabled".
- format(link))
+ frappe.throw("The price list {0} does not exist or is disabled".format(link))
self.buying, self.selling, self.currency = price_list_details
def update_item_details(self):
if self.item_code:
- self.item_name, self.item_description = frappe.db.get_value("Item",
- self.item_code,["item_name", "description"])
+ self.item_name, self.item_description = frappe.db.get_value("Item", self.item_code,["item_name", "description"])
def check_duplicates(self):
- conditions = "where item_code=%(item_code)s and price_list=%(price_list)s and name != %(name)s"
+ conditions = """where item_code = %(item_code)s and price_list = %(price_list)s and name != %(name)s"""
- for field in ['uom', 'valid_from',
- 'valid_upto', 'packing_unit', 'customer', 'supplier']:
+ for field in [
+ "uom",
+ "valid_from",
+ "valid_upto",
+ "packing_unit",
+ "customer",
+ "supplier",
+ "batch_no"]:
if self.get(field):
- conditions += " and {0} = %({1})s".format(field, field)
+ conditions += " and {0} = %({0})s ".format(field)
+ else:
+ conditions += "and (isnull({0}) or {0} = '')".format(field)
price_list_rate = frappe.db.sql("""
- SELECT price_list_rate
- FROM `tabItem Price`
- {conditions} """.format(conditions=conditions), self.as_dict())
+ select price_list_rate
+ from `tabItem Price`
+ {conditions}
+ """.format(conditions=conditions),
+ self.as_dict(),)
- if price_list_rate :
- frappe.throw(_("Item Price appears multiple times based on Price List, Supplier/Customer, Currency, Item, UOM, Qty and Dates."), ItemPriceDuplicateItem)
+ if price_list_rate:
+ frappe.throw(_("Item Price appears multiple times based on Price List, Supplier/Customer, Currency, Item, Batch, UOM, Qty, and Dates."), ItemPriceDuplicateItem,)
def before_save(self):
if self.selling:
self.reference = self.customer
if self.buying:
self.reference = self.supplier
-
+
if self.selling and not self.buying:
# if only selling then remove supplier
self.supplier = None
diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py
index 702acc3..f3d406e 100644
--- a/erpnext/stock/doctype/item_price/test_item_price.py
+++ b/erpnext/stock/doctype/item_price/test_item_price.py
@@ -138,4 +138,23 @@
# Valid price list must already exist
self.assertRaises(frappe.ValidationError, doc.save)
+ def test_empty_duplicate_validation(self):
+ # Check if none/empty values are not compared during insert validation
+ doc = frappe.copy_doc(test_records[2])
+ doc.customer = None
+ doc.price_list_rate = 21
+ doc.insert()
+
+ args = {
+ "price_list": doc.price_list,
+ "uom": "_Test UOM",
+ "transaction_date": '2017-04-18',
+ "qty": 7
+ }
+
+ price = get_price_list_rate_for(args, doc.item_code)
+ frappe.db.rollback()
+
+ self.assertEqual(price, 21)
+
test_records = frappe.get_test_records('Item Price')
diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
index f1e1fd3..9b1a47e 100644
--- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
+++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
@@ -1,88 +1,100 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "hash",
- "beta": 0,
- "creation": "2013-02-22 01:28:01",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 1,
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2013-02-22 01:28:01",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "specification",
+ "parameter_group",
+ "value",
+ "numeric",
+ "column_break_3",
+ "min_value",
+ "max_value",
+ "formula_based_criteria",
+ "acceptance_formula"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "specification",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Parameter",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "specification",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "200px",
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
- "width": "200px"
- },
+ "fieldname": "specification",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Parameter",
+ "oldfieldname": "specification",
+ "oldfieldtype": "Data",
+ "options": "Quality Inspection Parameter",
+ "print_width": "200px",
+ "reqd": 1,
+ "width": "100px"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "value",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Acceptance Criteria",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "value",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "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
+ "depends_on": "eval:(!doc.formula_based_criteria && !doc.numeric)",
+ "fieldname": "value",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Acceptance Criteria Value",
+ "oldfieldname": "value",
+ "oldfieldtype": "Data"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "formula_based_criteria",
+ "description": "Simple Python formula applied on Reading fields.<br> Numeric eg. 1: <b>reading_1 > 0.2 and reading_1 < 0.5</b><br>\nNumeric eg. 2: <b>mean > 3.5</b> (mean of populated fields)<br>\nValue based eg.: <b>reading_value in (\"A\", \"B\", \"C\")</b>",
+ "fieldname": "acceptance_formula",
+ "fieldtype": "Code",
+ "label": "Acceptance Criteria Formula"
+ },
+ {
+ "default": "0",
+ "fieldname": "formula_based_criteria",
+ "fieldtype": "Check",
+ "label": "Formula Based Criteria"
+ },
+ {
+ "depends_on": "eval:(!doc.formula_based_criteria && doc.numeric)",
+ "fieldname": "min_value",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Minimum Value"
+ },
+ {
+ "depends_on": "eval:(!doc.formula_based_criteria && doc.numeric)",
+ "fieldname": "max_value",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Maximum Value"
+ },
+ {
+ "default": "1",
+ "fieldname": "numeric",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Numeric",
+ "width": "80px"
+ },
+ {
+ "fetch_from": "specification.parameter_group",
+ "fieldname": "parameter_group",
+ "fieldtype": "Link",
+ "label": "Parameter Group",
+ "options": "Quality Inspection Parameter Group",
+ "read_only": 1
}
- ],
- "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": "2016-07-11 03:28:01.074316",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Quality Inspection Parameter",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "track_seen": 0
+ ],
+ "idx": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-04 18:50:02.056173",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Quality Inspection Parameter",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
index b24d621..c77b993 100644
--- a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
+++ b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2013-02-22 01:28:02",
"doctype": "DocType",
"document_type": "Document",
@@ -29,6 +30,8 @@
"options": "Item",
"read_only": 1,
"reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "100px"
},
{
@@ -41,6 +44,8 @@
"print_width": "300px",
"read_only": 1,
"reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1,
"width": "120px"
},
{
@@ -50,7 +55,9 @@
"no_copy": 1,
"options": "Purchase Invoice\nPurchase Receipt",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "receipt_document",
@@ -59,25 +66,33 @@
"no_copy": 1,
"options": "receipt_document_type",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_break2",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Qty",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "rate",
"fieldtype": "Currency",
"label": "Rate",
"options": "Company:company:default_currency",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "amount",
@@ -88,14 +103,19 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "applicable_charges",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Applicable Charges",
- "options": "Company:company:default_currency"
+ "options": "Company:company:default_currency",
+ "read_only_depends_on": "eval:parent.distribute_charges_based_on != 'Distribute Manually'",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "purchase_receipt_item",
@@ -104,22 +124,30 @@
"label": "Purchase Receipt Item",
"no_copy": 1,
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
- "options": "Cost Center"
+ "options": "Cost Center",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
- "label": "Accounting Dimensions"
+ "label": "Accounting Dimensions",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
@@ -128,12 +156,15 @@
"fieldtype": "Check",
"hidden": 1,
"label": "Is Fixed Asset",
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2020-09-18 17:26:09.703215",
+ "links": [],
+ "modified": "2021-01-25 23:09:23.322282",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Item",
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
index 0cc243d..4fcdb4c 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
@@ -1,12 +1,16 @@
{
+ "actions": [],
"creation": "2014-07-11 11:51:00.453717",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"expense_account",
+ "account_currency",
+ "exchange_rate",
"description",
"col_break3",
+ "base_amount",
"amount"
],
"fields": [
@@ -27,20 +31,43 @@
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
- "options": "Company:company:default_currency",
+ "options": "account_currency",
"reqd": 1
},
{
+ "depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))",
"fieldname": "expense_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Expense Account",
- "options": "Account",
- "reqd": 1
+ "mandatory_depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))",
+ "options": "Account"
+ },
+ {
+ "fieldname": "account_currency",
+ "fieldtype": "Link",
+ "label": "Account Currency",
+ "options": "Currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "exchange_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "precision": "9"
+ },
+ {
+ "fieldname": "base_amount",
+ "fieldtype": "Currency",
+ "label": "Base Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-09-30 18:28:32.070655",
+ "links": [],
+ "modified": "2020-12-26 01:07:23.233604",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Taxes and Charges",
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
index 5de1352..1abbc35 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
@@ -1,6 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
frappe.provide("erpnext.stock");
@@ -29,20 +30,9 @@
this.frm.add_fetch("receipt_document", "supplier", "supplier");
this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
-
- this.frm.set_query("expense_account", "taxes", function() {
- return {
- query: "erpnext.controllers.queries.tax_account_query",
- filters: {
- "account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
- "company": me.frm.doc.company
- }
- };
- });
-
},
- refresh: function(frm) {
+ refresh: function() {
var help_content =
`<br><br>
<table class="table table-bordered" style="background-color: #f9f9f9;">
@@ -72,6 +62,11 @@
</table>`;
set_field_options("landed_cost_help", help_content);
+
+ if (this.frm.doc.company) {
+ let company_currency = frappe.get_doc(":Company", this.frm.doc.company).default_currency;
+ this.frm.set_currency_labels(["total_taxes_and_charges"], company_currency);
+ }
},
get_items_from_purchase_receipts: function() {
@@ -97,34 +92,36 @@
set_total_taxes_and_charges: function() {
var total_taxes_and_charges = 0.0;
$.each(this.frm.doc.taxes || [], function(i, d) {
- total_taxes_and_charges += flt(d.amount)
+ total_taxes_and_charges += flt(d.base_amount);
});
- cur_frm.set_value("total_taxes_and_charges", total_taxes_and_charges);
+ this.frm.set_value("total_taxes_and_charges", total_taxes_and_charges);
},
set_applicable_charges_for_item: function() {
var me = this;
if(this.frm.doc.taxes.length) {
-
var total_item_cost = 0.0;
var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
- $.each(this.frm.doc.items || [], function(i, d) {
- total_item_cost += flt(d[based_on])
- });
- var total_charges = 0.0;
- $.each(this.frm.doc.items || [], function(i, item) {
- item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
- item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
- total_charges += item.applicable_charges
- });
+ if (based_on != 'distribute manually') {
+ $.each(this.frm.doc.items || [], function(i, d) {
+ total_item_cost += flt(d[based_on])
+ });
- if (total_charges != this.frm.doc.total_taxes_and_charges){
- var diff = this.frm.doc.total_taxes_and_charges - flt(total_charges)
- this.frm.doc.items.slice(-1)[0].applicable_charges += diff
+ var total_charges = 0.0;
+ $.each(this.frm.doc.items || [], function(i, item) {
+ item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
+ item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
+ total_charges += item.applicable_charges
+ });
+
+ if (total_charges != this.frm.doc.total_taxes_and_charges){
+ var diff = this.frm.doc.total_taxes_and_charges - flt(total_charges)
+ this.frm.doc.items.slice(-1)[0].applicable_charges += diff
+ }
+ refresh_field("items");
}
- refresh_field("items");
}
},
distribute_charges_based_on: function (frm) {
@@ -134,7 +131,16 @@
items_remove: () => {
this.trigger('set_applicable_charges_for_item');
}
-
});
cur_frm.script_manager.make(erpnext.stock.LandedCostVoucher);
+
+frappe.ui.form.on('Landed Cost Taxes and Charges', {
+ expense_account: function(frm, cdt, cdn) {
+ frm.events.set_account_currency(frm, cdt, cdn);
+ },
+
+ amount: function(frm, cdt, cdn) {
+ frm.events.set_base_amount(frm, cdt, cdn);
+ }
+});
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
index 0149280..059f925 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "naming_series:",
"creation": "2014-07-11 11:33:42.547339",
"doctype": "DocType",
@@ -7,6 +8,9 @@
"field_order": [
"naming_series",
"company",
+ "column_break_2",
+ "posting_date",
+ "section_break_5",
"purchase_receipts",
"purchase_receipt_items",
"get_items_from_purchase_receipts",
@@ -30,7 +34,9 @@
"options": "MAT-LCV-.YYYY.-",
"print_hide": 1,
"reqd": 1,
- "set_only_once": 1
+ "set_only_once": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "company",
@@ -40,24 +46,32 @@
"label": "Company",
"options": "Company",
"remember_last_selected_value": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "purchase_receipts",
"fieldtype": "Table",
"label": "Purchase Receipts",
"options": "Landed Cost Purchase Receipt",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "purchase_receipt_items",
"fieldtype": "Section Break",
- "label": "Purchase Receipt Items"
+ "label": "Purchase Receipt Items",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "get_items_from_purchase_receipts",
"fieldtype": "Button",
- "label": "Get Items From Purchase Receipts"
+ "label": "Get Items From Purchase Receipts",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "items",
@@ -65,42 +79,56 @@
"label": "Purchase Receipt Items",
"no_copy": 1,
"options": "Landed Cost Item",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "sec_break1",
"fieldtype": "Section Break",
- "label": "Applicable Charges"
+ "label": "Applicable Charges",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "taxes",
"fieldtype": "Table",
"label": "Taxes and Charges",
"options": "Landed Cost Taxes and Charges",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "section_break_9",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "total_taxes_and_charges",
"fieldtype": "Currency",
- "label": "Total Taxes and Charges",
+ "label": "Total Taxes and Charges (Company Currency)",
"options": "Company:company:default_currency",
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "col_break1",
- "fieldtype": "Column Break"
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "distribute_charges_based_on",
"fieldtype": "Select",
"label": "Distribute Charges Based On",
- "options": "Qty\nAmount",
- "reqd": 1
+ "options": "Qty\nAmount\nDistribute Manually",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "amended_from",
@@ -109,21 +137,51 @@
"no_copy": 1,
"options": "Landed Cost Voucher",
"print_hide": 1,
- "read_only": 1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "sec_break2",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "show_days": 1,
+ "show_seconds": 1
},
{
"fieldname": "landed_cost_help",
"fieldtype": "HTML",
- "label": "Landed Cost Help"
+ "label": "Landed Cost Help",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "label": "Posting Date",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "show_days": 1,
+ "show_seconds": 1
}
],
"icon": "icon-usd",
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
- "modified": "2019-11-21 15:34:10.846093",
+ "links": [],
+ "modified": "2021-01-25 23:07:30.468423",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Voucher",
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index bc3d326..69a8bf1 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -9,6 +9,7 @@
from frappe.model.document import Document
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.accounts.doctype.account.account import get_account_currency
+from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals
class LandedCostVoucher(Document):
def get_items_from_purchase_receipts(self):
@@ -39,13 +40,15 @@
def validate(self):
self.check_mandatory()
+ self.validate_purchase_receipts()
+ init_landed_taxes_and_totals(self)
+ self.set_total_taxes_and_charges()
if not self.get("items"):
self.get_items_from_purchase_receipts()
- else:
- self.validate_applicable_charges_for_item()
- self.validate_purchase_receipts()
- self.validate_expense_accounts()
- self.set_total_taxes_and_charges()
+
+ self.set_applicable_charges_on_item()
+ self.validate_applicable_charges_for_item()
+
def check_mandatory(self):
if not self.get("purchase_receipts"):
@@ -73,21 +76,37 @@
frappe.throw(_("Row {0}: Cost center is required for an item {1}")
.format(item.idx, item.item_code))
- def validate_expense_accounts(self):
- company_currency = erpnext.get_company_currency(self.company)
- for account in self.taxes:
- if get_account_currency(account.expense_account) != company_currency:
- frappe.throw(msg=_(""" Row {0}: Expense account currency should be same as company's default currency.
- Please select expense account with account currency as {1}""")
- .format(account.idx, frappe.bold(company_currency)), title=_("Invalid Account Currency"))
-
def set_total_taxes_and_charges(self):
- self.total_taxes_and_charges = sum([flt(d.amount) for d in self.get("taxes")])
+ self.total_taxes_and_charges = sum([flt(d.base_amount) for d in self.get("taxes")])
+
+ def set_applicable_charges_on_item(self):
+ if self.get('taxes') and self.distribute_charges_based_on != 'Distribute Manually':
+ total_item_cost = 0.0
+ total_charges = 0.0
+ item_count = 0
+ based_on_field = frappe.scrub(self.distribute_charges_based_on)
+
+ for item in self.get('items'):
+ total_item_cost += item.get(based_on_field)
+
+ for item in self.get('items'):
+ item.applicable_charges = flt(flt(item.get(based_on_field)) * (flt(self.total_taxes_and_charges) / flt(total_item_cost)),
+ item.precision('applicable_charges'))
+ total_charges += item.applicable_charges
+ item_count += 1
+
+ if total_charges != self.total_taxes_and_charges:
+ diff = self.total_taxes_and_charges - total_charges
+ self.get('items')[item_count - 1].applicable_charges += diff
def validate_applicable_charges_for_item(self):
based_on = self.distribute_charges_based_on.lower()
- total = sum([flt(d.get(based_on)) for d in self.get("items")])
+ if based_on != 'distribute manually':
+ total = sum([flt(d.get(based_on)) for d in self.get("items")])
+ else:
+ # consider for proportion while distributing manually
+ total = sum([flt(d.get('applicable_charges')) for d in self.get("items")])
if not total:
frappe.throw(_("Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'").format(based_on))
@@ -121,7 +140,7 @@
doc.set_landed_cost_voucher_amount()
# set valuation amount in pr item
- doc.update_valuation_rate("items")
+ doc.update_valuation_rate(reset_outgoing_rate=False)
# db_update will update and save landed_cost_voucher_amount and voucher_amount in PR
for item in doc.get("items"):
@@ -143,6 +162,7 @@
doc.docstatus = 1
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
doc.make_gl_entries()
+ doc.repost_future_sle_and_gle()
def validate_asset_qty_and_status(self, receipt_document_type, receipt_document):
for item in self.get('items'):
@@ -152,13 +172,12 @@
docs = frappe.db.get_all('Asset', filters={ receipt_document_type: item.receipt_document,
'item_code': item.item_code }, fields=['name', 'docstatus'])
if not docs or len(docs) != item.qty:
- frappe.throw(_('There are not enough asset created or linked to {0}. \
- Please create or link {1} Assets with respective document.').format(item.receipt_document, item.qty))
+ frappe.throw(_('There are not enough asset created or linked to {0}. Please create or link {1} Assets with respective document.').format(
+ item.receipt_document, item.qty))
if docs:
for d in docs:
if d.docstatus == 1:
- frappe.throw(_('{2} <b>{0}</b> has submitted Assets.\
- Remove Item <b>{1}</b> from table to continue.').format(
+ frappe.throw(_('{2} <b>{0}</b> has submitted Assets. Remove Item <b>{1}</b> from table to continue.').format(
item.receipt_document, item.item_code, item.receipt_document_type))
def update_rate_in_serial_no_for_non_asset_items(self, receipt_document):
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 3f2c5da..984ae46 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -7,9 +7,10 @@
import frappe
from frappe.utils import flt
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
- import set_perpetual_inventory, get_gl_entries, test_records as pr_test_records, make_purchase_receipt
+ import get_gl_entries, test_records as pr_test_records, make_purchase_receipt
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.account.test_account import get_inventory_account
+from erpnext.accounts.doctype.account.test_account import create_account
class TestLandedCostVoucher(unittest.TestCase):
def test_landed_cost_voucher(self):
@@ -27,7 +28,7 @@
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
- submit_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
+ create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
pr_lc_value = frappe.db.get_value("Purchase Receipt Item", {"parent": pr.name}, "landed_cost_voucher_amount")
self.assertEqual(pr_lc_value, 25.0)
@@ -89,7 +90,7 @@
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
- submit_landed_cost_voucher("Purchase Invoice", pi.name, pi.company)
+ create_landed_cost_voucher("Purchase Invoice", pi.name, pi.company)
pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name},
"landed_cost_voucher_amount")
@@ -137,7 +138,7 @@
serial_no_rate = frappe.db.get_value("Serial No", "SN001", "purchase_rate")
- submit_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
+ create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
serial_no = frappe.db.get_value("Serial No", "SN001",
["warehouse", "purchase_rate"], as_dict=1)
@@ -147,7 +148,6 @@
def test_landed_cost_voucher_for_odd_numbers (self):
-
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", do_not_save=True)
pr.items[0].cost_center = "Main - TCP1"
for x in range(2):
@@ -160,10 +160,10 @@
})
pr.submit()
- lcv = submit_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, 123.22)
+ lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, 123.22)
- self.assertEqual(lcv.items[0].applicable_charges, 41.07)
- self.assertEqual(lcv.items[2].applicable_charges, 41.08)
+ self.assertEqual(flt(lcv.items[0].applicable_charges, 2), 41.07)
+ self.assertEqual(flt(lcv.items[2].applicable_charges, 2), 41.08)
def test_multiple_landed_cost_voucher_against_pr(self):
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
@@ -206,6 +206,50 @@
self.assertEqual(pr.items[0].landed_cost_voucher_amount, 100)
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
+ def test_multi_currency_lcv(self):
+ from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
+
+ save_new_records(test_records)
+
+ ## Create USD Shipping charges_account
+ usd_shipping = create_account(account_name="Shipping Charges USD",
+ parent_account="Duties and Taxes - TCP1", company="_Test Company with perpetual inventory",
+ account_currency="USD")
+
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
+ supplier_warehouse = "Stores - TCP1")
+ pr.submit()
+
+ lcv = make_landed_cost_voucher(company = pr.company, receipt_document_type = "Purchase Receipt",
+ receipt_document=pr.name, charges=100, do_not_save=True)
+
+ lcv.append("taxes", {
+ "description": "Shipping Charges",
+ "expense_account": usd_shipping,
+ "amount": 10
+ })
+
+ lcv.save()
+ lcv.submit()
+ pr.load_from_db()
+
+ # Considering exchange rate from USD to INR as 62.9
+ self.assertEqual(lcv.total_taxes_and_charges, 729)
+ self.assertEqual(pr.items[0].landed_cost_voucher_amount, 729)
+
+ gl_entries = frappe.get_all("GL Entry", fields=["account", "credit", "credit_in_account_currency"],
+ filters={"voucher_no": pr.name, "account": ("in", ["Shipping Charges USD - TCP1", "Expenses Included In Valuation - TCP1"])})
+
+ expected_gl_entries = {
+ "Shipping Charges USD - TCP1": [629, 10],
+ "Expenses Included In Valuation - TCP1": [100, 100]
+ }
+
+ for entry in gl_entries:
+ amounts = expected_gl_entries.get(entry.account)
+ self.assertEqual(entry.credit, amounts[0])
+ self.assertEqual(entry.credit_in_account_currency, amounts[1])
+
def make_landed_cost_voucher(** args):
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
@@ -236,7 +280,7 @@
return lcv
-def submit_landed_cost_voucher(receipt_document_type, receipt_document, company, charges=50):
+def create_landed_cost_voucher(receipt_document_type, receipt_document, company, charges=50):
ref_doc = frappe.get_doc(receipt_document_type, receipt_document)
lcv = frappe.new_doc("Landed Cost Voucher")
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 3c4e353..527b0d3 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -2,6 +2,7 @@
// License: GNU General Public License v3. See license.txt
// eslint-disable-next-line
+frappe.provide("erpnext.accounts.dimensions");
{% include 'erpnext/public/js/controllers/buying.js' %};
frappe.ui.form.on('Material Request', {
@@ -66,6 +67,12 @@
filters: {'company': doc.company}
};
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
onload_post_render: function(frm) {
@@ -90,7 +97,7 @@
make_custom_buttons: function(frm) {
if (frm.doc.docstatus==0) {
frm.add_custom_button(__("Bill of Materials"),
- () => frm.events.get_items_from_bom(frm), __("Get items from"));
+ () => frm.events.get_items_from_bom(frm), __("Get Items From"));
}
if (frm.doc.docstatus == 1 && frm.doc.status != 'Stopped') {
@@ -147,7 +154,7 @@
if (frm.doc.docstatus===0) {
frm.add_custom_button(__('Sales Order'), () => frm.events.get_items_from_sales_order(frm),
- __("Get items from"));
+ __("Get Items From"));
}
if (frm.doc.docstatus == 1 && frm.doc.status == 'Stopped') {
@@ -173,7 +180,8 @@
source_doctype: "Sales Order",
target: frm,
setters: {
- customer: frm.doc.customer || undefined
+ customer: frm.doc.customer || undefined,
+ delivery_date: undefined,
},
get_query_filters: {
docstatus: 1,
@@ -280,7 +288,7 @@
fieldname:'default_supplier',
fieldtype: 'Link',
options: 'Supplier',
- description: __('Select a Supplier from the Default Supplier List of the items below.'),
+ description: __('Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.'),
get_query: () => {
return{
query: "erpnext.stock.doctype.material_request.material_request.get_default_supplier_query",
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 44503d2..d73349d 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -13,7 +13,9 @@
"material_request_type",
"transfer_status",
"customer",
+ "status",
"column_break_2",
+ "transaction_date",
"schedule_date",
"company",
"amended_from",
@@ -25,11 +27,8 @@
"scan_barcode",
"items",
"more_info",
- "requested_by",
- "transaction_date",
- "column_break2",
- "status",
"per_ordered",
+ "column_break2",
"per_received",
"printing_details",
"letter_head",
@@ -82,7 +81,8 @@
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
- "options": "Customer"
+ "options": "Customer",
+ "print_hide": 1
},
{
"fieldname": "column_break_2",
@@ -92,12 +92,12 @@
"allow_on_submit": 1,
"fieldname": "schedule_date",
"fieldtype": "Date",
+ "in_list_view": 1,
"label": "Required By"
},
{
"fieldname": "company",
"fieldtype": "Link",
- "in_list_view": 1,
"in_standard_filter": 1,
"label": "Company",
"oldfieldname": "company",
@@ -154,17 +154,9 @@
"options": "fa fa-file-text"
},
{
- "fieldname": "requested_by",
- "fieldtype": "Data",
- "in_standard_filter": 1,
- "label": "Requested For",
- "options": "Email"
- },
- {
"default": "Today",
"fieldname": "transaction_date",
"fieldtype": "Date",
- "in_list_view": 1,
"label": "Transaction Date",
"no_copy": 1,
"oldfieldname": "transaction_date",
@@ -197,7 +189,7 @@
"width": "100px"
},
{
- "depends_on": "eval:doc.docstatus==1",
+ "depends_on": "eval:doc.per_ordered > 0",
"fieldname": "per_ordered",
"fieldtype": "Percent",
"label": "% Ordered",
@@ -208,7 +200,7 @@
"read_only": 1
},
{
- "depends_on": "eval:doc.docstatus==1",
+ "depends_on": "eval:doc.per_received > 0",
"fieldname": "per_received",
"fieldtype": "Percent",
"label": "% Received",
@@ -282,13 +274,15 @@
},
{
"fieldname": "warehouse_section",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Warehouse"
},
{
- "description": "Sets 'For Warehouse' in each row of the Items table.",
+ "description": "Sets 'Target Warehouse' in each row of the Items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
- "label": "Set Warehouse",
+ "in_list_view": 1,
+ "label": "Set Target Warehouse",
"options": "Warehouse"
},
{
@@ -300,9 +294,10 @@
},
{
"depends_on": "eval:doc.material_request_type == 'Material Transfer'",
+ "description": "Sets 'Source Warehouse' in each row of the Items table.",
"fieldname": "set_from_warehouse",
"fieldtype": "Link",
- "label": "Set From Warehouse",
+ "label": "Set Source Warehouse",
"options": "Warehouse"
},
{
@@ -319,7 +314,7 @@
"idx": 70,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-10 13:27:54.891058",
+ "modified": "2020-09-19 01:04:09.285862",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request",
diff --git a/erpnext/stock/doctype/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py
index 0e4fb7a..f3e5e5d 100644
--- a/erpnext/stock/doctype/material_request/material_request_dashboard.py
+++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py
@@ -7,7 +7,7 @@
'fieldname': 'material_request',
'transactions': [
{
- 'label': _('Related'),
+ 'label': _('Reference'),
'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order']
},
{
diff --git a/erpnext/stock/doctype/material_request/material_request_list.js b/erpnext/stock/doctype/material_request/material_request_list.js
index 0d70958..de7a3d0 100644
--- a/erpnext/stock/doctype/material_request/material_request_list.js
+++ b/erpnext/stock/doctype/material_request/material_request_list.js
@@ -1,9 +1,10 @@
frappe.listview_settings['Material Request'] = {
add_fields: ["material_request_type", "status", "per_ordered", "per_received", "transfer_status"],
get_indicator: function(doc) {
- if(doc.status=="Stopped") {
+ var precision = frappe.defaults.get_default("float_precision");
+ if (doc.status=="Stopped") {
return [__("Stopped"), "red", "status,=,Stopped"];
- } else if(doc.transfer_status && doc.docstatus != 2) {
+ } else if (doc.transfer_status && doc.docstatus != 2) {
if (doc.transfer_status == "Not Started") {
return [__("Not Started"), "orange"];
} else if (doc.transfer_status == "In Transit") {
@@ -11,14 +12,14 @@
} else if (doc.transfer_status == "Completed") {
return [__("Completed"), "green"];
}
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 0) {
+ } else if (doc.docstatus==1 && flt(doc.per_ordered, precision) == 0) {
return [__("Pending"), "orange", "per_ordered,=,0"];
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) < 100) {
+ } else if (doc.docstatus==1 && flt(doc.per_ordered, precision) < 100) {
return [__("Partially ordered"), "yellow", "per_ordered,<,100"];
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 100) {
- if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) < 100 && flt(doc.per_received, 2) > 0) {
+ } else if (doc.docstatus==1 && flt(doc.per_ordered, precision) == 100) {
+ if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) < 100 && flt(doc.per_received, precision) > 0) {
return [__("Partially Received"), "yellow", "per_received,<,100"];
- } else if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) == 100) {
+ } else if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) == 100) {
return [__("Received"), "green", "per_received,=,100"];
} else if (doc.material_request_type == "Purchase") {
return [__("Ordered"), "green", "per_ordered,=,100"];
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 19924b1..72a3a5e 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -12,9 +12,6 @@
from erpnext.stock.doctype.item.test_item import create_item
class TestMaterialRequest(unittest.TestCase):
- def setUp(self):
- erpnext.set_perpetual_inventory(0)
-
def test_make_purchase_order(self):
mr = frappe.copy_doc(test_records[0]).insert()
@@ -427,6 +424,7 @@
"basic_rate": 1.0
})
se_doc.get("items")[1].update({
+ "item_code": "_Test Item Home Desktop 100",
"qty": 3.0,
"transfer_qty": 3.0,
"s_warehouse": "_Test Warehouse 1 - _TC",
@@ -537,7 +535,7 @@
mr = make_material_request(item_code='_Test FG Item', material_request_type='Manufacture',
uom="_Test UOM 1", conversion_factor=12)
-
+
requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
self.assertEqual(requested_qty, existing_requested_qty + 120)
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json
index 32bd4a0..25bbbbd 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.json
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.json
@@ -13,12 +13,10 @@
"schedule_date",
"section_break_4",
"description",
+ "column_break_12",
"item_group",
"brand",
- "image_section",
"image",
- "column_break_12",
- "manufacturer_part_no",
"quantity_and_warehouse",
"qty",
"stock_uom",
@@ -28,12 +26,26 @@
"uom",
"conversion_factor",
"stock_qty",
+ "qty_info_sec_break",
+ "min_order_qty",
+ "projected_qty",
+ "qty_info_col_break",
+ "actual_qty",
+ "ordered_qty",
+ "received_qty",
"rate_and_amount_section_break",
"rate",
"col_break3",
"amount",
"manufacture_details",
"manufacturer",
+ "manufacturer_part_no",
+ "col_break_mfg",
+ "bom_no",
+ "accounting_dimensions_section",
+ "project",
+ "dimension_col_break",
+ "cost_center",
"more_info",
"lead_time_date",
"sales_order",
@@ -41,19 +53,7 @@
"production_plan",
"material_request_plan_item",
"col_break4",
- "min_order_qty",
- "projected_qty",
- "actual_qty",
- "ordered_qty",
- "received_qty",
- "accounting_details",
"expense_account",
- "accounting_dimensions_section",
- "project",
- "dimension_col_break",
- "cost_center",
- "section_break_37",
- "bom_no",
"section_break_46",
"page_break"
],
@@ -164,7 +164,7 @@
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "For Warehouse",
+ "label": "Target Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
@@ -191,12 +191,14 @@
{
"fieldname": "rate",
"fieldtype": "Currency",
- "label": "Rate"
+ "label": "Rate",
+ "print_hide": 1
},
{
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
+ "print_hide": 1,
"read_only": 1
},
{
@@ -326,6 +328,7 @@
"report_hide": 1
},
{
+ "depends_on": "eval:doc.docstatus==1",
"fieldname": "ordered_qty",
"fieldtype": "Float",
"label": "Completed Qty",
@@ -336,12 +339,6 @@
"read_only": 1
},
{
- "collapsible": 1,
- "fieldname": "accounting_details",
- "fieldtype": "Section Break",
- "label": "Accounting Details"
- },
- {
"fieldname": "expense_account",
"fieldtype": "Link",
"label": "Expense Account",
@@ -367,21 +364,10 @@
"print_hide": 1
},
{
- "collapsible": 1,
- "fieldname": "image_section",
- "fieldtype": "Section Break",
- "label": "Image"
- },
- {
- "depends_on": "eval:parent.material_request_type == \"Manufacture\"",
- "fieldname": "section_break_37",
- "fieldtype": "Section Break",
- "label": "Manufacturing"
- },
- {
+ "depends_on": "eval:doc.docstatus==1",
"fieldname": "received_qty",
"fieldtype": "Float",
- "label": "Received Quantity",
+ "label": "Received Qty",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
@@ -398,6 +384,7 @@
},
{
"collapsible": 1,
+ "depends_on": "eval:in_list([\"Manufacture\", \"Purchase\"], parent.material_request_type)",
"fieldname": "manufacture_details",
"fieldtype": "Section Break",
"label": "Manufacture"
@@ -430,10 +417,11 @@
"depends_on": "eval:parent.material_request_type == \"Material Transfer\"",
"fieldname": "from_warehouse",
"fieldtype": "Link",
- "label": "Source Warehouse (Material Transfer)",
+ "label": "Source Warehouse",
"options": "Warehouse"
},
{
+ "allow_on_submit": 1,
"fieldname": "bom_no",
"fieldtype": "Link",
"label": "BOM No",
@@ -444,12 +432,25 @@
{
"fieldname": "section_break_46",
"fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "col_break_mfg",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "qty_info_sec_break",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "qty_info_col_break",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-15 09:00:00.992835",
+ "modified": "2020-10-02 11:44:36.553064",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request Item",
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.py b/erpnext/stock/doctype/material_request_item/material_request_item.py
index 6c6ecfe..16f007f 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.py
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.py
@@ -6,12 +6,10 @@
from __future__ import unicode_literals
import frappe
-from erpnext.controllers.print_settings import print_settings_for_item_table
from frappe.model.document import Document
class MaterialRequestItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
def on_doctype_update():
frappe.db.add_index("Material Request Item", ["item_code", "warehouse"])
\ No newline at end of file
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index 2ac5c42..f1d7f8c 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2013-02-22 01:28:00",
"doctype": "DocType",
"editable_grid": 1,
@@ -14,6 +15,7 @@
"target_warehouse",
"column_break_9",
"qty",
+ "uom",
"section_break_9",
"serial_no",
"column_break_11",
@@ -23,7 +25,7 @@
"actual_qty",
"projected_qty",
"column_break_16",
- "uom",
+ "incoming_rate",
"page_break",
"prevdoc_doctype",
"parent_detail_docname"
@@ -199,11 +201,21 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "incoming_rate",
+ "fieldtype": "Currency",
+ "label": "Incoming Rate",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-11-26 20:09:59.400960",
+ "links": [],
+ "modified": "2020-09-24 09:25:13.050151",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
@@ -212,4 +224,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 0da57b7..d723fac 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -25,8 +25,8 @@
if not frappe.get_cached_value('Item', item.item_code, 'has_serial_no'):
continue
if not item.serial_no:
- frappe.throw(_("Row #{0}: {1} does not have any available serial numbers in {2}".format(
- frappe.bold(item.idx), frappe.bold(item.item_code), frappe.bold(item.warehouse))),
+ frappe.throw(_("Row #{0}: {1} does not have any available serial numbers in {2}").format(
+ frappe.bold(item.idx), frappe.bold(item.item_code), frappe.bold(item.warehouse)),
title=_("Serial Nos Required"))
if len(item.serial_no.split('\n')) == item.picked_qty:
continue
@@ -380,7 +380,7 @@
stock_entry.set_incoming_rate()
stock_entry.set_actual_qty()
- stock_entry.calculate_rate_and_amount(update_finished_item_rate=False)
+ stock_entry.calculate_rate_and_amount()
return stock_entry.as_dict()
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index c504e23..57cc350 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -46,6 +46,8 @@
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
@@ -75,6 +77,7 @@
company: function(frm) {
frm.trigger("toggle_display_account_head");
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
toggle_display_account_head: function(frm) {
@@ -128,6 +131,7 @@
target: me.frm,
setters: {
supplier: me.frm.doc.supplier,
+ schedule_date: undefined
},
get_query_filters: {
docstatus: 1,
@@ -136,7 +140,7 @@
company: me.frm.doc.company
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
}
if(this.frm.doc.docstatus == 1 && this.frm.doc.status!="Closed") {
@@ -212,6 +216,10 @@
});
},
+ apply_putaway_rule: function() {
+ if (this.frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(this.frm);
+ }
+
});
// for backward compatibility: combine new and previous states
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index ce54fc8..32d349f 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1,5 +1,6 @@
{
"actions": [],
+ "allow_auto_repeat": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
@@ -20,6 +21,7 @@
"posting_date",
"posting_time",
"set_posting_time",
+ "apply_putaway_rule",
"is_return",
"return_against",
"section_addresses",
@@ -46,6 +48,7 @@
"set_warehouse",
"rejected_warehouse",
"col_break_warehouse",
+ "set_from_warehouse",
"is_subcontracted",
"supplier_warehouse",
"items_section",
@@ -110,8 +113,10 @@
"range",
"column_break4",
"per_billed",
+ "per_returned",
"is_internal_supplier",
"inter_company_reference",
+ "represents_company",
"subscription_detail",
"auto_repeat",
"printing_settings",
@@ -894,7 +899,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nTo Bill\nCompleted\nCancelled\nClosed",
+ "options": "\nDraft\nTo Bill\nCompleted\nReturn Issued\nCancelled\nClosed",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
@@ -1084,7 +1089,9 @@
"fieldname": "inter_company_reference",
"fieldtype": "Link",
"label": "Inter Company Reference",
+ "no_copy": 1,
"options": "Delivery Note",
+ "print_hide": 1,
"read_only": 1
},
{
@@ -1103,13 +1110,44 @@
"fieldtype": "Small Text",
"label": "Billing Address",
"read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "apply_putaway_rule",
+ "fieldtype": "Check",
+ "label": "Apply Putaway Rule"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "per_returned",
+ "fieldtype": "Percent",
+ "label": "% Returned",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.is_internal_supplier",
+ "description": "Sets 'From Warehouse' in each row of the items table.",
+ "fieldname": "set_from_warehouse",
+ "fieldtype": "Link",
+ "label": "Set From Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fetch_from": "supplier.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
+ "read_only": 1
}
],
"icon": "fa fa-truck",
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-03 23:20:26.381024",
+ "modified": "2020-12-26 20:49:39.106049",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 4e173ff..70687bda 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -55,20 +55,39 @@
'percent_join_field': 'material_request'
}]
if cint(self.is_return):
- self.status_updater.append({
- 'source_dt': 'Purchase Receipt Item',
- 'target_dt': 'Purchase Order Item',
- 'join_field': 'purchase_order_item',
- 'target_field': 'returned_qty',
- 'source_field': '-1 * qty',
- 'second_source_dt': 'Purchase Invoice Item',
- 'second_source_field': '-1 * qty',
- 'second_join_field': 'po_detail',
- 'extra_cond': """ and exists (select name from `tabPurchase Receipt`
- where name=`tabPurchase Receipt Item`.parent and is_return=1)""",
- 'second_source_extra_cond': """ and exists (select name from `tabPurchase Invoice`
- where name=`tabPurchase Invoice Item`.parent and is_return=1 and update_stock=1)"""
- })
+ self.status_updater.extend([
+ {
+ 'source_dt': 'Purchase Receipt Item',
+ 'target_dt': 'Purchase Order Item',
+ 'join_field': 'purchase_order_item',
+ 'target_field': 'returned_qty',
+ 'source_field': '-1 * qty',
+ 'second_source_dt': 'Purchase Invoice Item',
+ 'second_source_field': '-1 * qty',
+ 'second_join_field': 'po_detail',
+ 'extra_cond': """ and exists (select name from `tabPurchase Receipt`
+ where name=`tabPurchase Receipt Item`.parent and is_return=1)""",
+ 'second_source_extra_cond': """ and exists (select name from `tabPurchase Invoice`
+ where name=`tabPurchase Invoice Item`.parent and is_return=1 and update_stock=1)"""
+ },
+ {
+ 'source_dt': 'Purchase Receipt Item',
+ 'target_dt': 'Purchase Receipt Item',
+ 'join_field': 'purchase_receipt_item',
+ 'target_field': 'returned_qty',
+ 'target_parent_dt': 'Purchase Receipt',
+ 'target_parent_field': 'per_returned',
+ 'target_ref_field': 'received_stock_qty',
+ 'source_field': '-1 * received_stock_qty',
+ 'percent_join_field_parent': 'return_against'
+ }
+ ])
+
+ def before_validate(self):
+ from erpnext.stock.doctype.putaway_rule.putaway_rule import apply_putaway_rule
+
+ if self.get("items") and self.apply_putaway_rule and not self.get("is_return"):
+ apply_putaway_rule(self.doctype, self.get("items"), self.company)
def validate(self):
self.validate_posting_time()
@@ -90,6 +109,7 @@
if getdate(self.posting_date) > getdate(nowdate()):
throw(_("Posting Date cannot be future date"))
+
def validate_cwip_accounts(self):
for item in self.get('items'):
if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
@@ -168,6 +188,7 @@
update_serial_nos_after_submit(self, "items")
self.make_gl_entries()
+ self.repost_future_sle_and_gle()
def check_next_docstatus(self):
submit_rv = frappe.db.sql("""select t1.name
@@ -196,7 +217,8 @@
# because updating ordered qty in bin depends upon updated ordered qty in PO
self.update_stock_ledger()
self.make_gl_entries_on_cancel()
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+ self.repost_future_sle_and_gle()
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
self.delete_auto_created_batches()
def get_current_stock(self):
@@ -266,12 +288,16 @@
# Amount added through landed-cost-voucher
if d.landed_cost_voucher_amount and landed_cost_entries:
for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
+ account_currency = get_account_currency(account)
gl_entries.append(self.get_gl_dict({
"account": account,
+ "account_currency": account_currency,
"against": warehouse_account[d.warehouse]["account"],
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(amount),
+ "credit": (flt(amount["base_amount"]) if (amount["base_amount"] or
+ account_currency!=self.company_currency) else flt(amount["amount"])),
+ "credit_in_account_currency": flt(amount["amount"]),
"project": d.project
}, item=d))
@@ -296,12 +322,14 @@
if self.is_return or flt(d.item_tax_amount):
loss_account = expenses_included_in_valuation
else:
- loss_account = stock_rbnb
+ loss_account = self.get_company_default("default_expense_account")
+
+ cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
gl_entries.append(self.get_gl_dict({
"account": loss_account,
"against": warehouse_account[d.warehouse]["account"],
- "cost_center": d.cost_center,
+ "cost_center": cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": divisional_loss,
"project": d.project
@@ -310,7 +338,7 @@
elif d.warehouse not in warehouse_with_no_account or \
d.rejected_warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(d.warehouse)
- elif d.item_code not in stock_items and flt(d.qty) and auto_accounting_for_non_stock_items:
+ elif d.item_code not in stock_items and not d.is_fixed_asset and flt(d.qty) and auto_accounting_for_non_stock_items:
service_received_but_not_billed_account = self.get_company_default("service_received_but_not_billed")
credit_currency = get_account_currency(service_received_but_not_billed_account)
@@ -478,7 +506,7 @@
frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(valuation_rate))
def update_status(self, status):
- self.set_status(update=True, status = status)
+ self.set_status(update=True, status=status)
self.notify_update()
clear_doctype_notifications(self)
@@ -490,7 +518,7 @@
for pr in set(updated_pr):
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", pr)
- pr_doc.update_billing_percentage(update_modified=update_modified)
+ update_billing_percentage(pr_doc, update_modified=update_modified)
self.load_from_db()
@@ -500,7 +528,7 @@
where po_detail=%s and (pr_detail is null or pr_detail = '') and docstatus=1""", po_detail)
billed_against_po = billed_against_po and billed_against_po[0][0] or 0
- # Get all Delivery Note Item rows against the Sales Order Item row
+ # Get all Purchase Receipt Item rows against the Purchase Order Item row
pr_details = frappe.db.sql("""select pr_item.name, pr_item.amount, pr_item.parent
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
where pr.name=pr_item.parent and pr_item.purchase_order_item=%s
@@ -530,9 +558,44 @@
return updated_pr
+def update_billing_percentage(pr_doc, update_modified=True):
+ # Reload as billed amount was set in db directly
+ pr_doc.load_from_db()
+
+ # Update Billing % based on pending accepted qty
+ total_amount, total_billed_amount = 0, 0
+ for item in pr_doc.items:
+ return_data = frappe.db.get_list("Purchase Receipt",
+ fields = [
+ "sum(abs(`tabPurchase Receipt Item`.qty)) as qty"
+ ],
+ filters = [
+ ["Purchase Receipt", "docstatus", "=", 1],
+ ["Purchase Receipt", "is_return", "=", 1],
+ ["Purchase Receipt Item", "purchase_receipt_item", "=", item.name]
+ ])
+
+ returned_qty = return_data[0].qty if return_data else 0
+ returned_amount = flt(returned_qty) * flt(item.rate)
+ pending_amount = flt(item.amount) - returned_amount
+ total_billable_amount = pending_amount if item.billed_amt <= pending_amount else item.billed_amt
+
+ total_amount += total_billable_amount
+ total_billed_amount += flt(item.billed_amt)
+
+ percent_billed = round(100 * (total_billed_amount / (total_amount or 1)), 6)
+ pr_doc.db_set("per_billed", percent_billed)
+ pr_doc.load_from_db()
+
+ if update_modified:
+ pr_doc.set_status(update=True)
+ pr_doc.notify_update()
+
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
+ from erpnext.accounts.party import get_payment_terms_template
+
doc = frappe.get_doc('Purchase Receipt', source_name)
returned_qty_map = get_returned_qty_map(source_name)
invoiced_qty_map = get_invoiced_qty_map(source_name)
@@ -543,12 +606,14 @@
doc = frappe.get_doc(target)
doc.ignore_pricing_rule = 1
+ doc.payment_terms_template = get_payment_terms_template(source.supplier, "Supplier", source.company)
doc.run_method("onload")
doc.run_method("set_missing_values")
doc.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
target_doc.qty, returned_qty = get_pending_qty(source_doc)
+ target_doc.stock_qty = flt(target_doc.qty) * flt(target_doc.conversion_factor, target_doc.precision("conversion_factor"))
returned_qty_map[source_doc.name] = returned_qty
def get_pending_qty(item_row):
@@ -569,7 +634,8 @@
"doctype": "Purchase Invoice",
"field_map": {
"supplier_warehouse":"supplier_warehouse",
- "is_return": "is_return"
+ "is_return": "is_return",
+ "bill_date": "bill_date"
},
"validation": {
"docstatus": ["=", 1],
@@ -668,7 +734,13 @@
for lcv in landed_cost_vouchers:
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", lcv.parent)
- based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
+ #Use amount field for total item cost for manually cost distributed LCVs
+ if landed_cost_voucher_doc.distribute_charges_based_on == 'Distribute Manually':
+ based_on_field = 'amount'
+ else:
+ based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
total_item_cost = 0
for item in landed_cost_voucher_doc.items:
@@ -678,9 +750,16 @@
if item.receipt_document == purchase_document:
for account in landed_cost_voucher_doc.taxes:
item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
- item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
- item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, {
+ "amount": 0.0,
+ "base_amount": 0.0
+ })
+
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account]["amount"] += \
account.amount * item.get(based_on_field) / total_item_cost
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account]["base_amount"] += \
+ account.base_amount * item.get(based_on_field) / total_item_cost
+
return item_account_wise_cost
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
index e81f323..77711de 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
@@ -3,12 +3,14 @@
"transporter_name", "is_return", "status", "per_billed", "currency"],
get_indicator: function(doc) {
if(cint(doc.is_return)==1) {
- return [__("Return"), "darkgrey", "is_return,=,Yes"];
+ return [__("Return"), "gray", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
+ } else if (flt(doc.per_returned, 2) === 100) {
+ return [__("Return Issued"), "grey", "per_returned,=,100"];
} else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) < 100) {
return [__("To Bill"), "orange", "per_billed,<,100"];
- } else if (flt(doc.grand_total) === 0 || flt(doc.per_billed, 2) == 100) {
+ } else if (flt(doc.grand_total) === 0 || flt(doc.per_billed, 2) === 100) {
return [__("Completed"), "green", "per_billed,=,100"];
}
}
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 1e7153e..7741ee7 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -6,17 +6,18 @@
import json
import frappe, erpnext
import frappe.defaults
-from frappe.utils import cint, flt, cstr, today, random_string
+from frappe.utils import cint, flt, cstr, today, random_string, add_days
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
from erpnext.stock.doctype.item.test_item import create_item
-from erpnext import set_perpetual_inventory
from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.stock.doctype.item.test_item import make_item
from six import iteritems
+from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+
+
class TestPurchaseReceipt(unittest.TestCase):
def setUp(self):
- set_perpetual_inventory(0)
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
def test_reverse_purchase_receipt_sle(self):
@@ -42,6 +43,30 @@
frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 1)
def test_make_purchase_invoice(self):
+ if not frappe.db.exists('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice'):
+ frappe.get_doc({
+ 'doctype': 'Payment Terms Template',
+ 'template_name': '_Test Payment Terms Template For Purchase Invoice',
+ 'allocate_payment_based_on_payment_terms': 1,
+ 'terms': [
+ {
+ 'doctype': 'Payment Terms Template Detail',
+ 'invoice_portion': 50.00,
+ 'credit_days_based_on': 'Day(s) after invoice date',
+ 'credit_days': 00
+ },
+ {
+ 'doctype': 'Payment Terms Template Detail',
+ 'invoice_portion': 50.00,
+ 'credit_days_based_on': 'Day(s) after invoice date',
+ 'credit_days': 30
+ }]
+ }).insert()
+
+ template = frappe.db.get_value('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice')
+ old_template_in_supplier = frappe.db.get_value("Supplier", "_Test Supplier", "payment_terms")
+ frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", template)
+
pr = make_purchase_receipt(do_not_save=True)
self.assertRaises(frappe.ValidationError, make_purchase_invoice, pr.name)
pr.submit()
@@ -51,15 +76,33 @@
self.assertEqual(pi.doctype, "Purchase Invoice")
self.assertEqual(len(pi.get("items")), len(pr.get("items")))
- # modify rate
+ # test maintaining same rate throughout purchade cycle
pi.get("items")[0].rate = 200
self.assertRaises(frappe.ValidationError, frappe.get_doc(pi).submit)
+ # test if payment terms are fetched and set in PI
+ self.assertEqual(pi.payment_terms_template, template)
+ self.assertEqual(pi.payment_schedule[0].payment_amount, flt(pi.grand_total)/2)
+ self.assertEqual(pi.payment_schedule[0].invoice_portion, 50)
+ self.assertEqual(pi.payment_schedule[1].payment_amount, flt(pi.grand_total)/2)
+ self.assertEqual(pi.payment_schedule[1].invoice_portion, 50)
+
+ # teardown
+ pi.delete() # draft PI
+ pr.cancel()
+ frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", old_template_in_supplier)
+ frappe.get_doc('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice').delete()
+
def test_purchase_receipt_no_gl_entry(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+
company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC"}, "stock_value")
+ existing_bin_qty, existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item",
+ "warehouse": "_Test Warehouse - _TC"}, ["actual_qty", "stock_value"])
+
+ if existing_bin_qty < 0:
+ make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=abs(existing_bin_qty))
pr = make_purchase_receipt()
@@ -75,6 +118,8 @@
self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
+ pr.cancel()
+
def test_batched_serial_no_purchase(self):
item = frappe.db.exists("Item", {'item_name': 'Batched Serialized Item'})
if not item:
@@ -100,7 +145,10 @@
self.assertFalse(frappe.db.get_all('Serial No', {'batch_no': batch_no}))
def test_purchase_receipt_gl_entry(self):
- pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", get_multiple_items = True, get_taxes_and_charges = True)
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
+ warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1",
+ get_multiple_items = True, get_taxes_and_charges = True)
+
self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
@@ -143,22 +191,30 @@
rm_supp_cost = sum([d.amount for d in pr.get("supplied_items")])
self.assertEqual(pr.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
+
+ pr.cancel()
def test_subcontracting_gle_fg_item_rate_zero(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
- set_perpetual_inventory()
frappe.db.set_value("Buying Settings", None, "backflush_raw_materials_of_subcontract_based_on", "BOM")
- make_stock_entry(item_code="_Test Item", target="Work In Progress - TCP1", qty=100, basic_rate=100, company="_Test Company with perpetual inventory")
- make_stock_entry(item_code="_Test Item Home Desktop 100", target="Work In Progress - TCP1",
+
+ se1 = make_stock_entry(item_code="_Test Item", target="Work In Progress - TCP1",
qty=100, basic_rate=100, company="_Test Company with perpetual inventory")
+
+ se2 = make_stock_entry(item_code="_Test Item Home Desktop 100", target="Work In Progress - TCP1",
+ qty=100, basic_rate=100, company="_Test Company with perpetual inventory")
+
pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=0, is_subcontracted="Yes",
- company="_Test Company with perpetual inventory", warehouse='Stores - TCP1', supplier_warehouse='Work In Progress - TCP1')
+ company="_Test Company with perpetual inventory", warehouse='Stores - TCP1',
+ supplier_warehouse='Work In Progress - TCP1')
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
self.assertFalse(gl_entries)
- set_perpetual_inventory(0)
+ pr.cancel()
+ se1.cancel()
+ se2.cancel()
def test_subcontracting_over_receipt(self):
"""
@@ -174,24 +230,21 @@
update_backflush_based_on("Material Transferred for Subcontract")
item_code = "_Test Subcontracted FG Item 1"
- make_subcontracted_item(item_code)
+ make_subcontracted_item(item_code=item_code)
- po = create_purchase_order(item_code=item_code, qty=1,
+ po = create_purchase_order(item_code=item_code, qty=1, include_exploded_items=0,
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
#stock raw materials in a warehouse before transfer
- make_stock_entry(target="_Test Warehouse - _TC",
- item_code="_Test Item Home Desktop 100", qty=1, basic_rate=100)
- make_stock_entry(target="_Test Warehouse - _TC",
- item_code = "Test Extra Item 1", qty=1, basic_rate=100)
- make_stock_entry(target="_Test Warehouse - _TC",
- item_code = "_Test Item", qty=1, basic_rate=100)
-
+ se1 = make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Test Extra Item 1", qty=10, basic_rate=100)
+ se2 = make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "_Test FG Item", qty=1, basic_rate=100)
rm_items = [
{
"item_code": item_code,
"rm_item_code": po.supplied_items[0].rm_item_code,
- "item_name": "_Test Item",
+ "item_name": "_Test FG Item",
"qty": po.supplied_items[0].required_qty,
"warehouse": "_Test Warehouse - _TC",
"stock_uom": "Nos"
@@ -203,14 +256,6 @@
"qty": po.supplied_items[1].required_qty,
"warehouse": "_Test Warehouse - _TC",
"stock_uom": "Nos"
- },
- {
- "item_code": item_code,
- "rm_item_code": po.supplied_items[2].rm_item_code,
- "item_name": "_Test Item Home Desktop 100",
- "qty": po.supplied_items[2].required_qty,
- "warehouse": "_Test Warehouse - _TC",
- "stock_uom": "Nos"
}
]
rm_item_string = json.dumps(rm_items)
@@ -225,6 +270,13 @@
pr1.submit()
self.assertRaises(frappe.ValidationError, pr2.submit)
+ pr1.cancel()
+ se.cancel()
+ se1.cancel()
+ se2.cancel()
+ po.reload()
+ po.cancel()
+
def test_serial_no_supplier(self):
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
self.assertEqual(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"),
@@ -255,11 +307,17 @@
self.assertEqual(frappe.db.get_value("Serial No", serial_no, "warehouse"),
pr.get("items")[0].rejected_warehouse)
- def test_purchase_return(self):
+ pr.cancel()
- pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
+ def test_purchase_return_partial(self):
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
+ warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
- return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", is_return=1, return_against=pr.name, qty=-2)
+ return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
+ warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1",
+ is_return=1, return_against=pr.name, qty=-2, do_not_submit=1)
+ return_pr.items[0].purchase_receipt_item = pr.items[0].name
+ return_pr.submit()
# check sle
outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
@@ -283,6 +341,63 @@
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
+ # hack because new_doc isn't considering is_return portion of status_updater
+ returned = frappe.get_doc("Purchase Receipt", return_pr.name)
+ returned.update_prevdoc_status()
+ pr.load_from_db()
+
+ # Check if Original PR updated
+ self.assertEqual(pr.items[0].returned_qty, 2)
+ self.assertEqual(pr.per_returned, 40)
+
+ from erpnext.controllers.sales_and_purchase_return import make_return_doc
+ return_pr_2 = make_return_doc("Purchase Receipt", pr.name)
+
+ # Check if unreturned amount is mapped in 2nd return
+ self.assertEqual(return_pr_2.items[0].qty, -3)
+
+ # Make PI against unreturned amount
+ pi = make_purchase_invoice(pr.name)
+ pi.submit()
+
+ self.assertEqual(pi.items[0].qty, 3)
+
+ pr.load_from_db()
+ # PR should be completed on billing all unreturned amount
+ self.assertEqual(pr.items[0].billed_amt, 150)
+ self.assertEqual(pr.per_billed, 100)
+ self.assertEqual(pr.status, 'Completed')
+
+ pi.load_from_db()
+ pi.cancel()
+
+ pr.load_from_db()
+ self.assertEqual(pr.per_billed, 0)
+
+ return_pr.cancel()
+ pr.cancel()
+
+ def test_purchase_return_full(self):
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
+ supplier_warehouse = "Work in Progress - TCP1")
+
+ return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
+ supplier_warehouse = "Work in Progress - TCP1", is_return=1, return_against=pr.name, qty=-5, do_not_submit=1)
+ return_pr.items[0].purchase_receipt_item = pr.items[0].name
+ return_pr.submit()
+
+ # hack because new_doc isn't considering is_return portion of status_updater
+ returned = frappe.get_doc("Purchase Receipt", return_pr.name)
+ returned.update_prevdoc_status()
+ pr.load_from_db()
+
+ # Check if Original PR updated
+ self.assertEqual(pr.items[0].returned_qty, 5)
+ self.assertEqual(pr.per_returned, 100)
+ self.assertEqual(pr.status, 'Return Issued')
+
+ return_pr.cancel()
+ pr.cancel()
def test_purchase_return_for_rejected_qty(self):
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
@@ -301,6 +416,9 @@
self.assertEqual(actual_qty, -2)
+ return_pr.cancel()
+ pr.cancel()
+
def test_purchase_return_for_serialized_items(self):
def _check_serial_no_values(serial_no, field_values):
@@ -328,6 +446,10 @@
"delivery_document_no": return_pr.name
})
+ return_pr.cancel()
+ pr.reload()
+ pr.cancel()
+
def test_purchase_return_for_multi_uom(self):
item_code = "_Test Purchase Return For Multi-UOM"
if not frappe.db.exists('Item', item_code):
@@ -344,6 +466,9 @@
self.assertEqual(abs(return_pr.items[0].stock_qty), 1.0)
+ return_pr.cancel()
+ pr.cancel()
+
def test_closed_purchase_receipt(self):
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_purchase_receipt_status
@@ -353,6 +478,9 @@
update_purchase_receipt_status(pr.name, "Closed")
self.assertEqual(frappe.db.get_value("Purchase Receipt", pr.name, "status"), "Closed")
+ pr.reload()
+ pr.cancel()
+
def test_pr_billing_status(self):
# PO -> PR1 -> PI and PO -> PI and PO -> PR2
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
@@ -390,10 +518,21 @@
self.assertEqual(pr1.per_billed, 100)
self.assertEqual(pr1.status, "Completed")
+ pr2.load_from_db()
self.assertEqual(pr2.get("items")[0].billed_amt, 2000)
self.assertEqual(pr2.per_billed, 80)
self.assertEqual(pr2.status, "To Bill")
+ pr2.cancel()
+ pi2.reload()
+ pi2.cancel()
+ pi1.reload()
+ pi1.cancel()
+ pr1.reload()
+ pr1.cancel()
+ po.reload()
+ po.cancel()
+
def test_serial_no_against_purchase_receipt(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -421,6 +560,8 @@
self.assertEqual(serial_no, frappe.db.get_value("Serial No",
{"purchase_document_type": "Purchase Receipt", "purchase_document_no": new_pr_doc.name}, "name"))
+ new_pr_doc.cancel()
+
def test_not_accept_duplicate_serial_no(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
@@ -431,15 +572,18 @@
item_code = item.name
serial_no = random_string(5)
- make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no)
- create_delivery_note(item_code=item_code, qty=1, serial_no=serial_no)
+ pr1 = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no)
+ dn = create_delivery_note(item_code=item_code, qty=1, serial_no=serial_no)
- pr = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no, do_not_submit=True)
- self.assertRaises(SerialNoDuplicateError, pr.submit)
+ pr2 = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no, do_not_submit=True)
+ self.assertRaises(SerialNoDuplicateError, pr2.submit)
se = make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1,
serial_no=serial_no, basic_rate=100, do_not_submit=True)
- self.assertRaises(SerialNoDuplicateError, se.submit)
+ se.submit()
+
+ dn.cancel()
+ pr1.cancel()
def test_auto_asset_creation(self):
asset_item = "Test Asset Item"
@@ -461,7 +605,7 @@
'company_name': '_Test Company',
'fixed_asset_account': '_Test Fixed Asset - _TC',
'accumulated_depreciation_account': '_Test Accumulated Depreciations - _TC',
- 'depreciation_expense_account': '_Test Depreciation - _TC'
+ 'depreciation_expense_account': '_Test Depreciations - _TC'
}]
}).insert()
@@ -480,6 +624,8 @@
location = frappe.db.get_value('Asset', assets[0].name, 'location')
self.assertEquals(location, "Test Location")
+ pr.cancel()
+
def test_purchase_return_with_submitted_asset(self):
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return
@@ -506,6 +652,9 @@
pr_return.submit()
+ pr_return.cancel()
+ pr.cancel()
+
def test_purchase_receipt_cost_center(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
cost_center = "_Test Cost Center for BS Account - TCP1"
@@ -517,7 +666,8 @@
'location_name': 'Test Location'
}).insert()
- pr = make_purchase_receipt(cost_center=cost_center, company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
+ pr = make_purchase_receipt(cost_center=cost_center, company="_Test Company with perpetual inventory",
+ warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
@@ -535,6 +685,8 @@
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+ pr.cancel()
+
def test_purchase_receipt_cost_center_with_balance_sheet_account(self):
if not frappe.db.exists('Location', 'Test Location'):
frappe.get_doc({
@@ -560,6 +712,8 @@
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+ pr.cancel()
+
def test_make_purchase_invoice_from_pr_for_returned_qty(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, create_pr_against_po
@@ -575,6 +729,12 @@
pi = make_purchase_invoice(pr.name)
self.assertEquals(pi.items[0].qty, 3)
+ pr1.cancel()
+ pr.reload()
+ pr.cancel()
+ po.reload()
+ po.cancel()
+
def test_make_purchase_invoice_from_pr_with_returned_qty_duplicate_items(self):
pr1 = make_purchase_receipt(qty=8, do_not_submit=True)
pr1.append("items", {
@@ -601,8 +761,14 @@
self.assertEquals(pi2.items[0].qty, 2)
self.assertEquals(pi2.items[1].qty, 1)
+ pr2.cancel()
+ pi1.cancel()
+ pr1.reload()
+ pr1.cancel()
+
def test_stock_transfer_from_purchase_receipt(self):
- pr1 = make_purchase_receipt(warehouse = 'Work In Progress - TCP1', company="_Test Company with perpetual inventory")
+ pr1 = make_purchase_receipt(warehouse = 'Work In Progress - TCP1',
+ company="_Test Company with perpetual inventory")
pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
warehouse = "Stores - TCP1", do_not_save=1)
@@ -625,18 +791,20 @@
for sle in sl_entries:
self.assertEqual(expected_sle[sle.warehouse], sle.actual_qty)
- def test_stock_transfer_from_purchase_receipt_with_valuation(self):
- warehouse = frappe.get_doc('Warehouse', 'Work In Progress - TCP1')
- warehouse.account = '_Test Account Stock In Hand - TCP1'
- warehouse.save()
+ pr.cancel()
+ pr1.cancel()
- pr1 = make_purchase_receipt(warehouse = 'Work In Progress - TCP1',
+ def test_stock_transfer_from_purchase_receipt_with_valuation(self):
+ create_warehouse("_Test Warehouse for Valuation", company="_Test Company with perpetual inventory",
+ properties={"account": '_Test Account Stock In Hand - TCP1'})
+
+ pr1 = make_purchase_receipt(warehouse = '_Test Warehouse for Valuation - TCP1',
company="_Test Company with perpetual inventory")
pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
warehouse = "Stores - TCP1", do_not_save=1)
- pr.items[0].from_warehouse = 'Work In Progress - TCP1'
+ pr.items[0].from_warehouse = '_Test Warehouse for Valuation - TCP1'
pr.supplier_warehouse = ''
@@ -661,7 +829,7 @@
]
expected_sle = {
- 'Work In Progress - TCP1': -5,
+ '_Test Warehouse for Valuation - TCP1': -5,
'Stores - TCP1': 5
}
@@ -673,8 +841,76 @@
self.assertEqual(gle.debit, expected_gle[i][1])
self.assertEqual(gle.credit, expected_gle[i][2])
- warehouse.account = ''
- warehouse.save()
+ pr.cancel()
+ pr1.cancel()
+
+
+ def test_subcontracted_pr_for_multi_transfer_batches(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+ from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry, make_purchase_receipt
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import (update_backflush_based_on,
+ create_purchase_order)
+
+ update_backflush_based_on("Material Transferred for Subcontract")
+ item_code = "_Test Subcontracted FG Item 3"
+
+ make_item('Sub Contracted Raw Material 3', {
+ 'is_stock_item': 1,
+ 'is_sub_contracted_item': 1,
+ 'has_batch_no': 1,
+ 'create_new_batch': 1
+ })
+
+ create_subcontracted_item(item_code=item_code, has_batch_no=1,
+ raw_materials=["Sub Contracted Raw Material 3"])
+
+ order_qty = 500
+ po = create_purchase_order(item_code=item_code, qty=order_qty,
+ is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
+
+ ste1=make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Sub Contracted Raw Material 3", qty=300, basic_rate=100)
+ ste2=make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Sub Contracted Raw Material 3", qty=200, basic_rate=100)
+
+ transferred_batch = {
+ ste1.items[0].batch_no : 300,
+ ste2.items[0].batch_no : 200
+ }
+
+ rm_items = [
+ {"item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 3","item_name":"_Test Item",
+ "qty":300,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos", "name": po.supplied_items[0].name},
+ {"item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 3","item_name":"_Test Item",
+ "qty":200,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos", "name": po.supplied_items[0].name}
+ ]
+
+ rm_item_string = json.dumps(rm_items)
+ se = frappe.get_doc(make_rm_stock_entry(po.name, rm_item_string))
+ self.assertEqual(len(se.items), 2)
+ se.items[0].batch_no = ste1.items[0].batch_no
+ se.items[1].batch_no = ste2.items[0].batch_no
+ se.submit()
+
+ supplied_qty = frappe.db.get_value("Purchase Order Item Supplied",
+ {"parent": po.name, "rm_item_code": "Sub Contracted Raw Material 3"}, "supplied_qty")
+
+ self.assertEqual(supplied_qty, 500.00)
+
+ pr = make_purchase_receipt(po.name)
+ pr.save()
+ self.assertEqual(len(pr.supplied_items), 2)
+
+ for row in pr.supplied_items:
+ self.assertEqual(transferred_batch.get(row.batch_no), row.consumed_qty)
+
+ update_backflush_based_on("BOM")
+
+ pr.delete()
+ se.cancel()
+ ste2.cancel()
+ ste1.cancel()
+ po.cancel()
def get_sl_entries(voucher_type, voucher_no):
return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
@@ -771,6 +1007,8 @@
pr.posting_date = args.posting_date or today()
if args.posting_time:
pr.posting_time = args.posting_time
+ if args.posting_date or args.posting_time:
+ pr.set_posting_time = 1
pr.company = args.company or "_Test Company"
pr.supplier = args.supplier or "_Test Supplier"
pr.is_subcontracted = args.is_subcontracted or "No"
@@ -778,6 +1016,7 @@
pr.currency = args.currency or "INR"
pr.is_return = args.is_return
pr.return_against = args.return_against
+ pr.apply_putaway_rule = args.apply_putaway_rule
qty = args.qty or 5
received_qty = args.received_qty or qty
rejected_qty = args.rejected_qty or flt(received_qty) - flt(qty)
@@ -793,6 +1032,7 @@
"rejected_warehouse": args.rejected_warehouse or "_Test Rejected Warehouse - _TC" if rejected_qty != 0 else "",
"rate": args.rate if args.rate != None else 50,
"conversion_factor": args.conversion_factor or 1.0,
+ "stock_qty": flt(qty) * (flt(args.conversion_factor) or 1.0),
"serial_no": args.serial_no,
"stock_uom": args.stock_uom or "_Test UOM",
"uom": uom,
@@ -816,6 +1056,33 @@
pr.submit()
return pr
+def create_subcontracted_item(**args):
+ from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
+ args = frappe._dict(args)
+
+ if not frappe.db.exists('Item', args.item_code):
+ make_item(args.item_code, {
+ 'is_stock_item': 1,
+ 'is_sub_contracted_item': 1,
+ 'has_batch_no': args.get("has_batch_no") or 0
+ })
+
+ if not args.raw_materials:
+ if not frappe.db.exists('Item', "Test Extra Item 1"):
+ make_item("Test Extra Item 1", {
+ 'is_stock_item': 1,
+ })
+
+ if not frappe.db.exists('Item', "Test Extra Item 2"):
+ make_item("Test Extra Item 2", {
+ 'is_stock_item': 1,
+ })
+
+ args.raw_materials = ['_Test FG Item', 'Test Extra Item 1']
+
+ if not frappe.db.get_value('BOM', {'item': args.item_code}, 'name'):
+ make_bom(item = args.item_code, raw_materials = args.get("raw_materials"))
test_dependencies = ["BOM", "Item Price", "Location"]
test_records = frappe.get_test_records('Purchase Receipt')
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index c1e1f90..efe3642 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -28,15 +28,25 @@
"uom",
"stock_uom",
"conversion_factor",
- "stock_qty",
"retain_sample",
"sample_quantity",
+ "tracking_section",
+ "received_stock_qty",
+ "stock_qty",
+ "col_break_tracking_section",
+ "returned_qty",
"rate_and_amount",
"price_list_rate",
- "discount_percentage",
- "discount_amount",
"col_break3",
"base_price_list_rate",
+ "discount_and_margin_section",
+ "margin_type",
+ "margin_rate_or_amount",
+ "rate_with_margin",
+ "column_break_37",
+ "discount_percentage",
+ "discount_amount",
+ "base_rate_with_margin",
"sec_break1",
"rate",
"amount",
@@ -44,6 +54,7 @@
"base_rate",
"base_amount",
"pricing_rules",
+ "stock_uom_rate",
"is_free_item",
"section_break_29",
"net_rate",
@@ -72,6 +83,8 @@
"purchase_order_item",
"material_request_item",
"purchase_receipt_item",
+ "delivery_note_item",
+ "putaway_rule",
"section_break_45",
"allow_zero_valuation_rate",
"bom",
@@ -526,7 +539,7 @@
{
"fieldname": "stock_qty",
"fieldtype": "Float",
- "label": "Accepted Qty as per Stock UOM",
+ "label": "Accepted Qty in Stock UOM",
"oldfieldname": "stock_qty",
"oldfieldtype": "Currency",
"print_hide": 1,
@@ -814,11 +827,12 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.is_internal_supplier",
"fieldname": "from_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "label": "Supplier Warehouse",
+ "label": "From Warehouse",
"options": "Warehouse"
},
{
@@ -834,12 +848,104 @@
"collapsible": 1,
"fieldname": "image_column",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "putaway_rule",
+ "fieldtype": "Link",
+ "label": "Putaway Rule",
+ "no_copy": 1,
+ "options": "Putaway Rule",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "tracking_section",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "col_break_tracking_section",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "returned_qty",
+ "fieldname": "returned_qty",
+ "fieldtype": "Float",
+ "label": "Returned Qty in Stock UOM",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "received_stock_qty",
+ "fieldtype": "Float",
+ "label": "Received Qty in Stock UOM",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval: doc.uom != doc.stock_uom",
+ "fieldname": "stock_uom_rate",
+ "fieldtype": "Currency",
+ "label": "Rate of Stock UOM",
+ "no_copy": 1,
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "delivery_note_item",
+ "fieldtype": "Data",
+ "label": "Delivery Note Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "discount_and_margin_section",
+ "fieldtype": "Section Break",
+ "label": "Discount and Margin"
+ },
+ {
+ "depends_on": "price_list_rate",
+ "fieldname": "margin_type",
+ "fieldtype": "Select",
+ "label": "Margin Type",
+ "options": "\nPercentage\nAmount",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate",
+ "fieldname": "margin_rate_or_amount",
+ "fieldtype": "Float",
+ "label": "Margin Rate or Amount",
+ "print_hide": 1
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "rate_with_margin",
+ "fieldtype": "Currency",
+ "label": "Rate With Margin",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_37",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "label": "Rate With Margin (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-28 19:01:21.154963",
+ "modified": "2021-02-23 00:59:14.360847",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
index 679bd1e..b79bb5d 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
@@ -5,8 +5,6 @@
import frappe
from frappe.model.document import Document
-from erpnext.controllers.print_settings import print_settings_for_item_table
class PurchaseReceiptItem(Document):
- def __setup__(self):
- print_settings_for_item_table(self)
+ pass
diff --git a/erpnext/config/__init__.py b/erpnext/stock/doctype/putaway_rule/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/stock/doctype/putaway_rule/__init__.py
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.js b/erpnext/stock/doctype/putaway_rule/putaway_rule.js
new file mode 100644
index 0000000..e056920
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.js
@@ -0,0 +1,43 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Putaway Rule', {
+ setup: function(frm) {
+ frm.set_query("warehouse", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ "is_group": 0
+ }
+ };
+ });
+ },
+
+ uom: function(frm) {
+ if (frm.doc.item_code && frm.doc.uom) {
+ return frm.call({
+ method: "erpnext.stock.get_item_details.get_conversion_factor",
+ args: {
+ item_code: frm.doc.item_code,
+ uom: frm.doc.uom
+ },
+ callback: function(r) {
+ if (!r.exc) {
+ let stock_capacity = flt(frm.doc.capacity) * flt(r.message.conversion_factor);
+ frm.set_value('conversion_factor', r.message.conversion_factor);
+ frm.set_value('stock_capacity', stock_capacity);
+ }
+ }
+ });
+ }
+ },
+
+ capacity: function(frm) {
+ let stock_capacity = flt(frm.doc.capacity) * flt(frm.doc.conversion_factor);
+ frm.set_value('stock_capacity', stock_capacity);
+ }
+
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.json b/erpnext/stock/doctype/putaway_rule/putaway_rule.json
new file mode 100644
index 0000000..a003f49
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.json
@@ -0,0 +1,160 @@
+{
+ "actions": [],
+ "autoname": "PUT-.####",
+ "creation": "2020-11-09 11:39:46.489501",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "disable",
+ "item_code",
+ "item_name",
+ "warehouse",
+ "priority",
+ "col_break_capacity",
+ "company",
+ "capacity",
+ "uom",
+ "conversion_factor",
+ "stock_uom",
+ "stock_capacity"
+ ],
+ "fields": [
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Item",
+ "options": "Item",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "item_code.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Warehouse",
+ "options": "Warehouse",
+ "reqd": 1
+ },
+ {
+ "fieldname": "col_break_capacity",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "capacity",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Capacity",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "item_code.stock_uom",
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "options": "UOM",
+ "read_only": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "priority",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Priority"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "disable",
+ "fieldtype": "Check",
+ "label": "Disable"
+ },
+ {
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "no_copy": 1,
+ "options": "UOM"
+ },
+ {
+ "fieldname": "stock_capacity",
+ "fieldtype": "Float",
+ "label": "Capacity in Stock UOM",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "label": "Conversion Factor",
+ "no_copy": 1,
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-11-25 20:39:19.973437",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Putaway Rule",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "permlevel": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "item_code",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
new file mode 100644
index 0000000..ea26cac
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
@@ -0,0 +1,235 @@
+# -*- 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 copy
+import json
+from collections import defaultdict
+from six import string_types
+from frappe import _
+from frappe.utils import flt, floor, nowdate, cint
+from frappe.model.document import Document
+from erpnext.stock.utils import get_stock_balance
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+class PutawayRule(Document):
+ def validate(self):
+ self.validate_duplicate_rule()
+ self.validate_warehouse_and_company()
+ self.validate_capacity()
+ self.validate_priority()
+ self.set_stock_capacity()
+
+ def validate_duplicate_rule(self):
+ existing_rule = frappe.db.exists("Putaway Rule", {"item_code": self.item_code, "warehouse": self.warehouse})
+ if existing_rule and existing_rule != self.name:
+ frappe.throw(_("Putaway Rule already exists for Item {0} in Warehouse {1}.")
+ .format(frappe.bold(self.item_code), frappe.bold(self.warehouse)),
+ title=_("Duplicate"))
+
+ def validate_priority(self):
+ if self.priority < 1:
+ frappe.throw(_("Priority cannot be lesser than 1."), title=_("Invalid Priority"))
+
+ def validate_warehouse_and_company(self):
+ company = frappe.db.get_value("Warehouse", self.warehouse, "company")
+ if company != self.company:
+ frappe.throw(_("Warehouse {0} does not belong to Company {1}.")
+ .format(frappe.bold(self.warehouse), frappe.bold(self.company)),
+ title=_("Invalid Warehouse"))
+
+ def validate_capacity(self):
+ stock_uom = frappe.db.get_value("Item", self.item_code, "stock_uom")
+ balance_qty = get_stock_balance(self.item_code, self.warehouse, nowdate())
+
+ if flt(self.stock_capacity) < flt(balance_qty):
+ frappe.throw(_("Warehouse Capacity for Item '{0}' must be greater than the existing stock level of {1} {2}.")
+ .format(self.item_code, frappe.bold(balance_qty), stock_uom),
+ title=_("Insufficient Capacity"))
+
+ if not self.capacity:
+ frappe.throw(_("Capacity must be greater than 0"), title=_("Invalid"))
+
+ def set_stock_capacity(self):
+ self.stock_capacity = (flt(self.conversion_factor) or 1) * flt(self.capacity)
+
+@frappe.whitelist()
+def get_available_putaway_capacity(rule):
+ stock_capacity, item_code, warehouse = frappe.db.get_value("Putaway Rule", rule,
+ ["stock_capacity", "item_code", "warehouse"])
+ balance_qty = get_stock_balance(item_code, warehouse, nowdate())
+ free_space = flt(stock_capacity) - flt(balance_qty)
+ return free_space if free_space > 0 else 0
+
+@frappe.whitelist()
+def apply_putaway_rule(doctype, items, company, sync=None, purpose=None):
+ """ Applies Putaway Rule on line items.
+
+ items: List of Purchase Receipt/Stock Entry Items
+ company: Company in the Purchase Receipt/Stock Entry
+ doctype: Doctype to apply rule on
+ purpose: Purpose of Stock Entry
+ sync (optional): Sync with client side only for client side calls
+ """
+ if isinstance(items, string_types):
+ items = json.loads(items)
+
+ items_not_accomodated, updated_table = [], []
+ item_wise_rules = defaultdict(list)
+
+ for item in items:
+ if isinstance(item, dict):
+ item = frappe._dict(item)
+
+ source_warehouse = item.get("s_warehouse")
+ serial_nos = get_serial_nos(item.get("serial_no"))
+ item.conversion_factor = flt(item.conversion_factor) or 1.0
+ pending_qty, item_code = flt(item.qty), item.item_code
+ pending_stock_qty = flt(item.transfer_qty) if doctype == "Stock Entry" else flt(item.stock_qty)
+ uom_must_be_whole_number = frappe.db.get_value('UOM', item.uom, 'must_be_whole_number')
+
+ if not pending_qty or not item_code:
+ updated_table = add_row(item, pending_qty, source_warehouse or item.warehouse, updated_table)
+ continue
+
+ at_capacity, rules = get_ordered_putaway_rules(item_code, company, source_warehouse=source_warehouse)
+
+ if not rules:
+ warehouse = source_warehouse or item.warehouse
+ if at_capacity:
+ # rules available, but no free space
+ items_not_accomodated.append([item_code, pending_qty])
+ else:
+ updated_table = add_row(item, pending_qty, warehouse, updated_table)
+ continue
+
+ # maintain item/item-warehouse wise rules, to handle if item is entered twice
+ # in the table, due to different price, etc.
+ key = item_code
+ if doctype == "Stock Entry" and purpose == "Material Transfer" and source_warehouse:
+ key = (item_code, source_warehouse)
+
+ if not item_wise_rules[key]:
+ item_wise_rules[key] = rules
+
+ for rule in item_wise_rules[key]:
+ if pending_stock_qty > 0 and rule.free_space:
+ stock_qty_to_allocate = flt(rule.free_space) if pending_stock_qty >= flt(rule.free_space) else pending_stock_qty
+ qty_to_allocate = stock_qty_to_allocate / item.conversion_factor
+
+ if uom_must_be_whole_number:
+ qty_to_allocate = floor(qty_to_allocate)
+ stock_qty_to_allocate = qty_to_allocate * item.conversion_factor
+
+ if not qty_to_allocate: break
+
+ updated_table = add_row(item, qty_to_allocate, rule.warehouse, updated_table,
+ rule.name, serial_nos=serial_nos)
+
+ pending_stock_qty -= stock_qty_to_allocate
+ pending_qty -= qty_to_allocate
+ rule["free_space"] -= stock_qty_to_allocate
+
+ if not pending_stock_qty > 0: break
+
+ # if pending qty after applying all rules, add row without warehouse
+ if pending_stock_qty > 0:
+ items_not_accomodated.append([item.item_code, pending_qty])
+
+ if items_not_accomodated:
+ show_unassigned_items_message(items_not_accomodated)
+
+ items[:] = updated_table if updated_table else items # modify items table
+
+ if sync and json.loads(sync): # sync with client side
+ return items
+
+def get_ordered_putaway_rules(item_code, company, source_warehouse=None):
+ """Returns an ordered list of putaway rules to apply on an item."""
+ filters = {
+ "item_code": item_code,
+ "company": company,
+ "disable": 0
+ }
+ if source_warehouse:
+ filters.update({"warehouse": ["!=", source_warehouse]})
+
+ rules = frappe.get_all("Putaway Rule",
+ fields=["name", "item_code", "stock_capacity", "priority", "warehouse"],
+ filters=filters,
+ order_by="priority asc, capacity desc")
+
+ if not rules:
+ return False, None
+
+ vacant_rules = []
+ for rule in rules:
+ balance_qty = get_stock_balance(rule.item_code, rule.warehouse, nowdate())
+ free_space = flt(rule.stock_capacity) - flt(balance_qty)
+ if free_space > 0:
+ rule["free_space"] = free_space
+ vacant_rules.append(rule)
+
+ if not vacant_rules:
+ # After iterating through rules, if no rules are left
+ # then there is not enough space left in any rule
+ return True, None
+
+ vacant_rules = sorted(vacant_rules, key = lambda i: (i['priority'], -i['free_space']))
+
+ return False, vacant_rules
+
+def add_row(item, to_allocate, warehouse, updated_table, rule=None, serial_nos=None):
+ new_updated_table_row = copy.deepcopy(item)
+ new_updated_table_row.idx = 1 if not updated_table else cint(updated_table[-1].idx) + 1
+ new_updated_table_row.name = None
+ new_updated_table_row.qty = to_allocate
+
+ if item.doctype == "Stock Entry Detail":
+ new_updated_table_row.t_warehouse = warehouse
+ new_updated_table_row.transfer_qty = flt(to_allocate) * flt(new_updated_table_row.conversion_factor)
+ else:
+ new_updated_table_row.stock_qty = flt(to_allocate) * flt(new_updated_table_row.conversion_factor)
+ new_updated_table_row.warehouse = warehouse
+ new_updated_table_row.rejected_qty = 0
+ new_updated_table_row.received_qty = to_allocate
+
+ if rule:
+ new_updated_table_row.putaway_rule = rule
+ if serial_nos:
+ new_updated_table_row.serial_no = get_serial_nos_to_allocate(serial_nos, to_allocate)
+
+ updated_table.append(new_updated_table_row)
+ return updated_table
+
+def show_unassigned_items_message(items_not_accomodated):
+ msg = _("The following Items, having Putaway Rules, could not be accomodated:") + "<br><br>"
+ formatted_item_rows = ""
+
+ for entry in items_not_accomodated:
+ item_link = frappe.utils.get_link_to_form("Item", entry[0])
+ formatted_item_rows += """
+ <td>{0}</td>
+ <td>{1}</td>
+ </tr>""".format(item_link, frappe.bold(entry[1]))
+
+ msg += """
+ <table class="table">
+ <thead>
+ <td>{0}</td>
+ <td>{1}</td>
+ </thead>
+ {2}
+ </table>
+ """.format(_("Item"), _("Unassigned Qty"), formatted_item_rows)
+
+ frappe.msgprint(msg, title=_("Insufficient Capacity"), is_minimizable=True, wide=True)
+
+def get_serial_nos_to_allocate(serial_nos, to_allocate):
+ if serial_nos:
+ allocated_serial_nos = serial_nos[0: cint(to_allocate)]
+ serial_nos[:] = serial_nos[cint(to_allocate):] # pop out allocated serial nos and modify list
+ return "\n".join(allocated_serial_nos) if allocated_serial_nos else ""
+ else: return ""
\ No newline at end of file
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule_list.js b/erpnext/stock/doctype/putaway_rule/putaway_rule_list.js
new file mode 100644
index 0000000..725e91e
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule_list.js
@@ -0,0 +1,18 @@
+frappe.listview_settings['Putaway Rule'] = {
+ add_fields: ["disable"],
+ get_indicator: (doc) => {
+ if (doc.disable) {
+ return [__("Disabled"), "darkgrey", "disable,=,1"];
+ } else {
+ return [__("Active"), "blue", "disable,=,0"];
+ }
+ },
+
+ reports: [
+ {
+ name: 'Warehouse Capacity Summary',
+ report_type: 'Page',
+ route: 'warehouse-capacity-summary'
+ }
+ ]
+};
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
new file mode 100644
index 0000000..86f7dc3
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -0,0 +1,389 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+import frappe
+import unittest
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.get_item_details import get_conversion_factor
+from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+from erpnext.stock.doctype.batch.test_batch import make_new_batch
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+
+class TestPutawayRule(unittest.TestCase):
+ def setUp(self):
+ if not frappe.db.exists("Item", "_Rice"):
+ make_item("_Rice", {
+ 'is_stock_item': 1,
+ 'has_batch_no' : 1,
+ 'create_new_batch': 1,
+ 'stock_uom': 'Kg'
+ })
+
+ if not frappe.db.exists("Warehouse", {"warehouse_name": "Rack 1"}):
+ create_warehouse("Rack 1")
+ if not frappe.db.exists("Warehouse", {"warehouse_name": "Rack 2"}):
+ create_warehouse("Rack 2")
+
+ self.warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
+ self.warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
+
+ if not frappe.db.exists("UOM", "Bag"):
+ new_uom = frappe.new_doc("UOM")
+ new_uom.uom_name = "Bag"
+ new_uom.save()
+
+ def test_putaway_rules_priority(self):
+ """Test if rule is applied by priority, irrespective of free space."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+ uom="Kg")
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=300,
+ uom="Kg", priority=2)
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1,
+ do_not_submit=1)
+ self.assertEqual(len(pr.items), 2)
+ self.assertEqual(pr.items[0].qty, 200)
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
+ self.assertEqual(pr.items[1].qty, 100)
+ self.assertEqual(pr.items[1].warehouse, self.warehouse_2)
+
+ pr.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rules_with_same_priority(self):
+ """Test if rule with more free space is applied,
+ among two rules with same priority and capacity."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=500,
+ uom="Kg")
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=500,
+ uom="Kg")
+
+ # out of 500 kg capacity, occupy 100 kg in warehouse_1
+ stock_receipt = make_stock_entry(item_code="_Rice", target=self.warehouse_1, qty=100, basic_rate=50)
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=700, apply_putaway_rule=1,
+ do_not_submit=1)
+ self.assertEqual(len(pr.items), 2)
+ self.assertEqual(pr.items[0].qty, 500)
+ # warehouse_2 has 500 kg free space, it is given priority
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_2)
+ self.assertEqual(pr.items[1].qty, 200)
+ # warehouse_1 has 400 kg free space, it is given less priority
+ self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
+
+ stock_receipt.cancel()
+ pr.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rules_with_insufficient_capacity(self):
+ """Test if qty exceeding capacity, is handled."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=100,
+ uom="Kg")
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=200,
+ uom="Kg")
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=350, apply_putaway_rule=1,
+ do_not_submit=1)
+ self.assertEqual(len(pr.items), 2)
+ self.assertEqual(pr.items[0].qty, 200)
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_2)
+ self.assertEqual(pr.items[1].qty, 100)
+ self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
+ # total 300 assigned, 50 unassigned
+
+ pr.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rules_multi_uom(self):
+ """Test rules applied on uom other than stock uom."""
+ item = frappe.get_doc("Item", "_Rice")
+ if not frappe.db.get_value("UOM Conversion Detail", {"parent": "_Rice", "uom": "Bag"}):
+ item.append("uoms", {
+ "uom": "Bag",
+ "conversion_factor": 1000
+ })
+ item.save()
+
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=3,
+ uom="Bag")
+ self.assertEqual(rule_1.stock_capacity, 3000)
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=4,
+ uom="Bag")
+ self.assertEqual(rule_2.stock_capacity, 4000)
+
+ # populate 'Rack 1' with 1 Bag, making the free space 2 Bags
+ stock_receipt = make_stock_entry(item_code="_Rice", target=self.warehouse_1, qty=1000, basic_rate=50)
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=6, uom="Bag", stock_uom="Kg",
+ conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1)
+ self.assertEqual(len(pr.items), 2)
+ self.assertEqual(pr.items[0].qty, 4)
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_2)
+ self.assertEqual(pr.items[1].qty, 2)
+ self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
+
+ stock_receipt.cancel()
+ pr.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rules_multi_uom_whole_uom(self):
+ """Test if whole UOMs are handled."""
+ item = frappe.get_doc("Item", "_Rice")
+ if not frappe.db.get_value("UOM Conversion Detail", {"parent": "_Rice", "uom": "Bag"}):
+ item.append("uoms", {
+ "uom": "Bag",
+ "conversion_factor": 1000
+ })
+ item.save()
+
+ frappe.db.set_value("UOM", "Bag", "must_be_whole_number", 1)
+
+ # Putaway Rule in different UOM
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=1,
+ uom="Bag")
+ self.assertEqual(rule_1.stock_capacity, 1000)
+ # Putaway Rule in Stock UOM
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=500)
+ self.assertEqual(rule_2.stock_capacity, 500)
+ # total capacity is 1500 Kg
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=2, uom="Bag", stock_uom="Kg",
+ conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1)
+ self.assertEqual(len(pr.items), 1)
+ self.assertEqual(pr.items[0].qty, 1)
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
+ # leftover space was for 500 kg (0.5 Bag)
+ # Since Bag is a whole UOM, 1(out of 2) Bag will be unassigned
+
+ pr.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rules_with_reoccurring_item(self):
+ """Test rules on same item entered multiple times with different rate."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+ uom="Kg")
+ # total capacity is 200 Kg
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=100, apply_putaway_rule=1,
+ do_not_submit=1)
+ pr.append("items", {
+ "item_code": "_Rice",
+ "warehouse": "_Test Warehouse - _TC",
+ "qty": 200,
+ "uom": "Kg",
+ "stock_uom": "Kg",
+ "stock_qty": 200,
+ "received_qty": 200,
+ "rate": 100,
+ "conversion_factor": 1.0,
+ }) # same item entered again in PR but with different rate
+ pr.save()
+ self.assertEqual(len(pr.items), 2)
+ self.assertEqual(pr.items[0].qty, 100)
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
+ self.assertEqual(pr.items[0].putaway_rule, rule_1.name)
+ # same rule applied to second item row
+ # with previous assignment considered
+ self.assertEqual(pr.items[1].qty, 100) # 100 unassigned in second row from 200
+ self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
+ self.assertEqual(pr.items[1].putaway_rule, rule_1.name)
+
+ pr.delete()
+ rule_1.delete()
+
+ def test_validate_over_receipt_in_warehouse(self):
+ """Test if overreceipt is blocked in the presence of putaway rules."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+ uom="Kg")
+
+ pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1,
+ do_not_submit=1)
+ self.assertEqual(len(pr.items), 1)
+ self.assertEqual(pr.items[0].qty, 200) # 100 is unassigned fro 300 Kg
+ self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
+ self.assertEqual(pr.items[0].putaway_rule, rule_1.name)
+
+ # force overreceipt and disable apply putaway rule in PR
+ pr.items[0].qty = 300
+ pr.items[0].stock_qty = 300
+ pr.apply_putaway_rule = 0
+ self.assertRaises(frappe.ValidationError, pr.save)
+
+ pr.delete()
+ rule_1.delete()
+
+ def test_putaway_rule_on_stock_entry_material_transfer(self):
+ """Test if source warehouse is considered while applying rules."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+ uom="Kg") # higher priority
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=100,
+ uom="Kg", priority=2)
+
+ stock_entry = make_stock_entry(item_code="_Rice", source=self.warehouse_1, qty=200,
+ target="_Test Warehouse - _TC", purpose="Material Transfer",
+ apply_putaway_rule=1, do_not_submit=1)
+
+ stock_entry_item = stock_entry.get("items")[0]
+
+ # since source warehouse is Rack 1, rule 1 (for Rack 1) will be avoided
+ # even though it has more free space and higher priority
+ self.assertEqual(stock_entry_item.t_warehouse, self.warehouse_2)
+ self.assertEqual(stock_entry_item.qty, 100) # unassigned 100 out of 200 Kg
+ self.assertEqual(stock_entry_item.putaway_rule, rule_2.name)
+
+ stock_entry.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rule_on_stock_entry_material_transfer_reoccuring_item(self):
+ """Test if reoccuring item is correctly considered."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=300,
+ uom="Kg")
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=600,
+ uom="Kg", priority=2)
+
+ # create SE with first row having source warehouse as Rack 2
+ stock_entry = make_stock_entry(item_code="_Rice", source=self.warehouse_2, qty=200,
+ target="_Test Warehouse - _TC", purpose="Material Transfer",
+ apply_putaway_rule=1, do_not_submit=1)
+
+ # Add rows with source warehouse as Rack 1
+ stock_entry.extend("items", [
+ {
+ "item_code": "_Rice",
+ "s_warehouse": self.warehouse_1,
+ "t_warehouse": "_Test Warehouse - _TC",
+ "qty": 100,
+ "basic_rate": 50,
+ "conversion_factor": 1.0,
+ "transfer_qty": 100
+ },
+ {
+ "item_code": "_Rice",
+ "s_warehouse": self.warehouse_1,
+ "t_warehouse": "_Test Warehouse - _TC",
+ "qty": 200,
+ "basic_rate": 60,
+ "conversion_factor": 1.0,
+ "transfer_qty": 200
+ }
+ ])
+
+ stock_entry.save()
+
+ # since source warehouse was Rack 2, exclude rule_2
+ self.assertEqual(stock_entry.items[0].t_warehouse, self.warehouse_1)
+ self.assertEqual(stock_entry.items[0].qty, 200)
+ self.assertEqual(stock_entry.items[0].putaway_rule, rule_1.name)
+
+ # since source warehouse was Rack 1, exclude rule_1 even though it has
+ # higher priority
+ self.assertEqual(stock_entry.items[1].t_warehouse, self.warehouse_2)
+ self.assertEqual(stock_entry.items[1].qty, 100)
+ self.assertEqual(stock_entry.items[1].putaway_rule, rule_2.name)
+
+ self.assertEqual(stock_entry.items[2].t_warehouse, self.warehouse_2)
+ self.assertEqual(stock_entry.items[2].qty, 200)
+ self.assertEqual(stock_entry.items[2].putaway_rule, rule_2.name)
+
+ stock_entry.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rule_on_stock_entry_material_transfer_batch_serial_item(self):
+ """Test if batch and serial items are split correctly."""
+ if not frappe.db.exists("Item", "Water Bottle"):
+ make_item("Water Bottle", {
+ "is_stock_item": 1,
+ "has_batch_no" : 1,
+ "create_new_batch": 1,
+ "has_serial_no": 1,
+ "serial_no_series": "BOTTL-.####",
+ "stock_uom": "Nos"
+ })
+
+ rule_1 = create_putaway_rule(item_code="Water Bottle", warehouse=self.warehouse_1, capacity=3,
+ uom="Nos")
+ rule_2 = create_putaway_rule(item_code="Water Bottle", warehouse=self.warehouse_2, capacity=2,
+ uom="Nos")
+
+ make_new_batch(batch_id="BOTTL-BATCH-1", item_code="Water Bottle")
+
+ pr = make_purchase_receipt(item_code="Water Bottle", qty=5, do_not_submit=1)
+ pr.items[0].batch_no = "BOTTL-BATCH-1"
+ pr.save()
+ pr.submit()
+
+ serial_nos = frappe.get_list("Serial No", filters={"purchase_document_no": pr.name, "status": "Active"})
+ serial_nos = [d.name for d in serial_nos]
+
+ stock_entry = make_stock_entry(item_code="Water Bottle", source="_Test Warehouse - _TC", qty=5,
+ target="Finished Goods - _TC", purpose="Material Transfer",
+ apply_putaway_rule=1, do_not_save=1)
+ stock_entry.items[0].batch_no = "BOTTL-BATCH-1"
+ stock_entry.items[0].serial_no = "\n".join(serial_nos)
+ stock_entry.save()
+
+ self.assertEqual(stock_entry.items[0].t_warehouse, self.warehouse_1)
+ self.assertEqual(stock_entry.items[0].qty, 3)
+ self.assertEqual(stock_entry.items[0].putaway_rule, rule_1.name)
+ self.assertEqual(stock_entry.items[0].serial_no, "\n".join(serial_nos[:3]))
+ self.assertEqual(stock_entry.items[0].batch_no, "BOTTL-BATCH-1")
+
+ self.assertEqual(stock_entry.items[1].t_warehouse, self.warehouse_2)
+ self.assertEqual(stock_entry.items[1].qty, 2)
+ self.assertEqual(stock_entry.items[1].putaway_rule, rule_2.name)
+ self.assertEqual(stock_entry.items[1].serial_no, "\n".join(serial_nos[3:]))
+ self.assertEqual(stock_entry.items[1].batch_no, "BOTTL-BATCH-1")
+
+ stock_entry.delete()
+ pr.cancel()
+ rule_1.delete()
+ rule_2.delete()
+
+ def test_putaway_rule_on_stock_entry_material_receipt(self):
+ """Test if rules are applied in Stock Entry of type Receipt."""
+ rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+ uom="Kg") # more capacity
+ rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=100,
+ uom="Kg")
+
+ stock_entry = make_stock_entry(item_code="_Rice", qty=100,
+ target="_Test Warehouse - _TC", purpose="Material Receipt",
+ apply_putaway_rule=1, do_not_submit=1)
+
+ stock_entry_item = stock_entry.get("items")[0]
+
+ self.assertEqual(stock_entry_item.t_warehouse, self.warehouse_1)
+ self.assertEqual(stock_entry_item.qty, 100)
+ self.assertEqual(stock_entry_item.putaway_rule, rule_1.name)
+
+ stock_entry.delete()
+ rule_1.delete()
+ rule_2.delete()
+
+def create_putaway_rule(**args):
+ args = frappe._dict(args)
+ putaway = frappe.new_doc("Putaway Rule")
+
+ putaway.disable = args.disable or 0
+ putaway.company = args.company or "_Test Company"
+ putaway.item_code = args.item or args.item_code or "_Test Item"
+ putaway.warehouse = args.warehouse
+ putaway.priority = args.priority or 1
+ putaway.capacity = args.capacity or 1
+ putaway.stock_uom = frappe.db.get_value("Item", putaway.item_code, "stock_uom")
+ putaway.uom = args.uom or putaway.stock_uom
+ putaway.conversion_factor = get_conversion_factor(putaway.item_code, putaway.uom)['conversion_factor']
+
+ if not args.do_not_save:
+ putaway.save()
+
+ return putaway
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.js b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
index 22f29e0..f7565fd 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.js
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
@@ -4,6 +4,60 @@
cur_frm.cscript.refresh = cur_frm.cscript.inspection_type;
frappe.ui.form.on("Quality Inspection", {
+
+ setup: function(frm) {
+ frm.set_query("batch_no", function() {
+ return {
+ filters: {
+ "item": frm.doc.item_code
+ }
+ };
+ });
+
+ // Serial No based on item_code
+ frm.set_query("item_serial_no", function() {
+ let filters = {};
+ if (frm.doc.item_code) {
+ filters = {
+ 'item_code': frm.doc.item_code
+ };
+ }
+ return { filters: filters };
+ });
+
+ // item code based on GRN/DN
+ frm.set_query("item_code", function(doc) {
+ let doctype = doc.reference_type;
+
+ if (doc.reference_type !== "Job Card") {
+ doctype = (doc.reference_type == "Stock Entry") ?
+ "Stock Entry Detail" : doc.reference_type + " Item";
+ }
+
+ if (doc.reference_type && doc.reference_name) {
+ let filters = {
+ "from": doctype,
+ "inspection_type": doc.inspection_type
+ };
+
+ if (doc.reference_type == doctype)
+ filters["reference_name"] = doc.reference_name;
+ else
+ filters["parent"] = doc.reference_name;
+
+ return {
+ query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
+ filters: filters
+ };
+ }
+ });
+ },
+
+ refresh: function(frm) {
+ // Ignore cancellation of reference doctype on cancel all.
+ frm.ignore_doctypes_on_cancel_all = [frm.doc.reference_type];
+ },
+
item_code: function(frm) {
if (frm.doc.item_code) {
return frm.call({
@@ -26,45 +80,5 @@
}
});
}
- }
-})
-
-// item code based on GRN/DN
-cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) {
- const doctype = (doc.reference_type == "Stock Entry") ?
- "Stock Entry Detail" : doc.reference_type + " Item";
-
- if (doc.reference_type && doc.reference_name) {
- return {
- query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
- filters: {
- "from": doctype,
- "parent": doc.reference_name,
- "inspection_type": doc.inspection_type
- }
- };
- }
-},
-
-// Serial No based on item_code
-cur_frm.fields_dict['item_serial_no'].get_query = function(doc, cdt, cdn) {
- var filters = {};
- if (doc.item_code) {
- filters = {
- 'item_code': doc.item_code
- }
- }
- return { filters: filters }
-}
-
-cur_frm.set_query("batch_no", function(doc) {
- return {
- filters: {
- "item": doc.item_code
- }
- }
-})
-
-cur_frm.add_fetch('item_code', 'item_name', 'item_name');
-cur_frm.add_fetch('item_code', 'description', 'description');
-
+ },
+});
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.json b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
index 3643174..edfe7e9 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.json
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
@@ -73,7 +73,7 @@
"fieldname": "reference_type",
"fieldtype": "Select",
"label": "Reference Type",
- "options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry",
+ "options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry\nJob Card",
"reqd": 1
},
{
@@ -136,6 +136,7 @@
"width": "50%"
},
{
+ "fetch_from": "item_code.item_name",
"fieldname": "item_name",
"fieldtype": "Data",
"in_global_search": 1,
@@ -143,6 +144,7 @@
"read_only": 1
},
{
+ "fetch_from": "item_code.description",
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description",
@@ -236,7 +238,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-09-12 16:11:31.910508",
+ "modified": "2020-12-18 19:59:55.710300",
"modified_by": "Administrator",
"module": "Stock",
"name": "Quality Inspection",
@@ -257,7 +259,6 @@
"write": 1
}
],
- "quick_entry": 1,
"search_fields": "item_code, report_date, reference_name",
"show_name_in_global_search": 1,
"sort_field": "modified",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index c3bb514..58b1eca 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -4,15 +4,20 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+from frappe import _
+from frappe.utils import flt, cint
from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
import get_template_details
-from frappe.model.mapper import get_mapped_doc
class QualityInspection(Document):
def validate(self):
if not self.readings and self.item_code:
self.get_item_specification_details()
+ if self.readings:
+ self.inspect_and_set_status()
+
def get_item_specification_details(self):
if not self.quality_inspection_template:
self.quality_inspection_template = frappe.db.get_value('Item',
@@ -24,8 +29,7 @@
parameters = get_template_details(self.quality_inspection_template)
for d in parameters:
child = self.append('readings', {})
- child.specification = d.specification
- child.value = d.value
+ child.update(d)
child.status = "Accepted"
def get_quality_inspection_template(self):
@@ -47,16 +51,114 @@
def update_qc_reference(self):
quality_inspection = self.name if self.docstatus == 1 else ""
- doctype = self.reference_type + ' Item'
- if self.reference_type == 'Stock Entry':
- doctype = 'Stock Entry Detail'
- if self.reference_type and self.reference_name:
- frappe.db.sql("""update `tab{child_doc}` t1, `tab{parent_doc}` t2
- set t1.quality_inspection = %s, t2.modified = %s
- where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name"""
- .format(parent_doc=self.reference_type, child_doc=doctype),
- (quality_inspection, self.modified, self.reference_name, self.item_code))
+ if self.reference_type == 'Job Card':
+ if self.reference_name:
+ frappe.db.sql("""
+ UPDATE `tab{doctype}`
+ SET quality_inspection = %s, modified = %s
+ WHERE name = %s and production_item = %s
+ """.format(doctype=self.reference_type),
+ (quality_inspection, self.modified, self.reference_name, self.item_code))
+
+ else:
+ doctype = self.reference_type + ' Item'
+ if self.reference_type == 'Stock Entry':
+ doctype = 'Stock Entry Detail'
+
+ if self.reference_type and self.reference_name:
+ conditions = ""
+ if self.batch_no and self.docstatus == 1:
+ conditions += " and t1.batch_no = '%s'"%(self.batch_no)
+
+ if self.docstatus == 2: # if cancel, then remove qi link wherever same name
+ conditions += " and t1.quality_inspection = '%s'"%(self.name)
+
+ frappe.db.sql("""
+ UPDATE
+ `tab{child_doc}` t1, `tab{parent_doc}` t2
+ SET
+ t1.quality_inspection = %s, t2.modified = %s
+ WHERE
+ t1.parent = %s
+ and t1.item_code = %s
+ and t1.parent = t2.name
+ {conditions}
+ """.format(parent_doc=self.reference_type, child_doc=doctype, conditions=conditions),
+ (quality_inspection, self.modified, self.reference_name, self.item_code))
+
+ def inspect_and_set_status(self):
+ for reading in self.readings:
+ if not reading.manual_inspection: # dont auto set status if manual
+ if reading.formula_based_criteria:
+ self.set_status_based_on_acceptance_formula(reading)
+ else:
+ # if not formula based check acceptance values set
+ self.set_status_based_on_acceptance_values(reading)
+
+ def set_status_based_on_acceptance_values(self, reading):
+ if not cint(reading.numeric):
+ result = reading.get("reading_value") == reading.get("value")
+ else:
+ # numeric readings
+ result = self.min_max_criteria_passed(reading)
+
+ reading.status = "Accepted" if result else "Rejected"
+
+ def min_max_criteria_passed(self, reading):
+ """Determine whether all readings fall in the acceptable range."""
+ for i in range(1, 11):
+ reading_value = reading.get("reading_" + str(i))
+ if reading_value is not None and reading_value.strip():
+ result = flt(reading.get("min_value")) <= flt(reading_value) <= flt(reading.get("max_value"))
+ if not result: return False
+ return True
+
+ def set_status_based_on_acceptance_formula(self, reading):
+ if not reading.acceptance_formula:
+ frappe.throw(_("Row #{0}: Acceptance Criteria Formula is required.").format(reading.idx),
+ title=_("Missing Formula"))
+
+ condition = reading.acceptance_formula
+ data = self.get_formula_evaluation_data(reading)
+
+ try:
+ result = frappe.safe_eval(condition, None, data)
+ reading.status = "Accepted" if result else "Rejected"
+ except NameError as e:
+ field = frappe.bold(e.args[0].split()[1])
+ frappe.throw(_("Row #{0}: {1} is not a valid reading field. Please refer to the field description.")
+ .format(reading.idx, field),
+ title=_("Invalid Formula"))
+ except Exception:
+ frappe.throw(_("Row #{0}: Acceptance Criteria Formula is incorrect.").format(reading.idx),
+ title=_("Invalid Formula"))
+
+ def get_formula_evaluation_data(self, reading):
+ data = {}
+ if not cint(reading.numeric):
+ data = {"reading_value": reading.get("reading_value")}
+ else:
+ # numeric readings
+ for i in range(1, 11):
+ field = "reading_" + str(i)
+ data[field] = flt(reading.get(field))
+ data["mean"] = self.calculate_mean(reading)
+
+ return data
+
+ def calculate_mean(self, reading):
+ """Calculate mean of all non-empty readings."""
+ from statistics import mean
+ readings_list = []
+
+ for i in range(1, 11):
+ reading_value = reading.get("reading_" + str(i))
+ if reading_value is not None and reading_value.strip():
+ readings_list.append(flt(reading_value))
+
+ actual_mean = mean(readings_list) if readings_list else 0
+ return actual_mean
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
@@ -66,27 +168,44 @@
mcond = get_match_cond(filters["from"])
cond, qi_condition = "", "and (quality_inspection is null or quality_inspection = '')"
- if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']\
- and filters.get("inspection_type") != "In Process":
- cond = """and item_code in (select name from `tabItem` where
- inspection_required_before_purchase = 1)"""
- elif filters.get('from') in ['Sales Invoice Item', 'Delivery Note Item']\
- and filters.get("inspection_type") != "In Process":
- cond = """and item_code in (select name from `tabItem` where
- inspection_required_before_delivery = 1)"""
- elif filters.get('from') == 'Stock Entry Detail':
- cond = """and s_warehouse is null"""
+ if filters.get("parent"):
+ if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']\
+ and filters.get("inspection_type") != "In Process":
+ cond = """and item_code in (select name from `tabItem` where
+ inspection_required_before_purchase = 1)"""
+ elif filters.get('from') in ['Sales Invoice Item', 'Delivery Note Item']\
+ and filters.get("inspection_type") != "In Process":
+ cond = """and item_code in (select name from `tabItem` where
+ inspection_required_before_delivery = 1)"""
+ elif filters.get('from') == 'Stock Entry Detail':
+ cond = """and s_warehouse is null"""
- if filters.get('from') in ['Supplier Quotation Item']:
- qi_condition = ""
+ if filters.get('from') in ['Supplier Quotation Item']:
+ qi_condition = ""
- return frappe.db.sql(""" select item_code from `tab{doc}`
- where parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
- {qi_condition} {cond} {mcond}
- order by item_code limit {start}, {page_len}""".format(doc=filters.get('from'),
- parent=filters.get('parent'), cond = cond, mcond = mcond, start = start,
- page_len = page_len, qi_condition = qi_condition),
- {'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
+ return frappe.db.sql("""
+ SELECT item_code
+ FROM `tab{doc}`
+ WHERE parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
+ {qi_condition} {cond} {mcond}
+ ORDER BY item_code limit {start}, {page_len}
+ """.format(doc=filters.get('from'),
+ cond = cond, mcond = mcond, start = start,
+ page_len = page_len, qi_condition = qi_condition),
+ {'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
+
+ elif filters.get("reference_name"):
+ return frappe.db.sql("""
+ SELECT production_item
+ FROM `tab{doc}`
+ WHERE name = %(reference_name)s and docstatus < 2 and production_item like %(txt)s
+ {qi_condition} {cond} {mcond}
+ ORDER BY production_item
+ LIMIT {start}, {page_len}
+ """.format(doc=filters.get("from"),
+ cond = cond, mcond = mcond, start = start,
+ page_len = page_len, qi_condition = qi_condition),
+ {'reference_name': filters.get('reference_name'), 'txt': "%%%s%%" % txt})
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index bb535c1..a7dfc9e 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -7,6 +7,7 @@
from frappe.utils import nowdate
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError, QualityInspectionNotSubmittedError
# test_records = frappe.get_test_records('Quality Inspection')
@@ -17,10 +18,12 @@
frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1)
def test_qa_for_delivery(self):
+ make_stock_entry(item_code="_Test Item with QA", target="_Test Warehouse - _TC", qty=1, basic_rate=100)
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+
self.assertRaises(QualityInspectionRequiredError, dn.submit)
- qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected", submit=True)
+ qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected")
dn.reload()
self.assertRaises(QualityInspectionRejectedError, dn.submit)
@@ -28,12 +31,89 @@
dn.reload()
dn.submit()
+ qa.cancel()
+ dn.reload()
+ dn.cancel()
+
def test_qa_not_submit(self):
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
- qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, submit = False)
+ qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, do_not_submit=True)
dn.items[0].quality_inspection = qa.name
self.assertRaises(QualityInspectionNotSubmittedError, dn.submit)
+ qa.delete()
+ dn.delete()
+
+ def test_value_based_qi_readings(self):
+ # Test QI based on acceptance values (Non formula)
+ dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+ readings = [{
+ "specification": "Iron Content", # numeric reading
+ "min_value": 0.1,
+ "max_value": 0.9,
+ "reading_1": "0.4"
+ },
+ {
+ "specification": "Particle Inspection Needed", # non-numeric reading
+ "numeric": 0,
+ "value": "Yes",
+ "reading_value": "Yes"
+ }]
+
+ qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name,
+ readings=readings, do_not_save=True)
+ qa.save()
+
+ # status must be auto set as per formula
+ self.assertEqual(qa.readings[0].status, "Accepted")
+ self.assertEqual(qa.readings[1].status, "Accepted")
+
+ qa.delete()
+ dn.delete()
+
+ def test_formula_based_qi_readings(self):
+ dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+ readings = [{
+ "specification": "Iron Content", # numeric reading
+ "formula_based_criteria": 1,
+ "acceptance_formula": "reading_1 > 0.35 and reading_1 < 0.50",
+ "reading_1": "0.4"
+ },
+ {
+ "specification": "Calcium Content", # numeric reading
+ "formula_based_criteria": 1,
+ "acceptance_formula": "reading_1 > 0.20 and reading_1 < 0.50",
+ "reading_1": "0.7"
+ },
+ {
+ "specification": "Mg Content", # numeric reading
+ "formula_based_criteria": 1,
+ "acceptance_formula": "mean < 0.9",
+ "reading_1": "0.5",
+ "reading_2": "0.7",
+ "reading_3": "random text" # check if random string input causes issues
+ },
+ {
+ "specification": "Calcium Content", # non-numeric reading
+ "formula_based_criteria": 1,
+ "numeric": 0,
+ "acceptance_formula": "reading_value in ('Grade A', 'Grade B', 'Grade C')",
+ "reading_value": "Grade B"
+ }]
+
+ qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name,
+ readings=readings, do_not_save=True)
+ qa.save()
+
+ # status must be auto set as per formula
+ self.assertEqual(qa.readings[0].status, "Accepted")
+ self.assertEqual(qa.readings[1].status, "Rejected")
+ self.assertEqual(qa.readings[2].status, "Accepted")
+ self.assertEqual(qa.readings[3].status, "Accepted")
+
+ qa.delete()
+ dn.delete()
+
def create_quality_inspection(**args):
args = frappe._dict(args)
qa = frappe.new_doc("Quality Inspection")
@@ -44,12 +124,35 @@
qa.item_code = args.item_code or "_Test Item with QA"
qa.sample_size = 1
qa.inspected_by = frappe.session.user
- qa.append("readings", {
- "specification": "Size",
- "status": args.status
- })
- qa.save()
- if args.submit:
- qa.submit()
+ qa.status = args.status or "Accepted"
+
+ if not args.readings:
+ create_quality_inspection_parameter("Size")
+ readings = {"specification": "Size", "min_value": 0, "max_value": 10}
+ else:
+ readings = args.readings
+
+ if args.status == "Rejected":
+ readings["reading_1"] = "12" # status is auto set in child on save
+
+ if isinstance(readings, list):
+ for entry in readings:
+ create_quality_inspection_parameter(entry["specification"])
+ qa.append("readings", entry)
+ else:
+ qa.append("readings", readings)
+
+ if not args.do_not_save:
+ qa.save()
+ if not args.do_not_submit:
+ qa.submit()
return qa
+
+def create_quality_inspection_parameter(parameter):
+ if not frappe.db.exists("Quality Inspection Parameter", parameter):
+ frappe.get_doc({
+ "doctype": "Quality Inspection Parameter",
+ "parameter": parameter,
+ "description": parameter
+ }).insert()
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/stock/doctype/quality_inspection_parameter/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/stock/doctype/quality_inspection_parameter/__init__.py
diff --git a/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.js b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.js
new file mode 100644
index 0000000..47c7e11
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Quality Inspection Parameter', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json
new file mode 100644
index 0000000..418b482
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json
@@ -0,0 +1,96 @@
+{
+ "actions": [],
+ "autoname": "field:parameter",
+ "creation": "2020-12-28 17:06:00.254129",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "parameter",
+ "parameter_group",
+ "description"
+ ],
+ "fields": [
+ {
+ "fieldname": "parameter",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Parameter",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "label": "Description"
+ },
+ {
+ "fieldname": "parameter_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Parameter Group",
+ "options": "Quality Inspection Parameter Group"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-02-19 20:33:30.657406",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Quality Inspection 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
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Quality Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "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/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py
new file mode 100644
index 0000000..8678422
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class QualityInspectionParameter(Document):
+ pass
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py
similarity index 76%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py
index 2ad7984..cefdc08 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestQualityInspectionParameter(unittest.TestCase):
pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/stock/doctype/quality_inspection_parameter_group/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/stock/doctype/quality_inspection_parameter_group/__init__.py
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.js b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.js
new file mode 100644
index 0000000..8716a29
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.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('Quality Inspection Parameter Group', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.json b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.json
new file mode 100644
index 0000000..5726474
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.json
@@ -0,0 +1,82 @@
+{
+ "actions": [],
+ "autoname": "field:group_name",
+ "creation": "2021-02-04 18:44:12.223295",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "group_name"
+ ],
+ "fields": [
+ {
+ "fieldname": "group_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Parameter Group Name",
+ "reqd": 1,
+ "unique": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-02-04 18:44:12.223295",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Quality Inspection Parameter Group",
+ "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": "Stock User",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Quality Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "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/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
new file mode 100644
index 0000000..1a3b1a0
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
@@ -0,0 +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 QualityInspectionParameterGroup(Document):
+ pass
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py b/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
new file mode 100644
index 0000000..212d4b8
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
@@ -0,0 +1,10 @@
+# -*- 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 TestQualityInspectionParameterGroup(unittest.TestCase):
+ pass
diff --git a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json
index f9f8a71..0eff5a8 100644
--- a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json
+++ b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json
@@ -1,45 +1,61 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-02-22 01:27:43",
"doctype": "DocType",
"editable_grid": 1,
+ "engine": "InnoDB",
"field_order": [
"specification",
+ "parameter_group",
+ "status",
"value",
+ "numeric",
+ "manual_inspection",
+ "column_break_4",
+ "min_value",
+ "max_value",
+ "formula_based_criteria",
+ "acceptance_formula",
+ "section_break_3",
+ "reading_value",
+ "section_break_14",
"reading_1",
"reading_2",
"reading_3",
"reading_4",
+ "column_break_10",
"reading_5",
"reading_6",
"reading_7",
"reading_8",
+ "column_break_14",
"reading_9",
- "reading_10",
- "status"
+ "reading_10"
],
"fields": [
{
"columns": 3,
"fieldname": "specification",
- "fieldtype": "Data",
+ "fieldtype": "Link",
"in_list_view": 1,
"label": "Parameter",
"oldfieldname": "specification",
"oldfieldtype": "Data",
+ "options": "Quality Inspection Parameter",
"reqd": 1
},
{
"columns": 2,
+ "depends_on": "eval:(!doc.formula_based_criteria && !doc.numeric)",
"fieldname": "value",
"fieldtype": "Data",
- "in_list_view": 1,
- "label": "Acceptance Criteria",
+ "label": "Acceptance Criteria Value",
"oldfieldname": "value",
"oldfieldtype": "Data"
},
{
- "columns": 1,
+ "columns": 2,
"fieldname": "reading_1",
"fieldtype": "Data",
"in_list_view": 1,
@@ -51,7 +67,6 @@
"columns": 1,
"fieldname": "reading_2",
"fieldtype": "Data",
- "in_list_view": 1,
"label": "Reading 2",
"oldfieldname": "reading_2",
"oldfieldtype": "Data"
@@ -60,7 +75,6 @@
"columns": 1,
"fieldname": "reading_3",
"fieldtype": "Data",
- "in_list_view": 1,
"label": "Reading 3",
"oldfieldname": "reading_3",
"oldfieldtype": "Data"
@@ -123,16 +137,100 @@
"label": "Status",
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "Accepted\nRejected"
+ "options": "\nAccepted\nRejected"
+ },
+ {
+ "depends_on": "eval:!doc.numeric",
+ "fieldname": "section_break_3",
+ "fieldtype": "Section Break",
+ "label": "Value Based Inspection"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "formula_based_criteria",
+ "description": "Simple Python formula applied on Reading fields.<br> Numeric eg. 1: <b>reading_1 > 0.2 and reading_1 < 0.5</b><br>\nNumeric eg. 2: <b>mean > 3.5</b> (mean of populated fields)<br>\nValue based eg.: <b>reading_value in (\"A\", \"B\", \"C\")</b>",
+ "fieldname": "acceptance_formula",
+ "fieldtype": "Code",
+ "label": "Acceptance Criteria Formula"
+ },
+ {
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_14",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "formula_based_criteria",
+ "fieldtype": "Check",
+ "label": "Formula Based Criteria"
+ },
+ {
+ "depends_on": "eval:(!doc.formula_based_criteria && doc.numeric)",
+ "description": "Applied on each reading.",
+ "fieldname": "min_value",
+ "fieldtype": "Float",
+ "label": "Minimum Value"
+ },
+ {
+ "depends_on": "eval:(!doc.formula_based_criteria && doc.numeric)",
+ "description": "Applied on each reading.",
+ "fieldname": "max_value",
+ "fieldtype": "Float",
+ "label": "Maximum Value"
+ },
+ {
+ "columns": 2,
+ "depends_on": "eval:!doc.numeric",
+ "fieldname": "reading_value",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Reading Value"
+ },
+ {
+ "depends_on": "numeric",
+ "fieldname": "section_break_14",
+ "fieldtype": "Section Break",
+ "label": "Numeric Inspection"
+ },
+ {
+ "default": "0",
+ "description": "Set the status manually.",
+ "fieldname": "manual_inspection",
+ "fieldtype": "Check",
+ "label": "Manual Inspection"
+ },
+ {
+ "default": "1",
+ "fieldname": "numeric",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Numeric"
+ },
+ {
+ "fetch_from": "specification.parameter_group",
+ "fieldname": "parameter_group",
+ "fieldtype": "Link",
+ "label": "Parameter Group",
+ "options": "Quality Inspection Parameter Group",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-07-11 18:48:12.667404",
+ "links": [],
+ "modified": "2021-02-04 19:15:37.991221",
"modified_by": "Administrator",
"module": "Stock",
"name": "Quality Inspection Reading",
"owner": "Administrator",
"permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
index 0d9a903..01d2031 100644
--- a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
@@ -12,5 +12,8 @@
def get_template_details(template):
if not template: return []
- return frappe.get_all('Item Quality Inspection Parameter', fields=["specification", "value"],
- filters={'parenttype': 'Quality Inspection Template', 'parent': template}, order_by="idx")
\ No newline at end of file
+ return frappe.get_all('Item Quality Inspection Parameter',
+ fields=["specification", "value", "acceptance_formula",
+ "numeric", "formula_based_criteria", "min_value", "max_value"],
+ filters={'parenttype': 'Quality Inspection Template', 'parent': template},
+ order_by="idx")
\ No newline at end of file
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/stock/doctype/repost_item_valuation/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/stock/doctype/repost_item_valuation/__init__.py
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
new file mode 100644
index 0000000..b3e4286
--- /dev/null
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
@@ -0,0 +1,52 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Repost Item Valuation', {
+ setup: function(frm) {
+ frm.set_query("warehouse", () => {
+ let filters = {
+ 'is_group': 0
+ };
+ if (frm.doc.company) filters['company'] = frm.doc.company;
+ return {filters: filters};
+ });
+
+ frm.set_query("voucher_type", () => {
+ return {
+ filters: {
+ name: ['in', ['Purchase Receipt', 'Purchase Invoice', 'Delivery Note',
+ 'Sales Invoice', 'Stock Entry', 'Stock Reconciliation']]
+ }
+ };
+ });
+
+ if (frm.doc.company) {
+ frm.set_query("voucher_no", () => {
+ return {
+ filters: {
+ company: frm.doc.company
+ }
+ };
+ });
+ }
+ },
+ refresh: function(frm) {
+ if (frm.doc.status == "Failed" && frm.doc.docstatus==1) {
+ frm.add_custom_button(__('Restart'), function () {
+ frm.trigger("restart_reposting");
+ }).addClass("btn-primary");
+ }
+ },
+
+ restart_reposting: function(frm) {
+ frappe.call({
+ method: "restart_reposting",
+ doc: frm.doc,
+ callback: function(r) {
+ if (!r.exc) {
+ frm.refresh();
+ }
+ }
+ });
+ }
+});
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
new file mode 100644
index 0000000..071fc86
--- /dev/null
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
@@ -0,0 +1,215 @@
+{
+ "actions": [],
+ "autoname": "REPOST-ITEM-VAL-.######",
+ "creation": "2020-10-22 22:27:07.742161",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "based_on",
+ "voucher_type",
+ "voucher_no",
+ "item_code",
+ "warehouse",
+ "posting_date",
+ "posting_time",
+ "column_break_5",
+ "status",
+ "company",
+ "allow_negative_stock",
+ "via_landed_cost_voucher",
+ "allow_zero_rate",
+ "amended_from",
+ "error_section",
+ "error_log"
+ ],
+ "fields": [
+ {
+ "depends_on": "eval:doc.based_on=='Item and Warehouse'",
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "label": "Item Code",
+ "mandatory_depends_on": "eval:doc.based_on=='Item and Warehouse'",
+ "options": "Item"
+ },
+ {
+ "depends_on": "eval:doc.based_on=='Item and Warehouse'",
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "mandatory_depends_on": "eval:doc.based_on=='Item and Warehouse'",
+ "options": "Warehouse"
+ },
+ {
+ "fetch_from": "voucher_no.posting_date",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "label": "Posting Date",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "voucher_no.posting_time",
+ "fieldname": "posting_time",
+ "fieldtype": "Time",
+ "label": "Posting Time"
+ },
+ {
+ "default": "Queued",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Queued\nIn Progress\nCompleted\nFailed",
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Repost Item Valuation",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.status=='Failed'",
+ "fieldname": "error_section",
+ "fieldtype": "Section Break",
+ "label": "Error"
+ },
+ {
+ "fieldname": "error_log",
+ "fieldtype": "Long Text",
+ "label": "Error Log",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fetch_from": "warehouse.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "depends_on": "eval:doc.based_on=='Transaction'",
+ "fieldname": "voucher_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Voucher Type",
+ "mandatory_depends_on": "eval:doc.based_on=='Transaction'",
+ "options": "DocType"
+ },
+ {
+ "depends_on": "eval:doc.based_on=='Transaction'",
+ "fieldname": "voucher_no",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Voucher No",
+ "mandatory_depends_on": "eval:doc.based_on=='Transaction'",
+ "options": "voucher_type"
+ },
+ {
+ "default": "Transaction",
+ "fieldname": "based_on",
+ "fieldtype": "Select",
+ "label": "Based On",
+ "options": "Transaction\nItem and Warehouse",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_negative_stock",
+ "fieldtype": "Check",
+ "label": "Allow Negative Stock"
+ },
+ {
+ "default": "0",
+ "fieldname": "via_landed_cost_voucher",
+ "fieldtype": "Check",
+ "label": "Via Landed Cost Voucher"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_zero_rate",
+ "fieldtype": "Check",
+ "label": "Allow Zero Rate"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-12-10 07:52:12.476589",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Repost Item Valuation",
+ "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": "Stock User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
new file mode 100644
index 0000000..559f9a5
--- /dev/null
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -0,0 +1,134 @@
+# -*- 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, erpnext
+from frappe.model.document import Document
+from frappe.utils import cint, get_link_to_form, add_to_date, today
+from erpnext.stock.stock_ledger import repost_future_sle
+from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
+from frappe.utils.user import get_users_with_role
+from frappe import _
+class RepostItemValuation(Document):
+ def validate(self):
+ self.set_status()
+ self.reset_field_values()
+ self.set_company()
+
+ def reset_field_values(self):
+ if self.based_on == 'Transaction':
+ self.item_code = None
+ self.warehouse = None
+ else:
+ self.voucher_type = None
+ self.voucher_no = None
+
+ def set_company(self):
+ if self.voucher_type and self.voucher_no:
+ self.company = frappe.get_cached_value(self.voucher_type, self.voucher_no, "company")
+ elif self.warehouse:
+ self.company = frappe.get_cached_value("Warehouse", self.warehouse, "company")
+
+ def set_status(self, status=None):
+ if not status:
+ status = 'Queued'
+ self.db_set('status', status)
+
+ def on_submit(self):
+ frappe.enqueue(repost, timeout=1800, queue='long',
+ job_name='repost_sle', now=frappe.flags.in_test, doc=self)
+
+ def restart_reposting(self):
+ self.set_status('Queued')
+ frappe.enqueue(repost, timeout=1800, queue='long',
+ job_name='repost_sle', now=True, doc=self)
+
+def repost(doc):
+ try:
+ if not frappe.db.exists("Repost Item Valuation", doc.name):
+ return
+
+ doc.set_status('In Progress')
+ frappe.db.commit()
+
+ repost_sl_entries(doc)
+ repost_gl_entries(doc)
+
+ doc.set_status('Completed')
+ except Exception:
+ frappe.db.rollback()
+ traceback = frappe.get_traceback()
+ frappe.log_error(traceback)
+
+ message = frappe.message_log.pop()
+ if traceback:
+ message += "<br>" + "Traceback: <br>" + traceback
+ frappe.db.set_value(doc.doctype, doc.name, 'error_log', message)
+
+ notify_error_to_stock_managers(doc, message)
+ doc.set_status('Failed')
+ raise
+ finally:
+ frappe.db.commit()
+
+def repost_sl_entries(doc):
+ if doc.based_on == 'Transaction':
+ repost_future_sle(voucher_type=doc.voucher_type, voucher_no=doc.voucher_no,
+ allow_negative_stock=doc.allow_negative_stock, via_landed_cost_voucher=doc.via_landed_cost_voucher)
+ else:
+ repost_future_sle(args=[frappe._dict({
+ "item_code": doc.item_code,
+ "warehouse": doc.warehouse,
+ "posting_date": doc.posting_date,
+ "posting_time": doc.posting_time
+ })], allow_negative_stock=doc.allow_negative_stock, via_landed_cost_voucher=doc.via_landed_cost_voucher)
+
+def repost_gl_entries(doc):
+ if not cint(erpnext.is_perpetual_inventory_enabled(doc.company)):
+ return
+
+ if doc.based_on == 'Transaction':
+ ref_doc = frappe.get_doc(doc.voucher_type, doc.voucher_no)
+ items, warehouses = ref_doc.get_items_and_warehouses()
+ else:
+ items = [doc.item_code]
+ warehouses = [doc.warehouse]
+
+ update_gl_entries_after(doc.posting_date, doc.posting_time,
+ warehouses, items, company=doc.company)
+
+def notify_error_to_stock_managers(doc, traceback):
+ recipients = get_users_with_role("Stock Manager")
+ if not recipients:
+ get_users_with_role("System Manager")
+
+ subject = _("Error while reposting item valuation")
+ message = (_("Hi,") + "<br>"
+ + _("An error has been appeared while reposting item valuation via {0}")
+ .format(get_link_to_form(doc.doctype, doc.name)) + "<br>"
+ + _("Please check the error message and take necessary actions to fix the error and then restart the reposting again.")
+ )
+ frappe.sendmail(recipients=recipients, subject=subject, message=message)
+
+def repost_entries():
+ riv_entries = get_repost_item_valuation_entries()
+
+ for row in riv_entries:
+ doc = frappe.get_cached_doc('Repost Item Valuation', row.name)
+ repost(doc)
+
+ riv_entries = get_repost_item_valuation_entries()
+ if riv_entries:
+ return
+
+ for d in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
+ check_if_stock_and_account_balance_synced(today(), d.company)
+
+def get_repost_item_valuation_entries():
+ date = add_to_date(today(), hours=-12)
+
+ return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation`
+ WHERE status != 'Completed' and creation <= %s and docstatus = 1
+ ORDER BY timestamp(posting_date, posting_time) asc, creation asc
+ """, date, as_dict=1)
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
index 2ad7984..13ceb68 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestRepostItemValuation(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index f7ff916..c8d8ca9 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -6,12 +6,13 @@
import json
from frappe.model.naming import make_autoname
-from frappe.utils import cint, cstr, flt, add_days, nowdate, getdate
+from frappe.utils import cint, cstr, flt, add_days, nowdate, getdate, get_link_to_form
from erpnext.stock.get_item_details import get_reserved_qty_for_so
from frappe import _, ValidationError
from erpnext.controllers.stock_controller import StockController
+from six import string_types
from six.moves import map
class SerialNoCannotCreateDirectError(ValidationError): pass
class SerialNoCannotCannotChangeError(ValidationError): pass
@@ -133,17 +134,13 @@
sle_dict = self.get_stock_ledger_entries(serial_no)
if sle_dict:
if sle_dict.get("incoming", []):
- sle_list = [sle for sle in sle_dict["incoming"] if sle.is_cancelled == 0]
- if sle_list:
- entries["purchase_sle"] = sle_list[0]
+ entries["purchase_sle"] = sle_dict["incoming"][0]
if len(sle_dict.get("incoming", [])) - len(sle_dict.get("outgoing", [])) > 0:
entries["last_sle"] = sle_dict["incoming"][0]
else:
entries["last_sle"] = sle_dict["outgoing"][0]
- sle_list = [sle for sle in sle_dict["outgoing"] if sle.is_cancelled == 0]
- if sle_list:
- entries["delivery_sle"] = sle_list[0]
+ entries["delivery_sle"] = sle_dict["outgoing"][0]
return entries
@@ -154,11 +151,12 @@
for sle in frappe.db.sql("""
SELECT voucher_type, voucher_no,
- posting_date, posting_time, incoming_rate, actual_qty, serial_no, is_cancelled
+ posting_date, posting_time, incoming_rate, actual_qty, serial_no
FROM
`tabStock Ledger Entry`
WHERE
item_code=%s AND company = %s
+ AND is_cancelled = 0
AND (serial_no = %s
OR serial_no like %s
OR serial_no like %s
@@ -178,7 +176,7 @@
def on_trash(self):
sl_entries = frappe.db.sql("""select serial_no from `tabStock Ledger Entry`
- where serial_no like %s and item_code=%s""",
+ where serial_no like %s and item_code=%s and is_cancelled=0""",
("%%%s%%" % self.name, self.item_code), as_dict=True)
# Find the exact match
@@ -228,7 +226,7 @@
if serial_nos:
frappe.throw(_("Item {0} is not setup for Serial Nos. Column must be blank").format(sle.item_code),
SerialNoNotRequiredError)
- else:
+ elif not sle.is_cancelled:
if serial_nos:
if cint(sle.actual_qty) != flt(sle.actual_qty):
frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
@@ -243,21 +241,18 @@
for serial_no in serial_nos:
if frappe.db.exists("Serial No", serial_no):
sr = frappe.db.get_value("Serial No", serial_no, ["name", "item_code", "batch_no", "sales_order",
- "delivery_document_no", "delivery_document_type", "warehouse",
+ "delivery_document_no", "delivery_document_type", "warehouse", "purchase_document_type",
"purchase_document_no", "company"], as_dict=1)
- if sr and cint(sle.actual_qty) < 0 and sr.warehouse != sle.warehouse:
- frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}")
- .format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse), SerialNoWarehouseError)
-
if sr.item_code!=sle.item_code:
if not allow_serial_nos_with_different_item(serial_no, sle):
frappe.throw(_("Serial No {0} does not belong to Item {1}").format(serial_no,
sle.item_code), SerialNoItemError)
- if cint(sle.actual_qty) > 0 and has_duplicate_serial_no(sr, sle):
- frappe.throw(_("Serial No {0} has already been received").format(serial_no),
- SerialNoDuplicateError)
+ if cint(sle.actual_qty) > 0 and has_serial_no_exists(sr, sle):
+ doc_name = frappe.bold(get_link_to_form(sr.purchase_document_type, sr.purchase_document_no))
+ frappe.throw(_("Serial No {0} has already been received in the {1} #{2}")
+ .format(frappe.bold(serial_no), sr.purchase_document_type, doc_name), SerialNoDuplicateError)
if (sr.delivery_document_no and sle.voucher_type not in ['Stock Entry', 'Stock Reconciliation']
and sle.voucher_type == sr.delivery_document_type):
@@ -276,7 +271,7 @@
frappe.throw(_("Serial No {0} does not belong to Batch {1}").format(serial_no,
sle.batch_no), SerialNoBatchError)
- if not sr.warehouse:
+ if not sle.is_cancelled and not sr.warehouse:
frappe.throw(_("Serial No {0} does not belong to any Warehouse")
.format(serial_no), SerialNoWarehouseError)
@@ -285,8 +280,10 @@
if sle.voucher_type == "Sales Invoice":
if not frappe.db.exists("Sales Invoice Item", {"parent": sle.voucher_no,
"item_code": sle.item_code, "sales_order": sr.sales_order}):
- frappe.throw(_("Cannot deliver Serial No {0} of item {1} as it is reserved \
- to fullfill Sales Order {2}").format(sr.name, sle.item_code, sr.sales_order))
+ frappe.throw(
+ _("Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2}")
+ .format(sr.name, sle.item_code, sr.sales_order)
+ )
elif sle.voucher_type == "Delivery Note":
if not frappe.db.exists("Delivery Note Item", {"parent": sle.voucher_no,
"item_code": sle.item_code, "against_sales_order": sr.sales_order}):
@@ -295,8 +292,10 @@
if not invoice or frappe.db.exists("Sales Invoice Item",
{"parent": invoice, "item_code": sle.item_code,
"sales_order": sr.sales_order}):
- frappe.throw(_("Cannot deliver Serial No {0} of item {1} as it is reserved to \
- fullfill Sales Order {2}").format(sr.name, sle.item_code, sr.sales_order))
+ frappe.throw(
+ _("Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2}")
+ .format(sr.name, sle.item_code, sr.sales_order)
+ )
# if Sales Order reference in Delivery Note or Invoice validate SO reservations for item
if sle.voucher_type == "Sales Invoice":
sales_order = frappe.db.get_value("Sales Invoice Item", {"parent": sle.voucher_no,
@@ -322,6 +321,12 @@
elif cint(sle.actual_qty) < 0 or not item_det.serial_no_series:
frappe.throw(_("Serial Nos Required for Serialized Item {0}").format(sle.item_code),
SerialNoRequiredError)
+ elif serial_nos:
+ for serial_no in serial_nos:
+ sr = frappe.db.get_value("Serial No", serial_no, ["name", "warehouse"], as_dict=1)
+ if sr and cint(sle.actual_qty) < 0 and sr.warehouse != sle.warehouse:
+ frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}")
+ .format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse))
def validate_material_transfer_entry(sle_doc):
sle_doc.update({
@@ -329,20 +334,22 @@
"skip_serial_no_validaiton": False
})
- if (sle_doc.voucher_type == "Stock Entry" and
+ if (sle_doc.voucher_type == "Stock Entry" and not sle_doc.is_cancelled and
frappe.get_cached_value("Stock Entry", sle_doc.voucher_no, "purpose") == "Material Transfer"):
if sle_doc.actual_qty < 0:
sle_doc.skip_update_serial_no = True
else:
sle_doc.skip_serial_no_validaiton = True
-def validate_so_serial_no(sr, sales_order,):
+def validate_so_serial_no(sr, sales_order):
if not sr.sales_order or sr.sales_order!= sales_order:
- frappe.throw(_("""Sales Order {0} has reservation for item {1}, you can
- only deliver reserved {1} against {0}. Serial No {2} cannot
- be delivered""").format(sales_order, sr.item_code, sr.name))
+ msg = (_("Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.")
+ .format(sales_order, sr.item_code))
-def has_duplicate_serial_no(sn, sle):
+ frappe.throw(_("""{0} Serial No {1} cannot be delivered""")
+ .format(msg, sr.name))
+
+def has_serial_no_exists(sn, sle):
if (sn.warehouse and not sle.skip_serial_no_validaiton
and sle.voucher_type != 'Stock Reconciliation'):
return True
@@ -352,12 +359,13 @@
status = False
if sn.purchase_document_no:
- if sle.voucher_type in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"] and \
- sn.delivery_document_type not in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"]:
+ if (sle.voucher_type in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"] and
+ sn.delivery_document_type not in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"]):
status = True
- if status and sle.voucher_type == 'Stock Entry' and \
- frappe.db.get_value('Stock Entry', sle.voucher_no, 'purpose') != 'Material Receipt':
+ # If status is receipt then system will allow to in-ward the delivered serial no
+ if (status and sle.voucher_type == "Stock Entry" and frappe.db.get_value("Stock Entry",
+ sle.voucher_no, "purpose") in ("Material Receipt", "Material Transfer")):
status = False
return status
@@ -372,7 +380,7 @@
stock_entry = frappe.get_cached_doc("Stock Entry", sle.voucher_no)
if stock_entry.purpose in ("Repack", "Manufacture"):
for d in stock_entry.get("items"):
- if d.serial_no and (d.s_warehouse or d.t_warehouse):
+ if d.serial_no and (d.s_warehouse if not sle.is_cancelled else d.t_warehouse):
serial_nos = get_serial_nos(d.serial_no)
if sle_serial_no in serial_nos:
allow_serial_nos = True
@@ -381,7 +389,7 @@
def update_serial_nos(sle, item_det):
if sle.skip_update_serial_no: return
- if not sle.serial_no and cint(sle.actual_qty) > 0 \
+ if not sle.is_cancelled and not sle.serial_no and cint(sle.actual_qty) > 0 \
and item_det.has_serial_no == 1 and item_det.serial_no_series:
serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty)
frappe.db.set(sle, "serial_no", serial_nos)
@@ -413,7 +421,7 @@
if is_new:
created_numbers.append(sr.name)
- form_links = list(map(lambda d: frappe.utils.get_link_to_form('Serial No', d), created_numbers))
+ form_links = list(map(lambda d: get_link_to_form('Serial No', d), created_numbers))
# Setting up tranlated title field for all cases
singular_title = _("Serial Number Created")
@@ -443,6 +451,9 @@
from tabItem where name=%s""", item_code, as_dict=True)[0]
def get_serial_nos(serial_no):
+ if isinstance(serial_no, list):
+ return serial_no
+
return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n')
if s.strip()]
@@ -538,54 +549,81 @@
return serial_nos
@frappe.whitelist()
-def auto_fetch_serial_number(qty, item_code, warehouse, batch_nos=None, for_doctype=None):
- filters = {
- "item_code": item_code,
- "warehouse": warehouse,
- "delivery_document_no": "",
- "sales_invoice": ""
- }
+def auto_fetch_serial_number(qty, item_code, warehouse, posting_date=None, batch_nos=None, for_doctype=None):
+ filters = { "item_code": item_code, "warehouse": warehouse }
if batch_nos:
try:
- filters["batch_no"] = ["in", json.loads(batch_nos)]
+ filters["batch_no"] = json.loads(batch_nos) if (type(json.loads(batch_nos)) == list) else [json.loads(batch_nos)]
except:
- filters["batch_no"] = ["in", [batch_nos]]
+ filters["batch_no"] = [batch_nos]
+ if posting_date:
+ filters["expiry_date"] = posting_date
+
+ serial_numbers = []
if for_doctype == 'POS Invoice':
- reserved_serial_nos, unreserved_serial_nos = get_pos_reserved_serial_nos(filters, qty)
- return unreserved_serial_nos
+ reserved_sr_nos = get_pos_reserved_serial_nos(filters)
+ serial_numbers = fetch_serial_numbers(filters, qty, do_not_include=reserved_sr_nos)
+ else:
+ serial_numbers = fetch_serial_numbers(filters, qty)
- serial_numbers = frappe.get_list("Serial No", filters=filters, limit=qty, order_by="creation")
- return [item['name'] for item in serial_numbers]
+ return [d.get('name') for d in serial_numbers]
@frappe.whitelist()
-def get_pos_reserved_serial_nos(filters, qty=None):
- batch_no_cond = ""
- if filters.get("batch_no"):
- batch_no_cond = "and item.batch_no = {}".format(frappe.db.escape(filters.get('batch_no')))
+def get_pos_reserved_serial_nos(filters):
+ if isinstance(filters, string_types):
+ filters = json.loads(filters)
- reserved_serial_nos_str = [d.serial_no for d in frappe.db.sql("""select item.serial_no as serial_no
+ pos_transacted_sr_nos = frappe.db.sql("""select item.serial_no as serial_no
from `tabPOS Invoice` p, `tabPOS Invoice Item` item
- where p.name = item.parent
- and p.consolidated_invoice is NULL
+ where p.name = item.parent
+ and p.consolidated_invoice is NULL
and p.docstatus = 1
and item.docstatus = 1
- and item.item_code = %s
- and item.warehouse = %s
- {}
- """.format(batch_no_cond), [filters.get('item_code'), filters.get('warehouse')], as_dict=1)]
+ and item.item_code = %(item_code)s
+ and item.warehouse = %(warehouse)s
+ and item.serial_no is NOT NULL and item.serial_no != ''
+ """, filters, as_dict=1)
- reserved_serial_nos = []
- for s in reserved_serial_nos_str:
- if not s: continue
+ reserved_sr_nos = []
+ for d in pos_transacted_sr_nos:
+ reserved_sr_nos += get_serial_nos(d.serial_no)
- serial_nos = s.split("\n")
- serial_nos = ' '.join(serial_nos).split() # remove whitespaces
- if len(serial_nos): reserved_serial_nos += serial_nos
+ return reserved_sr_nos
- filters["name"] = ["not in", reserved_serial_nos]
- serial_numbers = frappe.get_list("Serial No", filters=filters, limit=qty, order_by="creation")
- unreserved_serial_nos = [item['name'] for item in serial_numbers]
+def fetch_serial_numbers(filters, qty, do_not_include=[]):
+ batch_join_selection = ""
+ batch_no_condition = ""
+ batch_nos = filters.get("batch_no")
+ expiry_date = filters.get("expiry_date")
+ if batch_nos:
+ batch_no_condition = """and sr.batch_no in ({}) """.format(', '.join(["'%s'" % d for d in batch_nos]))
- return reserved_serial_nos, unreserved_serial_nos
\ No newline at end of file
+ if expiry_date:
+ batch_join_selection = "LEFT JOIN `tabBatch` batch on sr.batch_no = batch.name "
+ expiry_date_cond = "AND ifnull(batch.expiry_date, '2500-12-31') >= %(expiry_date)s "
+ batch_no_condition += expiry_date_cond
+
+ excluded_sr_nos = ", ".join(["" + frappe.db.escape(sr) + "" for sr in do_not_include]) or "''"
+ serial_numbers = frappe.db.sql("""
+ SELECT sr.name FROM `tabSerial No` sr {batch_join_selection}
+ WHERE
+ sr.name not in ({excluded_sr_nos}) AND
+ sr.item_code = %(item_code)s AND
+ sr.warehouse = %(warehouse)s AND
+ ifnull(sr.sales_invoice,'') = '' AND
+ ifnull(sr.delivery_document_no, '') = ''
+ {batch_no_condition}
+ ORDER BY
+ sr.creation
+ LIMIT
+ {qty}
+ """.format(
+ excluded_sr_nos=excluded_sr_nos,
+ qty=qty or 1,
+ batch_join_selection=batch_join_selection,
+ batch_no_condition=batch_no_condition
+ ), filters, as_dict=1)
+
+ return serial_numbers
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index ab06107..ed70790 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -12,7 +12,6 @@
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
test_dependencies = ["Item"]
test_records = frappe.get_test_records('Serial No')
@@ -38,8 +37,6 @@
self.assertTrue(SerialNoCannotCannotChangeError, sr.save)
def test_inter_company_transfer(self):
- set_perpetual_inventory(0, "_Test Company 1")
- set_perpetual_inventory(0)
se = make_serialized_item(target_warehouse="_Test Warehouse - _TC")
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
diff --git a/erpnext/config/__init__.py b/erpnext/stock/doctype/shipment/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/stock/doctype/shipment/__init__.py
diff --git a/erpnext/stock/doctype/shipment/shipment.js b/erpnext/stock/doctype/shipment/shipment.js
new file mode 100644
index 0000000..7af16af
--- /dev/null
+++ b/erpnext/stock/doctype/shipment/shipment.js
@@ -0,0 +1,451 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Shipment', {
+ address_query: function(frm, link_doctype, link_name, is_your_company_address) {
+ return {
+ query: 'frappe.contacts.doctype.address.address.address_query',
+ filters: {
+ link_doctype: link_doctype,
+ link_name: link_name,
+ is_your_company_address: is_your_company_address
+ }
+ };
+ },
+ contact_query: function(frm, link_doctype, link_name) {
+ return {
+ query: 'frappe.contacts.doctype.contact.contact.contact_query',
+ filters: {
+ link_doctype: link_doctype,
+ link_name: link_name
+ }
+ };
+ },
+ onload: function(frm) {
+ frm.set_query("delivery_address_name", () => {
+ let delivery_to = `delivery_${frappe.model.scrub(frm.doc.delivery_to_type)}`;
+ return frm.events.address_query(frm, frm.doc.delivery_to_type, frm.doc[delivery_to], frm.doc.delivery_to_type === 'Company' ? 1 : 0);
+ });
+ frm.set_query("pickup_address_name", () => {
+ let pickup_from = `pickup_${frappe.model.scrub(frm.doc.pickup_from_type)}`;
+ return frm.events.address_query(frm, frm.doc.pickup_from_type, frm.doc[pickup_from], frm.doc.pickup_from_type === 'Company' ? 1 : 0);
+ });
+ frm.set_query("delivery_contact_name", () => {
+ let delivery_to = `delivery_${frappe.model.scrub(frm.doc.delivery_to_type)}`;
+ return frm.events.contact_query(frm, frm.doc.delivery_to_type, frm.doc[delivery_to]);
+ });
+ frm.set_query("pickup_contact_name", () => {
+ let pickup_from = `pickup_${frappe.model.scrub(frm.doc.pickup_from_type)}`;
+ return frm.events.contact_query(frm, frm.doc.pickup_from_type, frm.doc[pickup_from]);
+ });
+ frm.set_query("delivery_note", "shipment_delivery_note", function() {
+ let customer = '';
+ if (frm.doc.delivery_to_type == "Customer") {
+ customer = frm.doc.delivery_customer;
+ }
+ if (frm.doc.delivery_to_type == "Company") {
+ customer = frm.doc.delivery_company;
+ }
+ if (customer) {
+ return {
+ filters: {
+ customer: customer,
+ docstatus: 1,
+ status: ["not in", ["Cancelled"]]
+ }
+ };
+ }
+ });
+ },
+ refresh: function() {
+ $('div[data-fieldname=pickup_address] > div > .clearfix').hide();
+ $('div[data-fieldname=pickup_contact] > div > .clearfix').hide();
+ $('div[data-fieldname=delivery_address] > div > .clearfix').hide();
+ $('div[data-fieldname=delivery_contact] > div > .clearfix').hide();
+ },
+ before_save: function(frm) {
+ let delivery_to = `delivery_${frappe.model.scrub(frm.doc.delivery_to_type)}`;
+ frm.set_value("delivery_to", frm.doc[delivery_to]);
+ let pickup_from = `pickup_${frappe.model.scrub(frm.doc.pickup_from_type)}`;
+ frm.set_value("pickup", frm.doc[pickup_from]);
+ },
+ set_pickup_company_address: function(frm) {
+ frappe.db.get_value('Address', {
+ address_title: frm.doc.pickup_company,
+ is_your_company_address: 1
+ }, 'name', (r) => {
+ frm.set_value("pickup_address_name", r.name);
+ });
+ },
+ set_delivery_company_address: function(frm) {
+ frappe.db.get_value('Address', {
+ address_title: frm.doc.delivery_company,
+ is_your_company_address: 1
+ }, 'name', (r) => {
+ frm.set_value("delivery_address_name", r.name);
+ });
+ },
+ pickup_from_type: function(frm) {
+ if (frm.doc.pickup_from_type == 'Company') {
+ frm.set_value("pickup_company", frappe.defaults.get_default('company'));
+ frm.set_value("pickup_customer", '');
+ frm.set_value("pickup_supplier", '');
+ } else {
+ frm.trigger('clear_pickup_fields');
+ }
+ if (frm.doc.pickup_from_type == 'Customer') {
+ frm.set_value("pickup_company", '');
+ frm.set_value("pickup_supplier", '');
+ }
+ if (frm.doc.pickup_from_type == 'Supplier') {
+ frm.set_value("pickup_customer", '');
+ frm.set_value("pickup_company", '');
+ }
+ },
+ delivery_to_type: function(frm) {
+ if (frm.doc.delivery_to_type == 'Company') {
+ frm.set_value("delivery_company", frappe.defaults.get_default('company'));
+ frm.set_value("delivery_customer", '');
+ frm.set_value("delivery_supplier", '');
+ } else {
+ frm.trigger('clear_delivery_fields');
+ }
+ if (frm.doc.delivery_to_type == 'Customer') {
+ frm.set_value("delivery_company", '');
+ frm.set_value("delivery_supplier", '');
+ }
+ if (frm.doc.delivery_to_type == 'Supplier') {
+ frm.set_value("delivery_customer", '');
+ frm.set_value("delivery_company", '');
+ frm.toggle_display("shipment_delivery_note", false);
+ } else {
+ frm.toggle_display("shipment_delivery_note", true);
+ }
+ },
+ delivery_address_name: function(frm) {
+ if (frm.doc.delivery_to_type == 'Company') {
+ erpnext.utils.get_address_display(frm, 'delivery_address_name', 'delivery_address', true);
+ } else {
+ erpnext.utils.get_address_display(frm, 'delivery_address_name', 'delivery_address', false);
+ }
+ },
+ pickup_address_name: function(frm) {
+ if (frm.doc.pickup_from_type == 'Company') {
+ erpnext.utils.get_address_display(frm, 'pickup_address_name', 'pickup_address', true);
+ } else {
+ erpnext.utils.get_address_display(frm, 'pickup_address_name', 'pickup_address', false);
+ }
+ },
+ get_contact_display: function(frm, contact_name, contact_type) {
+ frappe.call({
+ method: "frappe.contacts.doctype.contact.contact.get_contact_details",
+ args: { contact: contact_name },
+ callback: function(r) {
+ if (r.message) {
+ if (!(r.message.contact_email && (r.message.contact_phone || r.message.contact_mobile))) {
+ if (contact_type == 'Delivery') {
+ frm.set_value('delivery_contact_name', '');
+ frm.set_value('delivery_contact', '');
+ } else {
+ frm.set_value('pickup_contact_name', '');
+ frm.set_value('pickup_contact', '');
+ }
+ frappe.throw(__("Email or Phone/Mobile of the Contact are mandatory to continue.")
+ + "</br>" + __("Please set Email/Phone for the contact")
+ + ` <a href='/app/contact/${contact_name}'>${contact_name}</a>`);
+ }
+ let contact_display = r.message.contact_display;
+ if (r.message.contact_email) {
+ contact_display += '<br>' + r.message.contact_email;
+ }
+ if (r.message.contact_phone) {
+ contact_display += '<br>' + r.message.contact_phone;
+ }
+ if (r.message.contact_mobile && !r.message.contact_phone) {
+ contact_display += '<br>' + r.message.contact_mobile;
+ }
+ if (contact_type == 'Delivery') {
+ frm.set_value('delivery_contact', contact_display);
+ if (r.message.contact_email) {
+ frm.set_value('delivery_contact_email', r.message.contact_email);
+ }
+ } else {
+ frm.set_value('pickup_contact', contact_display);
+ if (r.message.contact_email) {
+ frm.set_value('pickup_contact_email', r.message.contact_email);
+ }
+ }
+ }
+ }
+ });
+ },
+ delivery_contact_name: function(frm) {
+ if (frm.doc.delivery_contact_name) {
+ frm.events.get_contact_display(frm, frm.doc.delivery_contact_name, 'Delivery');
+ }
+ },
+ pickup_contact_name: function(frm) {
+ if (frm.doc.pickup_contact_name) {
+ frm.events.get_contact_display(frm, frm.doc.pickup_contact_name, 'Pickup');
+ }
+ },
+ pickup_contact_person: function(frm) {
+ if (frm.doc.pickup_contact_person) {
+ frappe.call({
+ method: "erpnext.stock.doctype.shipment.shipment.get_company_contact",
+ args: { user: frm.doc.pickup_contact_person },
+ callback: function({ message }) {
+ const r = message;
+ let contact_display = `${r.first_name} ${r.last_name}`;
+ if (r.email) {
+ contact_display += `<br>${ r.email }`;
+ frm.set_value('pickup_contact_email', r.email);
+ }
+ if (r.phone) {
+ contact_display += `<br>${ r.phone }`;
+ }
+ if (r.mobile_no && !r.phone) {
+ contact_display += `<br>${ r.mobile_no }`;
+ }
+ frm.set_value('pickup_contact', contact_display);
+ }
+ });
+ } else {
+ if (frm.doc.pickup_from_type === 'Company') {
+ frappe.call({
+ method: "erpnext.stock.doctype.shipment.shipment.get_company_contact",
+ args: { user: frappe.session.user },
+ callback: function({ message }) {
+ const r = message;
+ let contact_display = `${r.first_name} ${r.last_name}`;
+ if (r.email) {
+ contact_display += `<br>${ r.email }`;
+ frm.set_value('pickup_contact_email', r.email);
+ }
+ if (r.phone) {
+ contact_display += `<br>${ r.phone }`;
+ }
+ if (r.mobile_no && !r.phone) {
+ contact_display += `<br>${ r.mobile_no }`;
+ }
+ frm.set_value('pickup_contact', contact_display);
+ }
+ });
+ }
+ }
+ },
+ set_company_contact: function(frm, delivery_type) {
+ frappe.db.get_value('User', { name: frappe.session.user }, ['full_name', 'last_name', 'email', 'phone', 'mobile_no'], (r) => {
+ if (!(r.last_name && r.email && (r.phone || r.mobile_no))) {
+ if (delivery_type == 'Delivery') {
+ frm.set_value('delivery_company', '');
+ frm.set_value('delivery_contact', '');
+ } else {
+ frm.set_value('pickup_company', '');
+ frm.set_value('pickup_contact', '');
+ }
+ frappe.throw(__("Last Name, Email or Phone/Mobile of the user are mandatory to continue.") + "</br>"
+ + __("Please first set Last Name, Email and Phone for the user")
+ + ` <a href="/app/user/${frappe.session.user}">${frappe.session.user}</a>`);
+ }
+ let contact_display = r.full_name;
+ if (r.email) {
+ contact_display += '<br>' + r.email;
+ }
+ if (r.phone) {
+ contact_display += '<br>' + r.phone;
+ }
+ if (r.mobile_no && !r.phone) {
+ contact_display += '<br>' + r.mobile_no;
+ }
+ if (delivery_type == 'Delivery') {
+ frm.set_value('delivery_contact', contact_display);
+ if (r.email) {
+ frm.set_value('delivery_contact_email', r.email);
+ }
+ } else {
+ frm.set_value('pickup_contact', contact_display);
+ if (r.email) {
+ frm.set_value('pickup_contact_email', r.email);
+ }
+ }
+ });
+ frm.set_value('pickup_contact_person', frappe.session.user);
+ },
+ pickup_company: function(frm) {
+ if (frm.doc.pickup_from_type == 'Company' && frm.doc.pickup_company) {
+ frm.trigger('set_pickup_company_address');
+ frm.events.set_company_contact(frm, 'Pickup');
+ }
+ },
+ delivery_company: function(frm) {
+ if (frm.doc.delivery_to_type == 'Company' && frm.doc.delivery_company) {
+ frm.trigger('set_delivery_company_address');
+ frm.events.set_company_contact(frm, 'Delivery');
+ }
+ },
+ delivery_customer: function(frm) {
+ frm.trigger('clear_delivery_fields');
+ if (frm.doc.delivery_customer) {
+ frm.events.set_address_name(frm, 'Customer', frm.doc.delivery_customer, 'Delivery');
+ frm.events.set_contact_name(frm, 'Customer', frm.doc.delivery_customer, 'Delivery');
+ }
+ },
+ delivery_supplier: function(frm) {
+ frm.trigger('clear_delivery_fields');
+ if (frm.doc.delivery_supplier) {
+ frm.events.set_address_name(frm, 'Supplier', frm.doc.delivery_supplier, 'Delivery');
+ frm.events.set_contact_name(frm, 'Supplier', frm.doc.delivery_supplier, 'Delivery');
+ }
+ },
+ pickup_customer: function(frm) {
+ if (frm.doc.pickup_customer) {
+ frm.events.set_address_name(frm, 'Customer', frm.doc.pickup_customer, 'Pickup');
+ frm.events.set_contact_name(frm, 'Customer', frm.doc.pickup_customer, 'Pickup');
+ }
+ },
+ pickup_supplier: function(frm) {
+ if (frm.doc.pickup_supplier) {
+ frm.events.set_address_name(frm, 'Supplier', frm.doc.pickup_supplier, 'Pickup');
+ frm.events.set_contact_name(frm, 'Supplier', frm.doc.pickup_supplier, 'Pickup');
+ }
+ },
+ set_address_name: function(frm, ref_doctype, ref_docname, delivery_type) {
+ frappe.call({
+ method: "erpnext.stock.doctype.shipment.shipment.get_address_name",
+ args: {
+ ref_doctype: ref_doctype,
+ docname: ref_docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ if (delivery_type == 'Delivery') {
+ frm.set_value('delivery_address_name', r.message);
+ } else {
+ frm.set_value('pickup_address_name', r.message);
+ }
+ }
+ }
+ });
+ },
+ set_contact_name: function(frm, ref_doctype, ref_docname, delivery_type) {
+ frappe.call({
+ method: "erpnext.stock.doctype.shipment.shipment.get_contact_name",
+ args: {
+ ref_doctype: ref_doctype,
+ docname: ref_docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ if (delivery_type == 'Delivery') {
+ frm.set_value('delivery_contact_name', r.message);
+ } else {
+ frm.set_value('pickup_contact_name', r.message);
+ }
+ }
+ }
+ });
+ },
+ add_template: function(frm) {
+ if (frm.doc.parcel_template) {
+ frappe.model.with_doc("Shipment Parcel Template", frm.doc.parcel_template, () => {
+ let parcel_template = frappe.model.get_doc("Shipment Parcel Template", frm.doc.parcel_template);
+ let row = frappe.model.add_child(frm.doc, "Shipment Parcel", "shipment_parcel");
+ row.length = parcel_template.length;
+ row.width = parcel_template.width;
+ row.height = parcel_template.height;
+ row.weight = parcel_template.weight;
+ frm.refresh_fields("shipment_parcel");
+ });
+ }
+ },
+ pickup_date: function(frm) {
+ if (frm.doc.pickup_date < frappe.datetime.get_today()) {
+ frappe.throw(__("Pickup Date cannot be before this day"));
+ }
+ if (frm.doc.pickup_date == frappe.datetime.get_today()) {
+ var pickup_time = frm.events.get_pickup_time(frm);
+ frm.set_value("pickup_from", pickup_time);
+ frm.trigger('set_pickup_to_time');
+ }
+ },
+ pickup_from: function(frm) {
+ var pickup_time = frm.events.get_pickup_time(frm);
+ if (frm.doc.pickup_from && frm.doc.pickup_date == frappe.datetime.get_today()) {
+ let current_hour = pickup_time.split(':')[0];
+ let current_min = pickup_time.split(':')[1];
+ let pickup_hour = frm.doc.pickup_from.split(':')[0];
+ let pickup_min = frm.doc.pickup_from.split(':')[1];
+ if (pickup_hour < current_hour || (pickup_hour == current_hour && pickup_min < current_min)) {
+ frm.set_value("pickup_from", pickup_time);
+ frappe.throw(__("Pickup Time cannot be in the past"));
+ }
+ }
+ frm.trigger('set_pickup_to_time');
+ },
+ get_pickup_time: function() {
+ let current_hour = new Date().getHours();
+ let current_min = new Date().toLocaleString('en-US', {minute: 'numeric'});
+ if (current_min < 30) {
+ current_min = '30';
+ } else {
+ current_min = '00';
+ current_hour = Number(current_hour)+1;
+ }
+ let pickup_time = current_hour +':'+ current_min;
+ return pickup_time;
+ },
+ set_pickup_to_time: function(frm) {
+ let pickup_to_hour = Number(frm.doc.pickup_from.split(':')[0])+5;
+ let pickup_to_min = frm.doc.pickup_from.split(':')[1];
+ let pickup_to = pickup_to_hour +':'+ pickup_to_min;
+ frm.set_value("pickup_to", pickup_to);
+ },
+ clear_pickup_fields: function(frm) {
+ let fields = ["pickup_address_name", "pickup_contact_name", "pickup_address", "pickup_contact", "pickup_contact_email", "pickup_contact_person"];
+ for (let field of fields) {
+ frm.set_value(field, '');
+ }
+ },
+ clear_delivery_fields: function(frm) {
+ let fields = ["delivery_address_name", "delivery_contact_name", "delivery_address", "delivery_contact", "delivery_contact_email"];
+ for (let field of fields) {
+ frm.set_value(field, '');
+ }
+ },
+ remove_email_row: function(frm, table, fieldname) {
+ $.each(frm.doc[table] || [], function(i, detail) {
+ if (detail.email === fieldname) {
+ cur_frm.get_field(table).grid.grid_rows[i].remove();
+ }
+ });
+ }
+});
+
+frappe.ui.form.on('Shipment Delivery Note', {
+ delivery_note: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ if (row.delivery_note) {
+ let row_index = row.idx - 1;
+ if (validate_duplicate(frm, 'shipment_delivery_note', row.delivery_note, row_index)) {
+ frappe.throw(__("You have entered a duplicate Delivery Note on Row") + ` ${row.idx}. ` + __("Please rectify and try again."));
+ }
+ }
+ },
+ grand_total: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ if (row.grand_total) {
+ var value_of_goods = parseFloat(frm.doc.value_of_goods)+parseFloat(row.grand_total);
+ frm.set_value("value_of_goods", Math.round(value_of_goods));
+ frm.refresh_fields("value_of_goods");
+ }
+ },
+});
+
+var validate_duplicate = function(frm, table, fieldname, index) {
+ return (
+ table === 'shipment_delivery_note'
+ ? frm.doc[table].some((detail, i) => detail.delivery_note === fieldname && !(index === i))
+ : frm.doc[table].some((detail, i) => detail.email === fieldname && !(index === i))
+ );
+};
diff --git a/erpnext/stock/doctype/shipment/shipment.json b/erpnext/stock/doctype/shipment/shipment.json
new file mode 100644
index 0000000..76c331c
--- /dev/null
+++ b/erpnext/stock/doctype/shipment/shipment.json
@@ -0,0 +1,472 @@
+{
+ "actions": [],
+ "autoname": "SHIPMENT-.#####",
+ "creation": "2020-07-09 10:58:52.508703",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "heading_pickup_from",
+ "pickup_from_type",
+ "pickup_company",
+ "pickup_customer",
+ "pickup_supplier",
+ "pickup",
+ "pickup_address_name",
+ "pickup_address",
+ "pickup_contact_person",
+ "pickup_contact_name",
+ "pickup_contact_email",
+ "pickup_contact",
+ "column_break_2",
+ "heading_delivery_to",
+ "delivery_to_type",
+ "delivery_company",
+ "delivery_customer",
+ "delivery_supplier",
+ "delivery_to",
+ "delivery_address_name",
+ "delivery_address",
+ "delivery_contact_name",
+ "delivery_contact_email",
+ "delivery_contact",
+ "parcels_section",
+ "shipment_parcel",
+ "parcel_template",
+ "add_template",
+ "column_break_28",
+ "shipment_delivery_note",
+ "shipment_details_section",
+ "pallets",
+ "value_of_goods",
+ "pickup_date",
+ "pickup_from",
+ "pickup_to",
+ "column_break_36",
+ "shipment_type",
+ "pickup_type",
+ "incoterm",
+ "description_of_content",
+ "section_break_40",
+ "shipment_information_section",
+ "service_provider",
+ "shipment_id",
+ "shipment_amount",
+ "status",
+ "tracking_url",
+ "column_break_55",
+ "carrier",
+ "carrier_service",
+ "awb_number",
+ "tracking_status",
+ "tracking_status_info",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "heading_pickup_from",
+ "fieldtype": "Heading",
+ "label": "Pickup from"
+ },
+ {
+ "default": "Company",
+ "fieldname": "pickup_from_type",
+ "fieldtype": "Select",
+ "label": "Pickup from",
+ "options": "Company\nCustomer\nSupplier"
+ },
+ {
+ "depends_on": "eval:doc.pickup_from_type == 'Company'",
+ "fieldname": "pickup_company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "depends_on": "eval:doc.pickup_from_type == 'Customer'",
+ "fieldname": "pickup_customer",
+ "fieldtype": "Link",
+ "label": "Customer",
+ "options": "Customer"
+ },
+ {
+ "depends_on": "eval:doc.pickup_from_type == 'Supplier'",
+ "fieldname": "pickup_supplier",
+ "fieldtype": "Link",
+ "label": "Supplier",
+ "options": "Supplier"
+ },
+ {
+ "fieldname": "pickup",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "Pickup From",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.pickup_customer || doc.pickup_supplier || doc.pickup_from_type == \"Company\"",
+ "fieldname": "pickup_address_name",
+ "fieldtype": "Link",
+ "label": "Address",
+ "options": "Address",
+ "reqd": 1
+ },
+ {
+ "fieldname": "pickup_address",
+ "fieldtype": "Small Text",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.pickup_customer || doc.pickup_supplier || doc.pickup_from_type !== \"Company\"",
+ "fieldname": "pickup_contact_name",
+ "fieldtype": "Link",
+ "label": "Contact",
+ "mandatory_depends_on": "eval: doc.pickup_from_type !== 'Company'",
+ "options": "Contact"
+ },
+ {
+ "fieldname": "pickup_contact_email",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Contact Email",
+ "read_only": 1
+ },
+ {
+ "fieldname": "pickup_contact",
+ "fieldtype": "Small Text",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "heading_delivery_to",
+ "fieldtype": "Heading",
+ "label": "Delivery to"
+ },
+ {
+ "default": "Customer",
+ "fieldname": "delivery_to_type",
+ "fieldtype": "Select",
+ "label": "Delivery to",
+ "options": "Company\nCustomer\nSupplier"
+ },
+ {
+ "depends_on": "eval:doc.delivery_to_type == 'Company'",
+ "fieldname": "delivery_company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "depends_on": "eval:doc.delivery_to_type == 'Customer'",
+ "fieldname": "delivery_customer",
+ "fieldtype": "Link",
+ "label": "Customer",
+ "options": "Customer"
+ },
+ {
+ "depends_on": "eval:doc.delivery_to_type == 'Supplier'",
+ "fieldname": "delivery_supplier",
+ "fieldtype": "Link",
+ "label": "Supplier",
+ "options": "Supplier"
+ },
+ {
+ "fieldname": "delivery_to",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "Delivery To",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.delivery_customer || doc.delivery_supplier || doc.delivery_to_type == \"Company\"",
+ "fieldname": "delivery_address_name",
+ "fieldtype": "Link",
+ "label": "Address",
+ "options": "Address",
+ "reqd": 1
+ },
+ {
+ "fieldname": "delivery_address",
+ "fieldtype": "Small Text",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.delivery_customer || doc.delivery_supplier || doc.delivery_to_type == \"Company\"",
+ "fieldname": "delivery_contact_name",
+ "fieldtype": "Link",
+ "label": "Contact",
+ "mandatory_depends_on": "eval: doc.delivery_from_type !== 'Company'",
+ "options": "Contact"
+ },
+ {
+ "fieldname": "delivery_contact_email",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Contact Email",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.delivery_contact_name",
+ "fieldname": "delivery_contact",
+ "fieldtype": "Small Text",
+ "read_only": 1
+ },
+ {
+ "fieldname": "parcels_section",
+ "fieldtype": "Section Break",
+ "label": "Parcels"
+ },
+ {
+ "fieldname": "shipment_parcel",
+ "fieldtype": "Table",
+ "label": "Shipment Parcel",
+ "options": "Shipment Parcel"
+ },
+ {
+ "fieldname": "parcel_template",
+ "fieldtype": "Link",
+ "label": "Parcel Template",
+ "options": "Shipment Parcel Template"
+ },
+ {
+ "depends_on": "eval:doc.docstatus !== 1\n",
+ "fieldname": "add_template",
+ "fieldtype": "Button",
+ "label": "Add Template"
+ },
+ {
+ "fieldname": "column_break_28",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "shipment_details_section",
+ "fieldtype": "Section Break",
+ "label": "Shipment details"
+ },
+ {
+ "default": "No",
+ "fieldname": "pallets",
+ "fieldtype": "Select",
+ "label": "Pallets",
+ "options": "No\nYes"
+ },
+ {
+ "fieldname": "value_of_goods",
+ "fieldtype": "Currency",
+ "label": "Value of Goods",
+ "precision": "2",
+ "reqd": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "pickup_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Pickup Date",
+ "reqd": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "09:00",
+ "fieldname": "pickup_from",
+ "fieldtype": "Time",
+ "label": "Pickup from"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "17:00",
+ "fieldname": "pickup_to",
+ "fieldtype": "Time",
+ "label": "Pickup to"
+ },
+ {
+ "fieldname": "column_break_36",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "Goods",
+ "fieldname": "shipment_type",
+ "fieldtype": "Select",
+ "label": "Shipment Type",
+ "options": "Goods\nDocuments"
+ },
+ {
+ "default": "Pickup",
+ "fieldname": "pickup_type",
+ "fieldtype": "Select",
+ "label": "Pickup Type",
+ "options": "Pickup\nSelf delivery"
+ },
+ {
+ "fieldname": "description_of_content",
+ "fieldtype": "Small Text",
+ "label": "Description of Content",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_40",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "shipment_information_section",
+ "fieldtype": "Section Break",
+ "label": "Shipment Information"
+ },
+ {
+ "fieldname": "service_provider",
+ "fieldtype": "Data",
+ "label": "Service Provider",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "shipment_id",
+ "fieldtype": "Data",
+ "label": "Shipment ID",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "shipment_amount",
+ "fieldtype": "Currency",
+ "label": "Shipment Amount",
+ "no_copy": 1,
+ "precision": "2",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Draft\nSubmitted\nBooked\nCancelled\nCompleted",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "tracking_url",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "label": "Tracking URL",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "carrier",
+ "fieldtype": "Data",
+ "label": "Carrier",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "carrier_service",
+ "fieldtype": "Data",
+ "label": "Carrier Service",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "awb_number",
+ "fieldtype": "Data",
+ "label": "AWB Number",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "tracking_status",
+ "fieldtype": "Select",
+ "label": "Tracking Status",
+ "no_copy": 1,
+ "options": "\nIn Progress\nDelivered\nReturned\nLost",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "tracking_status_info",
+ "fieldtype": "Data",
+ "label": "Tracking Status Info",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Shipment",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_55",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "incoterm",
+ "fieldtype": "Select",
+ "label": "Incoterm",
+ "options": "EXW (Ex Works)\nFCA (Free Carrier)\nCPT (Carriage Paid To)\nCIP (Carriage and Insurance Paid to)\nDPU (Delivered At Place Unloaded)\nDAP (Delivered At Place)\nDDP (Delivered Duty Paid)"
+ },
+ {
+ "fieldname": "shipment_delivery_note",
+ "fieldtype": "Table",
+ "label": "Shipment Delivery Note",
+ "options": "Shipment Delivery Note"
+ },
+ {
+ "depends_on": "eval:doc.pickup_from_type === 'Company'",
+ "fieldname": "pickup_contact_person",
+ "fieldtype": "Link",
+ "label": "Pickup Contact Person",
+ "mandatory_depends_on": "eval:doc.pickup_from_type === 'Company'",
+ "options": "User"
+ }
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-12-25 15:02:34.891976",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Shipment",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "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
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/shipment/shipment.py b/erpnext/stock/doctype/shipment/shipment.py
new file mode 100644
index 0000000..4697a7b
--- /dev/null
+++ b/erpnext/stock/doctype/shipment/shipment.py
@@ -0,0 +1,68 @@
+# -*- 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.utils import flt, get_time
+from frappe.model.document import Document
+from erpnext.accounts.party import get_party_shipping_address
+from frappe.contacts.doctype.contact.contact import get_default_contact
+
+class Shipment(Document):
+ def validate(self):
+ self.validate_weight()
+ self.validate_pickup_time()
+ self.set_value_of_goods()
+ if self.docstatus == 0:
+ self.status = 'Draft'
+
+ def on_submit(self):
+ if not self.shipment_parcel:
+ frappe.throw(_('Please enter Shipment Parcel information'))
+ if self.value_of_goods == 0:
+ frappe.throw(_('Value of goods cannot be 0'))
+ self.status = 'Submitted'
+
+ def on_cancel(self):
+ self.status = 'Cancelled'
+
+ def validate_weight(self):
+ for parcel in self.shipment_parcel:
+ if flt(parcel.weight) <= 0:
+ frappe.throw(_('Parcel weight cannot be 0'))
+
+ def validate_pickup_time(self):
+ if self.pickup_from and self.pickup_to and get_time(self.pickup_to) < get_time(self.pickup_from):
+ frappe.throw(_("Pickup To time should be greater than Pickup From time"))
+
+ def set_value_of_goods(self):
+ value_of_goods = 0
+ for entry in self.get("shipment_delivery_note"):
+ value_of_goods += flt(entry.get("grand_total"))
+ self.value_of_goods = value_of_goods if value_of_goods else self.value_of_goods
+
+@frappe.whitelist()
+def get_address_name(ref_doctype, docname):
+ # Return address name
+ return get_party_shipping_address(ref_doctype, docname)
+
+@frappe.whitelist()
+def get_contact_name(ref_doctype, docname):
+ # Return address name
+ return get_default_contact(ref_doctype, docname)
+
+@frappe.whitelist()
+def get_company_contact(user):
+ contact = frappe.db.get_value('User', user, [
+ 'first_name',
+ 'last_name',
+ 'email',
+ 'phone',
+ 'mobile_no',
+ 'gender',
+ ], as_dict=1)
+ if not contact.phone:
+ contact.phone = contact.mobile_no
+ return contact
diff --git a/erpnext/stock/doctype/shipment/shipment_list.js b/erpnext/stock/doctype/shipment/shipment_list.js
new file mode 100644
index 0000000..52b052c
--- /dev/null
+++ b/erpnext/stock/doctype/shipment/shipment_list.js
@@ -0,0 +1,8 @@
+frappe.listview_settings['Shipment'] = {
+ add_fields: ["status"],
+ get_indicator: function(doc) {
+ if (doc.status=='Booked') {
+ return [__("Booked"), "green"];
+ }
+ }
+};
\ No newline at end of file
diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py
new file mode 100644
index 0000000..9c3e22f
--- /dev/null
+++ b/erpnext/stock/doctype/shipment/test_shipment.py
@@ -0,0 +1,241 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+from datetime import date, timedelta
+
+import frappe
+import unittest
+from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment
+
+class TestShipment(unittest.TestCase):
+ def test_shipment_from_delivery_note(self):
+ delivery_note = create_test_delivery_note()
+ delivery_note.submit()
+ shipment = create_test_shipment([ delivery_note ])
+ shipment.submit()
+ second_shipment = make_shipment(delivery_note.name)
+ self.assertEqual(second_shipment.value_of_goods, delivery_note.grand_total)
+ self.assertEqual(len(second_shipment.shipment_delivery_note), 1)
+ self.assertEqual(second_shipment.shipment_delivery_note[0].delivery_note, delivery_note.name)
+
+def create_test_delivery_note():
+ company = get_shipment_company()
+ customer = get_shipment_customer()
+ item = get_shipment_item(company.name)
+ posting_date = date.today() + timedelta(days=1)
+
+ create_material_receipt(item, company.name)
+ delivery_note = frappe.new_doc("Delivery Note")
+ delivery_note.company = company.name
+ delivery_note.posting_date = posting_date.strftime("%Y-%m-%d")
+ delivery_note.posting_time = '10:00'
+ delivery_note.customer = customer.name
+ delivery_note.append('items',
+ {
+ "item_code": item.name,
+ "item_name": item.item_name,
+ "description": 'Test delivery note for shipment',
+ "qty": 5,
+ "uom": 'Nos',
+ "warehouse": 'Stores - SC',
+ "rate": item.standard_rate,
+ "cost_center": 'Main - SC'
+ }
+ )
+ delivery_note.insert()
+ frappe.db.commit()
+ return delivery_note
+
+
+def create_test_shipment(delivery_notes = None):
+ company = get_shipment_company()
+ company_address = get_shipment_company_address(company.name)
+ customer = get_shipment_customer()
+ customer_address = get_shipment_customer_address(customer.name)
+ customer_contact = get_shipment_customer_contact(customer.name)
+ posting_date = date.today() + timedelta(days=5)
+
+ shipment = frappe.new_doc("Shipment")
+ shipment.pickup_from_type = 'Company'
+ shipment.pickup_company = company.name
+ shipment.pickup_address_name = company_address.name
+ shipment.delivery_to_type = 'Customer'
+ shipment.delivery_customer = customer.name
+ shipment.delivery_address_name = customer_address.name
+ shipment.delivery_contact_name = customer_contact.name
+ shipment.pallets = 'No'
+ shipment.shipment_type = 'Goods'
+ shipment.value_of_goods = 1000
+ shipment.pickup_type = 'Pickup'
+ shipment.pickup_date = posting_date.strftime("%Y-%m-%d")
+ shipment.pickup_from = '09:00'
+ shipment.pickup_to = '17:00'
+ shipment.description_of_content = 'unit test entry'
+ for delivery_note in delivery_notes:
+ shipment.append('shipment_delivery_note',
+ {
+ "delivery_note": delivery_note.name
+ }
+ )
+ shipment.append('shipment_parcel',
+ {
+ "length": 5,
+ "width": 5,
+ "height": 5,
+ "weight": 5,
+ "count": 5
+ }
+ )
+ shipment.insert()
+ frappe.db.commit()
+ return shipment
+
+
+def get_shipment_customer_contact(customer_name):
+ contact_fname = 'Customer Shipment'
+ contact_lname = 'Testing'
+ customer_name = contact_fname + ' ' + contact_lname
+ contacts = frappe.get_all("Contact", fields=["name"], filters = {"name": customer_name})
+ if len(contacts):
+ return contacts[0]
+ else:
+ return create_customer_contact(contact_fname, contact_lname)
+
+
+def get_shipment_customer_address(customer_name):
+ address_title = customer_name + ' address 123'
+ customer_address = frappe.get_all("Address", fields=["name"], filters = {"address_title": address_title})
+ if len(customer_address):
+ return customer_address[0]
+ else:
+ return create_shipment_address(address_title, customer_name, 81929)
+
+def get_shipment_customer():
+ customer_name = 'Shipment Customer'
+ customer = frappe.get_all("Customer", fields=["name"], filters = {"name": customer_name})
+ if len(customer):
+ return customer[0]
+ else:
+ return create_shipment_customer(customer_name)
+
+def get_shipment_company_address(company_name):
+ address_title = company_name + ' address 123'
+ addresses = frappe.get_all("Address", fields=["name"], filters = {"address_title": address_title})
+ if len(addresses):
+ return addresses[0]
+ else:
+ return create_shipment_address(address_title, company_name, 80331)
+
+def get_shipment_company():
+ company_name = 'Shipment Company'
+ abbr = 'SC'
+ companies = frappe.get_all("Company", fields=["name"], filters = {"company_name": company_name})
+ if len(companies):
+ return companies[0]
+ else:
+ return create_shipment_company(company_name, abbr)
+
+def get_shipment_item(company_name):
+ item_name = 'Testing Shipment item'
+ items = frappe.get_all("Item",
+ fields=["name", "item_name", "item_code", "standard_rate"],
+ filters = {"item_name": item_name}
+ )
+ if len(items):
+ return items[0]
+ else:
+ return create_shipment_item(item_name, company_name)
+
+def create_shipment_address(address_title, company_name, postal_code):
+ address = frappe.new_doc("Address")
+ address.address_title = address_title
+ address.address_type = 'Shipping'
+ address.address_line1 = company_name + ' address line 1'
+ address.city = 'Random City'
+ address.postal_code = postal_code
+ address.country = 'Germany'
+ address.insert()
+ return address
+
+
+def create_customer_contact(fname, lname):
+ customer = frappe.new_doc("Contact")
+ customer.customer_name = fname + ' ' + lname
+ customer.first_name = fname
+ customer.last_name = lname
+ customer.is_primary_contact = 1
+ customer.is_billing_contact = 1
+ customer.append('email_ids',
+ {
+ 'email_id': 'randomme@email.com',
+ 'is_primary': 1
+ }
+ )
+ customer.append('phone_nos',
+ {
+ 'phone': '123123123',
+ 'is_primary_phone': 1,
+ 'is_primary_mobile_no': 1
+ }
+ )
+ customer.status = 'Passive'
+ customer.insert()
+ return customer
+
+
+def create_shipment_company(company_name, abbr):
+ company = frappe.new_doc("Company")
+ company.company_name = company_name
+ company.abbr = abbr
+ company.default_currency = 'EUR'
+ company.country = 'Germany'
+ company.enable_perpetual_inventory = 0
+ company.insert()
+ return company
+
+def create_shipment_customer(customer_name):
+ customer = frappe.new_doc("Customer")
+ customer.customer_name = customer_name
+ customer.customer_type = 'Company'
+ customer.customer_group = 'All Customer Groups'
+ customer.territory = 'All Territories'
+ customer.gst_category = 'Unregistered'
+ customer.insert()
+ return customer
+
+def create_material_receipt(item, company):
+ posting_date = date.today()
+ stock = frappe.new_doc("Stock Entry")
+ stock.company = company
+ stock.stock_entry_type = 'Material Receipt'
+ stock.posting_date = posting_date.strftime("%Y-%m-%d")
+ stock.append('items',
+ {
+ "t_warehouse": 'Stores - SC',
+ "item_code": item.name,
+ "qty": 5,
+ "uom": 'Nos',
+ "basic_rate": item.standard_rate,
+ "cost_center": 'Main - SC'
+ }
+ )
+ stock.insert()
+ stock.submit()
+
+
+def create_shipment_item(item_name, company_name):
+ item = frappe.new_doc("Item")
+ item.item_name = item_name
+ item.item_code = item_name
+ item.item_group = 'All Item Groups'
+ item.stock_uom = 'Nos'
+ item.standard_rate = 50
+ item.append('item_defaults',
+ {
+ "company": company_name,
+ "default_warehouse": 'Stores - SC'
+ }
+ )
+ item.insert()
+ return item
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/stock/doctype/shipment_delivery_note/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/stock/doctype/shipment_delivery_note/__init__.py
diff --git a/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.json b/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.json
new file mode 100644
index 0000000..8625913
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.json
@@ -0,0 +1,40 @@
+{
+ "actions": [],
+ "creation": "2020-07-09 11:52:57.939021",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "delivery_note",
+ "grand_total"
+ ],
+ "fields": [
+ {
+ "fieldname": "delivery_note",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Delivery Note",
+ "options": "Delivery Note",
+ "reqd": 1
+ },
+ {
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Value",
+ "read_only": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-12-02 15:44:34.028703",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Shipment Delivery Note",
+ "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/stock/doctype/shipment_delivery_note/shipment_delivery_note.py b/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.py
new file mode 100644
index 0000000..4342151
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class ShipmentDeliveryNote(Document):
+ pass
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/stock/doctype/shipment_parcel/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/stock/doctype/shipment_parcel/__init__.py
diff --git a/erpnext/stock/doctype/shipment_parcel/shipment_parcel.json b/erpnext/stock/doctype/shipment_parcel/shipment_parcel.json
new file mode 100644
index 0000000..6943edc
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_parcel/shipment_parcel.json
@@ -0,0 +1,65 @@
+{
+ "actions": [],
+ "creation": "2020-07-09 11:28:48.887737",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "length",
+ "width",
+ "height",
+ "weight",
+ "count"
+ ],
+ "fields": [
+ {
+ "fieldname": "length",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Length (cm)",
+ "reqd": 1
+ },
+ {
+ "fieldname": "width",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Width (cm)",
+ "reqd": 1
+ },
+ {
+ "fieldname": "height",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Height (cm)",
+ "reqd": 1
+ },
+ {
+ "fieldname": "weight",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Weight (kg)",
+ "precision": "1",
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "count",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Count",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-07-09 12:54:14.847170",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Shipment Parcel",
+ "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/stock/doctype/shipment_parcel/shipment_parcel.py b/erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
new file mode 100644
index 0000000..53e6ed5
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class ShipmentParcel(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/stock/doctype/shipment_parcel_template/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/stock/doctype/shipment_parcel_template/__init__.py
diff --git a/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.js b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.js
new file mode 100644
index 0000000..785a3b3
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Shipment Parcel Template', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.json b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.json
new file mode 100644
index 0000000..4735d9f
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.json
@@ -0,0 +1,78 @@
+{
+ "actions": [],
+ "autoname": "field:parcel_template_name",
+ "creation": "2020-07-09 11:43:43.470339",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "parcel_template_name",
+ "length",
+ "width",
+ "height",
+ "weight"
+ ],
+ "fields": [
+ {
+ "fieldname": "length",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Length (cm)",
+ "reqd": 1
+ },
+ {
+ "fieldname": "width",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Width (cm)",
+ "reqd": 1
+ },
+ {
+ "fieldname": "height",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Height (cm)",
+ "reqd": 1
+ },
+ {
+ "fieldname": "weight",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Weight (kg)",
+ "precision": "1",
+ "reqd": 1
+ },
+ {
+ "fieldname": "parcel_template_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Parcel Template Name",
+ "reqd": 1,
+ "unique": 1
+ }
+ ],
+ "links": [],
+ "modified": "2020-09-28 12:51:00.320421",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Shipment Parcel 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/stock/doctype/shipment_parcel_template/shipment_parcel_template.py b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.py
new file mode 100644
index 0000000..2a8d58d
--- /dev/null
+++ b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class ShipmentParcelTemplate(Document):
+ pass
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py
similarity index 77%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py
index 2ad7984..6e2caa7 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestShipmentParcelTemplate(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 39fd029..64dcbed 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -1,9 +1,20 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.stock");
+frappe.provide("erpnext.accounts.dimensions");
+
+{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
frappe.ui.form.on('Stock Entry', {
setup: function(frm) {
+ frm.set_indicator_formatter('item_code', function(doc) {
+ if (!doc.s_warehouse) {
+ return 'blue';
+ } else {
+ return (doc.qty<=doc.actual_qty) ? 'green' : 'orange';
+ }
+ });
+
frm.set_query('work_order', function() {
return {
filters: [
@@ -86,17 +97,9 @@
}
});
- frm.set_query("expense_account", "additional_costs", function() {
- return {
- query: "erpnext.controllers.queries.tax_account_query",
- filters: {
- "account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
- "company": frm.doc.company
- }
- };
- });
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
setup_quality_inspection: function(frm) {
@@ -225,22 +228,44 @@
docstatus: 1
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
frm.add_custom_button(__('Material Request'), function() {
- erpnext.utils.map_current_doc({
+ const allowed_request_types = ["Material Transfer", "Material Issue", "Customer Provided"];
+ const depends_on_condition = "eval:doc.material_request_type==='Customer Provided'";
+ const d = erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_stock_entry",
source_doctype: "Material Request",
target: frm,
date_field: "schedule_date",
- setters: {},
+ setters: [{
+ fieldtype: 'Select',
+ label: __('Purpose'),
+ options: allowed_request_types.join("\n"),
+ fieldname: 'material_request_type',
+ default: "Material Transfer",
+ mandatory: 1,
+ change() {
+ if (this.value === 'Customer Provided') {
+ d.dialog.get_field("customer").set_focus();
+ }
+ },
+ },
+ {
+ fieldtype: 'Link',
+ label: __('Customer'),
+ options: 'Customer',
+ fieldname: 'customer',
+ depends_on: depends_on_condition,
+ mandatory_depends_on: depends_on_condition,
+ }],
get_query_filters: {
docstatus: 1,
- material_request_type: ["in", ["Material Transfer", "Material Issue"]],
+ material_request_type: ["in", allowed_request_types],
status: ["not in", ["Transferred", "Issued"]]
}
})
- }, __("Get items from"));
+ }, __("Get Items From"));
}
if (frm.doc.docstatus===0 && frm.doc.purpose == "Material Issue") {
frm.add_custom_button(__('Expired Batches'), function() {
@@ -263,7 +288,7 @@
}
}
});
- }, __("Get items from"));
+ }, __("Get Items From"));
}
frm.events.show_bom_custom_button(frm);
@@ -282,7 +307,7 @@
},
stock_entry_type: function(frm){
- frm.remove_custom_button('Bill of Materials', "Get items from");
+ frm.remove_custom_button('Bill of Materials', "Get Items From");
frm.events.show_bom_custom_button(frm);
frm.trigger('add_to_transit');
},
@@ -312,6 +337,8 @@
frm.set_value("letter_head", company_doc.default_letter_head);
}
frm.trigger("toggle_display_account_head");
+
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}
},
@@ -425,9 +452,9 @@
show_bom_custom_button: function(frm){
if (frm.doc.docstatus === 0 &&
['Material Issue', 'Material Receipt', 'Material Transfer', 'Send to Subcontractor'].includes(frm.doc.purpose)) {
- frm.add_custom_button(__('Bill of Materials'), function() {
- frm.events.get_items_from_bom(frm);
- }, __("Get items from"));
+ frm.add_custom_button(__('Bill of Materials'), function() {
+ frm.events.get_items_from_bom(frm);
+ }, __("Get Items From"));
}
},
@@ -510,22 +537,31 @@
calculate_amount: function(frm) {
frm.events.calculate_total_additional_costs(frm);
-
- const total_basic_amount = frappe.utils.sum(
- (frm.doc.items || []).map(function(i) { return i.t_warehouse ? flt(i.basic_amount) : 0; })
- );
+ let total_basic_amount = 0;
+ if (in_list(["Repack", "Manufacture"], frm.doc.purpose)) {
+ total_basic_amount = frappe.utils.sum(
+ (frm.doc.items || []).map(function(i) {
+ return i.is_finished_item ? flt(i.basic_amount) : 0;
+ })
+ );
+ } else {
+ total_basic_amount = frappe.utils.sum(
+ (frm.doc.items || []).map(function(i) {
+ return i.t_warehouse ? flt(i.basic_amount) : 0;
+ })
+ );
+ }
for (let i in frm.doc.items) {
let item = frm.doc.items[i];
- if (item.t_warehouse && total_basic_amount) {
+ if (((in_list(["Repack", "Manufacture"], frm.doc.purpose) && item.is_finished_item) || item.t_warehouse) && total_basic_amount) {
item.additional_cost = (flt(item.basic_amount) / total_basic_amount) * frm.doc.total_additional_costs;
} else {
item.additional_cost = 0;
}
- item.amount = flt(item.basic_amount + flt(item.additional_cost),
- precision("amount", item));
+ item.amount = flt(item.basic_amount + flt(item.additional_cost), precision("amount", item));
if (flt(item.transfer_qty)) {
item.valuation_rate = flt(flt(item.basic_rate) + (flt(item.additional_cost) / flt(item.transfer_qty)),
@@ -538,7 +574,7 @@
calculate_total_additional_costs: function(frm) {
const total_additional_costs = frappe.utils.sum(
- (frm.doc.additional_costs || []).map(function(c) { return flt(c.amount); })
+ (frm.doc.additional_costs || []).map(function(c) { return flt(c.base_amount); })
);
frm.set_value("total_additional_costs",
@@ -555,6 +591,7 @@
add_to_transit: function(frm) {
if(frm.doc.add_to_transit && frm.doc.purpose=='Material Transfer') {
+ frm.set_value('to_warehouse', '');
frm.set_value('stock_entry_type', 'Material Transfer');
frm.fields_dict.to_warehouse.get_query = function() {
return {
@@ -565,14 +602,26 @@
}
};
};
- frappe.db.get_value('Company', frm.doc.company, 'default_in_transit_warehouse', (r) => {
+ frm.trigger('set_tansit_warehouse');
+ }
+ },
+
+ set_tansit_warehouse: function(frm) {
+ if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse) {
+ let dt = frm.doc.from_warehouse ? 'Warehouse' : 'Company';
+ let dn = frm.doc.from_warehouse ? frm.doc.from_warehouse : frm.doc.company;
+ frappe.db.get_value(dt, dn, 'default_in_transit_warehouse', (r) => {
if (r.default_in_transit_warehouse) {
frm.set_value('to_warehouse', r.default_in_transit_warehouse);
}
});
}
+ },
+
+ apply_putaway_rule: function (frm) {
+ if (frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(frm, frm.doc.purpose);
}
-})
+});
frappe.ui.form.on('Stock Entry Detail', {
qty: function(frm, cdt, cdn) {
@@ -666,7 +715,13 @@
});
refresh_field("items");
- if (!d.serial_no) {
+ let no_batch_serial_number_value = !d.serial_no;
+ if (d.has_batch_no && !d.has_serial_no) {
+ // check only batch_no for batched item
+ no_batch_serial_number_value = !d.batch_no;
+ }
+
+ if (no_batch_serial_number_value) {
erpnext.stock.select_batch_and_serial_no(frm, d);
}
}
@@ -707,8 +762,18 @@
};
frappe.ui.form.on('Landed Cost Taxes and Charges', {
- amount: function(frm) {
- frm.events.calculate_amount(frm);
+ amount: function(frm, cdt, cdn) {
+ frm.events.set_base_amount(frm, cdt, cdn);
+
+ // Adding this check because same table in used in LCV
+ // This causes an error if you try to post an LCV immediately after a Stock Entry
+ if (frm.doc.doctype == 'Stock Entry') {
+ frm.events.calculate_amount(frm);
+ }
+ },
+
+ expense_account: function(frm, cdt, cdn) {
+ frm.events.set_account_currency(frm, cdt, cdn);
}
});
@@ -756,15 +821,6 @@
}
}
- this.frm.set_indicator_formatter('item_code',
- function(doc) {
- if (!doc.s_warehouse) {
- return 'blue';
- } else {
- return (doc.qty<=doc.actual_qty) ? "green" : "orange"
- }
- })
-
this.frm.add_fetch("purchase_order", "supplier", "supplier");
frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier' }
@@ -841,6 +897,10 @@
}
},
+ fg_completed_qty: function() {
+ this.get_items();
+ },
+
get_items: function() {
var me = this;
if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no)
@@ -850,6 +910,7 @@
// if work order / bom is mentioned, get items
return this.frm.call({
doc: me.frm.doc,
+ freeze: true,
method: "get_items",
callback: function(r) {
if(!r.exc) refresh_field("items");
@@ -916,6 +977,7 @@
},
from_warehouse: function(doc) {
+ this.frm.trigger('set_tansit_warehouse');
this.set_warehouse_in_children(doc.items, "s_warehouse", doc.from_warehouse);
},
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 61e0df6..98c047a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -27,6 +27,7 @@
"set_posting_time",
"inspection_required",
"from_bom",
+ "apply_putaway_rule",
"sb1",
"bom_no",
"fg_completed_qty",
@@ -640,13 +641,21 @@
"fieldtype": "Check",
"label": "Add to Transit",
"no_copy": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:in_list([\"Material Transfer\", \"Material Receipt\"], doc.purpose)",
+ "fieldname": "apply_putaway_rule",
+ "fieldtype": "Check",
+ "label": "Apply Putaway Rule"
}
],
"icon": "fa fa-file-text",
"idx": 1,
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-11 19:10:07.954981",
+ "modified": "2020-12-09 14:58:13.267321",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index a92d04f..b5f7e05 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -18,7 +18,8 @@
from frappe.model.mapper import get_mapped_doc
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit, get_serial_nos
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
-
+from erpnext.accounts.general_ledger import process_gl_map
+from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals
import json
from six import string_types, itervalues, iteritems
@@ -42,6 +43,14 @@
for item in self.get("items"):
item.update(get_bin_details(item.item_code, item.s_warehouse))
+ def before_validate(self):
+ from erpnext.stock.doctype.putaway_rule.putaway_rule import apply_putaway_rule
+ apply_rule = self.apply_putaway_rule and (self.purpose in ["Material Transfer", "Material Receipt"])
+
+ if self.get("items") and apply_rule:
+ apply_putaway_rule(self.doctype, self.get("items"), self.company,
+ purpose=self.purpose)
+
def validate(self):
self.pro_doc = frappe._dict()
if self.work_order:
@@ -58,6 +67,7 @@
self.validate_warehouse()
self.validate_work_order()
self.validate_bom()
+ self.mark_finished_and_scrap_items()
self.validate_finished_goods()
self.validate_with_material_request()
self.validate_batch()
@@ -75,13 +85,12 @@
else:
set_batch_nos(self, 's_warehouse')
- self.set_incoming_rate()
self.validate_serialized_batch()
self.set_actual_qty()
- self.calculate_rate_and_amount(update_finished_item_rate=False)
+ self.calculate_rate_and_amount()
+ self.validate_putaway_capacity()
def on_submit(self):
-
self.update_stock_ledger()
update_serial_nos_after_submit(self, "items")
@@ -89,14 +98,18 @@
self.validate_purchase_order()
if self.purchase_order and self.purpose == "Send to Subcontractor":
self.update_purchase_order_supplied_items()
+
self.make_gl_entries()
+
+ self.repost_future_sle_and_gle()
self.update_cost_in_project()
self.validate_reserved_serial_no_consumption()
self.update_transferred_qty()
self.update_quality_inspection()
+
if self.work_order and self.purpose == "Manufacture":
self.update_so_in_serial_number()
-
+
if self.purpose == 'Material Transfer' and self.add_to_transit:
self.set_material_request_transfer_status('In Transit')
if self.purpose == 'Material Transfer' and self.outgoing_stock_entry:
@@ -113,13 +126,15 @@
self.update_work_order()
self.update_stock_ledger()
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
self.make_gl_entries_on_cancel()
+ self.repost_future_sle_and_gle()
self.update_cost_in_project()
self.update_transferred_qty()
self.update_quality_inspection()
self.delete_auto_created_batches()
+ self.delete_linked_stock_entry()
if self.purpose == 'Material Transfer' and self.add_to_transit:
self.set_material_request_transfer_status('Not Started')
@@ -148,10 +163,16 @@
if self.purpose not in valid_purposes:
frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
- if self.job_card and self.purpose != 'Material Transfer for Manufacture':
+ if self.job_card and self.purpose not in ['Material Transfer for Manufacture', 'Repack']:
frappe.throw(_("For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry")
.format(self.job_card))
+ def delete_linked_stock_entry(self):
+ if self.purpose == "Send to Warehouse":
+ for d in frappe.get_all("Stock Entry", filters={"docstatus": 0,
+ "outgoing_stock_entry": self.name, "purpose": "Receive at Warehouse"}):
+ frappe.delete_doc("Stock Entry", d.name)
+
def set_transfer_qty(self):
for item in self.get("items"):
if not flt(item.qty):
@@ -175,7 +196,7 @@
and (sed.t_warehouse is null or sed.t_warehouse = '')""", self.project, as_list=1)
amount = amount[0][0] if amount else 0
- additional_costs = frappe.db.sql(""" select ifnull(sum(sed.amount), 0)
+ additional_costs = frappe.db.sql(""" select ifnull(sum(sed.base_amount), 0)
from
`tabStock Entry` se, `tabLanded Cost Taxes and Charges` sed
where
@@ -205,7 +226,9 @@
for f in ("uom", "stock_uom", "description", "item_name", "expense_account",
"cost_center", "conversion_factor"):
- if f in ["stock_uom", "conversion_factor"] or not item.get(f):
+ if f == "stock_uom" or not item.get(f):
+ item.set(f, item_details.get(f))
+ if f == 'conversion_factor' and item.uom == item_details.get('stock_uom'):
item.set(f, item_details.get(f))
if not item.transfer_qty and item.qty:
@@ -246,12 +269,17 @@
item_code.append(item.item_code)
def validate_fg_completed_qty(self):
+ item_wise_qty = {}
if self.purpose == "Manufacture" and self.work_order:
- production_item = frappe.get_value('Work Order', self.work_order, 'production_item')
- for item in self.items:
- if item.item_code == production_item and item.t_warehouse and item.qty != self.fg_completed_qty:
- frappe.throw(_("Finished product quantity <b>{0}</b> and For Quantity <b>{1}</b> cannot be different")
- .format(item.qty, self.fg_completed_qty))
+ for d in self.items:
+ if d.is_finished_item:
+ item_wise_qty.setdefault(d.item_code, []).append(d.qty)
+
+ for item_code, qty_list in iteritems(item_wise_qty):
+ total = flt(sum(qty_list), frappe.get_precision("Stock Entry Detail", "qty"))
+ if self.fg_completed_qty != total:
+ frappe.throw(_("The finished product {0} quantity {1} and For Quantity {2} cannot be different")
+ .format(frappe.bold(item_code), frappe.bold(total), frappe.bold(self.fg_completed_qty)))
def validate_difference_account(self):
if not cint(erpnext.is_perpetual_inventory_enabled(self.company)):
@@ -307,7 +335,7 @@
if self.purpose == "Manufacture":
if validate_for_manufacture:
- if d.bom_no:
+ if d.is_finished_item or d.is_scrap_item:
d.s_warehouse = None
if not d.t_warehouse:
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
@@ -373,21 +401,6 @@
frappe.throw(_("Stock Entries already created for Work Order ")
+ self.work_order + ":" + ", ".join(other_ste), DuplicateEntryForWorkOrderError)
- def set_incoming_rate(self):
- if self.purpose == "Repack":
- self.set_basic_rate_for_finished_goods()
-
- for d in self.items:
- if d.s_warehouse:
- args = self.get_args_for_incoming_rate(d)
- d.basic_rate = get_incoming_rate(args)
- elif d.allow_zero_valuation_rate and not d.s_warehouse:
- d.basic_rate = 0.0
- elif d.t_warehouse and not d.basic_rate:
- d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
- self.doctype, self.name, d.allow_zero_valuation_rate,
- currency=erpnext.get_company_currency(self.company), company=self.company)
-
def set_actual_qty(self):
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
@@ -423,57 +436,66 @@
d.serial_no = transferred_serial_no
def get_stock_and_rate(self):
+ """
+ Updates rate and availability of all the items.
+ Called from Update Rate and Availability button.
+ """
self.set_work_order_details()
self.set_transfer_qty()
self.set_actual_qty()
self.calculate_rate_and_amount()
- def calculate_rate_and_amount(self, force=False,
- update_finished_item_rate=True, raise_error_if_no_rate=True):
- self.set_basic_rate(force, update_finished_item_rate, raise_error_if_no_rate)
+ def calculate_rate_and_amount(self, reset_outgoing_rate=True, raise_error_if_no_rate=True):
+ self.set_basic_rate(reset_outgoing_rate, raise_error_if_no_rate)
+ init_landed_taxes_and_totals(self)
self.distribute_additional_costs()
self.update_valuation_rate()
self.set_total_incoming_outgoing_value()
self.set_total_amount()
- def set_basic_rate(self, force=False, update_finished_item_rate=True, raise_error_if_no_rate=True):
- """get stock and incoming rate on posting date"""
- raw_material_cost = 0.0
- scrap_material_cost = 0.0
- fg_basic_rate = 0.0
+ def set_basic_rate(self, reset_outgoing_rate=True, raise_error_if_no_rate=True):
+ """
+ Set rate for outgoing, scrapped and finished items
+ """
+ # Set rate for outgoing items
+ outgoing_items_cost = self.set_rate_for_outgoing_items(reset_outgoing_rate, raise_error_if_no_rate)
+ finished_item_qty = sum([d.transfer_qty for d in self.items if d.is_finished_item])
+ # Set basic rate for incoming items
for d in self.get('items'):
- if d.t_warehouse: fg_basic_rate = flt(d.basic_rate)
- args = self.get_args_for_incoming_rate(d)
+ if d.s_warehouse or d.set_basic_rate_manually: continue
- # get basic rate
- if not d.bom_no:
- if (not flt(d.basic_rate) and not d.allow_zero_valuation_rate) or d.s_warehouse or force:
- basic_rate = flt(get_incoming_rate(args, raise_error_if_no_rate), self.precision("basic_rate", d))
- if basic_rate > 0:
- d.basic_rate = basic_rate
+ if d.allow_zero_valuation_rate:
+ d.basic_rate = 0.0
+ elif d.is_finished_item:
+ if self.purpose == "Manufacture":
+ d.basic_rate = self.get_basic_rate_for_manufactured_item(finished_item_qty, outgoing_items_cost)
+ elif self.purpose == "Repack":
+ d.basic_rate = self.get_basic_rate_for_repacked_items(d.transfer_qty, outgoing_items_cost)
+
+ if not d.basic_rate and not d.allow_zero_valuation_rate:
+ d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
+ self.doctype, self.name, d.allow_zero_valuation_rate,
+ currency=erpnext.get_company_currency(self.company), company=self.company,
+ raise_error_if_no_rate=raise_error_if_no_rate)
+
+ d.basic_rate = flt(d.basic_rate, d.precision("basic_rate"))
+ d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
+
+ def set_rate_for_outgoing_items(self, reset_outgoing_rate=True, raise_error_if_no_rate=True):
+ outgoing_items_cost = 0.0
+ for d in self.get('items'):
+ if d.s_warehouse:
+ if reset_outgoing_rate:
+ args = self.get_args_for_incoming_rate(d)
+ rate = get_incoming_rate(args, raise_error_if_no_rate)
+ if rate > 0:
+ d.basic_rate = rate
d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
if not d.t_warehouse:
- raw_material_cost += flt(d.basic_amount)
-
- # get scrap items basic rate
- if d.bom_no:
- if not flt(d.basic_rate) and not d.allow_zero_valuation_rate and \
- getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
- basic_rate = flt(get_incoming_rate(args, raise_error_if_no_rate),
- self.precision("basic_rate", d))
- if basic_rate > 0:
- d.basic_rate = basic_rate
- d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
-
- if getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
-
- scrap_material_cost += flt(d.basic_amount)
-
- number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
- if (fg_basic_rate == 0.0 and number_of_fg_items == 1) or update_finished_item_rate:
- self.set_basic_rate_for_finished_goods(raw_material_cost, scrap_material_cost)
+ outgoing_items_cost += flt(d.basic_amount)
+ return outgoing_items_cost
def get_args_for_incoming_rate(self, item):
return frappe._dict({
@@ -489,44 +511,44 @@
"allow_zero_valuation": item.allow_zero_valuation_rate,
})
- def set_basic_rate_for_finished_goods(self, raw_material_cost=0, scrap_material_cost=0):
- total_fg_qty = 0
- if not raw_material_cost and self.get("items"):
- raw_material_cost = sum([flt(row.basic_amount) for row in self.items
- if row.s_warehouse and not row.t_warehouse])
+ def get_basic_rate_for_repacked_items(self, finished_item_qty, outgoing_items_cost):
+ finished_items = [d.item_code for d in self.get("items") if d.is_finished_item]
+ if len(finished_items) == 1:
+ return flt(outgoing_items_cost / finished_item_qty)
+ else:
+ unique_finished_items = set(finished_items)
+ if len(unique_finished_items) == 1:
+ total_fg_qty = sum([flt(d.transfer_qty) for d in self.items if d.is_finished_item])
+ return flt(outgoing_items_cost / total_fg_qty)
- total_fg_qty = sum([flt(row.qty) for row in self.items
- if row.t_warehouse and not row.s_warehouse])
+ def get_basic_rate_for_manufactured_item(self, finished_item_qty, outgoing_items_cost=0):
+ scrap_items_cost = sum([flt(d.basic_amount) for d in self.get("items") if d.is_scrap_item])
- if self.purpose in ["Manufacture", "Repack"]:
- for d in self.get("items"):
- if (d.transfer_qty and (d.bom_no or d.t_warehouse)
- and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)):
+ # Get raw materials cost from BOM if multiple material consumption entries
+ if frappe.db.get_single_value("Manufacturing Settings", "material_consumption"):
+ bom_items = self.get_bom_raw_materials(finished_item_qty)
+ outgoing_items_cost = sum([flt(row.qty)*flt(row.rate) for row in bom_items.values()])
- if (self.work_order and self.purpose == "Manufacture"
- and frappe.db.get_single_value("Manufacturing Settings", "material_consumption")):
- bom_items = self.get_bom_raw_materials(d.transfer_qty)
- raw_material_cost = sum([flt(row.qty)*flt(row.rate) for row in bom_items.values()])
-
- if raw_material_cost and self.purpose == "Manufacture":
- d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
- d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
- elif self.purpose == "Repack" and total_fg_qty and not d.set_basic_rate_manually:
- d.basic_rate = flt(raw_material_cost) / flt(total_fg_qty)
- d.basic_amount = d.basic_rate * flt(d.qty)
+ return flt((outgoing_items_cost - scrap_items_cost) / finished_item_qty)
def distribute_additional_costs(self):
- if self.purpose == "Material Issue":
+ # If no incoming items, set additional costs blank
+ if not any([d.item_code for d in self.items if d.t_warehouse]):
self.additional_costs = []
- self.total_additional_costs = sum([flt(t.amount) for t in self.get("additional_costs")])
- total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+ self.total_additional_costs = sum([flt(t.base_amount) for t in self.get("additional_costs")])
- for d in self.get("items"):
- if d.t_warehouse and total_basic_amount:
- d.additional_cost = (flt(d.basic_amount) / total_basic_amount) * self.total_additional_costs
- else:
- d.additional_cost = 0
+ if self.purpose in ("Repack", "Manufacture"):
+ incoming_items_cost = sum([flt(t.basic_amount) for t in self.get("items") if t.is_finished_item])
+ else:
+ incoming_items_cost = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+
+ if incoming_items_cost:
+ for d in self.get("items"):
+ if (self.purpose in ("Repack", "Manufacture") and d.is_finished_item) or d.t_warehouse:
+ d.additional_cost = (flt(d.basic_amount) / incoming_items_cost) * self.total_additional_costs
+ else:
+ d.additional_cost = 0
def update_valuation_rate(self):
for d in self.get("items"):
@@ -569,8 +591,9 @@
qty_allowance = flt(frappe.db.get_single_value("Buying Settings",
"over_transfer_allowance"))
- if (self.purpose == "Send to Subcontractor" and self.purchase_order and
- backflush_raw_materials_based_on == 'BOM'):
+ if not (self.purpose == "Send to Subcontractor" and self.purchase_order): return
+
+ if (backflush_raw_materials_based_on == 'BOM'):
purchase_order = frappe.get_doc("Purchase Order", self.purchase_order)
for se_item in self.items:
item_code = se_item.original_item or se_item.item_code
@@ -607,6 +630,20 @@
if flt(total_supplied, precision) > flt(total_allowed, precision):
frappe.throw(_("Row {0}# Item {1} cannot be transferred more than {2} against Purchase Order {3}")
.format(se_item.idx, se_item.item_code, total_allowed, self.purchase_order))
+ elif backflush_raw_materials_based_on == "Material Transferred for Subcontract":
+ for row in self.items:
+ if not row.subcontracted_item:
+ frappe.throw(_("Row {0}: Subcontracted Item is mandatory for the raw material {1}")
+ .format(row.idx, frappe.bold(row.item_code)))
+ elif not row.po_detail:
+ filters = {
+ "parent": self.purchase_order, "docstatus": 1,
+ "rm_item_code": row.item_code, "main_item_code": row.subcontracted_item
+ }
+
+ po_detail = frappe.db.get_value("Purchase Order Item Supplied", filters, "name")
+ if po_detail:
+ row.db_set("po_detail", po_detail)
def validate_bom(self):
for d in self.get('items'):
@@ -614,71 +651,115 @@
item_code = d.original_item or d.item_code
validate_bom_no(item_code, d.bom_no)
+ def mark_finished_and_scrap_items(self):
+ if self.purpose in ("Repack", "Manufacture"):
+ if any([d.item_code for d in self.items if (d.is_finished_item and d.t_warehouse)]):
+ return
+
+ finished_item = self.get_finished_item()
+
+ for d in self.items:
+ if d.t_warehouse and not d.s_warehouse:
+ if self.purpose=="Repack" or d.item_code == finished_item:
+ d.is_finished_item = 1
+ else:
+ d.is_scrap_item = 1
+ else:
+ d.is_finished_item = 0
+ d.is_scrap_item = 0
+
+ def get_finished_item(self):
+ finished_item = None
+ if self.work_order:
+ finished_item = frappe.db.get_value("Work Order", self.work_order, "production_item")
+ elif self.bom_no:
+ finished_item = frappe.db.get_value("BOM", self.bom_no, "item")
+
+ return finished_item
+
def validate_finished_goods(self):
"""validation: finished good quantity should be same as manufacturing quantity"""
if not self.work_order: return
- items_with_target_warehouse = []
- allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
- "overproduction_percentage_for_work_order"))
-
production_item, wo_qty = frappe.db.get_value("Work Order",
self.work_order, ["production_item", "qty"])
+ finished_items = []
for d in self.get('items'):
- if (self.purpose != "Send to Subcontractor" and d.bom_no
- and flt(d.transfer_qty) > flt(self.fg_completed_qty) and d.item_code == production_item):
- frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
- format(d.idx, d.transfer_qty, self.fg_completed_qty))
+ if d.is_finished_item:
+ if d.item_code != production_item:
+ frappe.throw(_("Finished Item {0} does not match with Work Order {1}")
+ .format(d.item_code, self.work_order))
+ elif flt(d.transfer_qty) > flt(self.fg_completed_qty):
+ frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
+ format(d.idx, d.transfer_qty, self.fg_completed_qty))
+ finished_items.append(d.item_code)
- if self.work_order and self.purpose == "Manufacture" and d.t_warehouse:
- items_with_target_warehouse.append(d.item_code)
+ if len(set(finished_items)) > 1:
+ frappe.throw(_("Multiple items cannot be marked as finished item"))
- if self.work_order and self.purpose == "Manufacture":
+ if self.purpose == "Manufacture":
+ allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
+ "overproduction_percentage_for_work_order"))
+
allowed_qty = wo_qty + (allowance_percentage/100 * wo_qty)
if self.fg_completed_qty > allowed_qty:
frappe.throw(_("For quantity {0} should not be greater than work order quantity {1}")
.format(flt(self.fg_completed_qty), wo_qty))
- if production_item not in items_with_target_warehouse:
- frappe.throw(_("Finished Item {0} must be entered for Manufacture type entry")
- .format(production_item))
-
def update_stock_ledger(self):
sl_entries = []
+ finished_item_row = self.get_finished_item_row()
- # make sl entries for source warehouse first, then do for target warehouse
- for d in self.get('items'):
- if cstr(d.s_warehouse):
- sl_entries.append(self.get_sl_entries(d, {
- "warehouse": cstr(d.s_warehouse),
- "actual_qty": -flt(d.transfer_qty),
- "incoming_rate": 0
- }))
+ # make sl entries for source warehouse first
+ self.get_sle_for_source_warehouse(sl_entries, finished_item_row)
- for d in self.get('items'):
- if cstr(d.t_warehouse):
- sl_entries.append(self.get_sl_entries(d, {
- "warehouse": cstr(d.t_warehouse),
- "actual_qty": flt(d.transfer_qty),
- "incoming_rate": flt(d.valuation_rate)
- }))
+ # SLE for target warehouse
+ self.get_sle_for_target_warehouse(sl_entries, finished_item_row)
- # On cancellation, make stock ledger entry for
- # target warehouse first, to update serial no values properly
-
- # if cstr(d.s_warehouse) and self.docstatus == 2:
- # sl_entries.append(self.get_sl_entries(d, {
- # "warehouse": cstr(d.s_warehouse),
- # "actual_qty": -flt(d.transfer_qty),
- # "incoming_rate": 0
- # }))
-
+ # reverse sl entries if cancel
if self.docstatus == 2:
sl_entries.reverse()
self.make_sl_entries(sl_entries)
+ def get_finished_item_row(self):
+ finished_item_row = None
+ if self.purpose in ("Manufacture", "Repack"):
+ for d in self.get('items'):
+ if d.is_finished_item:
+ finished_item_row = d
+
+ return finished_item_row
+
+ def get_sle_for_source_warehouse(self, sl_entries, finished_item_row):
+ for d in self.get('items'):
+ if cstr(d.s_warehouse):
+ sle = self.get_sl_entries(d, {
+ "warehouse": cstr(d.s_warehouse),
+ "actual_qty": -flt(d.transfer_qty),
+ "incoming_rate": 0
+ })
+ if cstr(d.t_warehouse):
+ sle.dependant_sle_voucher_detail_no = d.name
+ elif finished_item_row and (finished_item_row.item_code != d.item_code or finished_item_row.t_warehouse != d.s_warehouse):
+ sle.dependant_sle_voucher_detail_no = finished_item_row.name
+
+ sl_entries.append(sle)
+
+ def get_sle_for_target_warehouse(self, sl_entries, finished_item_row):
+ for d in self.get('items'):
+ if cstr(d.t_warehouse):
+ sle = self.get_sl_entries(d, {
+ "warehouse": cstr(d.t_warehouse),
+ "actual_qty": flt(d.transfer_qty),
+ "incoming_rate": flt(d.valuation_rate)
+ })
+ if cstr(d.s_warehouse) or (finished_item_row and d.name == finished_item_row.name):
+ sle.recalculate_rate = 1
+
+ sl_entries.append(sle)
+
def get_gl_entries(self, warehouse_account):
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
@@ -695,13 +776,19 @@
for d in self.get("items"):
if d.t_warehouse:
item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
- item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
+ item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, {
+ "amount": 0.0,
+ "base_amount": 0.0
+ })
multiply_based_on = d.basic_amount if total_basic_amount else d.qty
- item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
+ item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["amount"] += \
flt(t.amount * multiply_based_on) / divide_based_on
+ item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["base_amount"] += \
+ flt(t.base_amount * multiply_based_on) / divide_based_on
+
if item_account_wise_additional_cost:
for d in self.get("items"):
for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})):
@@ -712,7 +799,8 @@
"against": d.expense_account,
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": amount
+ "credit_in_account_currency": flt(amount["amount"]),
+ "credit": flt(amount["base_amount"])
}, item=d))
gl_entries.append(self.get_gl_dict({
@@ -720,10 +808,10 @@
"against": account,
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": -1 * amount # put it as negative credit instead of debit purposefully
+ "credit": -1 * amount['base_amount'] # put it as negative credit instead of debit purposefully
}, item=d))
- return gl_entries
+ return process_gl_map(gl_entries)
def update_work_order(self):
def _validate_work_order(pro_doc):
@@ -736,6 +824,7 @@
if self.job_card:
job_doc = frappe.get_doc('Job Card', self.job_card)
job_doc.set_transferred_qty(update_status=True)
+ job_doc.set_transferred_qty_in_job_card(self)
if self.work_order:
pro_doc = frappe.get_doc("Work Order", self.work_order)
@@ -815,6 +904,13 @@
ret.get('has_batch_no') and not args.get('batch_no')):
args.batch_no = get_batch_no(args['item_code'], args['s_warehouse'], args['qty'])
+ if self.purpose == "Send to Subcontractor" and self.get("purchase_order") and args.get('item_code'):
+ subcontract_items = frappe.get_all("Purchase Order Item Supplied",
+ {"parent": self.purchase_order, "rm_item_code": args.get('item_code')}, "main_item_code")
+
+ if subcontract_items and len(subcontract_items) == 1:
+ ret["subcontracted_item"] = subcontract_items[0].main_item_code
+
return ret
def set_items_for_stock_in(self):
@@ -849,6 +945,8 @@
frappe.throw(_("Posting date and posting time is mandatory"))
self.set_work_order_details()
+ self.flags.backflush_based_on = frappe.db.get_single_value("Manufacturing Settings",
+ "backflush_raw_materials_based_on")
if self.bom_no:
@@ -865,14 +963,16 @@
item["to_warehouse"] = self.pro_doc.wip_warehouse
self.add_to_stock_entry_detail(item_dict)
- elif (self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
- and not self.pro_doc.skip_transfer and backflush_based_on == "Material Transferred for Manufacture"):
+ elif (self.work_order and (self.purpose == "Manufacture"
+ or self.purpose == "Material Consumption for Manufacture") and not self.pro_doc.skip_transfer
+ and self.flags.backflush_based_on == "Material Transferred for Manufacture"):
self.get_transfered_raw_materials()
- elif (self.work_order and backflush_based_on== "BOM" and
- (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
+ elif (self.work_order and (self.purpose == "Manufacture" or
+ self.purpose == "Material Consumption for Manufacture") and self.flags.backflush_based_on== "BOM"
and frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1):
self.get_unconsumed_raw_materials()
+
else:
if not self.fg_completed_qty:
frappe.throw(_("Manufacturing Quantity is mandatory"))
@@ -910,7 +1010,8 @@
self.set_scrap_items()
self.set_actual_qty()
- self.calculate_rate_and_amount(raise_error_if_no_rate=False)
+ self.validate_customer_provided_item()
+ self.calculate_rate_and_amount()
def set_scrap_items(self):
if self.purpose != "Send to Subcontractor" and self.purpose in ["Manufacture", "Repack"]:
@@ -961,6 +1062,7 @@
"stock_uom": item.stock_uom,
"expense_account": item.get("expense_account"),
"cost_center": item.get("buying_cost_center"),
+ "is_finished_item": 1
}
}, bom_no = self.bom_no)
@@ -999,32 +1101,29 @@
for item in itervalues(item_dict):
item.from_warehouse = ""
+ item.is_scrap_item = 1
return item_dict
def get_unconsumed_raw_materials(self):
wo = frappe.get_doc("Work Order", self.work_order)
wo_items = frappe.get_all('Work Order Item',
filters={'parent': self.work_order},
- fields=["item_code", "required_qty", "consumed_qty"]
+ fields=["item_code", "required_qty", "consumed_qty", "transferred_qty"]
)
+ work_order_qty = wo.material_transferred_for_manufacturing or wo.qty
for item in wo_items:
- qty = item.required_qty
-
item_account_details = get_item_defaults(item.item_code, self.company)
# Take into account consumption if there are any.
- if self.purpose == 'Manufacture':
- req_qty_each = flt(item.required_qty / wo.qty)
- if (flt(item.consumed_qty) != 0):
- remaining_qty = flt(item.consumed_qty) - (flt(wo.produced_qty) * req_qty_each)
- exhaust_qty = req_qty_each * wo.produced_qty
- if remaining_qty > exhaust_qty :
- if (remaining_qty/(req_qty_each * flt(self.fg_completed_qty))) >= 1:
- qty =0
- else:
- qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
- else:
- qty = req_qty_each * flt(self.fg_completed_qty)
+
+ wo_item_qty = item.transferred_qty or item.required_qty
+
+ req_qty_each = (
+ (flt(wo_item_qty) - flt(item.consumed_qty)) /
+ (flt(work_order_qty) - flt(wo.produced_qty))
+ )
+
+ qty = req_qty_each * flt(self.fg_completed_qty)
if qty > 0:
self.add_to_stock_entry_detail({
@@ -1104,15 +1203,23 @@
else:
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
else:
- qty = req_qty_each * flt(self.fg_completed_qty)
-
+ if self.flags.backflush_based_on == "Material Transferred for Manufacture":
+ qty = (item.qty/trans_qty) * flt(self.fg_completed_qty)
+ else:
+ qty = req_qty_each * flt(self.fg_completed_qty)
elif backflushed_materials.get(item.item_code):
for d in backflushed_materials.get(item.item_code):
if d.get(item.warehouse):
if (qty > req_qty):
- qty = req_qty
- qty-= d.get(item.warehouse)
+ qty = (qty/trans_qty) * flt(self.fg_completed_qty)
+
+ if consumed_qty and frappe.db.get_single_value("Manufacturing Settings",
+ "material_consumption"):
+ qty -= consumed_qty
+
+ if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')):
+ qty = frappe.utils.ceil(qty)
if qty > 0:
self.add_to_stock_entry_detail({
@@ -1137,12 +1244,24 @@
item_dict = self.get_pro_order_required_items(backflush_based_on)
max_qty = flt(self.pro_doc.qty)
+
+ allow_overproduction = False
+ overproduction_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
+ "overproduction_percentage_for_work_order"))
+
+ to_transfer_qty = flt(self.pro_doc.material_transferred_for_manufacturing) + flt(self.fg_completed_qty)
+ transfer_limit_qty = max_qty + ((max_qty * overproduction_percentage) / 100)
+
+ if transfer_limit_qty >= to_transfer_qty:
+ allow_overproduction = True
+
for item, item_details in iteritems(item_dict):
pending_to_issue = flt(item_details.required_qty) - flt(item_details.transferred_qty)
desire_to_transfer = flt(self.fg_completed_qty) * flt(item_details.required_qty) / max_qty
- if (desire_to_transfer <= pending_to_issue or
- (desire_to_transfer > 0 and backflush_based_on == "Material Transferred for Manufacture")):
+ if (desire_to_transfer <= pending_to_issue
+ or (desire_to_transfer > 0 and backflush_based_on == "Material Transferred for Manufacture")
+ or allow_overproduction):
item_dict[item]["qty"] = desire_to_transfer
elif pending_to_issue > 0:
item_dict[item]["qty"] = pending_to_issue
@@ -1185,8 +1304,6 @@
return item_dict
def add_to_stock_entry_detail(self, item_dict, bom_no=None):
- cost_center = frappe.db.get_value("Company", self.company, 'cost_center')
-
for d in item_dict:
stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom")
@@ -1197,9 +1314,12 @@
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
se_child.stock_uom = stock_uom
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
- se_child.cost_center = item_dict[d].get("cost_center") or cost_center
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
se_child.subcontracted_item = item_dict[d].get("main_item_code")
+ se_child.cost_center = (item_dict[d].get("cost_center") or
+ get_default_cost_center(item_dict[d], company = self.company))
+ se_child.is_finished_item = item_dict[d].get("is_finished_item", 0)
+ se_child.is_scrap_item = item_dict[d].get("is_scrap_item", 0)
for field in ["idx", "po_detail", "original_item",
"expense_account", "description", "item_name"]:
@@ -1238,9 +1358,6 @@
frappe.MappingMismatchError)
elif self.purpose == "Material Transfer" and self.add_to_transit:
continue
- elif mreq_item.warehouse != (item.s_warehouse if self.purpose == "Material Issue" else item.t_warehouse):
- frappe.throw(_("Warehouse for row {0} does not match Material Request").format(item.idx),
- frappe.MappingMismatchError)
def validate_batch(self):
if self.purpose in ["Material Transfer for Manufacture", "Manufacture", "Repack", "Send to Subcontractor"]:
@@ -1268,9 +1385,16 @@
#Update Supplied Qty in PO Supplied Items
frappe.db.sql("""UPDATE `tabPurchase Order Item Supplied` pos
- SET pos.supplied_qty = (SELECT ifnull(sum(transfer_qty), 0) FROM `tabStock Entry Detail` sed
- WHERE pos.name = sed.po_detail and sed.docstatus = 1)
- WHERE pos.docstatus = 1 and pos.parent = %s""", self.purchase_order)
+ SET
+ pos.supplied_qty = IFNULL((SELECT ifnull(sum(transfer_qty), 0)
+ FROM
+ `tabStock Entry Detail` sed, `tabStock Entry` se
+ WHERE
+ pos.name = sed.po_detail AND pos.rm_item_code = sed.item_code
+ AND pos.parent = se.purchase_order AND sed.docstatus = 1
+ AND se.name = sed.parent and se.purchase_order = %(po)s
+ ), 0)
+ WHERE pos.docstatus = 1 and pos.parent = %(po)s""", {"po": self.purchase_order})
#Update reserved sub contracted quantity in bin based on Supplied Item Details and
for d in self.get("items"):
@@ -1303,8 +1427,10 @@
for sr in get_serial_nos(item.serial_no):
sales_order = frappe.db.get_value("Serial No", sr, "sales_order")
if sales_order:
- frappe.throw(_("Item {0} (Serial No: {1}) cannot be consumed as is reserverd\
- to fullfill Sales Order {2}.").format(item.item_code, sr, sales_order))
+ msg = (_("(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.")
+ .format(sr, sales_order))
+
+ frappe.throw(_("Item {0} {1}").format(item.item_code, msg))
def update_transferred_qty(self):
if self.purpose == 'Material Transfer' and self.outgoing_stock_entry:
@@ -1370,7 +1496,7 @@
if self.outgoing_stock_entry:
parent_se = frappe.get_value("Stock Entry", self.outgoing_stock_entry, 'add_to_transit')
- for item in self.items:
+ for item in self.items:
material_request = item.material_request or None
if self.purpose == "Material Transfer" and material_request not in material_requests:
if self.outgoing_stock_entry and parent_se:
@@ -1430,7 +1556,7 @@
if add_to_transit:
warehouse = frappe.get_value('Material Request Item', source_doc.material_request_item, 'warehouse')
target_doc.t_warehouse = warehouse
-
+
target_doc.s_warehouse = source_doc.t_warehouse
target_doc.qty = source_doc.qty - source_doc.transferred_qty
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
index b78c6be..b12a854 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
@@ -53,6 +53,8 @@
args.target = args.to_warehouse
if args.item_code:
args.item = args.item_code
+ if args.apply_putaway_rule:
+ s.apply_putaway_rule = args.apply_putaway_rule
if isinstance(args.qty, string_types):
if '.' in args.qty:
@@ -118,7 +120,8 @@
"t_warehouse": args.target,
"qty": args.qty,
"basic_rate": args.rate or args.basic_rate,
- "conversion_factor": 1.0,
+ "conversion_factor": args.conversion_factor or 1.0,
+ "transfer_qty": flt(args.qty) * (flt(args.conversion_factor) or 1.0),
"serial_no": args.serial_no,
'batch_no': args.batch_no,
'cost_center': args.cost_center,
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index d98870d..123f0c8 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -6,7 +6,6 @@
import frappe.defaults
from frappe.utils import flt, nowdate, nowtime
from erpnext.stock.doctype.serial_no.serial_no import *
-from erpnext import set_perpetual_inventory
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
from erpnext.stock.stock_ledger import get_previous_sle
from frappe.permissions import add_user_permission, remove_user_permission
@@ -32,7 +31,6 @@
class TestStockEntry(unittest.TestCase):
def tearDown(self):
frappe.set_user("Administrator")
- set_perpetual_inventory(0)
def test_fifo(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
@@ -181,22 +179,20 @@
def test_material_transfer_gl_entry(self):
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
- create_stock_reconciliation(qty=100, rate=100)
-
mtn = make_stock_entry(item_code="_Test Item", source="Stores - TCP1",
- target="Finished Goods - TCP1", qty=45)
+ target="Finished Goods - TCP1", qty=45, company=company)
self.check_stock_ledger_entries("Stock Entry", mtn.name,
[["_Test Item", "Stores - TCP1", -45.0], ["_Test Item", "Finished Goods - TCP1", 45.0]])
- stock_in_hand_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
+ source_warehouse_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
- fixed_asset_account = get_inventory_account(mtn.company, mtn.get("items")[0].t_warehouse)
+ target_warehouse_account = get_inventory_account(mtn.company, mtn.get("items")[0].t_warehouse)
- if stock_in_hand_account == fixed_asset_account:
+ if source_warehouse_account == target_warehouse_account:
# no gl entry as both source and target warehouse has linked to same account.
self.assertFalse(frappe.db.sql("""select * from `tabGL Entry`
- where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name))
+ where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name, as_dict=1))
else:
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
@@ -204,8 +200,8 @@
self.check_gl_entries("Stock Entry", mtn.name,
sorted([
- [stock_in_hand_account, 0.0, stock_value_diff],
- [fixed_asset_account, stock_value_diff, 0.0],
+ [source_warehouse_account, 0.0, stock_value_diff],
+ [target_warehouse_account, stock_value_diff, 0.0],
])
)
@@ -213,7 +209,6 @@
def test_repack_no_change_in_valuation(self):
company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(0, company)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
@@ -235,8 +230,6 @@
order by account desc""", repack.name, as_dict=1)
self.assertFalse(gl_entries)
- set_perpetual_inventory(0, repack.company)
-
def test_repack_with_additional_costs(self):
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
@@ -474,7 +467,6 @@
def test_warehouse_company_validation(self):
company = frappe.db.get_value('Warehouse', '_Test Warehouse 2 - _TC1', 'company')
- set_perpetual_inventory(0, company)
frappe.get_doc("User", "test2@example.com")\
.add_roles("Sales User", "Sales Manager", "Stock User", "Stock Manager")
frappe.set_user("test2@example.com")
@@ -500,7 +492,7 @@
st1 = frappe.copy_doc(test_records[0])
st1.company = "_Test Company 1"
- set_perpetual_inventory(0, st1.company)
+
frappe.set_user("test@example.com")
st1.get("items")[0].t_warehouse="_Test Warehouse 2 - _TC1"
self.assertRaises(frappe.PermissionError, st1.insert)
@@ -698,47 +690,54 @@
repack.insert()
self.assertRaises(frappe.ValidationError, repack.submit)
- def test_material_consumption(self):
- from erpnext.manufacturing.doctype.work_order.work_order \
- import make_stock_entry as _make_stock_entry
- bom_no = frappe.db.get_value("BOM", {"item": "_Test FG Item 2",
- "is_default": 1, "docstatus": 1})
+ # def test_material_consumption(self):
+ # frappe.db.set_value("Manufacturing Settings", None, "backflush_raw_materials_based_on", "BOM")
+ # frappe.db.set_value("Manufacturing Settings", None, "material_consumption", "0")
- work_order = frappe.new_doc("Work Order")
- work_order.update({
- "company": "_Test Company",
- "fg_warehouse": "_Test Warehouse 1 - _TC",
- "production_item": "_Test FG Item 2",
- "bom_no": bom_no,
- "qty": 4.0,
- "stock_uom": "_Test UOM",
- "wip_warehouse": "_Test Warehouse - _TC",
- "additional_operating_cost": 1000
- })
- work_order.insert()
- work_order.submit()
+ # from erpnext.manufacturing.doctype.work_order.work_order \
+ # import make_stock_entry as _make_stock_entry
+ # bom_no = frappe.db.get_value("BOM", {"item": "_Test FG Item 2",
+ # "is_default": 1, "docstatus": 1})
- make_stock_entry(item_code="_Test Serialized Item With Series", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
- make_stock_entry(item_code="_Test Item 2", target="_Test Warehouse - _TC", qty=50, basic_rate=20)
+ # work_order = frappe.new_doc("Work Order")
+ # work_order.update({
+ # "company": "_Test Company",
+ # "fg_warehouse": "_Test Warehouse 1 - _TC",
+ # "production_item": "_Test FG Item 2",
+ # "bom_no": bom_no,
+ # "qty": 4.0,
+ # "stock_uom": "_Test UOM",
+ # "wip_warehouse": "_Test Warehouse - _TC",
+ # "additional_operating_cost": 1000,
+ # "use_multi_level_bom": 1
+ # })
+ # work_order.insert()
+ # work_order.submit()
- item_quantity = {
- '_Test Item': 10.0,
- '_Test Item 2': 12.0,
- '_Test Serialized Item With Series': 6.0
- }
+ # make_stock_entry(item_code="_Test Serialized Item With Series", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
+ # make_stock_entry(item_code="_Test Item 2", target="_Test Warehouse - _TC", qty=50, basic_rate=20)
- stock_entry = frappe.get_doc(_make_stock_entry(work_order.name, "Material Consumption for Manufacture", 2))
- for d in stock_entry.get('items'):
- self.assertEqual(item_quantity.get(d.item_code), d.qty)
+ # item_quantity = {
+ # '_Test Item': 2.0,
+ # '_Test Item 2': 12.0,
+ # '_Test Serialized Item With Series': 6.0
+ # }
+
+ # stock_entry = frappe.get_doc(_make_stock_entry(work_order.name, "Material Consumption for Manufacture", 2))
+ # for d in stock_entry.get('items'):
+ # self.assertEqual(item_quantity.get(d.item_code), d.qty)
def test_customer_provided_parts_se(self):
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
- se = make_stock_entry(item_code='CUST-0987', purpose = 'Material Receipt', qty=4, to_warehouse = "_Test Warehouse - _TC")
+ se = make_stock_entry(item_code='CUST-0987', purpose = 'Material Receipt',
+ qty=4, to_warehouse = "_Test Warehouse - _TC")
self.assertEqual(se.get("items")[0].allow_zero_valuation_rate, 1)
self.assertEqual(se.get("items")[0].amount, 0)
def test_gle_for_opening_stock_entry(self):
- mr = make_stock_entry(item_code="_Test Item", target="Stores - TCP1", company="_Test Company with perpetual inventory",qty=50, basic_rate=100, expense_account="Stock Adjustment - TCP1", is_opening="Yes", do_not_save=True)
+ mr = make_stock_entry(item_code="_Test Item", target="Stores - TCP1",
+ company="_Test Company with perpetual inventory", qty=50, basic_rate=100,
+ expense_account="Stock Adjustment - TCP1", is_opening="Yes", do_not_save=True)
self.assertRaises(OpeningEntryAccountError, mr.save)
@@ -753,37 +752,37 @@
def test_total_basic_amount_zero(self):
se = frappe.get_doc({"doctype":"Stock Entry",
- "purpose":"Material Receipt",
- "stock_entry_type":"Material Receipt",
- "posting_date": nowdate(),
- "company":"_Test Company with perpetual inventory",
- "items":[
- {
- "item_code":"Basil Leaves",
- "description":"Basil Leaves",
- "qty": 1,
- "basic_rate": 0,
- "uom":"Nos",
- "t_warehouse": "Stores - TCP1",
- "allow_zero_valuation_rate": 1,
- "cost_center": "Main - TCP1"
- },
- {
- "item_code":"Basil Leaves",
- "description":"Basil Leaves",
- "qty": 2,
- "basic_rate": 0,
- "uom":"Nos",
- "t_warehouse": "Stores - TCP1",
- "allow_zero_valuation_rate": 1,
- "cost_center": "Main - TCP1"
- },
- ],
- "additional_costs":[
- {"expense_account":"Miscellaneous Expenses - TCP1",
- "amount":100,
- "description": "miscellanous"}
- ]
+ "purpose":"Material Receipt",
+ "stock_entry_type":"Material Receipt",
+ "posting_date": nowdate(),
+ "company":"_Test Company with perpetual inventory",
+ "items":[
+ {
+ "item_code":"_Test Item",
+ "description":"_Test Item",
+ "qty": 1,
+ "basic_rate": 0,
+ "uom":"Nos",
+ "t_warehouse": "Stores - TCP1",
+ "allow_zero_valuation_rate": 1,
+ "cost_center": "Main - TCP1"
+ },
+ {
+ "item_code":"_Test Item",
+ "description":"_Test Item",
+ "qty": 2,
+ "basic_rate": 0,
+ "uom":"Nos",
+ "t_warehouse": "Stores - TCP1",
+ "allow_zero_valuation_rate": 1,
+ "cost_center": "Main - TCP1"
+ },
+ ],
+ "additional_costs":[
+ {"expense_account":"Miscellaneous Expenses - TCP1",
+ "amount":100,
+ "description": "miscellanous"
+ }]
})
se.insert()
se.submit()
@@ -795,6 +794,32 @@
])
)
+ def test_conversion_factor_change(self):
+ frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
+ repack_entry = frappe.copy_doc(test_records[3])
+ repack_entry.posting_date = nowdate()
+ repack_entry.posting_time = nowtime()
+ repack_entry.set_stock_entry_type()
+ repack_entry.insert()
+
+ # check current uom and conversion factor
+ self.assertTrue(repack_entry.items[0].uom, "_Test UOM")
+ self.assertTrue(repack_entry.items[0].conversion_factor, 1)
+
+ # change conversion factor
+ repack_entry.items[0].uom = "_Test UOM 1"
+ repack_entry.items[0].stock_uom = "_Test UOM 1"
+ repack_entry.items[0].conversion_factor = 2
+ repack_entry.save()
+ repack_entry.submit()
+
+ self.assertEqual(repack_entry.items[0].conversion_factor, 2)
+ self.assertEqual(repack_entry.items[0].uom, "_Test UOM 1")
+ self.assertEqual(repack_entry.items[0].qty, 50)
+ self.assertEqual(repack_entry.items[0].transfer_qty, 100)
+
+ frappe.db.set_default("allow_negative_stock", 0)
+
def make_serialized_item(**args):
args = frappe._dict(args)
se = frappe.copy_doc(test_records[0])
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index 7b9c129..864ff48 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -14,58 +14,63 @@
"t_warehouse",
"sec_break1",
"item_code",
- "col_break2",
"item_name",
+ "col_break2",
+ "is_finished_item",
+ "is_scrap_item",
+ "subcontracted_item",
"section_break_8",
"description",
"column_break_10",
"item_group",
"image",
"image_view",
- "quantity_and_rate",
- "set_basic_rate_manually",
+ "quantity_section",
"qty",
- "basic_rate",
- "basic_amount",
- "additional_cost",
- "amount",
- "valuation_rate",
- "col_break3",
- "uom",
- "conversion_factor",
- "stock_uom",
"transfer_qty",
"retain_sample",
+ "column_break_20",
+ "uom",
+ "stock_uom",
+ "conversion_factor",
"sample_quantity",
+ "rates_section",
+ "basic_rate",
+ "additional_cost",
+ "valuation_rate",
+ "allow_zero_valuation_rate",
+ "col_break3",
+ "set_basic_rate_manually",
+ "basic_amount",
+ "amount",
"serial_no_batch",
"serial_no",
"col_break4",
"batch_no",
- "quality_inspection",
"accounting",
"expense_account",
- "col_break5",
"accounting_dimensions_section",
"cost_center",
+ "project",
"dimension_col_break",
"more_info",
- "allow_zero_valuation_rate",
"actual_qty",
+ "transferred_qty",
"bom_no",
"allow_alternative_item",
"col_break6",
"material_request",
"material_request_item",
"original_item",
- "subcontracted_item",
"reference_section",
"against_stock_entry",
"ste_detail",
"po_detail",
+ "putaway_rule",
"column_break_51",
- "transferred_qty",
"reference_purchase_receipt",
- "project"
+ "quality_inspection",
+ "job_card_item"
],
"fields": [
{
@@ -161,11 +166,6 @@
"print_hide": 1
},
{
- "fieldname": "quantity_and_rate",
- "fieldtype": "Section Break",
- "label": "Quantity and Rate"
- },
- {
"bold": 1,
"fieldname": "qty",
"fieldtype": "Float",
@@ -238,7 +238,6 @@
"oldfieldname": "conversion_factor",
"oldfieldtype": "Currency",
"print_hide": 1,
- "read_only": 1,
"reqd": 1
},
{
@@ -324,10 +323,6 @@
"print_hide": 1
},
{
- "fieldname": "col_break5",
- "fieldtype": "Column Break"
- },
- {
"default": ":Company",
"depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))",
"fieldname": "cost_center",
@@ -337,6 +332,7 @@
"print_hide": 1
},
{
+ "collapsible": 1,
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Information"
@@ -416,6 +412,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.purpose == 'Send to Subcontractor'",
"fieldname": "subcontracted_item",
"fieldtype": "Link",
"label": "Subcontracted Item",
@@ -457,6 +454,7 @@
"read_only": 1
},
{
+ "collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
@@ -498,15 +496,59 @@
"depends_on": "eval:parent.purpose===\"Repack\" && doc.t_warehouse",
"fieldname": "set_basic_rate_manually",
"fieldtype": "Check",
- "label": "Set Basic Rate Manually",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Set Basic Rate Manually"
+ },
+ {
+ "depends_on": "eval:in_list([\"Material Transfer\", \"Material Receipt\"], parent.purpose)",
+ "fieldname": "putaway_rule",
+ "fieldtype": "Link",
+ "label": "Putaway Rule",
+ "no_copy": 1,
+ "options": "Putaway Rule",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "quantity_section",
+ "fieldtype": "Section Break",
+ "label": "Quantity"
+ },
+ {
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "rates_section",
+ "fieldtype": "Section Break",
+ "label": "Rates"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_scrap_item",
+ "fieldtype": "Check",
+ "label": "Is Scrap Item"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_finished_item",
+ "fieldtype": "Check",
+ "label": "Is Finished Item"
+ },
+ {
+ "fieldname": "job_card_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Job Card Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-06-08 12:57:03.172887",
+ "modified": "2021-02-11 13:47:50.158754",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Detail",
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index fda17e0..2463a21 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -8,26 +8,33 @@
"engine": "InnoDB",
"field_order": [
"item_code",
- "serial_no",
- "batch_no",
"warehouse",
"posting_date",
"posting_time",
+ "column_break_6",
"voucher_type",
"voucher_no",
"voucher_detail_no",
+ "dependant_sle_voucher_detail_no",
+ "recalculate_rate",
+ "section_break_11",
"actual_qty",
+ "qty_after_transaction",
"incoming_rate",
"outgoing_rate",
- "stock_uom",
- "qty_after_transaction",
+ "column_break_17",
"valuation_rate",
"stock_value",
"stock_value_difference",
"stock_queue",
- "project",
+ "section_break_21",
"company",
+ "stock_uom",
+ "project",
+ "batch_no",
+ "column_break_26",
"fiscal_year",
+ "serial_no",
"is_cancelled",
"to_rename"
],
@@ -50,7 +57,6 @@
{
"fieldname": "serial_no",
"fieldtype": "Long Text",
- "in_list_view": 1,
"label": "Serial No",
"print_width": "100px",
"read_only": 1,
@@ -59,7 +65,6 @@
{
"fieldname": "batch_no",
"fieldtype": "Data",
- "in_list_view": 1,
"label": "Batch No",
"oldfieldname": "batch_no",
"oldfieldtype": "Data",
@@ -119,6 +124,7 @@
"fieldname": "voucher_no",
"fieldtype": "Dynamic Link",
"in_filter": 1,
+ "in_list_view": 1,
"in_standard_filter": 1,
"label": "Voucher No",
"oldfieldname": "voucher_no",
@@ -142,6 +148,7 @@
"fieldname": "actual_qty",
"fieldtype": "Float",
"in_filter": 1,
+ "in_list_view": 1,
"label": "Actual Quantity",
"oldfieldname": "actual_qty",
"oldfieldtype": "Currency",
@@ -152,6 +159,7 @@
{
"fieldname": "incoming_rate",
"fieldtype": "Currency",
+ "in_list_view": 1,
"label": "Incoming Rate",
"oldfieldname": "incoming_rate",
"oldfieldtype": "Currency",
@@ -217,13 +225,11 @@
{
"fieldname": "stock_queue",
"fieldtype": "Text",
- "hidden": 1,
"label": "Stock Queue (FIFO)",
"oldfieldname": "fcfs_stack",
"oldfieldtype": "Text",
"print_hide": 1,
- "read_only": 1,
- "report_hide": 1
+ "read_only": 1
},
{
"fieldname": "project",
@@ -269,14 +275,48 @@
"hidden": 1,
"label": "To Rename",
"search_index": 1
+ },
+ {
+ "fieldname": "dependant_sle_voucher_detail_no",
+ "fieldtype": "Data",
+ "label": "Dependant SLE Voucher Detail No"
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_21",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_26",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "recalculate_rate",
+ "fieldtype": "Check",
+ "label": "Recalculate Incoming/Outgoing Rate",
+ "no_copy": 1,
+ "read_only": 1
}
],
"hide_toolbar": 1,
"icon": "fa fa-list",
"idx": 1,
"in_create": 1,
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-04-23 05:57:03.985520",
+ "modified": "2020-09-07 11:10:35.318872",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Ledger Entry",
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 101c6e0..b0e7440 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -5,13 +5,15 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import flt, getdate, add_days, formatdate
+from frappe.utils import flt, getdate, add_days, formatdate, get_datetime, date_diff
from frappe.model.document import Document
from datetime import date
from erpnext.controllers.item_variant import ItemTemplateCannotHaveStock
from erpnext.accounts.utils import get_fiscal_year
+from frappe.core.doctype.role.role import get_users
class StockFreezeError(frappe.ValidationError): pass
+class BackDatedStockTransaction(frappe.ValidationError): pass
exclude_from_linked_with = True
@@ -25,14 +27,17 @@
def validate(self):
self.flags.ignore_submit_comment = True
- from erpnext.stock.utils import validate_warehouse_company
+ from erpnext.stock.utils import validate_warehouse_company, validate_disabled_warehouse
self.validate_mandatory()
self.validate_item()
self.validate_batch()
+ validate_disabled_warehouse(self.warehouse)
validate_warehouse_company(self.warehouse, self.company)
self.scrub_posting_time()
self.validate_and_set_fiscal_year()
self.block_transactions_against_group_warehouse()
+ self.validate_with_last_transaction_posting_time()
+
def on_submit(self):
self.check_stock_frozen_date()
@@ -46,7 +51,7 @@
def calculate_batch_qty(self):
if self.batch_no:
batch_qty = frappe.db.get_value("Stock Ledger Entry",
- {"docstatus": 1, "batch_no": self.batch_no},
+ {"docstatus": 1, "batch_no": self.batch_no, "is_cancelled": 0},
"sum(actual_qty)") or 0
frappe.db.set_value("Batch", self.batch_no, "batch_qty", batch_qty)
@@ -86,14 +91,14 @@
# check if batch number is required
if self.voucher_type != 'Stock Reconciliation':
- if item_det.has_batch_no ==1:
+ if item_det.has_batch_no == 1:
batch_item = self.item_code if self.item_code == item_det.item_name else self.item_code + ":" + item_det.item_name
if not self.batch_no:
frappe.throw(_("Batch number is mandatory for Item {0}").format(batch_item))
elif not frappe.db.get_value("Batch",{"item": self.item_code, "name": self.batch_no}):
frappe.throw(_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, batch_item))
- elif item_det.has_batch_no ==0 and self.batch_no:
+ elif item_det.has_batch_no == 0 and self.batch_no and self.is_cancelled == 0:
frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
if item_det.has_variants:
@@ -139,6 +144,30 @@
from erpnext.stock.utils import is_group_warehouse
is_group_warehouse(self.warehouse)
+ def validate_with_last_transaction_posting_time(self):
+ authorized_role = frappe.db.get_single_value("Stock Settings", "role_allowed_to_create_edit_back_dated_transactions")
+ if authorized_role:
+ authorized_users = get_users(authorized_role)
+ if authorized_users and frappe.session.user not in authorized_users:
+ last_transaction_time = frappe.db.sql("""
+ select MAX(timestamp(posting_date, posting_time)) as posting_time
+ from `tabStock Ledger Entry`
+ where docstatus = 1 and item_code = %s
+ and warehouse = %s""", (self.item_code, self.warehouse))[0][0]
+
+ cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
+
+ if last_transaction_time and get_datetime(cur_doc_posting_datetime) < get_datetime(last_transaction_time):
+ msg = _("Last Stock Transaction for item {0} under warehouse {1} was on {2}.").format(frappe.bold(self.item_code),
+ frappe.bold(self.warehouse), frappe.bold(last_transaction_time))
+
+ msg += "<br><br>" + _("You are not authorized to make/edit Stock Transactions for Item {0} under warehouse {1} before this time.").format(
+ frappe.bold(self.item_code), frappe.bold(self.warehouse))
+
+ msg += "<br><br>" + _("Please contact any of the following users to {} this transaction.")
+ msg += "<br>" + "<br>".join(authorized_users)
+ frappe.throw(msg, BackDatedStockTransaction, title=_("Backdated Stock Entry"))
+
def on_doctype_update():
if not frappe.db.has_index('tabStock Ledger Entry', 'posting_sort_index'):
frappe.db.commit()
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index 04dae83..7ebd4e6 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -5,8 +5,399 @@
import frappe
import unittest
-
-# test_records = frappe.get_test_records('Stock Ledger Entry')
+from frappe.utils import today, add_days
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
+ import create_stock_reconciliation
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.stock_ledger import get_previous_sle
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import create_landed_cost_voucher
+from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import BackDatedStockTransaction
class TestStockLedgerEntry(unittest.TestCase):
- pass
+ def setUp(self):
+ items = create_items()
+
+ # delete SLE and BINs for all items
+ frappe.db.sql("delete from `tabStock Ledger Entry` where item_code in (%s)" % (', '.join(['%s']*len(items))), items)
+ frappe.db.sql("delete from `tabBin` where item_code in (%s)" % (', '.join(['%s']*len(items))), items)
+
+ def test_item_cost_reposting(self):
+ company = "_Test Company"
+
+ # _Test Item for Reposting at Stores warehouse on 10-04-2020: Qty = 50, Rate = 100
+ create_stock_reconciliation(
+ item_code="_Test Item for Reposting",
+ warehouse="Stores - _TC",
+ qty=50,
+ rate=100,
+ company=company,
+ expense_account = "Stock Adjustment - _TC",
+ posting_date='2020-04-10',
+ posting_time='14:00'
+ )
+
+ # _Test Item for Reposting at FG warehouse on 20-04-2020: Qty = 10, Rate = 200
+ create_stock_reconciliation(
+ item_code="_Test Item for Reposting",
+ warehouse="Finished Goods - _TC",
+ qty=10,
+ rate=200,
+ company=company,
+ expense_account = "Stock Adjustment - _TC",
+ posting_date='2020-04-20',
+ posting_time='14:00'
+ )
+
+ # _Test Item for Reposting transferred from Stores to FG warehouse on 30-04-2020
+ make_stock_entry(
+ item_code="_Test Item for Reposting",
+ source="Stores - _TC",
+ target="Finished Goods - _TC",
+ company=company,
+ qty=10,
+ expense_account="Stock Adjustment - _TC",
+ posting_date='2020-04-30',
+ posting_time='14:00'
+ )
+ target_wh_sle = get_previous_sle({
+ "item_code": "_Test Item for Reposting",
+ "warehouse": "Finished Goods - _TC",
+ "posting_date": '2020-04-30',
+ "posting_time": '14:00'
+ })
+
+ self.assertEqual(target_wh_sle.get("valuation_rate"), 150)
+
+ # Repack entry on 5-5-2020
+ repack = create_repack_entry(company=company, posting_date='2020-05-05', posting_time='14:00')
+
+ finished_item_sle = get_previous_sle({
+ "item_code": "_Test Finished Item for Reposting",
+ "warehouse": "Finished Goods - _TC",
+ "posting_date": '2020-05-05',
+ "posting_time": '14:00'
+ })
+ self.assertEqual(finished_item_sle.get("incoming_rate"), 540)
+ self.assertEqual(finished_item_sle.get("valuation_rate"), 540)
+
+ # Reconciliation for _Test Item for Reposting at Stores on 12-04-2020: Qty = 50, Rate = 150
+ create_stock_reconciliation(
+ item_code="_Test Item for Reposting",
+ warehouse="Stores - _TC",
+ qty=50,
+ rate=150,
+ company=company,
+ expense_account = "Stock Adjustment - _TC",
+ posting_date='2020-04-12',
+ posting_time='14:00'
+ )
+
+
+ # Check valuation rate of finished goods warehouse after back-dated entry at Stores
+ target_wh_sle = get_previous_sle({
+ "item_code": "_Test Item for Reposting",
+ "warehouse": "Finished Goods - _TC",
+ "posting_date": '2020-04-30',
+ "posting_time": '14:00'
+ })
+ self.assertEqual(target_wh_sle.get("incoming_rate"), 150)
+ self.assertEqual(target_wh_sle.get("valuation_rate"), 175)
+
+ # Check valuation rate of repacked item after back-dated entry at Stores
+ finished_item_sle = get_previous_sle({
+ "item_code": "_Test Finished Item for Reposting",
+ "warehouse": "Finished Goods - _TC",
+ "posting_date": '2020-05-05',
+ "posting_time": '14:00'
+ })
+ self.assertEqual(finished_item_sle.get("incoming_rate"), 790)
+ self.assertEqual(finished_item_sle.get("valuation_rate"), 790)
+
+ # Check updated rate in Repack entry
+ repack.reload()
+ self.assertEqual(repack.items[0].get("basic_rate"), 150)
+ self.assertEqual(repack.items[1].get("basic_rate"), 750)
+
+ def test_purchase_return_valuation_reposting(self):
+ pr = make_purchase_receipt(company="_Test Company", posting_date='2020-04-10',
+ warehouse="Stores - _TC", item_code="_Test Item for Reposting", qty=5, rate=100)
+
+ return_pr = make_purchase_receipt(company="_Test Company", posting_date='2020-04-15',
+ warehouse="Stores - _TC", item_code="_Test Item for Reposting", is_return=1, return_against=pr.name, qty=-2)
+
+ # check sle
+ outgoing_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
+ "voucher_no": return_pr.name}, ["outgoing_rate", "stock_value_difference"])
+
+ self.assertEqual(outgoing_rate, 100)
+ self.assertEqual(stock_value_difference, -200)
+
+ create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
+
+ outgoing_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
+ "voucher_no": return_pr.name}, ["outgoing_rate", "stock_value_difference"])
+
+ self.assertEqual(outgoing_rate, 110)
+ self.assertEqual(stock_value_difference, -220)
+
+ def test_sales_return_valuation_reposting(self):
+ company = "_Test Company"
+ item_code="_Test Item for Reposting"
+
+ # Purchase Return: Qty = 5, Rate = 100
+ pr = make_purchase_receipt(company=company, posting_date='2020-04-10',
+ warehouse="Stores - _TC", item_code=item_code, qty=5, rate=100)
+
+ #Delivery Note: Qty = 5, Rate = 150
+ dn = create_delivery_note(item_code=item_code, qty=5, rate=150, warehouse="Stores - _TC",
+ company=company, expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC")
+
+ # check outgoing_rate for DN
+ outgoing_rate = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ "voucher_no": dn.name}, "stock_value_difference") / 5)
+
+ self.assertEqual(dn.items[0].incoming_rate, 100)
+ self.assertEqual(outgoing_rate, 100)
+
+ # Return Entry: Qty = -2, Rate = 150
+ return_dn = create_delivery_note(is_return=1, return_against=dn.name, item_code=item_code, qty=-2, rate=150,
+ company=company, warehouse="Stores - _TC", expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC")
+
+ # check incoming rate for Return entry
+ incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": return_dn.name},
+ ["incoming_rate", "stock_value_difference"])
+
+ self.assertEqual(return_dn.items[0].incoming_rate, 100)
+ self.assertEqual(incoming_rate, 100)
+ self.assertEqual(stock_value_difference, 200)
+
+ #-------------------------------
+
+ # Landed Cost Voucher to update the rate of incoming Purchase Return: Additional cost = 50
+ lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
+
+ # check outgoing_rate for DN after reposting
+ outgoing_rate = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ "voucher_no": dn.name}, "stock_value_difference") / 5)
+ self.assertEqual(outgoing_rate, 110)
+
+ dn.reload()
+ self.assertEqual(dn.items[0].incoming_rate, 110)
+
+ # check incoming rate for Return entry after reposting
+ incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": return_dn.name},
+ ["incoming_rate", "stock_value_difference"])
+
+ self.assertEqual(incoming_rate, 110)
+ self.assertEqual(stock_value_difference, 220)
+
+ return_dn.reload()
+ self.assertEqual(return_dn.items[0].incoming_rate, 110)
+
+ # Cleanup data
+ return_dn.cancel()
+ dn.cancel()
+ lcv.cancel()
+ pr.cancel()
+
+ def test_reposting_of_sales_return_for_packed_item(self):
+ company = "_Test Company"
+ packed_item_code="_Test Item for Reposting"
+ bundled_item = "_Test Bundled Item for Reposting"
+ create_product_bundle_item(bundled_item, [[packed_item_code, 4]])
+
+ # Purchase Return: Qty = 50, Rate = 100
+ pr = make_purchase_receipt(company=company, posting_date='2020-04-10',
+ warehouse="Stores - _TC", item_code=packed_item_code, qty=50, rate=100)
+
+ #Delivery Note: Qty = 5, Rate = 150
+ dn = create_delivery_note(item_code=bundled_item, qty=5, rate=150, warehouse="Stores - _TC",
+ company=company, expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC")
+
+ # check outgoing_rate for DN
+ outgoing_rate = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ "voucher_no": dn.name}, "stock_value_difference") / 20)
+
+ self.assertEqual(dn.packed_items[0].incoming_rate, 100)
+ self.assertEqual(outgoing_rate, 100)
+
+ # Return Entry: Qty = -2, Rate = 150
+ return_dn = create_delivery_note(is_return=1, return_against=dn.name, item_code=bundled_item, qty=-2, rate=150,
+ company=company, warehouse="Stores - _TC", expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC")
+
+ # check incoming rate for Return entry
+ incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": return_dn.name},
+ ["incoming_rate", "stock_value_difference"])
+
+ self.assertEqual(return_dn.packed_items[0].incoming_rate, 100)
+ self.assertEqual(incoming_rate, 100)
+ self.assertEqual(stock_value_difference, 800)
+
+ #-------------------------------
+
+ # Landed Cost Voucher to update the rate of incoming Purchase Return: Additional cost = 50
+ lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
+
+ # check outgoing_rate for DN after reposting
+ outgoing_rate = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ "voucher_no": dn.name}, "stock_value_difference") / 20)
+ self.assertEqual(outgoing_rate, 101)
+
+ dn.reload()
+ self.assertEqual(dn.packed_items[0].incoming_rate, 101)
+
+ # check incoming rate for Return entry after reposting
+ incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": return_dn.name},
+ ["incoming_rate", "stock_value_difference"])
+
+ self.assertEqual(incoming_rate, 101)
+ self.assertEqual(stock_value_difference, 808)
+
+ return_dn.reload()
+ self.assertEqual(return_dn.packed_items[0].incoming_rate, 101)
+
+ # Cleanup data
+ return_dn.cancel()
+ dn.cancel()
+ lcv.cancel()
+ pr.cancel()
+
+ def test_sub_contracted_item_costing(self):
+ from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
+ company = "_Test Company"
+ rm_item_code="_Test Item for Reposting"
+ subcontracted_item = "_Test Subcontracted Item for Reposting"
+
+ frappe.db.set_value("Buying Settings", None, "backflush_raw_materials_of_subcontract_based_on", "BOM")
+ make_bom(item = subcontracted_item, raw_materials =[rm_item_code], currency="INR")
+
+ # Purchase raw materials on supplier warehouse: Qty = 50, Rate = 100
+ pr = make_purchase_receipt(company=company, posting_date='2020-04-10',
+ warehouse="Stores - _TC", item_code=rm_item_code, qty=10, rate=100)
+
+ # Purchase Receipt for subcontracted item
+ pr1 = make_purchase_receipt(company=company, posting_date='2020-04-20',
+ warehouse="Finished Goods - _TC", supplier_warehouse="Stores - _TC",
+ item_code=subcontracted_item, qty=10, rate=20, is_subcontracted="Yes")
+
+ self.assertEqual(pr1.items[0].valuation_rate, 120)
+
+ # Update raw material's valuation via LCV, Additional cost = 50
+ lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
+
+ pr1.reload()
+ self.assertEqual(pr1.items[0].valuation_rate, 125)
+
+ # check outgoing_rate for DN after reposting
+ incoming_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
+ "voucher_no": pr1.name, "item_code": subcontracted_item}, "incoming_rate")
+ self.assertEqual(incoming_rate, 125)
+
+ # cleanup data
+ pr1.cancel()
+ lcv.cancel()
+ pr.cancel()
+
+ def test_back_dated_entry_not_allowed(self):
+ # Back dated stock transactions are only allowed to stock managers
+ frappe.db.set_value("Stock Settings", None,
+ "role_allowed_to_create_edit_back_dated_transactions", "Stock Manager")
+
+ # Set User with Stock User role but not Stock Manager
+ try:
+ frappe.set_user("test@example.com")
+ user = frappe.get_doc("User", "test@example.com")
+ user.add_roles("Stock User")
+ user.remove_roles("Stock Manager")
+
+ stock_entry_on_today = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
+ back_dated_se_1 = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100,
+ posting_date=add_days(today(), -1), do_not_submit=True)
+
+ # Block back-dated entry
+ self.assertRaises(BackDatedStockTransaction, back_dated_se_1.submit)
+
+ user.add_roles("Stock Manager")
+
+ # Back dated entry allowed to Stock Manager
+ back_dated_se_2 = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100,
+ posting_date=add_days(today(), -1))
+
+ back_dated_se_2.cancel()
+ stock_entry_on_today.cancel()
+
+ finally:
+ frappe.db.set_value("Stock Settings", None, "role_allowed_to_create_edit_back_dated_transactions", None)
+ frappe.set_user("Administrator")
+
+
+def create_repack_entry(**args):
+ args = frappe._dict(args)
+ repack = frappe.new_doc("Stock Entry")
+ repack.stock_entry_type = "Repack"
+ repack.company = args.company or "_Test Company"
+ repack.posting_date = args.posting_date
+ repack.set_posting_time = 1
+ repack.append("items", {
+ "item_code": "_Test Item for Reposting",
+ "s_warehouse": "Stores - _TC",
+ "qty": 5,
+ "conversion_factor": 1,
+ "expense_account": "Stock Adjustment - _TC",
+ "cost_center": "Main - _TC"
+ })
+
+ repack.append("items", {
+ "item_code": "_Test Finished Item for Reposting",
+ "t_warehouse": "Finished Goods - _TC",
+ "qty": 1,
+ "conversion_factor": 1,
+ "expense_account": "Stock Adjustment - _TC",
+ "cost_center": "Main - _TC"
+ })
+
+ repack.append("additional_costs", {
+ "expense_account": "Freight and Forwarding Charges - _TC",
+ "description": "transport cost",
+ "amount": 40
+ })
+
+ repack.save()
+ repack.submit()
+
+ return repack
+
+def create_product_bundle_item(new_item_code, packed_items):
+ if not frappe.db.exists("Product Bundle", new_item_code):
+ item = frappe.new_doc("Product Bundle")
+ item.new_item_code = new_item_code
+
+ for d in packed_items:
+ item.append("items", {
+ "item_code": d[0],
+ "qty": d[1]
+ })
+
+ item.save()
+
+def create_items():
+ items = ["_Test Item for Reposting", "_Test Finished Item for Reposting",
+ "_Test Subcontracted Item for Reposting", "_Test Bundled Item for Reposting"]
+ for d in items:
+ properties = {"valuation_method": "FIFO"}
+ if d == "_Test Bundled Item for Reposting":
+ properties.update({"is_stock_item": 0})
+ elif d == "_Test Subcontracted Item for Reposting":
+ properties.update({"is_sub_contracted_item": 1})
+
+ make_item(d, properties=properties)
+
+ return items
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index ecee97c..ac4ed5e 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -2,6 +2,7 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.stock");
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Stock Reconciliation", {
onload: function(frm) {
@@ -26,6 +27,12 @@
if (!frm.doc.expense_account) {
frm.trigger("set_expense_account");
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
refresh: function(frm) {
@@ -109,6 +116,10 @@
frappe.model.set_value(cdt, cdn, "current_amount", r.message.rate * r.message.qty);
frappe.model.set_value(cdt, cdn, "amount", r.message.rate * r.message.qty);
frappe.model.set_value(cdt, cdn, "current_serial_no", r.message.serial_nos);
+
+ if (frm.doc.purpose == "Stock Reconciliation") {
+ frappe.model.set_value(cdt, cdn, "serial_no", r.message.serial_nos);
+ }
}
});
}
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index b81f8a0..b452e96 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -29,7 +29,10 @@
self.remove_items_with_no_change()
self.validate_data()
self.validate_expense_account()
+ self.validate_customer_provided_item()
+ self.set_zero_value_for_customer_provided_items()
self.set_total_qty_and_amount()
+ self.validate_putaway_capacity()
if self._action=="submit":
self.make_batches('warehouse')
@@ -37,14 +40,16 @@
def on_submit(self):
self.update_stock_ledger()
self.make_gl_entries()
+ self.repost_future_sle_and_gle()
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
update_serial_nos_after_submit(self, "items")
def on_cancel(self):
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+ self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
self.make_sle_on_cancel()
self.make_gl_entries_on_cancel()
+ self.repost_future_sle_and_gle()
def remove_items_with_no_change(self):
"""Remove items if qty or rate is not changed"""
@@ -67,6 +72,8 @@
if item_dict.get("serial_nos"):
item.current_serial_no = item_dict.get("serial_nos")
+ if self.purpose == "Stock Reconciliation":
+ item.serial_no = item.current_serial_no
item.current_qty = item_dict.get("qty")
item.current_valuation_rate = item_dict.get("rate")
@@ -212,7 +219,7 @@
if row.valuation_rate in ("", None):
row.valuation_rate = previous_sle.get("valuation_rate", 0)
- if row.qty and not row.valuation_rate:
+ if row.qty and not row.valuation_rate and not row.allow_zero_valuation_rate:
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
@@ -431,6 +438,20 @@
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
+ def set_zero_value_for_customer_provided_items(self):
+ changed_any_values = False
+
+ for d in self.get('items'):
+ is_customer_item = frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item')
+ if is_customer_item and d.valuation_rate:
+ d.valuation_rate = 0.0
+ changed_any_values = True
+
+ if changed_any_values:
+ msgprint(_("Valuation rate for customer provided items has been set to zero."),
+ title=_("Note"), indicator="blue")
+
+
def set_total_qty_and_amount(self):
for d in self.get("items"):
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
@@ -526,4 +547,4 @@
account = frappe.db.get_value('Account', {'is_group': 0,
'company': company, 'account_type': 'Temporary'}, 'name')
- return account
\ No newline at end of file
+ return account
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index 1571416..6690c6a 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -8,12 +8,11 @@
import frappe, unittest
from frappe.utils import flt, nowdate, nowtime
from erpnext.accounts.utils import get_stock_and_account_balance
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.doctype.item.test_item import create_item
-from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_available_serial_nos, get_stock_value_on
+from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class TestStockReconciliation(unittest.TestCase):
@@ -29,16 +28,17 @@
self._test_reco_sle_gle("Moving Average")
def _test_reco_sle_gle(self, valuation_method):
- insert_existing_sle(warehouse='Stores - TCP1')
+ se1, se2, se3 = insert_existing_sle(warehouse='Stores - TCP1')
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
# [[qty, valuation_rate, posting_date,
# posting_time, expected_stock_value, bin_qty, bin_valuation]]
+
input_data = [
- [50, 1000],
- [25, 900],
- ["", 1000],
- [20, ""],
- [0, ""]
+ [50, 1000, "2012-12-26", "12:00"],
+ [25, 900, "2012-12-26", "12:00"],
+ ["", 1000, "2012-12-20", "12:05"],
+ [20, "", "2012-12-26", "12:05"],
+ [0, "", "2012-12-31", "12:10"]
]
for d in input_data:
@@ -47,13 +47,13 @@
last_sle = get_previous_sle({
"item_code": "_Test Item",
"warehouse": "Stores - TCP1",
- "posting_date": nowdate(),
- "posting_time": nowtime()
+ "posting_date": d[2],
+ "posting_time": d[3]
})
# submit stock reconciliation
stock_reco = create_stock_reconciliation(qty=d[0], rate=d[1],
- posting_date=nowdate(), posting_time=nowtime(), warehouse="Stores - TCP1",
+ posting_date=d[2], posting_time=d[3], warehouse="Stores - TCP1",
company=company, expense_account = "Stock Adjustment - TCP1")
# check stock value
@@ -81,10 +81,15 @@
stock_reco.cancel()
+ se3.cancel()
+ se2.cancel()
+ se1.cancel()
+
def test_get_items(self):
- create_warehouse("_Test Warehouse Group 1", {"is_group": 1})
+ create_warehouse("_Test Warehouse Group 1",
+ {"is_group": 1, "company": "_Test Company", "parent_warehouse": "All Warehouses - _TC"})
create_warehouse("_Test Warehouse Ledger 1",
- {"is_group": 0, "parent_warehouse": "_Test Warehouse Group 1 - _TC"})
+ {"is_group": 0, "parent_warehouse": "_Test Warehouse Group 1 - _TC", "company": "_Test Company"})
create_item("_Test Stock Reco Item", is_stock_item=1, valuation_rate=100,
warehouse="_Test Warehouse Ledger 1 - _TC", opening_stock=100)
@@ -95,8 +100,6 @@
[items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]])
def test_stock_reco_for_serialized_item(self):
- set_perpetual_inventory()
-
to_delete_records = []
to_delete_serial_nos = []
@@ -124,7 +127,7 @@
to_delete_records.append(sr.name)
sr = create_stock_reconciliation(item_code=serial_item_code,
- warehouse = serial_warehouse, qty=5, rate=300, serial_no = '\n'.join(serial_nos))
+ warehouse = serial_warehouse, qty=5, rate=300)
serial_nos1 = get_serial_nos(sr.items[0].serial_no)
self.assertEqual(len(serial_nos1), 5)
@@ -148,8 +151,6 @@
stock_doc.cancel()
def test_stock_reco_for_batch_item(self):
- set_perpetual_inventory()
-
to_delete_records = []
to_delete_serial_nos = []
@@ -192,19 +193,31 @@
stock_doc = frappe.get_doc("Stock Reconciliation", d)
stock_doc.cancel()
+ def test_customer_provided_items(self):
+ item_code = 'Stock-Reco-customer-Item-100'
+ create_item(item_code, is_customer_provided_item = 1,
+ customer = '_Test Customer', is_purchase_item = 0)
+
+ sr = create_stock_reconciliation(item_code = item_code, qty = 10, rate = 420)
+
+ self.assertEqual(sr.get("items")[0].allow_zero_valuation_rate, 1)
+ self.assertEqual(sr.get("items")[0].valuation_rate, 0)
+ self.assertEqual(sr.get("items")[0].amount, 0)
def insert_existing_sle(warehouse):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
- make_stock_entry(posting_date=nowdate(), posting_time=nowtime(), item_code="_Test Item",
+ se1 = make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
target=warehouse, qty=10, basic_rate=700)
- make_stock_entry(posting_date=nowdate(), posting_time=nowtime(), item_code="_Test Item",
+ se2 = make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
source=warehouse, qty=15)
- make_stock_entry(posting_date=nowdate(), posting_time=nowtime(), item_code="_Test Item",
+ se3 = make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
target=warehouse, qty=15, basic_rate=1200)
+ return se1, se2, se3
+
def create_batch_or_serial_no_items():
create_warehouse("_Test Warehouse for Stock Reco1",
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
@@ -256,6 +269,10 @@
return sr
def set_valuation_method(item_code, valuation_method):
+ existing_valuation_method = get_valuation_method(item_code)
+ if valuation_method == existing_valuation_method:
+ return
+
frappe.db.set_value("Item", item_code, "valuation_method", valuation_method)
for warehouse in frappe.get_all("Warehouse", filters={"company": "_Test Company"}, fields=["name", "is_group"]):
diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
index e53db07..85c7ebe 100644
--- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
+++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
@@ -13,6 +13,7 @@
"qty",
"valuation_rate",
"amount",
+ "allow_zero_valuation_rate",
"serial_no_and_batch_section",
"serial_no",
"column_break_11",
@@ -166,10 +167,19 @@
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_zero_valuation_rate",
+ "fieldtype": "Check",
+ "label": "Allow Zero Valuation Rate",
+ "print_hide": 1,
+ "read_only": 1
}
],
"istable": 1,
- "modified": "2019-06-14 17:10:53.188305",
+ "links": [],
+ "modified": "2021-03-23 11:09:44.407157",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Reconciliation Item",
@@ -179,4 +189,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 9c5d3d8..84af57b 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -16,6 +16,7 @@
"action_if_quality_inspection_is_not_submitted",
"show_barcode_field",
"clean_description_html",
+ "disable_serial_no_and_batch_selector",
"section_break_7",
"auto_insert_price_list_rate_if_missing",
"allow_negative_stock",
@@ -28,7 +29,9 @@
"inter_warehouse_transfer_settings_section",
"allow_from_dn",
"allow_from_pr",
- "freeze_stock_entries",
+ "control_historical_stock_transactions_section",
+ "role_allowed_to_create_edit_back_dated_transactions",
+ "column_break_26",
"stock_frozen_upto",
"stock_frozen_upto_days",
"stock_auth_role",
@@ -82,7 +85,7 @@
"options": "FIFO\nMoving Average"
},
{
- "description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.",
+ "description": "The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.",
"fieldname": "over_delivery_receipt_allowance",
"fieldtype": "Float",
"label": "Over Delivery/Receipt Allowance (%)"
@@ -91,7 +94,7 @@
"default": "Stop",
"fieldname": "action_if_quality_inspection_is_not_submitted",
"fieldtype": "Select",
- "label": "Action if Quality inspection is not submitted",
+ "label": "Action If Quality Inspection Is Not Submitted",
"options": "Stop\nWarn"
},
{
@@ -114,7 +117,7 @@
"default": "0",
"fieldname": "auto_insert_price_list_rate_if_missing",
"fieldtype": "Check",
- "label": "Auto insert Price List rate if missing"
+ "label": "Auto Insert Price List Rate If Missing"
},
{
"default": "0",
@@ -130,13 +133,13 @@
"default": "1",
"fieldname": "automatically_set_serial_nos_based_on_fifo",
"fieldtype": "Check",
- "label": "Automatically Set Serial Nos based on FIFO"
+ "label": "Automatically Set Serial Nos Based on FIFO"
},
{
"default": "1",
"fieldname": "set_qty_in_transactions_based_on_serial_no_input",
"fieldtype": "Check",
- "label": "Set Qty in Transactions based on Serial No Input"
+ "label": "Set Qty in Transactions Based on Serial No Input"
},
{
"fieldname": "auto_material_request",
@@ -147,33 +150,32 @@
"default": "0",
"fieldname": "auto_indent",
"fieldtype": "Check",
- "label": "Raise Material Request when stock reaches re-order level"
+ "label": "Raise Material Request When Stock Reaches Re-order Level"
},
{
"default": "0",
"fieldname": "reorder_email_notify",
"fieldtype": "Check",
- "label": "Notify by Email on creation of automatic Material Request"
+ "label": "Notify by Email on Creation of Automatic Material Request"
},
{
- "fieldname": "freeze_stock_entries",
- "fieldtype": "Section Break",
- "label": "Freeze Stock Entries"
- },
- {
+ "description": "No stock transactions can be created or modified before this date.",
"fieldname": "stock_frozen_upto",
"fieldtype": "Date",
"label": "Stock Frozen Upto"
},
{
+ "description": "Stock transactions that are older than the mentioned days cannot be modified.",
"fieldname": "stock_frozen_upto_days",
"fieldtype": "Int",
- "label": "Freeze Stocks Older Than [Days]"
+ "label": "Freeze Stocks Older Than (Days)"
},
{
+ "depends_on": "eval:(doc.stock_frozen_upto || doc.stock_frozen_upto_days)",
+ "description": "The users with this Role are allowed to create/modify a stock transaction, even though the transaction is frozen.",
"fieldname": "stock_auth_role",
"fieldtype": "Link",
- "label": "Role Allowed to edit frozen stock",
+ "label": "Role Allowed to Edit Frozen Stock",
"options": "Role"
},
{
@@ -203,20 +205,43 @@
"default": "0",
"fieldname": "allow_from_dn",
"fieldtype": "Check",
- "label": "Allow Material Transfer From Delivery Note and Sales Invoice"
+ "label": "Allow Material Transfer from Delivery Note to Sales Invoice"
},
{
"default": "0",
"fieldname": "allow_from_pr",
"fieldtype": "Check",
- "label": "Allow Material Transfer From Purchase Receipt and Purchase Invoice"
+ "label": "Allow Material Transfer from Purchase Receipt to Purchase Invoice"
+ },
+ {
+ "description": "If mentioned, the system will allow only the users with this Role to create or modify any stock transaction earlier than the latest stock transaction for a specific item and warehouse. If set as blank, it allows all users to create/edit back-dated transactions.",
+ "fieldname": "role_allowed_to_create_edit_back_dated_transactions",
+ "fieldtype": "Link",
+ "label": "Role Allowed to Create/Edit Back-dated Transactions",
+ "options": "Role"
+ },
+ {
+ "fieldname": "column_break_26",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "control_historical_stock_transactions_section",
+ "fieldtype": "Section Break",
+ "label": "Control Historical Stock Transactions"
+ },
+ {
+ "default": "0",
+ "fieldname": "disable_serial_no_and_batch_selector",
+ "fieldtype": "Check",
+ "label": "Disable Serial No And Batch Selector"
}
],
"icon": "icon-cog",
"idx": 1,
+ "index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-06-20 11:39:15.344112",
+ "modified": "2021-01-18 13:15:38.352796",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",
@@ -234,5 +259,6 @@
],
"quick_entry": 1,
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py
index 4c7828b..3b9608b 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.py
@@ -55,7 +55,7 @@
""")
if sle:
- frappe.throw(_("Can't change valuation method, as there are transactions against some items which does not have it's own valuation method"))
+ frappe.throw(_("Can't change the valuation method, as there are transactions against some items which do not have its own valuation method"))
def validate_clean_description_html(self):
if int(self.clean_description_html or 0) \
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py
index 3101e8a..95478f6 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.py
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.py
@@ -10,13 +10,10 @@
import erpnext
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
-from erpnext import set_perpetual_inventory
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
-
test_records = frappe.get_test_records('Warehouse')
-
class TestWarehouse(unittest.TestCase):
def setUp(self):
if not frappe.get_value('Item', '_Test Item'):
@@ -37,63 +34,63 @@
self.assertEqual(child_warehouse.is_group, 0)
def test_warehouse_renaming(self):
- set_perpetual_inventory(1)
- create_warehouse("Test Warehouse for Renaming 1")
- account = get_inventory_account("_Test Company", "Test Warehouse for Renaming 1 - _TC")
+ create_warehouse("Test Warehouse for Renaming 1", company="_Test Company with perpetual inventory")
+ account = get_inventory_account("_Test Company with perpetual inventory", "Test Warehouse for Renaming 1 - TCP1")
self.assertTrue(frappe.db.get_value("Warehouse", filters={"account": account}))
# Rename with abbr
- if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"):
- frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC")
- frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
+ if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - TCP1"):
+ frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - TCP1")
+ frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 1 - TCP1", "Test Warehouse for Renaming 2 - TCP1")
self.assertTrue(frappe.db.get_value("Warehouse",
- filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
+ filters={"account": "Test Warehouse for Renaming 1 - TCP1"}))
# Rename without abbr
- if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"):
- frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC")
+ if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - TCP1"):
+ frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - TCP1")
- frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
+ frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 2 - TCP1", "Test Warehouse for Renaming 3")
self.assertTrue(frappe.db.get_value("Warehouse",
- filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
+ filters={"account": "Test Warehouse for Renaming 1 - TCP1"}))
# Another rename with multiple dashes
- if frappe.db.exists("Warehouse", "Test - Warehouse - Company - _TC"):
- frappe.delete_doc("Warehouse", "Test - Warehouse - Company - _TC")
- frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company")
+ if frappe.db.exists("Warehouse", "Test - Warehouse - Company - TCP1"):
+ frappe.delete_doc("Warehouse", "Test - Warehouse - Company - TCP1")
+ frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 3 - TCP1", "Test - Warehouse - Company")
def test_warehouse_merging(self):
- set_perpetual_inventory(1)
+ company = "_Test Company with perpetual inventory"
+ create_warehouse("Test Warehouse for Merging 1", company=company,
+ properties={"parent_warehouse": "All Warehouses - TCP1"})
+ create_warehouse("Test Warehouse for Merging 2", company=company,
+ properties={"parent_warehouse": "All Warehouses - TCP1"})
- create_warehouse("Test Warehouse for Merging 1")
- create_warehouse("Test Warehouse for Merging 2")
-
- make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 1 - _TC",
- qty=1, rate=100)
- make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 2 - _TC",
- qty=1, rate=100)
+ make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 1 - TCP1",
+ qty=1, rate=100, company=company)
+ make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 2 - TCP1",
+ qty=1, rate=100, company=company)
existing_bin_qty = (
cint(frappe.db.get_value("Bin",
- {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 1 - _TC"}, "actual_qty"))
+ {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 1 - TCP1"}, "actual_qty"))
+ cint(frappe.db.get_value("Bin",
- {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty"))
+ {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - TCP1"}, "actual_qty"))
)
- frappe.rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC",
- "Test Warehouse for Merging 2 - _TC", merge=True)
+ frappe.rename_doc("Warehouse", "Test Warehouse for Merging 1 - TCP1",
+ "Test Warehouse for Merging 2 - TCP1", merge=True)
- self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - _TC"))
+ self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - TCP1"))
bin_qty = frappe.db.get_value("Bin",
- {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty")
+ {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - TCP1"}, "actual_qty")
self.assertEqual(bin_qty, existing_bin_qty)
self.assertTrue(frappe.db.get_value("Warehouse",
- filters={"account": "Test Warehouse for Merging 2 - _TC"}))
+ filters={"account": "Test Warehouse for Merging 2 - TCP1"}))
def create_warehouse(warehouse_name, properties=None, company=None):
if not company:
diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js
index 1bea00e..1f17250 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.js
+++ b/erpnext/stock/doctype/warehouse/warehouse.js
@@ -3,6 +3,18 @@
frappe.ui.form.on("Warehouse", {
+ onload: function(frm) {
+ frm.set_query("default_in_transit_warehouse", function() {
+ return {
+ filters:{
+ 'warehouse_type' : 'Transit',
+ 'is_group': 0,
+ 'company': frm.doc.company
+ }
+ };
+ });
+ },
+
refresh: function(frm) {
frm.toggle_display('warehouse_name', frm.doc.__islocal);
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json
index 1cc600b..bddb114 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.json
+++ b/erpnext/stock/doctype/warehouse/warehouse.json
@@ -13,6 +13,7 @@
"column_break_3",
"warehouse_type",
"parent_warehouse",
+ "default_in_transit_warehouse",
"is_group",
"column_break_4",
"account",
@@ -230,13 +231,20 @@
{
"fieldname": "column_break_3",
"fieldtype": "Section Break"
+ },
+ {
+ "depends_on": "eval: doc.warehouse_type !== 'Transit';",
+ "fieldname": "default_in_transit_warehouse",
+ "fieldtype": "Link",
+ "label": "Default In-Transit Warehouse",
+ "options": "Warehouse"
}
],
"icon": "fa fa-building",
"idx": 1,
"is_tree": 1,
"links": [],
- "modified": "2020-08-03 18:41:52.442502",
+ "modified": "2021-02-16 17:21:52.380098",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse",
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index cd86be3..6c84f16 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -29,7 +29,6 @@
self.set_onload('account', account)
load_address_and_contact(self)
-
def on_update(self):
self.update_nsm_model()
diff --git a/erpnext/stock/doctype/warehouse/warehouse_tree.js b/erpnext/stock/doctype/warehouse/warehouse_tree.js
index 918d2f1..3665c05 100644
--- a/erpnext/stock/doctype/warehouse/warehouse_tree.js
+++ b/erpnext/stock/doctype/warehouse/warehouse_tree.js
@@ -19,7 +19,7 @@
ignore_fields:["parent_warehouse"],
onrender: function(node) {
if (node.data && node.data.balance!==undefined) {
- $('<span class="balance-area pull-right text-muted small">'
+ $('<span class="balance-area pull-right">'
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+ '</span>').insertBefore(node.$ul);
}
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 1a7c15e..70e4c2c 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -19,7 +19,7 @@
from six import string_types, iteritems
-sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']
+sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice', 'POS Invoice']
purchase_doctypes = ['Material Request', 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
@frappe.whitelist()
@@ -74,7 +74,9 @@
update_party_blanket_order(args, out)
- get_price_list_rate(args, item, out)
+ if not doc or cint(doc.get('is_return')) == 0:
+ # get price list rate only if the invoice is not a credit or debit note
+ get_price_list_rate(args, item, out)
if args.customer and cint(args.is_pos):
out.update(get_pos_profile_item_details(args.company, args))
@@ -312,7 +314,9 @@
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0,
"transaction_date": args.get("transaction_date"),
"against_blanket_order": args.get("against_blanket_order"),
- "bom_no": item.get("default_bom")
+ "bom_no": item.get("default_bom"),
+ "weight_per_unit": args.get("weight_per_unit") or item.get("weight_per_unit"),
+ "weight_uom": args.get("weight_uom") or item.get("weight_uom")
})
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
@@ -367,6 +371,9 @@
if meta.get_field("barcode"):
update_barcode_value(out)
+ if out.get("weight_per_unit"):
+ out['total_weight'] = out.weight_per_unit * out.stock_qty
+
return out
def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
@@ -398,6 +405,11 @@
else:
warehouse = args.get('warehouse')
+ if not warehouse:
+ default_warehouse = frappe.db.get_single_value("Stock Settings", "default_warehouse")
+ if frappe.db.get_value("Warehouse", default_warehouse, "company") == args.company:
+ return default_warehouse
+
return warehouse
def update_barcode_value(out):
@@ -554,23 +566,40 @@
else:
return None
-def get_default_cost_center(args, item, item_group, brand, company=None):
+def get_default_cost_center(args, item=None, item_group=None, brand=None, company=None):
cost_center = None
+
+ if not company and args.get("company"):
+ company = args.get("company")
+
if args.get('project'):
cost_center = frappe.db.get_value("Project", args.get("project"), "cost_center", cache=True)
- if not cost_center:
+ if not cost_center and (item and item_group and brand):
if args.get('customer'):
cost_center = item.get('selling_cost_center') or item_group.get('selling_cost_center') or brand.get('selling_cost_center')
else:
cost_center = item.get('buying_cost_center') or item_group.get('buying_cost_center') or brand.get('buying_cost_center')
- cost_center = cost_center or args.get("cost_center")
+ elif not cost_center and args.get("item_code") and company:
+ for method in ["get_item_defaults", "get_item_group_defaults", "get_brand_defaults"]:
+ path = "erpnext.stock.get_item_details.{0}".format(method)
+ data = frappe.get_attr(path)(args.get("item_code"), company)
+
+ if data and (data.selling_cost_center or data.buying_cost_center):
+ return data.selling_cost_center or data.buying_cost_center
+
+ if not cost_center and args.get("cost_center"):
+ cost_center = args.get("cost_center")
if (company and cost_center
and frappe.get_cached_value("Cost Center", cost_center, "company") != company):
return None
+ if not cost_center and company:
+ cost_center = frappe.get_cached_value("Company",
+ company, "cost_center")
+
return cost_center
def get_default_supplier(args, item, item_group, brand):
@@ -650,6 +679,8 @@
and price_list=%(price_list)s
and ifnull(uom, '') in ('', %(uom)s)"""
+ conditions += "and ifnull(batch_no, '') in ('', %(batch_no)s)"
+
if not ignore_party:
if args.get("customer"):
conditions += " and customer=%(customer)s"
@@ -668,7 +699,7 @@
return frappe.db.sql(""" select name, price_list_rate, uom
from `tabItem Price` {conditions}
- order by valid_from desc, uom desc """.format(conditions=conditions), args)
+ order by valid_from desc, batch_no desc, uom desc """.format(conditions=conditions), args)
def get_price_list_rate_for(args, item_code):
"""
@@ -687,6 +718,7 @@
"uom": args.get('uom'),
"transaction_date": args.get('transaction_date'),
"posting_date": args.get('posting_date'),
+ "batch_no": args.get('batch_no')
}
item_price_data = 0
diff --git a/erpnext/stock/landed_taxes_and_charges_common.js b/erpnext/stock/landed_taxes_and_charges_common.js
new file mode 100644
index 0000000..f3f6196
--- /dev/null
+++ b/erpnext/stock/landed_taxes_and_charges_common.js
@@ -0,0 +1,62 @@
+let document_list = ['Landed Cost Voucher', 'Stock Entry'];
+
+document_list.forEach((doctype) => {
+ frappe.ui.form.on(doctype, {
+ refresh: function(frm) {
+ let tax_field = frm.doc.doctype == 'Landed Cost Voucher' ? 'taxes' : 'additional_costs';
+ frm.set_query("expense_account", tax_field, function() {
+ return {
+ filters: {
+ "account_type": ['in', ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"]],
+ "company": frm.doc.company
+ }
+ };
+ });
+ },
+
+ set_account_currency: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ if (row.expense_account) {
+ frappe.db.get_value('Account', row.expense_account, 'account_currency', function(value) {
+ frappe.model.set_value(cdt, cdn, "account_currency", value.account_currency);
+ frm.events.set_exchange_rate(frm, cdt, cdn);
+ });
+ }
+ },
+
+ set_exchange_rate: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
+
+ if (row.account_currency == company_currency) {
+ row.exchange_rate = 1;
+ frm.set_df_property('taxes', 'hidden', 1, row.name, 'exchange_rate');
+ } else if (!row.exchange_rate || row.exchange_rate == 1) {
+ frm.set_df_property('taxes', 'hidden', 0, row.name, 'exchange_rate');
+ frappe.call({
+ method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
+ args: {
+ posting_date: frm.doc.posting_date,
+ account: row.expense_account,
+ account_currency: row.account_currency,
+ company: frm.doc.company
+ },
+ callback: function(r) {
+ if (r.message) {
+ frappe.model.set_value(cdt, cdn, "exchange_rate", r.message);
+ }
+ }
+ });
+ }
+
+ frm.refresh_field('taxes');
+ },
+
+ set_base_amount: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ frappe.model.set_value(cdt, cdn, "base_amount",
+ flt(flt(row.amount)*row.exchange_rate, precision("base_amount", row)));
+ }
+ });
+});
+
diff --git a/erpnext/stock/module_onboarding/stock/stock.json b/erpnext/stock/module_onboarding/stock/stock.json
index 1d5bf8c..8474648 100644
--- a/erpnext/stock/module_onboarding/stock/stock.json
+++ b/erpnext/stock/module_onboarding/stock/stock.json
@@ -19,7 +19,7 @@
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/stock",
"idx": 0,
"is_complete": 0,
- "modified": "2020-07-08 14:22:07.951891",
+ "modified": "2020-10-14 14:54:42.741971",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock",
diff --git a/erpnext/stock/onboarding_step/create_a_product/create_a_product.json b/erpnext/stock/onboarding_step/create_a_product/create_a_product.json
index d2068e1..335137d 100644
--- a/erpnext/stock/onboarding_step/create_a_product/create_a_product.json
+++ b/erpnext/stock/onboarding_step/create_a_product/create_a_product.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-12 18:30:02.489949",
+ "modified": "2020-10-14 14:53:00.133574",
"modified_by": "Administrator",
"name": "Create a Product",
"owner": "Administrator",
diff --git a/erpnext/stock/onboarding_step/create_a_purchase_receipt/create_a_purchase_receipt.json b/erpnext/stock/onboarding_step/create_a_purchase_receipt/create_a_purchase_receipt.json
index b7811a4..9012493 100644
--- a/erpnext/stock/onboarding_step/create_a_purchase_receipt/create_a_purchase_receipt.json
+++ b/erpnext/stock/onboarding_step/create_a_purchase_receipt/create_a_purchase_receipt.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-19 18:59:13.266713",
+ "modified": "2020-10-14 14:53:25.618434",
"modified_by": "Administrator",
"name": "Create a Purchase Receipt",
"owner": "Administrator",
diff --git a/erpnext/stock/onboarding_step/create_a_stock_entry/create_a_stock_entry.json b/erpnext/stock/onboarding_step/create_a_stock_entry/create_a_stock_entry.json
index 2b83f65..09902b8 100644
--- a/erpnext/stock/onboarding_step/create_a_stock_entry/create_a_stock_entry.json
+++ b/erpnext/stock/onboarding_step/create_a_stock_entry/create_a_stock_entry.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-15 03:30:58.047696",
+ "modified": "2020-10-14 14:53:00.105905",
"modified_by": "Administrator",
"name": "Create a Stock Entry",
"owner": "Administrator",
diff --git a/erpnext/stock/onboarding_step/create_a_supplier/create_a_supplier.json b/erpnext/stock/onboarding_step/create_a_supplier/create_a_supplier.json
index 7a64224..ef61fa3 100644
--- a/erpnext/stock/onboarding_step/create_a_supplier/create_a_supplier.json
+++ b/erpnext/stock/onboarding_step/create_a_supplier/create_a_supplier.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-14 22:09:10.043554",
+ "modified": "2020-10-14 14:53:00.120455",
"modified_by": "Administrator",
"name": "Create a Supplier",
"owner": "Administrator",
diff --git a/erpnext/stock/onboarding_step/introduction_to_stock_entry/introduction_to_stock_entry.json b/erpnext/stock/onboarding_step/introduction_to_stock_entry/introduction_to_stock_entry.json
index 009a44f..212e505 100644
--- a/erpnext/stock/onboarding_step/introduction_to_stock_entry/introduction_to_stock_entry.json
+++ b/erpnext/stock/onboarding_step/introduction_to_stock_entry/introduction_to_stock_entry.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-26 15:55:41.457289",
+ "modified": "2020-10-14 14:53:00.075177",
"modified_by": "Administrator",
"name": "Introduction to Stock Entry",
"owner": "Administrator",
diff --git a/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json b/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json
index 9457dee..75940ed 100644
--- a/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json
+++ b/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-07-04 12:33:16.970031",
+ "modified": "2020-10-14 14:53:25.538900",
"modified_by": "Administrator",
"name": "Setup your Warehouse",
"owner": "Administrator",
diff --git a/erpnext/stock/onboarding_step/stock_settings/stock_settings.json b/erpnext/stock/onboarding_step/stock_settings/stock_settings.json
index 7591bff..ae34afa 100644
--- a/erpnext/stock/onboarding_step/stock_settings/stock_settings.json
+++ b/erpnext/stock/onboarding_step/stock_settings/stock_settings.json
@@ -8,7 +8,7 @@
"is_mandatory": 0,
"is_single": 1,
"is_skipped": 0,
- "modified": "2020-05-15 03:55:15.444151",
+ "modified": "2020-10-14 14:53:00.092504",
"modified_by": "Administrator",
"name": "Stock Settings",
"owner": "Administrator",
diff --git a/erpnext/stock/page/stock_balance/stock_balance.js b/erpnext/stock/page/stock_balance/stock_balance.js
index da21c6b..bddffd4 100644
--- a/erpnext/stock/page/stock_balance/stock_balance.js
+++ b/erpnext/stock/page/stock_balance/stock_balance.js
@@ -65,6 +65,9 @@
frappe.require('assets/js/item-dashboard.min.js', function() {
page.item_dashboard = new erpnext.stock.ItemDashboard({
parent: page.main,
+ page_length: 20,
+ method: 'erpnext.stock.dashboard.item_dashboard.get_data',
+ template: 'item_dashboard_list'
})
page.item_dashboard.before_refresh = function() {
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/stock/page/warehouse_capacity_summary/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/stock/page/warehouse_capacity_summary/__init__.py
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html
new file mode 100644
index 0000000..90112c7
--- /dev/null
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html
@@ -0,0 +1,40 @@
+{% for d in data %}
+ <div class="dashboard-list-item" style="padding: 7px 15px;">
+ <div class="row">
+ <div class="col-sm-2 small" style="margin-top: 8px;">
+ <a data-type="warehouse" data-name="{{ d.warehouse }}">{{ d.warehouse }}</a>
+ </div>
+ <div class="col-sm-2 small" style="margin-top: 8px; ">
+ <a data-type="item" data-name="{{ d.item_code }}">{{ d.item_code }}</a>
+ </div>
+ <div class="col-sm-1 small" style="margin-top: 8px; ">
+ {{ d.stock_capacity }}
+ </div>
+ <div class="col-sm-2 small" style="margin-top: 8px; ">
+ {{ d.actual_qty }}
+ </div>
+ <div class="col-sm-2 small">
+ <div class="progress" title="Occupied Qty: {{ d.actual_qty }}" style="margin-bottom: 4px; height: 7px; margin-top: 14px;">
+ <div class="progress-bar" role="progressbar"
+ aria-valuenow="{{ d.percent_occupied }}"
+ aria-valuemin="0" aria-valuemax="100"
+ style="width:{{ d.percent_occupied }}%;
+ background-color: {{ d.color }}">
+ </div>
+ </div>
+ </div>
+ <div class="col-sm-1 small" style="margin-top: 8px;">
+ {{ d.percent_occupied }}%
+ </div>
+ {% if can_write %}
+ <div class="col-sm-1 text-right" style="margin-top: 2px;">
+ <button class="btn btn-default btn-xs btn-edit"
+ style="margin-top: 4px;margin-bottom: 4px;"
+ data-warehouse="{{ d.warehouse }}"
+ data-item="{{ escape(d.item_code) }}"
+ data-company="{{ escape(d.company) }}">{{ __("Edit Capacity") }}</a>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+{% endfor %}
\ No newline at end of file
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
new file mode 100644
index 0000000..b610e7d
--- /dev/null
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
@@ -0,0 +1,120 @@
+frappe.pages['warehouse-capacity-summary'].on_page_load = function(wrapper) {
+ var page = frappe.ui.make_app_page({
+ parent: wrapper,
+ title: 'Warehouse Capacity Summary',
+ single_column: true
+ });
+ page.set_secondary_action('Refresh', () => page.capacity_dashboard.refresh(), 'octicon octicon-sync');
+ page.start = 0;
+
+ page.company_field = page.add_field({
+ fieldname: 'company',
+ label: __('Company'),
+ fieldtype: 'Link',
+ options: 'Company',
+ reqd: 1,
+ default: frappe.defaults.get_default("company"),
+ change: function() {
+ page.capacity_dashboard.start = 0;
+ page.capacity_dashboard.refresh();
+ }
+ });
+
+ page.warehouse_field = page.add_field({
+ fieldname: 'warehouse',
+ label: __('Warehouse'),
+ fieldtype: 'Link',
+ options: 'Warehouse',
+ change: function() {
+ page.capacity_dashboard.start = 0;
+ page.capacity_dashboard.refresh();
+ }
+ });
+
+ page.item_field = page.add_field({
+ fieldname: 'item_code',
+ label: __('Item'),
+ fieldtype: 'Link',
+ options: 'Item',
+ change: function() {
+ page.capacity_dashboard.start = 0;
+ page.capacity_dashboard.refresh();
+ }
+ });
+
+ page.parent_warehouse_field = page.add_field({
+ fieldname: 'parent_warehouse',
+ label: __('Parent Warehouse'),
+ fieldtype: 'Link',
+ options: 'Warehouse',
+ get_query: function() {
+ return {
+ filters: {
+ "is_group": 1
+ }
+ };
+ },
+ change: function() {
+ page.capacity_dashboard.start = 0;
+ page.capacity_dashboard.refresh();
+ }
+ });
+
+ page.sort_selector = new frappe.ui.SortSelector({
+ parent: page.wrapper.find('.page-form'),
+ args: {
+ sort_by: 'stock_capacity',
+ sort_order: 'desc',
+ options: [
+ {fieldname: 'stock_capacity', label: __('Capacity (Stock UOM)')},
+ {fieldname: 'percent_occupied', label: __('% Occupied')},
+ {fieldname: 'actual_qty', label: __('Balance Qty (Stock ')}
+ ]
+ },
+ change: function(sort_by, sort_order) {
+ page.capacity_dashboard.sort_by = sort_by;
+ page.capacity_dashboard.sort_order = sort_order;
+ page.capacity_dashboard.start = 0;
+ page.capacity_dashboard.refresh();
+ }
+ });
+
+ frappe.require('assets/js/item-dashboard.min.js', function() {
+ $(frappe.render_template('warehouse_capacity_summary_header')).appendTo(page.main);
+
+ page.capacity_dashboard = new erpnext.stock.ItemDashboard({
+ page_name: "warehouse-capacity-summary",
+ page_length: 10,
+ parent: page.main,
+ sort_by: 'stock_capacity',
+ sort_order: 'desc',
+ method: 'erpnext.stock.dashboard.warehouse_capacity_dashboard.get_data',
+ template: 'warehouse_capacity_summary'
+ });
+
+ page.capacity_dashboard.before_refresh = function() {
+ this.item_code = page.item_field.get_value();
+ this.warehouse = page.warehouse_field.get_value();
+ this.parent_warehouse = page.parent_warehouse_field.get_value();
+ this.company = page.company_field.get_value();
+ };
+
+ page.capacity_dashboard.refresh();
+
+ let setup_click = function(doctype) {
+ page.main.on('click', 'a[data-type="'+ doctype.toLowerCase() +'"]', function() {
+ var name = $(this).attr('data-name');
+ var field = page[doctype.toLowerCase() + '_field'];
+ if (field.get_value()===name) {
+ frappe.set_route('Form', doctype, name);
+ } else {
+ field.set_input(name);
+ page.capacity_dashboard.refresh();
+ }
+ });
+ };
+
+ setup_click('Item');
+ setup_click('Warehouse');
+ });
+};
\ No newline at end of file
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.json b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.json
new file mode 100644
index 0000000..a6e5b45
--- /dev/null
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.json
@@ -0,0 +1,26 @@
+{
+ "content": null,
+ "creation": "2020-11-25 12:07:54.056208",
+ "docstatus": 0,
+ "doctype": "Page",
+ "idx": 0,
+ "modified": "2020-11-25 11:07:54.056208",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "warehouse-capacity-summary",
+ "owner": "Administrator",
+ "page_name": "Warehouse Capacity Summary",
+ "roles": [
+ {
+ "role": "Stock User"
+ },
+ {
+ "role": "Stock Manager"
+ }
+ ],
+ "script": null,
+ "standard": "Yes",
+ "style": null,
+ "system_page": 0,
+ "title": "Warehouse Capacity Summary"
+}
\ No newline at end of file
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
new file mode 100644
index 0000000..acaf180
--- /dev/null
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
@@ -0,0 +1,19 @@
+<div class="dashboard-list-item" style="padding: 12px 15px;">
+ <div class="row">
+ <div class="col-sm-2 small text-muted" style="margin-top: 8px;">
+ Warehouse
+ </div>
+ <div class="col-sm-2 small text-muted" style="margin-top: 8px;">
+ Item
+ </div>
+ <div class="col-sm-1 small text-muted" style="margin-top: 8px;">
+ Stock Capacity
+ </div>
+ <div class="col-sm-2 small text-muted" style="margin-top: 8px;">
+ Balance Stock Qty
+ </div>
+ <div class="col-sm-2 small text-muted" style="margin-top: 8px;">
+ % Occupied
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
index 2499c80..74b5a5a 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
@@ -4,6 +4,14 @@
frappe.query_reports["Batch-Wise Balance History"] = {
"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",
@@ -20,12 +28,46 @@
"reqd": 1
},
{
- "fieldname": "item",
- "label": __("Item"),
+ "fieldname":"item_code",
+ "label": __("Item Code"),
"fieldtype": "Link",
"options": "Item",
- "width": "80"
- }
+ "get_query": function() {
+ return {
+ filters: {
+ "has_batch_no": 1
+ }
+ };
+ }
+ },
+ {
+ "fieldname":"warehouse",
+ "label": __("Warehouse"),
+ "fieldtype": "Link",
+ "options": "Warehouse",
+ "get_query": function() {
+ let company = frappe.query_report.get_filter_value('company');
+ return {
+ filters: {
+ "company": company
+ }
+ };
+ }
+ },
+ {
+ "fieldname":"batch_no",
+ "label": __("Batch No"),
+ "fieldtype": "Link",
+ "options": "Batch",
+ "get_query": function() {
+ let item_code = frappe.query_report.get_filter_value('item_code');
+ return {
+ filters: {
+ "item": item_code
+ }
+ };
+ }
+ },
],
"formatter": function (value, row, column, data, default_formatter) {
if (column.fieldname == "Batch" && data && !!data["Batch"]) {
@@ -43,4 +85,4 @@
frappe.set_route("query-report", "Stock Ledger");
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 8f3e246..087c12e 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -57,6 +57,10 @@
else:
frappe.throw(_("'To Date' is required"))
+ for field in ["item_code", "warehouse", "batch_no", "company"]:
+ if filters.get(field):
+ conditions += " and {0} = {1}".format(field, frappe.db.escape(filters.get(field)))
+
return conditions
diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py
index aa3ed92..12f3297 100644
--- a/erpnext/stock/report/item_prices/item_prices.py
+++ b/erpnext/stock/report/item_prices/item_prices.py
@@ -77,38 +77,33 @@
return item_rate_map
def get_last_purchase_rate():
-
item_last_purchase_rate_map = {}
- query = """select * from (select
- result.item_code,
- result.base_rate
- from (
- (select
- po_item.item_code,
- po_item.item_name,
- po.transaction_date as posting_date,
- po_item.base_price_list_rate,
- po_item.discount_percentage,
- po_item.base_rate
- from `tabPurchase Order` po, `tabPurchase Order Item` po_item
- where po.name = po_item.parent and po.docstatus = 1)
- union
- (select
- pr_item.item_code,
- pr_item.item_name,
- pr.posting_date,
- pr_item.base_price_list_rate,
- pr_item.discount_percentage,
- pr_item.base_rate
- from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
- where pr.name = pr_item.parent and pr.docstatus = 1)
- ) result
- order by result.item_code asc, result.posting_date desc) result_wrapper
- group by item_code"""
+ query = """select * from (
+ (select
+ po_item.item_code,
+ po.transaction_date as posting_date,
+ po_item.base_rate
+ from `tabPurchase Order` po, `tabPurchase Order Item` po_item
+ where po.name = po_item.parent and po.docstatus = 1)
+ union
+ (select
+ pr_item.item_code,
+ pr.posting_date,
+ pr_item.base_rate
+ from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
+ where pr.name = pr_item.parent and pr.docstatus = 1)
+ union
+ (select
+ pi_item.item_code,
+ pi.posting_date,
+ pi_item.base_rate
+ from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
+ where pi.name = pi_item.parent and pi.docstatus = 1 and pi.update_stock = 1)
+ ) result order by result.item_code asc, result.posting_date asc"""
for d in frappe.db.sql(query, as_dict=1):
- item_last_purchase_rate_map.setdefault(d.item_code, d.base_rate)
+ item_last_purchase_rate_map[d.item_code] = d.base_rate
return item_last_purchase_rate_map
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 4af3c54..ff603fc 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -16,10 +16,12 @@
data = []
for item, item_dict in iteritems(item_details):
+ earliest_age, latest_age = 0, 0
fifo_queue = sorted(filter(_func, item_dict["fifo_queue"]), key=_func)
details = item_dict["details"]
- if not fifo_queue or (not item_dict.get("total_qty")): continue
+
+ if not fifo_queue: continue
average_age = get_average_age(fifo_queue, to_date)
earliest_age = date_diff(to_date, fifo_queue[0][1])
@@ -60,7 +62,7 @@
range1 = range2 = range3 = above_range3 = 0.0
for item in fifo_queue:
age = date_diff(to_date, item[1])
-
+
if age <= filters.range1:
range1 += flt(item[0])
elif age <= filters.range2:
@@ -69,7 +71,7 @@
range3 += flt(item[0])
else:
above_range3 += flt(item[0])
-
+
return range1, range2, range3, above_range3
def get_columns(filters):
@@ -170,7 +172,8 @@
item_details.setdefault(key, {"details": d, "fifo_queue": []})
fifo_queue = item_details[key]["fifo_queue"]
- transferred_item_details.setdefault((d.voucher_no, d.name), [])
+ transferred_item_key = (d.voucher_no, d.name, d.warehouse)
+ transferred_item_details.setdefault(transferred_item_key, [])
if d.voucher_type == "Stock Reconciliation":
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[key].get("qty_after_transaction", 0))
@@ -178,10 +181,10 @@
serial_no_list = get_serial_nos(d.serial_no) if d.serial_no else []
if d.actual_qty > 0:
- if transferred_item_details.get((d.voucher_no, d.name)):
- batch = transferred_item_details[(d.voucher_no, d.name)][0]
+ if transferred_item_details.get(transferred_item_key):
+ batch = transferred_item_details[transferred_item_key][0]
fifo_queue.append(batch)
- transferred_item_details[((d.voucher_no, d.name))].pop(0)
+ transferred_item_details[transferred_item_key].pop(0)
else:
if serial_no_list:
for serial_no in serial_no_list:
@@ -205,11 +208,11 @@
# if batch qty > 0
# not enough or exactly same qty in current batch, clear batch
qty_to_pop -= flt(batch[0])
- transferred_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
+ transferred_item_details[transferred_item_key].append(fifo_queue.pop(0))
else:
# all from current batch
batch[0] = flt(batch[0]) - qty_to_pop
- transferred_item_details[(d.voucher_no, d.name)].append([qty_to_pop, batch[1]])
+ transferred_item_details[transferred_item_key].append([qty_to_pop, batch[1]])
qty_to_pop = 0
item_details[key]["qty_after_transaction"] = d.qty_after_transaction
@@ -230,7 +233,8 @@
from `tabItem` {item_conditions}) item
where item_code = item.name and
company = %(company)s and
- posting_date <= %(to_date)s
+ posting_date <= %(to_date)s and
+ is_cancelled != 1
{sle_conditions}
order by posting_date, posting_time, sle.creation, actual_qty""" #nosec
.format(item_conditions=get_item_conditions(filters),
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index 54eefdf..0cc8ca4 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -7,9 +7,11 @@
from frappe.utils import getdate, flt
from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
from erpnext.accounts.utils import get_fiscal_year
+from erpnext.stock.utils import is_reposting_item_valuation_in_progress
from six import iteritems
def execute(filters=None):
+ is_reposting_item_valuation_in_progress()
filters = frappe._dict(filters or {})
columns = get_columns(filters)
data = get_data(filters)
diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
index 1af68dd..14d543b 100644
--- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
+++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
@@ -57,8 +57,7 @@
if report_filters.account:
stock_accounts = [report_filters.account]
else:
- stock_accounts = [k.name
- for k in get_stock_accounts(report_filters.company)]
+ stock_accounts = get_stock_accounts(report_filters.company)
filters.update({
"account": ("in", stock_accounts)
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 042087a..6dfede4 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -7,12 +7,13 @@
from frappe.utils import flt, cint, getdate, now, date_diff
from erpnext.stock.utils import add_additional_uom_columns
from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
-
+from erpnext.stock.utils import is_reposting_item_valuation_in_progress
from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age
from six import iteritems
def execute(filters=None):
+ is_reposting_item_valuation_in_progress()
if not filters: filters = {}
validate_filters(filters)
@@ -164,10 +165,11 @@
select
sle.item_code, warehouse, sle.posting_date, sle.actual_qty, sle.valuation_rate,
sle.company, sle.voucher_type, sle.qty_after_transaction, sle.stock_value_difference,
- sle.item_code as name, sle.voucher_no
+ sle.item_code as name, sle.voucher_no, sle.stock_value
from
`tabStock Ledger Entry` sle force index (posting_sort_index)
where sle.docstatus < 2 %s %s
+ and is_cancelled = 0
order by sle.posting_date, sle.posting_time, sle.creation, sle.actual_qty""" % #nosec
(item_conditions_sql, conditions), as_dict=1)
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js
index 6f12c27..fe2417b 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.js
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.js
@@ -82,11 +82,6 @@
"label": __("Include UOM"),
"fieldtype": "Link",
"options": "UOM"
- },
- {
- "fieldname": "show_cancelled_entries",
- "label": __("Show Cancelled Entries"),
- "fieldtype": "Check"
}
],
"formatter": function (value, row, column, data, default_formatter) {
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index fe8ad71..36996e9 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -5,10 +5,12 @@
import frappe
from frappe.utils import cint, flt
-from erpnext.stock.utils import update_included_uom_in_report
+from erpnext.stock.utils import update_included_uom_in_report, is_reposting_item_valuation_in_progress
from frappe import _
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
def execute(filters=None):
+ is_reposting_item_valuation_in_progress()
include_uom = filters.get("include_uom")
columns = get_columns()
items = get_items(filters)
@@ -24,6 +26,7 @@
actual_qty = stock_value = 0
+ available_serial_nos = {}
for sle in sl_entries:
item_detail = item_details[sle.item_code]
@@ -47,6 +50,9 @@
"out_qty": min(sle.actual_qty, 0)
})
+ if sle.serial_no:
+ update_available_serial_nos(available_serial_nos, sle)
+
data.append(sle)
if include_uom:
@@ -55,6 +61,26 @@
update_included_uom_in_report(columns, data, include_uom, conversion_factors)
return columns, data
+def update_available_serial_nos(available_serial_nos, sle):
+ serial_nos = get_serial_nos(sle.serial_no)
+ key = (sle.item_code, sle.warehouse)
+ if key not in available_serial_nos:
+ available_serial_nos.setdefault(key, [])
+
+ existing_serial_no = available_serial_nos[key]
+ for sn in serial_nos:
+ if sle.actual_qty > 0:
+ if sn in existing_serial_no:
+ existing_serial_no.remove(sn)
+ else:
+ existing_serial_no.append(sn)
+ else:
+ if sn in existing_serial_no:
+ existing_serial_no.remove(sn)
+ else:
+ existing_serial_no.append(sn)
+
+ sle.balance_serial_no = '\n'.join(existing_serial_no)
def get_columns():
columns = [
@@ -76,7 +102,8 @@
{"label": _("Voucher Type"), "fieldname": "voucher_type", "width": 110},
{"label": _("Voucher #"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 100},
{"label": _("Batch"), "fieldname": "batch_no", "fieldtype": "Link", "options": "Batch", "width": 100},
- {"label": _("Serial #"), "fieldname": "serial_no", "fieldtype": "Link", "options": "Serial No", "width": 100},
+ {"label": _("Serial No"), "fieldname": "serial_no", "fieldtype": "Link", "options": "Serial No", "width": 100},
+ {"label": _("Balance Serial No"), "fieldname": "balance_serial_no", "width": 100},
{"label": _("Project"), "fieldname": "project", "fieldtype": "Link", "options": "Project", "width": 100},
{"label": _("Company"), "fieldname": "company", "fieldtype": "Link", "options": "Company", "width": 110}
]
@@ -111,7 +138,7 @@
`tabStock Ledger Entry` sle
WHERE
company = %(company)s
- AND posting_date BETWEEN %(from_date)s AND %(to_date)s
+ AND is_cancelled = 0 AND posting_date BETWEEN %(from_date)s AND %(to_date)s
{sle_conditions}
{item_conditions_sql}
ORDER BY
@@ -182,9 +209,6 @@
if filters.get("project"):
conditions.append("project=%(project)s")
- if not filters.get("show_cancelled_entries"):
- conditions.append("is_cancelled = 0")
-
return "and {}".format(" and ".join(conditions)) if conditions else ""
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index c8efb16..1183e41 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -5,9 +5,10 @@
import frappe
from frappe import _
from frappe.utils import flt, today
-from erpnext.stock.utils import update_included_uom_in_report
+from erpnext.stock.utils import update_included_uom_in_report, is_reposting_item_valuation_in_progress
def execute(filters=None):
+ is_reposting_item_valuation_in_progress()
filters = frappe._dict(filters or {})
include_uom = filters.get("include_uom")
columns = get_columns()
diff --git a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
index 55f041c..78e95df 100644
--- a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
+++ b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
@@ -6,10 +6,17 @@
from frappe import _
def execute(filters=None):
+ validate_warehouse(filters)
columns = get_columns()
data = get_data(filters.warehouse)
return columns, data
+def validate_warehouse(filters):
+ company = filters.company
+ warehouse = filters.warehouse
+ if not frappe.db.exists("Warehouse", {"name": warehouse, "company": company}):
+ frappe.throw(_("Warehouse: {0} does not belong to {1}").format(warehouse, company))
+
def get_columns():
columns = [
{
diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
index ebcb106..04f7d34 100644
--- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
+++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
@@ -11,9 +11,11 @@
from erpnext.stock.report.stock_balance.stock_balance import (get_item_details,
get_item_reorder_details, get_item_warehouse_map, get_items, get_stock_ledger_entries)
from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age
+from erpnext.stock.utils import is_reposting_item_valuation_in_progress
from six import iteritems
def execute(filters=None):
+ is_reposting_item_valuation_in_progress()
if not filters: filters = {}
validate_filters(filters)
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index b5ae1b7..8ba1f1c 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -6,6 +6,7 @@
from frappe.utils import flt, cstr, nowdate, nowtime
from erpnext.stock.utils import update_bin
from erpnext.stock.stock_ledger import update_entries_after
+from erpnext.controllers.stock_controller import create_repost_item_valuation_entry
def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
"""
@@ -56,12 +57,18 @@
update_bin_qty(item_code, warehouse, qty_dict)
def repost_actual_qty(item_code, warehouse, allow_zero_rate=False, allow_negative_stock=False):
- update_entries_after({ "item_code": item_code, "warehouse": warehouse },
- allow_zero_rate=allow_zero_rate, allow_negative_stock=allow_negative_stock)
+ create_repost_item_valuation_entry({
+ "item_code": item_code,
+ "warehouse": warehouse,
+ "posting_date": "1900-01-01",
+ "posting_time": "00:01",
+ "allow_negative_stock": allow_negative_stock,
+ "allow_zero_rate": allow_zero_rate
+ })
def get_balance_qty_from_sle(item_code, warehouse):
balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
- where item_code=%s and warehouse=%s
+ where item_code=%s and warehouse=%s and is_cancelled=0
order by posting_date desc, posting_time desc, creation desc
limit 1""", (item_code, warehouse))
@@ -191,7 +198,7 @@
print(d[0], d[1], d[2], serial_nos[0][0])
sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
- where item_code = %s and warehouse = %s
+ where item_code = %s and warehouse = %s and is_cancelled = 0
order by posting_date desc limit 1""", (d[0], d[1]))
sle_dict = {
@@ -223,7 +230,8 @@
})
update_bin(args)
- update_entries_after({
+
+ create_repost_item_valuation_entry({
"item_code": d[0],
"warehouse": d[1],
"posting_date": posting_date,
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index f4490f1..121c51c 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -5,9 +5,10 @@
import frappe, erpnext
from frappe import _
from frappe.utils import cint, flt, cstr, now, now_datetime
+from frappe.model.meta import get_field_precision
from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
+from erpnext.stock.utils import get_bin
import json
-
from six import iteritems
# future reposting
@@ -22,37 +23,44 @@
cancel = sl_entries[0].get("is_cancelled")
if cancel:
+ validate_cancellation(sl_entries)
set_as_cancel(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
for sle in sl_entries:
- sle_id = None
- if via_landed_cost_voucher or cancel:
- sle['posting_date'] = now_datetime().strftime('%Y-%m-%d')
- sle['posting_time'] = now_datetime().strftime('%H:%M:%S.%f')
+ if cancel:
+ sle['actual_qty'] = -flt(sle.get('actual_qty'))
- if cancel:
- sle['actual_qty'] = -flt(sle.get('actual_qty'))
+ if sle['actual_qty'] < 0 and not sle.get('outgoing_rate'):
+ sle['outgoing_rate'] = get_incoming_outgoing_rate_for_cancel(sle.item_code,
+ sle.voucher_type, sle.voucher_no, sle.voucher_detail_no)
+ sle['incoming_rate'] = 0.0
- if sle['actual_qty'] < 0 and not sle.get('outgoing_rate'):
- sle['outgoing_rate'] = get_incoming_outgoing_rate_for_cancel(sle.item_code,
- sle.voucher_type, sle.voucher_no, sle.voucher_detail_no)
- sle['incoming_rate'] = 0.0
-
- if sle['actual_qty'] > 0 and not sle.get('incoming_rate'):
- sle['incoming_rate'] = get_incoming_outgoing_rate_for_cancel(sle.item_code,
- sle.voucher_type, sle.voucher_no, sle.voucher_detail_no)
- sle['outgoing_rate'] = 0.0
-
+ if sle['actual_qty'] > 0 and not sle.get('incoming_rate'):
+ sle['incoming_rate'] = get_incoming_outgoing_rate_for_cancel(sle.item_code,
+ sle.voucher_type, sle.voucher_no, sle.voucher_detail_no)
+ sle['outgoing_rate'] = 0.0
if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation":
- sle_id = make_entry(sle, allow_negative_stock, via_landed_cost_voucher)
+ sle_doc = make_entry(sle, allow_negative_stock, via_landed_cost_voucher)
- args = sle.copy()
- args.update({
- "sle_id": sle_id
- })
+ args = sle_doc.as_dict()
update_bin(args, allow_negative_stock, via_landed_cost_voucher)
+def validate_cancellation(args):
+ if args[0].get("is_cancelled"):
+ repost_entry = frappe.db.get_value("Repost Item Valuation", {
+ 'voucher_type': args[0].voucher_type,
+ 'voucher_no': args[0].voucher_no,
+ 'docstatus': 1
+ }, ['name', 'status'], as_dict=1)
+
+ if repost_entry:
+ if repost_entry.status == 'In Progress':
+ frappe.throw(_("Cannot cancel the transaction. Reposting of item valuation on submission is not completed yet."))
+ if repost_entry.status == 'Queued':
+ doc = frappe.get_doc("Repost Item Valuation", repost_entry.name)
+ doc.cancel()
+ doc.delete()
def set_as_cancel(voucher_type, voucher_no):
frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled=1,
@@ -68,8 +76,37 @@
sle.via_landed_cost_voucher = via_landed_cost_voucher
sle.insert()
sle.submit()
- return sle.name
+ return sle
+def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=None, via_landed_cost_voucher=False):
+ if not args and voucher_type and voucher_no:
+ args = get_args_for_voucher(voucher_type, voucher_no)
+
+ distinct_item_warehouses = [(d.item_code, d.warehouse) for d in args]
+
+ i = 0
+ while i < len(args):
+ obj = update_entries_after({
+ "item_code": args[i].item_code,
+ "warehouse": args[i].warehouse,
+ "posting_date": args[i].posting_date,
+ "posting_time": args[i].posting_time,
+ "creation": args[i].get("creation")
+ }, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
+
+ for item_wh, new_sle in iteritems(obj.new_items):
+ if item_wh not in distinct_item_warehouses:
+ args.append(new_sle)
+
+ i += 1
+
+def get_args_for_voucher(voucher_type, voucher_no):
+ return frappe.db.get_all("Stock Ledger Entry",
+ filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
+ fields=["item_code", "warehouse", "posting_date", "posting_time", "creation"],
+ order_by="creation asc",
+ group_by="item_code, warehouse"
+ )
class update_entries_after(object):
"""
@@ -86,141 +123,328 @@
}
"""
def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1):
- from frappe.model.meta import get_field_precision
-
- self.exceptions = []
+ self.exceptions = {}
self.verbose = verbose
self.allow_zero_rate = allow_zero_rate
- self.allow_negative_stock = allow_negative_stock
self.via_landed_cost_voucher = via_landed_cost_voucher
- if not self.allow_negative_stock:
- self.allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings",
- "allow_negative_stock"))
+ self.allow_negative_stock = allow_negative_stock \
+ or cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
- self.args = args
- for key, value in iteritems(args):
- setattr(self, key, value)
+ self.args = frappe._dict(args)
+ self.item_code = args.get("item_code")
+ if self.args.sle_id:
+ self.args['name'] = self.args.sle_id
- self.previous_sle = self.get_sle_before_datetime()
- self.previous_sle = self.previous_sle[0] if self.previous_sle else frappe._dict()
+ self.company = frappe.get_cached_value("Warehouse", self.args.warehouse, "company")
+ self.get_precision()
+ self.valuation_method = get_valuation_method(self.item_code)
+ self.new_items = {}
+
+ self.data = frappe._dict()
+ self.initialize_previous_data(self.args)
+
+ self.build()
+
+ def get_precision(self):
+ company_base_currency = frappe.get_cached_value('Company', self.company, "default_currency")
+ self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"),
+ currency=company_base_currency)
+
+ def initialize_previous_data(self, args):
+ """
+ Get previous sl entries for current item for each related warehouse
+ and assigns into self.data dict
+
+ :Data Structure:
+
+ self.data = {
+ warehouse1: {
+ 'previus_sle': {},
+ 'qty_after_transaction': 10,
+ 'valuation_rate': 100,
+ 'stock_value': 1000,
+ 'prev_stock_value': 1000,
+ 'stock_queue': '[[10, 100]]',
+ 'stock_value_difference': 1000
+ }
+ }
+
+ """
+ self.data.setdefault(args.warehouse, frappe._dict())
+ warehouse_dict = self.data[args.warehouse]
+ previous_sle = self.get_previous_sle_of_current_voucher(args)
+ warehouse_dict.previous_sle = previous_sle
for key in ("qty_after_transaction", "valuation_rate", "stock_value"):
- setattr(self, key, flt(self.previous_sle.get(key)))
+ setattr(warehouse_dict, key, flt(previous_sle.get(key)))
- self.company = frappe.db.get_value("Warehouse", self.warehouse, "company")
- self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"),
- currency=frappe.get_cached_value('Company', self.company, "default_currency"))
+ warehouse_dict.update({
+ "prev_stock_value": previous_sle.stock_value or 0.0,
+ "stock_queue": json.loads(previous_sle.stock_queue or "[]"),
+ "stock_value_difference": 0.0
+ })
- self.prev_stock_value = self.previous_sle.stock_value or 0.0
- self.stock_queue = json.loads(self.previous_sle.stock_queue or "[]")
- self.valuation_method = get_valuation_method(self.item_code)
- self.stock_value_difference = 0.0
- self.build(args.get('sle_id'))
+ def get_previous_sle_of_current_voucher(self, args):
+ """get stock ledger entries filtered by specific posting datetime conditions"""
- def build(self, sle_id):
- if sle_id:
- sle = get_sle_by_id(sle_id)
- self.process_sle(sle)
+ args['time_format'] = '%H:%i:%s'
+ if not args.get("posting_date"):
+ args["posting_date"] = "1900-01-01"
+ if not args.get("posting_time"):
+ args["posting_time"] = "00:00"
+
+ sle = frappe.db.sql("""
+ select *, timestamp(posting_date, posting_time) as "timestamp"
+ from `tabStock Ledger Entry`
+ where item_code = %(item_code)s
+ and warehouse = %(warehouse)s
+ and is_cancelled = 0
+ and timestamp(posting_date, time_format(posting_time, %(time_format)s)) < timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
+ order by timestamp(posting_date, posting_time) desc, creation desc
+ limit 1""", args, as_dict=1)
+
+ return sle[0] if sle else frappe._dict()
+
+
+ def build(self):
+ from erpnext.controllers.stock_controller import future_sle_exists
+
+ if self.args.get("sle_id"):
+ self.process_sle_against_current_timestamp()
+ if not future_sle_exists(self.args):
+ self.update_bin()
else:
- # includes current entry!
- entries_to_fix = self.get_sle_after_datetime()
- for sle in entries_to_fix:
+ entries_to_fix = self.get_future_entries_to_fix()
+
+ i = 0
+ while i < len(entries_to_fix):
+ sle = entries_to_fix[i]
+ i += 1
+
self.process_sle(sle)
+ if sle.dependant_sle_voucher_detail_no:
+ entries_to_fix = self.get_dependent_entries_to_fix(entries_to_fix, sle)
+
+ self.update_bin()
+
if self.exceptions:
self.raise_exceptions()
- self.update_bin()
+ def process_sle_against_current_timestamp(self):
+ sl_entries = self.get_sle_against_current_voucher()
+ for sle in sl_entries:
+ self.process_sle(sle)
- def update_bin(self):
- # update bin
- bin_name = frappe.db.get_value("Bin", {
- "item_code": self.item_code,
- "warehouse": self.warehouse
- })
+ def get_sle_against_current_voucher(self):
+ self.args['time_format'] = '%H:%i:%s'
- if not bin_name:
- bin_doc = frappe.get_doc({
- "doctype": "Bin",
- "item_code": self.item_code,
- "warehouse": self.warehouse
- })
- bin_doc.insert(ignore_permissions=True)
- else:
- bin_doc = frappe.get_doc("Bin", bin_name)
+ return frappe.db.sql("""
+ select
+ *, timestamp(posting_date, posting_time) as "timestamp"
+ from
+ `tabStock Ledger Entry`
+ where
+ item_code = %(item_code)s
+ and warehouse = %(warehouse)s
+ and timestamp(posting_date, time_format(posting_time, %(time_format)s)) = timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
- bin_doc.update({
- "valuation_rate": self.valuation_rate,
- "actual_qty": self.qty_after_transaction,
- "stock_value": self.stock_value
- })
- bin_doc.flags.via_stock_ledger_entry = True
+ order by
+ creation ASC
+ for update
+ """, self.args, as_dict=1)
- bin_doc.save(ignore_permissions=True)
+ def get_future_entries_to_fix(self):
+ # includes current entry!
+ args = self.data[self.args.warehouse].previous_sle \
+ or frappe._dict({"item_code": self.item_code, "warehouse": self.args.warehouse})
+
+ return list(self.get_sle_after_datetime(args))
+
+ def get_dependent_entries_to_fix(self, entries_to_fix, sle):
+ dependant_sle = get_sle_by_voucher_detail_no(sle.dependant_sle_voucher_detail_no,
+ excluded_sle=sle.name)
+
+ if not dependant_sle:
+ return entries_to_fix
+ elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse == self.args.warehouse:
+ return entries_to_fix
+ elif dependant_sle.item_code != self.item_code:
+ if (dependant_sle.item_code, dependant_sle.warehouse) not in self.new_items:
+ self.new_items[(dependant_sle.item_code, dependant_sle.warehouse)] = dependant_sle
+ return entries_to_fix
+ elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse in self.data:
+ return entries_to_fix
+ self.initialize_previous_data(dependant_sle)
+
+ args = self.data[dependant_sle.warehouse].previous_sle \
+ or frappe._dict({"item_code": self.item_code, "warehouse": dependant_sle.warehouse})
+ future_sle_for_dependant = list(self.get_sle_after_datetime(args))
+
+ entries_to_fix.extend(future_sle_for_dependant)
+ return sorted(entries_to_fix, key=lambda k: k['timestamp'])
def process_sle(self, sle):
+ # previous sle data for this warehouse
+ self.wh_data = self.data[sle.warehouse]
+
if (sle.serial_no and not self.via_landed_cost_voucher) or not cint(self.allow_negative_stock):
# validate negative stock for serialized items, fifo valuation
# or when negative stock is not allowed for moving average
if not self.validate_negative_stock(sle):
- self.qty_after_transaction += flt(sle.actual_qty)
+ self.wh_data.qty_after_transaction += flt(sle.actual_qty)
return
+ # Get dynamic incoming/outgoing rate
+ self.get_dynamic_incoming_outgoing_rate(sle)
+
if sle.serial_no:
self.get_serialized_values(sle)
- self.qty_after_transaction += flt(sle.actual_qty)
+ self.wh_data.qty_after_transaction += flt(sle.actual_qty)
if sle.voucher_type == "Stock Reconciliation":
- self.qty_after_transaction = sle.qty_after_transaction
+ self.wh_data.qty_after_transaction = sle.qty_after_transaction
- self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
+ self.wh_data.stock_value = flt(self.wh_data.qty_after_transaction) * flt(self.wh_data.valuation_rate)
else:
if sle.voucher_type=="Stock Reconciliation" and not sle.batch_no:
# assert
- self.valuation_rate = sle.valuation_rate
- self.qty_after_transaction = sle.qty_after_transaction
- self.stock_queue = [[self.qty_after_transaction, self.valuation_rate]]
- self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
+ self.wh_data.valuation_rate = sle.valuation_rate
+ self.wh_data.qty_after_transaction = sle.qty_after_transaction
+ self.wh_data.stock_queue = [[self.wh_data.qty_after_transaction, self.wh_data.valuation_rate]]
+ self.wh_data.stock_value = flt(self.wh_data.qty_after_transaction) * flt(self.wh_data.valuation_rate)
else:
if self.valuation_method == "Moving Average":
self.get_moving_average_values(sle)
- self.qty_after_transaction += flt(sle.actual_qty)
- self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
+ self.wh_data.qty_after_transaction += flt(sle.actual_qty)
+ self.wh_data.stock_value = flt(self.wh_data.qty_after_transaction) * flt(self.wh_data.valuation_rate)
else:
self.get_fifo_values(sle)
- self.qty_after_transaction += flt(sle.actual_qty)
- self.stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in self.stock_queue))
+ self.wh_data.qty_after_transaction += flt(sle.actual_qty)
+ self.wh_data.stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in self.wh_data.stock_queue))
# rounding as per precision
- self.stock_value = flt(self.stock_value, self.precision)
-
- stock_value_difference = self.stock_value - self.prev_stock_value
-
- self.prev_stock_value = self.stock_value
+ self.wh_data.stock_value = flt(self.wh_data.stock_value, self.precision)
+ stock_value_difference = self.wh_data.stock_value - self.wh_data.prev_stock_value
+ self.wh_data.prev_stock_value = self.wh_data.stock_value
# update current sle
- sle.qty_after_transaction = self.qty_after_transaction
- sle.valuation_rate = self.valuation_rate
- sle.stock_value = self.stock_value
- sle.stock_queue = json.dumps(self.stock_queue)
+ sle.qty_after_transaction = self.wh_data.qty_after_transaction
+ sle.valuation_rate = self.wh_data.valuation_rate
+ sle.stock_value = self.wh_data.stock_value
+ sle.stock_queue = json.dumps(self.wh_data.stock_queue)
sle.stock_value_difference = stock_value_difference
sle.doctype="Stock Ledger Entry"
frappe.get_doc(sle).db_update()
+ self.update_outgoing_rate_on_transaction(sle)
+
def validate_negative_stock(self, sle):
"""
validate negative stock for entries current datetime onwards
will not consider cancelled entries
"""
- diff = self.qty_after_transaction + flt(sle.actual_qty)
+ diff = self.wh_data.qty_after_transaction + flt(sle.actual_qty)
if diff < 0 and abs(diff) > 0.0001:
# negative stock!
exc = sle.copy().update({"diff": diff})
- self.exceptions.append(exc)
+ self.exceptions.setdefault(sle.warehouse, []).append(exc)
return False
else:
return True
+ def get_dynamic_incoming_outgoing_rate(self, sle):
+ # Get updated incoming/outgoing rate from transaction
+ if sle.recalculate_rate:
+ rate = self.get_incoming_outgoing_rate_from_transaction(sle)
+
+ if flt(sle.actual_qty) >= 0:
+ sle.incoming_rate = rate
+ else:
+ sle.outgoing_rate = rate
+
+ def get_incoming_outgoing_rate_from_transaction(self, sle):
+ rate = 0
+ # Material Transfer, Repack, Manufacturing
+ if sle.voucher_type == "Stock Entry":
+ rate = frappe.db.get_value("Stock Entry Detail", sle.voucher_detail_no, "valuation_rate")
+ # Sales and Purchase Return
+ elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"):
+ if frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_return"):
+ from erpnext.controllers.sales_and_purchase_return import get_rate_for_return # don't move this import to top
+ rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code, voucher_detail_no=sle.voucher_detail_no)
+ else:
+ if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
+ rate_field = "valuation_rate"
+ else:
+ rate_field = "incoming_rate"
+
+ # check in item table
+ item_code, incoming_rate = frappe.db.get_value(sle.voucher_type + " Item",
+ sle.voucher_detail_no, ["item_code", rate_field])
+
+ if item_code == sle.item_code:
+ rate = incoming_rate
+ else:
+ if sle.voucher_type in ("Delivery Note", "Sales Invoice"):
+ ref_doctype = "Packed Item"
+ else:
+ ref_doctype = "Purchase Receipt Item Supplied"
+
+ rate = frappe.db.get_value(ref_doctype, {"parent_detail_docname": sle.voucher_detail_no,
+ "item_code": sle.item_code}, rate_field)
+
+ return rate
+
+ def update_outgoing_rate_on_transaction(self, sle):
+ """
+ Update outgoing rate in Stock Entry, Delivery Note, Sales Invoice and Sales Return
+ In case of Stock Entry, also calculate FG Item rate and total incoming/outgoing amount
+ """
+ if sle.actual_qty and sle.voucher_detail_no:
+ outgoing_rate = abs(flt(sle.stock_value_difference)) / abs(sle.actual_qty)
+
+ if flt(sle.actual_qty) < 0 and sle.voucher_type == "Stock Entry":
+ self.update_rate_on_stock_entry(sle, outgoing_rate)
+ elif sle.voucher_type in ("Delivery Note", "Sales Invoice"):
+ self.update_rate_on_delivery_and_sales_return(sle, outgoing_rate)
+ elif flt(sle.actual_qty) < 0 and sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
+ self.update_rate_on_purchase_receipt(sle, outgoing_rate)
+
+ def update_rate_on_stock_entry(self, sle, outgoing_rate):
+ frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate)
+
+ # Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
+ stock_entry = frappe.get_doc("Stock Entry", sle.voucher_no)
+ stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)
+ stock_entry.db_update()
+ for d in stock_entry.items:
+ d.db_update()
+
+ def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate):
+ # Update item's incoming rate on transaction
+ item_code = frappe.db.get_value(sle.voucher_type + " Item", sle.voucher_detail_no, "item_code")
+ if item_code == sle.item_code:
+ frappe.db.set_value(sle.voucher_type + " Item", sle.voucher_detail_no, "incoming_rate", outgoing_rate)
+ else:
+ # packed item
+ frappe.db.set_value("Packed Item",
+ {"parent_detail_docname": sle.voucher_detail_no, "item_code": sle.item_code},
+ "incoming_rate", outgoing_rate)
+
+ def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
+ if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
+ frappe.db.set_value(sle.voucher_type + " Item", sle.voucher_detail_no, "base_net_rate", outgoing_rate)
+ else:
+ frappe.db.set_value("Purchase Receipt Item Supplied", sle.voucher_detail_no, "rate", outgoing_rate)
+
+ # Recalculate subcontracted item's rate in case of subcontracted purchase receipt/invoice
+ if frappe.db.get_value(sle.voucher_type, sle.voucher_no, "is_subcontracted"):
+ doc = frappe.get_doc(sle.voucher_type, sle.voucher_no)
+ doc.update_valuation_rate(reset_outgoing_rate=False)
+ for d in (doc.items + doc.supplied_items):
+ d.db_update()
+
def get_serialized_values(self, sle):
incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty)
@@ -228,7 +452,7 @@
if incoming_rate < 0:
# wrong incoming rate
- incoming_rate = self.valuation_rate
+ incoming_rate = self.wh_data.valuation_rate
stock_value_change = 0
if incoming_rate:
@@ -236,22 +460,25 @@
elif actual_qty < 0:
# In case of delivery/stock issue, get average purchase rate
# of serial nos of current entry
- outgoing_value = self.get_incoming_value_for_serial_nos(sle, serial_nos)
- stock_value_change = -1 * outgoing_value
+ if not sle.is_cancelled:
+ outgoing_value = self.get_incoming_value_for_serial_nos(sle, serial_nos)
+ stock_value_change = -1 * outgoing_value
+ else:
+ stock_value_change = actual_qty * sle.outgoing_rate
- new_stock_qty = self.qty_after_transaction + actual_qty
+ new_stock_qty = self.wh_data.qty_after_transaction + actual_qty
if new_stock_qty > 0:
- new_stock_value = (self.qty_after_transaction * self.valuation_rate) + stock_value_change
+ new_stock_value = (self.wh_data.qty_after_transaction * self.wh_data.valuation_rate) + stock_value_change
if new_stock_value >= 0:
# calculate new valuation rate only if stock value is positive
# else it remains the same as that of previous entry
- self.valuation_rate = new_stock_value / new_stock_qty
+ self.wh_data.valuation_rate = new_stock_value / new_stock_qty
- if not self.valuation_rate and sle.voucher_detail_no:
+ if not self.wh_data.valuation_rate and sle.voucher_detail_no:
allow_zero_rate = self.check_if_allow_zero_valuation_rate(sle.voucher_type, sle.voucher_detail_no)
if not allow_zero_rate:
- self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
+ self.wh_data.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
currency=erpnext.get_company_currency(sle.company))
@@ -287,39 +514,38 @@
def get_moving_average_values(self, sle):
actual_qty = flt(sle.actual_qty)
- new_stock_qty = flt(self.qty_after_transaction) + actual_qty
+ new_stock_qty = flt(self.wh_data.qty_after_transaction) + actual_qty
if new_stock_qty >= 0:
if actual_qty > 0:
- if flt(self.qty_after_transaction) <= 0:
- self.valuation_rate = sle.incoming_rate
+ if flt(self.wh_data.qty_after_transaction) <= 0:
+ self.wh_data.valuation_rate = sle.incoming_rate
else:
- new_stock_value = (self.qty_after_transaction * self.valuation_rate) + \
+ new_stock_value = (self.wh_data.qty_after_transaction * self.wh_data.valuation_rate) + \
(actual_qty * sle.incoming_rate)
- self.valuation_rate = new_stock_value / new_stock_qty
+ self.wh_data.valuation_rate = new_stock_value / new_stock_qty
elif sle.outgoing_rate:
if new_stock_qty:
- new_stock_value = (self.qty_after_transaction * self.valuation_rate) + \
+ new_stock_value = (self.wh_data.qty_after_transaction * self.wh_data.valuation_rate) + \
(actual_qty * sle.outgoing_rate)
- self.valuation_rate = new_stock_value / new_stock_qty
+ self.wh_data.valuation_rate = new_stock_value / new_stock_qty
else:
- self.valuation_rate = sle.outgoing_rate
-
+ self.wh_data.valuation_rate = sle.outgoing_rate
else:
- if flt(self.qty_after_transaction) >= 0 and sle.outgoing_rate:
- self.valuation_rate = sle.outgoing_rate
+ if flt(self.wh_data.qty_after_transaction) >= 0 and sle.outgoing_rate:
+ self.wh_data.valuation_rate = sle.outgoing_rate
- if not self.valuation_rate and actual_qty > 0:
- self.valuation_rate = sle.incoming_rate
+ if not self.wh_data.valuation_rate and actual_qty > 0:
+ self.wh_data.valuation_rate = sle.incoming_rate
# Get valuation rate from previous SLE or Item master, if item does not have the
# allow zero valuration rate flag set
- if not self.valuation_rate and sle.voucher_detail_no:
+ if not self.wh_data.valuation_rate and sle.voucher_detail_no:
allow_zero_valuation_rate = self.check_if_allow_zero_valuation_rate(sle.voucher_type, sle.voucher_detail_no)
if not allow_zero_valuation_rate:
- self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
+ self.wh_data.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
currency=erpnext.get_company_currency(sle.company))
@@ -329,22 +555,22 @@
outgoing_rate = flt(sle.outgoing_rate)
if actual_qty > 0:
- if not self.stock_queue:
- self.stock_queue.append([0, 0])
+ if not self.wh_data.stock_queue:
+ self.wh_data.stock_queue.append([0, 0])
# last row has the same rate, just updated the qty
- if self.stock_queue[-1][1]==incoming_rate:
- self.stock_queue[-1][0] += actual_qty
+ if self.wh_data.stock_queue[-1][1]==incoming_rate:
+ self.wh_data.stock_queue[-1][0] += actual_qty
else:
- if self.stock_queue[-1][0] > 0:
- self.stock_queue.append([actual_qty, incoming_rate])
+ if self.wh_data.stock_queue[-1][0] > 0:
+ self.wh_data.stock_queue.append([actual_qty, incoming_rate])
else:
- qty = self.stock_queue[-1][0] + actual_qty
- self.stock_queue[-1] = [qty, incoming_rate]
+ qty = self.wh_data.stock_queue[-1][0] + actual_qty
+ self.wh_data.stock_queue[-1] = [qty, incoming_rate]
else:
qty_to_pop = abs(actual_qty)
while qty_to_pop:
- if not self.stock_queue:
+ if not self.wh_data.stock_queue:
# Get valuation rate from last sle if exists or from valuation rate field in item master
allow_zero_valuation_rate = self.check_if_allow_zero_valuation_rate(sle.voucher_type, sle.voucher_detail_no)
if not allow_zero_valuation_rate:
@@ -354,35 +580,35 @@
else:
_rate = 0
- self.stock_queue.append([0, _rate])
+ self.wh_data.stock_queue.append([0, _rate])
index = None
if outgoing_rate > 0:
# Find the entry where rate matched with outgoing rate
- for i, v in enumerate(self.stock_queue):
+ for i, v in enumerate(self.wh_data.stock_queue):
if v[1] == outgoing_rate:
index = i
break
# If no entry found with outgoing rate, collapse stack
if index == None:
- new_stock_value = sum((d[0]*d[1] for d in self.stock_queue)) - qty_to_pop*outgoing_rate
- new_stock_qty = sum((d[0] for d in self.stock_queue)) - qty_to_pop
- self.stock_queue = [[new_stock_qty, new_stock_value/new_stock_qty if new_stock_qty > 0 else outgoing_rate]]
+ new_stock_value = sum((d[0]*d[1] for d in self.wh_data.stock_queue)) - qty_to_pop*outgoing_rate
+ new_stock_qty = sum((d[0] for d in self.wh_data.stock_queue)) - qty_to_pop
+ self.wh_data.stock_queue = [[new_stock_qty, new_stock_value/new_stock_qty if new_stock_qty > 0 else outgoing_rate]]
break
else:
index = 0
# select first batch or the batch with same rate
- batch = self.stock_queue[index]
+ batch = self.wh_data.stock_queue[index]
if qty_to_pop >= batch[0]:
# consume current batch
qty_to_pop = qty_to_pop - batch[0]
- self.stock_queue.pop(index)
- if not self.stock_queue and qty_to_pop:
+ self.wh_data.stock_queue.pop(index)
+ if not self.wh_data.stock_queue and qty_to_pop:
# stock finished, qty still remains to be withdrawn
# negative stock, keep in as a negative batch
- self.stock_queue.append([-qty_to_pop, outgoing_rate or batch[1]])
+ self.wh_data.stock_queue.append([-qty_to_pop, outgoing_rate or batch[1]])
break
else:
@@ -391,14 +617,14 @@
batch[0] = batch[0] - qty_to_pop
qty_to_pop = 0
- stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in self.stock_queue))
- stock_qty = sum((flt(batch[0]) for batch in self.stock_queue))
+ stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in self.wh_data.stock_queue))
+ stock_qty = sum((flt(batch[0]) for batch in self.wh_data.stock_queue))
if stock_qty:
- self.valuation_rate = stock_value / flt(stock_qty)
+ self.wh_data.valuation_rate = stock_value / flt(stock_qty)
- if not self.stock_queue:
- self.stock_queue.append([0, sle.incoming_rate or sle.outgoing_rate or self.valuation_rate])
+ if not self.wh_data.stock_queue:
+ self.wh_data.stock_queue.append([0, sle.incoming_rate or sle.outgoing_rate or self.wh_data.valuation_rate])
def check_if_allow_zero_valuation_rate(self, voucher_type, voucher_detail_no):
ref_item_dt = ""
@@ -413,39 +639,55 @@
else:
return 0
- def get_sle_before_datetime(self):
+ def get_sle_before_datetime(self, args):
"""get previous stock ledger entry before current time-bucket"""
- if self.args.get('sle_id'):
- self.args['name'] = self.args.get('sle_id')
+ sle = get_stock_ledger_entries(args, "<", "desc", "limit 1", for_update=False)
+ sle = sle[0] if sle else frappe._dict()
+ return sle
- return get_stock_ledger_entries(self.args, "<=", "desc", "limit 1", for_update=False)
-
- def get_sle_after_datetime(self):
+ def get_sle_after_datetime(self, args):
"""get Stock Ledger Entries after a particular datetime, for reposting"""
- return get_stock_ledger_entries(self.previous_sle or frappe._dict({
- "item_code": self.args.get("item_code"), "warehouse": self.args.get("warehouse") }),
- ">", "asc", for_update=True, check_serial_no=False)
+ return get_stock_ledger_entries(args, ">", "asc", for_update=True, check_serial_no=False)
def raise_exceptions(self):
- deficiency = min(e["diff"] for e in self.exceptions)
+ msg_list = []
+ for warehouse, exceptions in iteritems(self.exceptions):
+ deficiency = min(e["diff"] for e in exceptions)
- if ((self.exceptions[0]["voucher_type"], self.exceptions[0]["voucher_no"]) in
- frappe.local.flags.currently_saving):
+ if ((exceptions[0]["voucher_type"], exceptions[0]["voucher_no"]) in
+ frappe.local.flags.currently_saving):
- msg = _("{0} units of {1} needed in {2} to complete this transaction.").format(
- abs(deficiency), frappe.get_desk_link('Item', self.item_code),
- frappe.get_desk_link('Warehouse', self.warehouse))
- else:
- msg = _("{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction.").format(
- abs(deficiency), frappe.get_desk_link('Item', self.item_code),
- frappe.get_desk_link('Warehouse', self.warehouse),
- self.exceptions[0]["posting_date"], self.exceptions[0]["posting_time"],
- frappe.get_desk_link(self.exceptions[0]["voucher_type"], self.exceptions[0]["voucher_no"]))
+ msg = _("{0} units of {1} needed in {2} to complete this transaction.").format(
+ abs(deficiency), frappe.get_desk_link('Item', exceptions[0]["item_code"]),
+ frappe.get_desk_link('Warehouse', warehouse))
+ else:
+ msg = _("{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction.").format(
+ abs(deficiency), frappe.get_desk_link('Item', exceptions[0]["item_code"]),
+ frappe.get_desk_link('Warehouse', warehouse),
+ exceptions[0]["posting_date"], exceptions[0]["posting_time"],
+ frappe.get_desk_link(exceptions[0]["voucher_type"], exceptions[0]["voucher_no"]))
- if self.verbose:
- frappe.throw(msg, NegativeStockError, title='Insufficient Stock')
- else:
- raise NegativeStockError(msg)
+ if msg:
+ msg_list.append(msg)
+
+ if msg_list:
+ message = "\n\n".join(msg_list)
+ if self.verbose:
+ frappe.throw(message, NegativeStockError, title='Insufficient Stock')
+ else:
+ raise NegativeStockError(message)
+
+ def update_bin(self):
+ # update bin for each warehouse
+ for warehouse, data in iteritems(self.data):
+ bin_doc = get_bin(self.item_code, warehouse)
+ bin_doc.update({
+ "valuation_rate": data.valuation_rate,
+ "actual_qty": data.qty_after_transaction,
+ "stock_value": data.stock_value
+ })
+ bin_doc.flags.via_stock_ledger_entry = True
+ bin_doc.save(ignore_permissions=True)
def get_previous_sle(args, for_update=False):
"""
@@ -489,6 +731,7 @@
select *, timestamp(posting_date, posting_time) as "timestamp"
from `tabStock Ledger Entry`
where item_code = %%(item_code)s
+ and is_cancelled = 0
%(conditions)s
order by timestamp(posting_date, posting_time) %(order)s, creation %(order)s
%(limit)s %(for_update)s""" % {
@@ -498,10 +741,11 @@
"order": order
}, previous_sle, as_dict=1, debug=debug)
-def get_sle_by_id(sle_id):
- return frappe.db.get_all('Stock Ledger Entry',
- fields=['*', 'timestamp(posting_date, posting_time) as timestamp'],
- filters={'name': sle_id})[0]
+def get_sle_by_voucher_detail_no(voucher_detail_no, excluded_sle=None):
+ return frappe.db.get_value('Stock Ledger Entry',
+ {'voucher_detail_no': voucher_detail_no, 'name': ['!=', excluded_sle]},
+ ['item_code', 'warehouse', 'posting_date', 'posting_time', 'timestamp(posting_date, posting_time) as timestamp'],
+ as_dict=1)
def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
allow_zero_rate=False, currency=None, company=None, raise_error_if_no_rate=True):
@@ -529,7 +773,7 @@
order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, voucher_no, voucher_type))
if last_valuation_rate:
- return flt(last_valuation_rate[0][0]) # as there is previous records, it might come with zero rate
+ return flt(last_valuation_rate[0][0])
# If negative stock allowed, and item delivered without any incoming entry,
# system does not found any SLE, then take valuation rate from Item
@@ -561,3 +805,55 @@
frappe.throw(msg=msg, title=_("Valuation Rate Missing"))
return valuation_rate
+
+def update_qty_in_future_sle(args, allow_negative_stock=None):
+ frappe.db.sql("""
+ update `tabStock Ledger Entry`
+ set qty_after_transaction = qty_after_transaction + {qty}
+ where
+ item_code = %(item_code)s
+ and warehouse = %(warehouse)s
+ and voucher_no != %(voucher_no)s
+ and is_cancelled = 0
+ and (timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s)
+ or (
+ timestamp(posting_date, posting_time) = timestamp(%(posting_date)s, %(posting_time)s)
+ and creation > %(creation)s
+ )
+ )
+ """.format(qty=args.actual_qty), args)
+
+ validate_negative_qty_in_future_sle(args, allow_negative_stock)
+
+def validate_negative_qty_in_future_sle(args, allow_negative_stock=None):
+ allow_negative_stock = allow_negative_stock \
+ or cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
+
+ if args.actual_qty < 0 and not allow_negative_stock:
+ sle = get_future_sle_with_negative_qty(args)
+ if sle:
+ message = _("{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction.").format(
+ abs(sle[0]["qty_after_transaction"]),
+ frappe.get_desk_link('Item', args.item_code),
+ frappe.get_desk_link('Warehouse', args.warehouse),
+ sle[0]["posting_date"], sle[0]["posting_time"],
+ frappe.get_desk_link(sle[0]["voucher_type"], sle[0]["voucher_no"]))
+
+ frappe.throw(message, NegativeStockError, title='Insufficient Stock')
+
+def get_future_sle_with_negative_qty(args):
+ return frappe.db.sql("""
+ select
+ qty_after_transaction, posting_date, posting_time,
+ voucher_type, voucher_no
+ from `tabStock Ledger Entry`
+ where
+ item_code = %(item_code)s
+ and warehouse = %(warehouse)s
+ and voucher_no != %(voucher_no)s
+ and timestamp(posting_date, posting_time) >= timestamp(%(posting_date)s, %(posting_time)s)
+ and is_cancelled = 0
+ and qty_after_transaction < 0
+ order by timestamp(posting_date, posting_time) asc
+ limit 1
+ """, args, as_dict=1)
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 11e758f..0af3d90 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -5,7 +5,7 @@
import frappe, erpnext
from frappe import _
import json
-from frappe.utils import flt, cstr, nowdate, nowtime
+from frappe.utils import flt, cstr, nowdate, nowtime, get_link_to_form
from six import string_types
@@ -63,6 +63,7 @@
SELECT item_code, stock_value, name, warehouse
FROM `tabStock Ledger Entry` sle
WHERE posting_date <= %s {0}
+ and is_cancelled = 0
ORDER BY timestamp(posting_date, posting_time) DESC, creation DESC
""".format(condition), values, as_dict=1)
@@ -211,7 +212,7 @@
currency=erpnext.get_company_currency(args.get('company')), company=args.get('company'),
raise_error_if_no_rate=raise_error_if_no_rate)
- return in_rate
+ return flt(in_rate)
def get_avg_purchase_rate(serial_nos):
"""get average value of serial numbers"""
@@ -283,12 +284,15 @@
if frappe.db.get_value("Warehouse", warehouse, "is_group"):
frappe.throw(_("Group node warehouse is not allowed to select for transactions"))
+def validate_disabled_warehouse(warehouse):
+ if frappe.db.get_value("Warehouse", warehouse, "disabled"):
+ frappe.throw(_("Disabled Warehouse {0} cannot be used for this transaction.").format(get_link_to_form('Warehouse', warehouse)))
+
def update_included_uom_in_report(columns, result, include_uom, conversion_factors):
if not include_uom or not conversion_factors:
return
convertible_cols = {}
-
is_dict_obj = False
if isinstance(result[0], dict):
is_dict_obj = True
@@ -310,13 +314,13 @@
for row_idx, row in enumerate(result):
data = row.items() if is_dict_obj else enumerate(row)
for key, value in data:
- if not key in convertible_columns or not conversion_factors[row_idx]:
+ if key not in convertible_columns or not conversion_factors[row_idx-1]:
continue
if convertible_columns.get(key) == 'rate':
- new_value = flt(value) * conversion_factors[row_idx]
+ new_value = flt(value) * conversion_factors[row_idx-1]
else:
- new_value = flt(value) / conversion_factors[row_idx]
+ new_value = flt(value) / conversion_factors[row_idx-1]
if not is_dict_obj:
row.insert(key+1, new_value)
@@ -376,4 +380,10 @@
outgoing_rate = outgoing_rate[0][0] if outgoing_rate else 0.0
- return outgoing_rate
\ No newline at end of file
+ return outgoing_rate
+
+def is_reposting_item_valuation_in_progress():
+ reposting_in_progress = frappe.db.exists("Repost Item Valuation",
+ {'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
+ if reposting_in_progress:
+ frappe.msgprint(_("Item valuation reposting in progress. Report might show incorrect item valuation."), alert=1)
\ No newline at end of file
diff --git a/erpnext/stock/workspace/stock/stock.json b/erpnext/stock/workspace/stock/stock.json
new file mode 100644
index 0000000..3221dc4
--- /dev/null
+++ b/erpnext/stock/workspace/stock/stock.json
@@ -0,0 +1,721 @@
+{
+ "cards_label": "Masters & Reports",
+ "category": "Modules",
+ "charts": [
+ {
+ "chart_name": "Warehouse wise Stock Value"
+ }
+ ],
+ "creation": "2020-03-02 15:43:10.096528",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "stock",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Stock",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Items and Pricing",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item",
+ "link_to": "Item",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Group",
+ "link_to": "Item Group",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Product Bundle",
+ "link_to": "Product Bundle",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Price List",
+ "link_to": "Price List",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Price",
+ "link_to": "Item Price",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Shipping Rule",
+ "link_to": "Shipping Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Pricing Rule",
+ "link_to": "Pricing Rule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Alternative",
+ "link_to": "Item Alternative",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Manufacturer",
+ "link_to": "Item Manufacturer",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Customs Tariff Number",
+ "link_to": "Customs Tariff Number",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Transactions",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Material Request",
+ "link_to": "Material Request",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Entry",
+ "link_to": "Stock Entry",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Customer",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Delivery Note",
+ "link_to": "Delivery Note",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item, Supplier",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Purchase Receipt",
+ "link_to": "Purchase Receipt",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Pick List",
+ "link_to": "Pick List",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Delivery Trip",
+ "link_to": "Delivery Trip",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock Ledger",
+ "link_to": "Stock Ledger",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock Balance",
+ "link_to": "Stock Balance",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock Projected Qty",
+ "link_to": "Stock Projected Qty",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Summary",
+ "link_to": "stock-balance",
+ "link_type": "Page",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock Ageing",
+ "link_to": "Stock Ageing",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item Price Stock",
+ "link_to": "Item Price Stock",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Settings",
+ "link_to": "Stock Settings",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Warehouse",
+ "link_to": "Warehouse",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Unit of Measure (UOM)",
+ "link_to": "UOM",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Variant Settings",
+ "link_to": "Item Variant Settings",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Brand",
+ "link_to": "Brand",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item Attribute",
+ "link_to": "Item Attribute",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "UOM Conversion Factor",
+ "link_to": "UOM Conversion Factor",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Serial No and Batch",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Serial No",
+ "link_to": "Serial No",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Batch",
+ "link_to": "Batch",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Installation Note",
+ "link_to": "Installation Note",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Serial No",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Serial No Service Contract Expiry",
+ "link_to": "Serial No Service Contract Expiry",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Serial No",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Serial No Status",
+ "link_to": "Serial No Status",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Serial No",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Serial No Warranty Expiry",
+ "link_to": "Serial No Warranty Expiry",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tools",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Stock Reconciliation",
+ "link_to": "Stock Reconciliation",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Landed Cost Voucher",
+ "link_to": "Landed Cost Voucher",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Packing Slip",
+ "link_to": "Packing Slip",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Inspection",
+ "link_to": "Quality Inspection",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quality Inspection Template",
+ "link_to": "Quality Inspection Template",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quick Stock Balance",
+ "link_to": "Quick Stock Balance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Key Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Item Price",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item-wise Price List Rate",
+ "link_to": "Item-wise Price List Rate",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Stock Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock Analytics",
+ "link_to": "Stock Analytics",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock Qty vs Serial No Count",
+ "link_to": "Stock Qty vs Serial No Count",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Delivery Note",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Delivery Note Trends",
+ "link_to": "Delivery Note Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Receipt",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Receipt Trends",
+ "link_to": "Purchase Receipt Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Order Analysis",
+ "link_to": "Sales Order Analysis",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Purchase Order Analysis",
+ "link_to": "Purchase Order Analysis",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Bin",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item Shortage Report",
+ "link_to": "Item Shortage Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Batch",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Batch-Wise Balance History",
+ "link_to": "Batch-Wise Balance History",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Other Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Material Request",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Requested Items To Be Transferred",
+ "link_to": "Requested Items To Be Transferred",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Stock Ledger Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Batch Item Expiry Status",
+ "link_to": "Batch Item Expiry Status",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Price List",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item Prices",
+ "link_to": "Item Prices",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Itemwise Recommended Reorder Level",
+ "link_to": "Itemwise Recommended Reorder Level",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item Variant Details",
+ "link_to": "Item Variant Details",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Subcontracted Raw Materials To Be Transferred",
+ "link_to": "Subcontracted Raw Materials To Be Transferred",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Purchase Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Subcontracted Item To Be Received",
+ "link_to": "Subcontracted Item To Be Received",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Stock Ledger Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Stock and Account Value Comparison",
+ "link_to": "Stock and Account Value Comparison",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:36.282890",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Stock",
+ "onboarding": "Stock",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Green",
+ "format": "{} Available",
+ "label": "Item",
+ "link_to": "Item",
+ "stats_filter": "{\n \"disabled\" : 0\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} Pending",
+ "label": "Material Request",
+ "link_to": "Material Request",
+ "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Pending\"\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Stock Entry",
+ "link_to": "Stock Entry",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} To Bill",
+ "label": "Purchase Receipt",
+ "link_to": "Purchase Receipt",
+ "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Bill\"\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Yellow",
+ "format": "{} To Bill",
+ "label": "Delivery Note",
+ "link_to": "Delivery Note",
+ "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Bill\"\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Stock Ledger",
+ "link_to": "Stock Ledger",
+ "type": "Report"
+ },
+ {
+ "label": "Stock Balance",
+ "link_to": "Stock Balance",
+ "type": "Report"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Stock",
+ "type": "Dashboard"
+ }
+ ],
+ "shortcuts_label": "Quick Access"
+}
\ No newline at end of file
diff --git a/erpnext/support/desk_page/support/support.json b/erpnext/support/desk_page/support/support.json
deleted file mode 100644
index 28410f3..0000000
--- a/erpnext/support/desk_page/support/support.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "cards": [
- {
- "hidden": 0,
- "label": "Issues",
- "links": "[\n {\n \"description\": \"Support queries from customers.\",\n \"label\": \"Issue\",\n \"name\": \"Issue\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Issue Type.\",\n \"label\": \"Issue Type\",\n \"name\": \"Issue Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Issue Priority.\",\n \"label\": \"Issue Priority\",\n \"name\": \"Issue Priority\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Maintenance",
- "links": "[\n {\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Service Level Agreement",
- "links": "[\n {\n \"description\": \"Service Level Agreement.\",\n \"label\": \"Service Level Agreement\",\n \"name\": \"Service Level Agreement\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Warranty",
- "links": "[\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Single unit of an Item.\",\n \"label\": \"Serial No\",\n \"name\": \"Serial No\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Settings",
- "links": "[\n {\n \"label\": \"Support Settings\",\n \"name\": \"Support Settings\",\n \"type\": \"doctype\"\n }\n]"
- },
- {
- "hidden": 0,
- "label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"First Response Time for Issues\",\n \"name\": \"First Response Time for Issues\",\n \"type\": \"report\"\n }\n]"
- }
- ],
- "category": "Modules",
- "charts": [],
- "creation": "2020-03-02 15:48:23.224699",
- "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": "Support",
- "modified": "2020-08-11 15:49:34.307341",
- "modified_by": "Administrator",
- "module": "Support",
- "name": "Support",
- "owner": "Administrator",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
- "shortcuts": [
- {
- "color": "#ffc4c4",
- "format": "{} Assigned",
- "label": "Issue",
- "link_to": "Issue",
- "stats_filter": "{\n \"_assign\": [\"like\", '%' + frappe.session.user + '%'],\n \"status\": \"Open\"\n}",
- "type": "DocType"
- },
- {
- "label": "Maintenance Visit",
- "link_to": "Maintenance Visit",
- "type": "DocType"
- },
- {
- "label": "Service Level Agreement",
- "link_to": "Service Level Agreement",
- "type": "DocType"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index fe01d4b..9fe12f9 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -1,6 +1,13 @@
frappe.ui.form.on("Issue", {
onload: function(frm) {
frm.email_field = "raised_by";
+ frm.set_query("customer", function () {
+ return {
+ filters: {
+ "disabled": 0
+ }
+ };
+ });
frappe.db.get_value("Support Settings", {name: "Support Settings"},
["allow_resetting_service_level_agreement", "track_service_level_agreement"], (r) => {
@@ -21,14 +28,14 @@
},
callback: function (r) {
if (r && r.message) {
- frm.set_query('priority', function() {
+ frm.set_query("priority", function() {
return {
filters: {
"name": ["in", r.message.priority],
}
};
});
- frm.set_query('service_level_agreement', function() {
+ frm.set_query("service_level_agreement", function() {
return {
filters: {
"name": ["in", r.message.service_level_agreements],
@@ -42,12 +49,12 @@
},
refresh: function (frm) {
- if (frm.doc.status !== "Closed" && frm.doc.agreement_status === "Ongoing") {
- if (frm.doc.service_level_agreement) {
+ if (frm.doc.status !== "Closed") {
+ if (frm.doc.service_level_agreement && frm.doc.agreement_status === "Ongoing") {
frappe.call({
- 'method': 'frappe.client.get',
+ "method": "frappe.client.get",
args: {
- doctype: 'Service Level Agreement',
+ doctype: "Service Level Agreement",
name: frm.doc.service_level_agreement
},
callback: function(data) {
@@ -127,8 +134,8 @@
reset_sla.clear();
frappe.show_alert({
- indicator: 'green',
- message: __('Resetting Service Level Agreement.')
+ indicator: "green",
+ message: __("Resetting Service Level Agreement.")
});
frm.call("reset_service_level_agreement", {
@@ -145,56 +152,73 @@
reset_sla.show();
},
- timeline_refresh: function(frm) {
- // create button for "Help Article"
- if(frappe.model.can_create('Help Article')) {
- // Removing Help Article button if exists to avoid multiple occurance
- frm.timeline.wrapper.find('.comment-header .asset-details .btn-add-to-kb').remove();
- $('<button class="btn btn-xs btn-link btn-add-to-kb text-muted hidden-xs pull-right">'+
- __('Help Article') + '</button>')
- .appendTo(frm.timeline.wrapper.find('.comment-header .asset-details:not([data-communication-type="Comment"])'))
- .on('click', function() {
- var content = $(this).parents('.timeline-item:first').find('.timeline-item-content').html();
- var doc = frappe.model.get_new_doc('Help Article');
- doc.title = frm.doc.subject;
- doc.content = content;
- frappe.set_route('Form', 'Help Article', doc.name);
- });
- }
- if (!frm.timeline.wrapper.find('.btn-split-issue').length) {
- let split_issue = __("Split Issue")
- $(`<button class="btn btn-xs btn-link btn-add-to-kb text-muted hidden-xs btn-split-issue pull-right" style="display:inline-block; margin-right: 15px">
- ${split_issue}
- </button>`)
- .appendTo(frm.timeline.wrapper.find('.comment-header .asset-details:not([data-communication-type="Comment"])'))
- if (!frm.timeline.wrapper.data("split-issue-event-attached")){
+ timeline_refresh: function(frm) {
+ if (!frm.timeline.wrapper.find(".btn-split-issue").length) {
+ let split_issue_btn = $(`
+ <a class="action-btn btn-split-issue" title="${__("Split Issue")}">
+ ${frappe.utils.icon('branch', 'sm')}
+ </a>
+ `);
+
+ let communication_box = frm.timeline.wrapper.find('.timeline-item[data-doctype="Communication"]');
+ communication_box.find('.actions').prepend(split_issue_btn);
+
+ if (!frm.timeline.wrapper.data("split-issue-event-attached")) {
frm.timeline.wrapper.on('click', '.btn-split-issue', (e) => {
var dialog = new frappe.ui.Dialog({
title: __("Split Issue"),
fields: [
- {fieldname: 'subject', fieldtype: 'Data', reqd:1, label: __('Subject'), description: __('All communications including and above this shall be moved into the new Issue')}
+ {
+ fieldname: "subject",
+ fieldtype: "Data",
+ reqd: 1,
+ label: __("Subject"),
+ description: __("All communications including and above this shall be moved into the new Issue")
+ }
],
primary_action_label: __("Split"),
- primary_action: function() {
+ primary_action: () => {
frm.call("split_issue", {
subject: dialog.fields_dict.subject.value,
communication_id: e.currentTarget.closest(".timeline-item").getAttribute("data-name")
}, (r) => {
- let url = window.location.href
- let arr = url.split("/");
- let result = arr[0] + "//" + arr[2]
- frappe.msgprint(`New issue created: <a href="${result}/desk#Form/Issue/${r.message}">${r.message}</a>`)
+ frappe.msgprint(`New issue created: <a href="/app/issue/${r.message}">${r.message}</a>`);
frm.reload_doc();
dialog.hide();
});
}
});
- dialog.show()
- })
- frm.timeline.wrapper.data("split-issue-event-attached", true)
+ dialog.show();
+ });
+ frm.timeline.wrapper.data("split-issue-event-attached", true);
}
}
+
+ // create button for "Help Article"
+ // if (frappe.model.can_create("Help Article")) {
+ // // Removing Help Article button if exists to avoid multiple occurrence
+ // frm.timeline.wrapper.find('.action-btn .btn-add-to-kb').remove();
+
+ // let help_article = $(`
+ // <a class="action-btn btn-add-to-kb" title="${__('Help Article')}">
+ // ${frappe.utils.icon('solid-info', 'sm')}
+ // </a>
+ // `);
+
+ // let communication_box = frm.timeline.wrapper.find('.timeline-item[data-doctype="Communication"]');
+ // communication_box.find('.actions').prepend(help_article);
+ // if (!frm.timeline.wrapper.data("help-article-event-attached")) {
+ // frm.timeline.wrapper.on('click', '.btn-add-to-kb', function () {
+ // const content = $(this).parents('.timeline-item[data-doctype="Communication"]:first').find(".content").html();
+ // const doc = frappe.model.get_new_doc("Help Article");
+ // doc.title = frm.doc.subject;
+ // doc.content = content;
+ // frappe.set_route("Form", "Help Article", doc.name);
+ // });
+ // }
+ // frm.timeline.wrapper.data("help-article-event-attached", true);
+ // }
},
});
@@ -226,7 +250,7 @@
function get_time_left(timestamp, agreement_status) {
const diff = moment(timestamp).diff(moment());
const diff_display = diff >= 44500 ? moment.duration(diff).humanize() : "Failed";
- let indicator = (diff_display == 'Failed' && agreement_status != "Fulfilled") ? "red" : "green";
+ let indicator = (diff_display == "Failed" && agreement_status != "Fulfilled") ? "red" : "green";
return {"diff_display": diff_display, "indicator": indicator};
}
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 920c13c..bbbbc4a 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -7,7 +7,7 @@
from frappe import _
from frappe import utils
from frappe.model.document import Document
-from frappe.utils import time_diff_in_hours, now_datetime, getdate, get_weekdays, add_to_date, today, get_time, get_datetime, time_diff_in_seconds, time_diff
+from frappe.utils import now_datetime, getdate, get_weekdays, add_to_date, get_time, get_datetime, time_diff_in_seconds
from datetime import datetime, timedelta
from frappe.model.mapper import get_mapped_doc
from frappe.utils.user import is_website_user
@@ -207,14 +207,17 @@
"comment_type": "Info",
"reference_doctype": "Issue",
"reference_name": replicated_issue.name,
- "content": " - Split the Issue from <a href='#Form/Issue/{0}'>{1}</a>".format(self.name, frappe.bold(self.name)),
+ "content": " - Split the Issue from <a href='/app/Form/Issue/{0}'>{1}</a>".format(self.name, frappe.bold(self.name)),
}).insert(ignore_permissions=True)
return replicated_issue.name
def before_insert(self):
if frappe.db.get_single_value("Support Settings", "track_service_level_agreement"):
- self.set_response_and_resolution_time()
+ if frappe.flags.in_test:
+ self.set_response_and_resolution_time(priority=self.priority, service_level_agreement=self.service_level_agreement)
+ else:
+ self.set_response_and_resolution_time()
def set_response_and_resolution_time(self, priority=None, service_level_agreement=None):
service_level_agreement = get_active_service_level_agreement_for(priority=priority,
@@ -355,13 +358,13 @@
doc = frappe.get_doc("Issue", issue.name)
if not doc.first_responded_on: # first_responded_on set when first reply is sent to customer
- variance = round(time_diff_in_hours(doc.response_by, current_time), 2)
+ variance = round(time_diff_in_seconds(doc.response_by, current_time), 2)
frappe.db.set_value(dt="Issue", dn=doc.name, field="response_by_variance", val=variance, update_modified=False)
if variance < 0:
frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
if not doc.resolution_date: # resolution_date set when issue has been closed
- variance = round(time_diff_in_hours(doc.resolution_by, current_time), 2)
+ variance = round(time_diff_in_seconds(doc.resolution_by, current_time), 2)
frappe.db.set_value(dt="Issue", dn=doc.name, field="resolution_by_variance", val=variance, update_modified=False)
if variance < 0:
frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
diff --git a/erpnext/support/doctype/issue/issue_list.js b/erpnext/support/doctype/issue/issue_list.js
index 513a8dc..e04498e 100644
--- a/erpnext/support/doctype/issue/issue_list.js
+++ b/erpnext/support/doctype/issue/issue_list.js
@@ -28,7 +28,7 @@
} else if (doc.status === 'Closed') {
return [__(doc.status), "green", "status,=," + doc.status];
} else {
- return [__(doc.status), "darkgrey", "status,=," + doc.status];
+ return [__(doc.status), "gray", "status,=," + doc.status];
}
}
}
diff --git a/erpnext/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index c962dc6..46d02d8 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -12,7 +12,6 @@
class TestIssue(unittest.TestCase):
def setUp(self):
frappe.db.sql("delete from `tabService Level Agreement`")
- frappe.db.sql("delete from `tabEmployee`")
frappe.db.set_value("Support Settings", None, "track_service_level_agreement", 1)
create_service_level_agreements_for_issues()
@@ -135,15 +134,19 @@
self.assertEqual(flt(issue.total_hold_time, 2), 2700)
-def make_issue(creation=None, customer=None, index=0):
+def make_issue(creation=None, customer=None, index=0, priority=None, issue_type=None):
issue = frappe.get_doc({
"doctype": "Issue",
"subject": "Service Level Agreement Issue {0}".format(index),
"customer": customer,
"raised_by": "test@example.com",
"description": "Service Level Agreement Issue",
+ "issue_type": issue_type,
+ "priority": priority,
"creation": creation,
- "service_level_agreement_creation": creation
+ "opening_date": creation,
+ "service_level_agreement_creation": creation,
+ "company": "_Test Company"
}).insert(ignore_permissions=True)
return issue
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/support/report/issue_analytics/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/support/report/issue_analytics/__init__.py
diff --git a/erpnext/support/report/issue_analytics/issue_analytics.js b/erpnext/support/report/issue_analytics/issue_analytics.js
new file mode 100644
index 0000000..f87b2c2
--- /dev/null
+++ b/erpnext/support/report/issue_analytics/issue_analytics.js
@@ -0,0 +1,141 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Issue Analytics"] = {
+ "filters": [
+ {
+ fieldname: "company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("Company"),
+ reqd: 1
+ },
+ {
+ fieldname: "based_on",
+ label: __("Based On"),
+ fieldtype: "Select",
+ options: ["Customer", "Issue Type", "Issue Priority", "Assigned To"],
+ default: "Customer",
+ reqd: 1
+ },
+ {
+ fieldname: "from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.defaults.get_global_default("year_start_date"),
+ reqd: 1
+ },
+ {
+ fieldname:"to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.defaults.get_global_default("year_end_date"),
+ reqd: 1
+ },
+ {
+ fieldname: "range",
+ label: __("Range"),
+ fieldtype: "Select",
+ options: [
+ { "value": "Weekly", "label": __("Weekly") },
+ { "value": "Monthly", "label": __("Monthly") },
+ { "value": "Quarterly", "label": __("Quarterly") },
+ { "value": "Yearly", "label": __("Yearly") }
+ ],
+ default: "Monthly",
+ reqd: 1
+ },
+ {
+ fieldname: "status",
+ label: __("Status"),
+ fieldtype: "Select",
+ options:[
+ {label: __('Open'), value: 'Open'},
+ {label: __('Replied'), value: 'Replied'},
+ {label: __('Resolved'), value: 'Resolved'},
+ {label: __('Closed'), value: 'Closed'}
+ ]
+ },
+ {
+ fieldname: "priority",
+ label: __("Issue Priority"),
+ fieldtype: "Link",
+ options: "Issue Priority"
+ },
+ {
+ fieldname: "customer",
+ label: __("Customer"),
+ fieldtype: "Link",
+ options: "Customer"
+ },
+ {
+ fieldname: "project",
+ label: __("Project"),
+ fieldtype: "Link",
+ options: "Project"
+ },
+ {
+ fieldname: "assigned_to",
+ label: __("Assigned To"),
+ fieldtype: "Link",
+ options: "User"
+ }
+ ],
+ 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) {
+ if (data && data.length) {
+ row_name = data[2].content;
+ row_values = data.slice(3).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;
+
+ var found = false;
+
+ for(var 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;
+ }
+ },
+ }
+ });
+ }
+};
\ No newline at end of file
diff --git a/erpnext/support/report/issue_analytics/issue_analytics.json b/erpnext/support/report/issue_analytics/issue_analytics.json
new file mode 100644
index 0000000..dd18498
--- /dev/null
+++ b/erpnext/support/report/issue_analytics/issue_analytics.json
@@ -0,0 +1,26 @@
+{
+ "add_total_row": 1,
+ "columns": [],
+ "creation": "2020-10-09 19:52:10.227317",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-10-11 19:43:19.358625",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Issue Analytics",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Issue",
+ "report_name": "Issue Analytics",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Support Team"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/support/report/issue_analytics/issue_analytics.py b/erpnext/support/report/issue_analytics/issue_analytics.py
new file mode 100644
index 0000000..3fdb10d
--- /dev/null
+++ b/erpnext/support/report/issue_analytics/issue_analytics.py
@@ -0,0 +1,221 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import json
+from six import iteritems
+from frappe import _, scrub
+from frappe.utils import getdate, flt, add_to_date, add_days
+from erpnext.accounts.utils import get_fiscal_year
+
+def execute(filters=None):
+ return IssueAnalytics(filters).run()
+
+class IssueAnalytics(object):
+ def __init__(self, filters=None):
+ """Issue Analytics Report"""
+ self.filters = frappe._dict(filters or {})
+ 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_columns(self):
+ self.columns = []
+
+ if self.filters.based_on == 'Customer':
+ self.columns.append({
+ 'label': _('Customer'),
+ 'options': 'Customer',
+ 'fieldname': 'customer',
+ 'fieldtype': 'Link',
+ 'width': 200
+ })
+
+ elif self.filters.based_on == 'Assigned To':
+ self.columns.append({
+ 'label': _('User'),
+ 'fieldname': 'user',
+ 'fieldtype': 'Link',
+ 'options': 'User',
+ 'width': 200
+ })
+
+ elif self.filters.based_on == 'Issue Type':
+ self.columns.append({
+ 'label': _('Issue Type'),
+ 'fieldname': 'issue_type',
+ 'fieldtype': 'Link',
+ 'options': 'Issue Type',
+ 'width': 200
+ })
+
+ elif self.filters.based_on == 'Issue Priority':
+ self.columns.append({
+ 'label': _('Issue Priority'),
+ 'fieldname': 'priority',
+ 'fieldtype': 'Link',
+ 'options': 'Issue Priority',
+ 'width': 200
+ })
+
+ 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):
+ self.get_issues()
+ self.get_rows()
+
+ def get_period(self, date):
+ months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+ if self.filters.range == 'Weekly':
+ period = 'Week ' + str(date.isocalendar()[1])
+ elif self.filters.range == 'Monthly':
+ period = str(months[date.month - 1])
+ elif self.filters.range == 'Quarterly':
+ period = 'Quarter ' + str(((date.month - 1) // 3) + 1)
+ else:
+ year = get_fiscal_year(date, self.filters.company)
+ period = str(year[0])
+
+ if getdate(self.filters.from_date).year != getdate(self.filters.to_date).year and self.filters.range != 'Yearly':
+ period += ' ' + str(date.year)
+
+ return period
+
+ def get_period_date_ranges(self):
+ from dateutil.relativedelta import relativedelta, MO
+ 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_issues(self):
+ filters = self.get_common_filters()
+ self.field_map = {
+ 'Customer': 'customer',
+ 'Issue Type': 'issue_type',
+ 'Issue Priority': 'priority',
+ 'Assigned To': '_assign'
+ }
+
+ self.entries = frappe.db.get_all('Issue',
+ fields=[self.field_map.get(self.filters.based_on), 'name', 'opening_date'],
+ filters=filters
+ )
+
+ def get_common_filters(self):
+ filters = {}
+ filters['opening_date'] = ('between', [self.filters.from_date, self.filters.to_date])
+
+ if self.filters.get('assigned_to'):
+ filters['_assign'] = ('like', '%' + self.filters.get('assigned_to') + '%')
+
+ for entry in ['company', 'status', 'priority', 'customer', 'project']:
+ 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.issue_periodic_data):
+ if self.filters.based_on == 'Customer':
+ row = {'customer': entity}
+ elif self.filters.based_on == 'Assigned To':
+ row = {'user': entity}
+ elif self.filters.based_on == 'Issue Type':
+ row = {'issue_type': entity}
+ elif self.filters.based_on == 'Issue Priority':
+ row = {'priority': 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.issue_periodic_data = frappe._dict()
+
+ for d in self.entries:
+ period = self.get_period(d.get('opening_date'))
+
+ if self.filters.based_on == 'Assigned To':
+ if d._assign:
+ for entry in json.loads(d._assign):
+ self.issue_periodic_data.setdefault(entry, frappe._dict()).setdefault(period, 0.0)
+ self.issue_periodic_data[entry][period] += 1
+
+ else:
+ field = self.field_map.get(self.filters.based_on)
+ value = d.get(field)
+ if not value:
+ value = _('Not Specified')
+
+ self.issue_periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0.0)
+ self.issue_periodic_data[value][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'
+ }
\ No newline at end of file
diff --git a/erpnext/support/report/issue_analytics/test_issue_analytics.py b/erpnext/support/report/issue_analytics/test_issue_analytics.py
new file mode 100644
index 0000000..7748319
--- /dev/null
+++ b/erpnext/support/report/issue_analytics/test_issue_analytics.py
@@ -0,0 +1,214 @@
+from __future__ import unicode_literals
+import unittest
+import frappe
+from frappe.utils import getdate, add_months
+from erpnext.support.report.issue_analytics.issue_analytics import execute
+from erpnext.support.doctype.issue.test_issue import make_issue, create_customer
+from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues
+from frappe.desk.form.assign_to import add as add_assignment
+
+months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+class TestIssueAnalytics(unittest.TestCase):
+ @classmethod
+ def setUpClass(self):
+ frappe.db.sql("delete from `tabIssue` where company='_Test Company'")
+ frappe.db.set_value("Support Settings", None, "track_service_level_agreement", 1)
+
+ current_month_date = getdate()
+ last_month_date = add_months(current_month_date, -1)
+ self.current_month = str(months[current_month_date.month - 1]).lower()
+ self.last_month = str(months[last_month_date.month - 1]).lower()
+ if current_month_date.year != last_month_date.year:
+ self.current_month += '_' + str(current_month_date.year)
+ self.last_month += '_' + str(last_month_date.year)
+
+ def test_issue_analytics(self):
+ create_service_level_agreements_for_issues()
+ create_issue_types()
+ create_records()
+
+ self.compare_result_for_customer()
+ self.compare_result_for_issue_type()
+ self.compare_result_for_issue_priority()
+ self.compare_result_for_assignment()
+
+ def compare_result_for_customer(self):
+ filters = {
+ 'company': '_Test Company',
+ 'based_on': 'Customer',
+ 'from_date': add_months(getdate(), -1),
+ 'to_date': getdate(),
+ 'range': 'Monthly'
+ }
+
+ report = execute(filters)
+
+ expected_data = [
+ {
+ 'customer': '__Test Customer 2',
+ self.last_month: 1.0,
+ self.current_month: 0.0,
+ 'total': 1.0
+ },
+ {
+ 'customer': '__Test Customer 1',
+ self.last_month: 0.0,
+ self.current_month: 1.0,
+ 'total': 1.0
+ },
+ {
+ 'customer': '__Test Customer',
+ self.last_month: 1.0,
+ self.current_month: 1.0,
+ 'total': 2.0
+ }
+ ]
+
+ self.assertEqual(expected_data, report[1]) # rows
+ self.assertEqual(len(report[0]), 4) # cols
+
+ def compare_result_for_issue_type(self):
+ filters = {
+ 'company': '_Test Company',
+ 'based_on': 'Issue Type',
+ 'from_date': add_months(getdate(), -1),
+ 'to_date': getdate(),
+ 'range': 'Monthly'
+ }
+
+ report = execute(filters)
+
+ expected_data = [
+ {
+ 'issue_type': 'Discomfort',
+ self.last_month: 1.0,
+ self.current_month: 0.0,
+ 'total': 1.0
+ },
+ {
+ 'issue_type': 'Service Request',
+ self.last_month: 0.0,
+ self.current_month: 1.0,
+ 'total': 1.0
+ },
+ {
+ 'issue_type': 'Bug',
+ self.last_month: 1.0,
+ self.current_month: 1.0,
+ 'total': 2.0
+ }
+ ]
+
+ self.assertEqual(expected_data, report[1]) # rows
+ self.assertEqual(len(report[0]), 4) # cols
+
+ def compare_result_for_issue_priority(self):
+ filters = {
+ 'company': '_Test Company',
+ 'based_on': 'Issue Priority',
+ 'from_date': add_months(getdate(), -1),
+ 'to_date': getdate(),
+ 'range': 'Monthly'
+ }
+
+ report = execute(filters)
+
+ expected_data = [
+ {
+ 'priority': 'Medium',
+ self.last_month: 1.0,
+ self.current_month: 1.0,
+ 'total': 2.0
+ },
+ {
+ 'priority': 'Low',
+ self.last_month: 1.0,
+ self.current_month: 0.0,
+ 'total': 1.0
+ },
+ {
+ 'priority': 'High',
+ self.last_month: 0.0,
+ self.current_month: 1.0,
+ 'total': 1.0
+ }
+ ]
+
+ self.assertEqual(expected_data, report[1]) # rows
+ self.assertEqual(len(report[0]), 4) # cols
+
+ def compare_result_for_assignment(self):
+ filters = {
+ 'company': '_Test Company',
+ 'based_on': 'Assigned To',
+ 'from_date': add_months(getdate(), -1),
+ 'to_date': getdate(),
+ 'range': 'Monthly'
+ }
+
+ report = execute(filters)
+
+ expected_data = [
+ {
+ 'user': 'test@example.com',
+ self.last_month: 1.0,
+ self.current_month: 1.0,
+ 'total': 2.0
+ },
+ {
+ 'user': 'test1@example.com',
+ self.last_month: 2.0,
+ self.current_month: 1.0,
+ 'total': 3.0
+ }
+ ]
+
+ self.assertEqual(expected_data, report[1]) # rows
+ self.assertEqual(len(report[0]), 4) # cols
+
+
+def create_issue_types():
+ for entry in ['Bug', 'Service Request', 'Discomfort']:
+ if not frappe.db.exists('Issue Type', entry):
+ frappe.get_doc({
+ 'doctype': 'Issue Type',
+ '__newname': entry
+ }).insert()
+
+
+def create_records():
+ create_customer("__Test Customer", "_Test SLA Customer Group", "__Test SLA Territory")
+ create_customer("__Test Customer 1", "_Test SLA Customer Group", "__Test SLA Territory")
+ create_customer("__Test Customer 2", "_Test SLA Customer Group", "__Test SLA Territory")
+
+ current_month_date = getdate()
+ last_month_date = add_months(current_month_date, -1)
+
+ issue = make_issue(current_month_date, "__Test Customer", 2, "High", "Bug")
+ add_assignment({
+ "assign_to": ["test@example.com"],
+ "doctype": "Issue",
+ "name": issue.name
+ })
+
+ issue = make_issue(last_month_date, "__Test Customer", 2, "Low", "Bug")
+ add_assignment({
+ "assign_to": ["test1@example.com"],
+ "doctype": "Issue",
+ "name": issue.name
+ })
+
+ issue = make_issue(current_month_date, "__Test Customer 1", 2, "Medium", "Service Request")
+ add_assignment({
+ "assign_to": ["test1@example.com"],
+ "doctype": "Issue",
+ "name": issue.name
+ })
+
+ issue = make_issue(last_month_date, "__Test Customer 2", 2, "Medium", "Discomfort")
+ add_assignment({
+ "assign_to": ["test@example.com", "test1@example.com"],
+ "doctype": "Issue",
+ "name": issue.name
+ })
\ No newline at end of file
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/support/report/issue_summary/__init__.py
similarity index 100%
copy from erpnext/accounts/page/bank_reconciliation/__init__.py
copy to erpnext/support/report/issue_summary/__init__.py
diff --git a/erpnext/support/report/issue_summary/issue_summary.js b/erpnext/support/report/issue_summary/issue_summary.js
new file mode 100644
index 0000000..684482a
--- /dev/null
+++ b/erpnext/support/report/issue_summary/issue_summary.js
@@ -0,0 +1,73 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Issue Summary"] = {
+ "filters": [
+ {
+ fieldname: "company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("Company"),
+ reqd: 1
+ },
+ {
+ fieldname: "based_on",
+ label: __("Based On"),
+ fieldtype: "Select",
+ options: ["Customer", "Issue Type", "Issue Priority", "Assigned To"],
+ default: "Customer",
+ reqd: 1
+ },
+ {
+ fieldname: "from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.defaults.get_global_default("year_start_date"),
+ reqd: 1
+ },
+ {
+ fieldname:"to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.defaults.get_global_default("year_end_date"),
+ reqd: 1
+ },
+ {
+ fieldname: "status",
+ label: __("Status"),
+ fieldtype: "Select",
+ options:[
+ {label: __('Open'), value: 'Open'},
+ {label: __('Replied'), value: 'Replied'},
+ {label: __('Resolved'), value: 'Resolved'},
+ {label: __('Closed'), value: 'Closed'}
+ ]
+ },
+ {
+ fieldname: "priority",
+ label: __("Issue Priority"),
+ fieldtype: "Link",
+ options: "Issue Priority"
+ },
+ {
+ fieldname: "customer",
+ label: __("Customer"),
+ fieldtype: "Link",
+ options: "Customer"
+ },
+ {
+ fieldname: "project",
+ label: __("Project"),
+ fieldtype: "Link",
+ options: "Project"
+ },
+ {
+ fieldname: "assigned_to",
+ label: __("Assigned To"),
+ fieldtype: "Link",
+ options: "User"
+ }
+ ]
+};
\ No newline at end of file
diff --git a/erpnext/support/report/issue_summary/issue_summary.json b/erpnext/support/report/issue_summary/issue_summary.json
new file mode 100644
index 0000000..b8a580c
--- /dev/null
+++ b/erpnext/support/report/issue_summary/issue_summary.json
@@ -0,0 +1,26 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2020-10-12 01:01:55.181777",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-10-12 14:54:55.655920",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Issue Summary",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Issue",
+ "report_name": "Issue Summary",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Support Team"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py
new file mode 100644
index 0000000..7861e30
--- /dev/null
+++ b/erpnext/support/report/issue_summary/issue_summary.py
@@ -0,0 +1,351 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import json
+from six import iteritems
+from frappe import _, scrub
+from frappe.utils import flt
+
+def execute(filters=None):
+ return IssueSummary(filters).run()
+
+class IssueSummary(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()
+ self.get_report_summary()
+
+ return self.columns, self.data, None, self.chart, self.report_summary
+
+ def get_columns(self):
+ self.columns = []
+
+ if self.filters.based_on == 'Customer':
+ self.columns.append({
+ 'label': _('Customer'),
+ 'options': 'Customer',
+ 'fieldname': 'customer',
+ 'fieldtype': 'Link',
+ 'width': 200
+ })
+
+ elif self.filters.based_on == 'Assigned To':
+ self.columns.append({
+ 'label': _('User'),
+ 'fieldname': 'user',
+ 'fieldtype': 'Link',
+ 'options': 'User',
+ 'width': 200
+ })
+
+ elif self.filters.based_on == 'Issue Type':
+ self.columns.append({
+ 'label': _('Issue Type'),
+ 'fieldname': 'issue_type',
+ 'fieldtype': 'Link',
+ 'options': 'Issue Type',
+ 'width': 200
+ })
+
+ elif self.filters.based_on == 'Issue Priority':
+ self.columns.append({
+ 'label': _('Issue Priority'),
+ 'fieldname': 'priority',
+ 'fieldtype': 'Link',
+ 'options': 'Issue Priority',
+ 'width': 200
+ })
+
+ self.statuses = ['Open', 'Replied', 'Resolved', 'Closed']
+ for status in self.statuses:
+ self.columns.append({
+ 'label': _(status),
+ 'fieldname': scrub(status),
+ 'fieldtype': 'Int',
+ 'width': 80
+ })
+
+ self.columns.append({
+ 'label': _('Total Issues'),
+ 'fieldname': 'total_issues',
+ 'fieldtype': 'Int',
+ 'width': 100
+ })
+
+ self.sla_status_map = {
+ 'SLA Failed': 'failed',
+ 'SLA Fulfilled': 'fulfilled',
+ 'SLA Ongoing': 'ongoing'
+ }
+
+ for label, fieldname in self.sla_status_map.items():
+ self.columns.append({
+ 'label': _(label),
+ 'fieldname': fieldname,
+ 'fieldtype': 'Int',
+ 'width': 100
+ })
+
+ self.metrics = ['Avg First Response Time', 'Avg Response Time', 'Avg Hold Time',
+ 'Avg Resolution Time', 'Avg User Resolution Time']
+
+ for metric in self.metrics:
+ self.columns.append({
+ 'label': _(metric),
+ 'fieldname': scrub(metric),
+ 'fieldtype': 'Duration',
+ 'width': 170
+ })
+
+ def get_data(self):
+ self.get_issues()
+ self.get_rows()
+
+ def get_issues(self):
+ filters = self.get_common_filters()
+ self.field_map = {
+ 'Customer': 'customer',
+ 'Issue Type': 'issue_type',
+ 'Issue Priority': 'priority',
+ 'Assigned To': '_assign'
+ }
+
+ self.entries = frappe.db.get_all('Issue',
+ fields=[self.field_map.get(self.filters.based_on), 'name', 'opening_date', 'status', 'avg_response_time',
+ 'first_response_time', 'total_hold_time', 'user_resolution_time', 'resolution_time', 'agreement_status'],
+ filters=filters
+ )
+
+ def get_common_filters(self):
+ filters = {}
+ filters['opening_date'] = ('between', [self.filters.from_date, self.filters.to_date])
+
+ if self.filters.get('assigned_to'):
+ filters['_assign'] = ('like', '%' + self.filters.get('assigned_to') + '%')
+
+ for entry in ['company', 'status', 'priority', 'customer', 'project']:
+ if self.filters.get(entry):
+ filters[entry] = self.filters.get(entry)
+
+ return filters
+
+ def get_rows(self):
+ self.data = []
+ self.get_summary_data()
+
+ for entity, data in iteritems(self.issue_summary_data):
+ if self.filters.based_on == 'Customer':
+ row = {'customer': entity}
+ elif self.filters.based_on == 'Assigned To':
+ row = {'user': entity}
+ elif self.filters.based_on == 'Issue Type':
+ row = {'issue_type': entity}
+ elif self.filters.based_on == 'Issue Priority':
+ row = {'priority': entity}
+
+ for status in self.statuses:
+ count = flt(data.get(status, 0.0))
+ row[scrub(status)] = count
+
+ row['total_issues'] = data.get('total_issues', 0.0)
+
+ for sla_status in self.sla_status_map.values():
+ value = flt(data.get(sla_status), 0.0)
+ row[sla_status] = value
+
+ for metric in self.metrics:
+ value = flt(data.get(scrub(metric)), 0.0)
+ row[scrub(metric)] = value
+
+ self.data.append(row)
+
+ def get_summary_data(self):
+ self.issue_summary_data = frappe._dict()
+
+ for d in self.entries:
+ status = d.status
+ agreement_status = scrub(d.agreement_status)
+
+ if self.filters.based_on == 'Assigned To':
+ if d._assign:
+ for entry in json.loads(d._assign):
+ self.issue_summary_data.setdefault(entry, frappe._dict()).setdefault(status, 0.0)
+ self.issue_summary_data.setdefault(entry, frappe._dict()).setdefault(agreement_status, 0.0)
+ self.issue_summary_data.setdefault(entry, frappe._dict()).setdefault('total_issues', 0.0)
+ self.issue_summary_data[entry][status] += 1
+ self.issue_summary_data[entry][agreement_status] += 1
+ self.issue_summary_data[entry]['total_issues'] += 1
+
+ else:
+ field = self.field_map.get(self.filters.based_on)
+ value = d.get(field)
+ if not value:
+ value = _('Not Specified')
+
+ self.issue_summary_data.setdefault(value, frappe._dict()).setdefault(status, 0.0)
+ self.issue_summary_data.setdefault(value, frappe._dict()).setdefault(agreement_status, 0.0)
+ self.issue_summary_data.setdefault(value, frappe._dict()).setdefault('total_issues', 0.0)
+ self.issue_summary_data[value][status] += 1
+ self.issue_summary_data[value][agreement_status] += 1
+ self.issue_summary_data[value]['total_issues'] += 1
+
+ self.get_metrics_data()
+
+ def get_metrics_data(self):
+ issues = []
+
+ metrics_list = ['avg_response_time', 'avg_first_response_time', 'avg_hold_time',
+ 'avg_resolution_time', 'avg_user_resolution_time']
+
+ for entry in self.entries:
+ issues.append(entry.name)
+
+ field = self.field_map.get(self.filters.based_on)
+
+ if issues:
+ if self.filters.based_on == 'Assigned To':
+ assignment_map = frappe._dict()
+ for d in self.entries:
+ if d._assign:
+ for entry in json.loads(d._assign):
+ for metric in metrics_list:
+ self.issue_summary_data.setdefault(entry, frappe._dict()).setdefault(metric, 0.0)
+
+ self.issue_summary_data[entry]['avg_response_time'] += d.get('avg_response_time') or 0.0
+ self.issue_summary_data[entry]['avg_first_response_time'] += d.get('first_response_time') or 0.0
+ self.issue_summary_data[entry]['avg_hold_time'] += d.get('total_hold_time') or 0.0
+ self.issue_summary_data[entry]['avg_resolution_time'] += d.get('resolution_time') or 0.0
+ self.issue_summary_data[entry]['avg_user_resolution_time'] += d.get('user_resolution_time') or 0.0
+
+ if not assignment_map.get(entry):
+ assignment_map[entry] = 0
+ assignment_map[entry] += 1
+
+ for entry in assignment_map:
+ for metric in metrics_list:
+ self.issue_summary_data[entry][metric] /= flt(assignment_map.get(entry))
+
+ else:
+ data = frappe.db.sql("""
+ SELECT
+ {0}, AVG(first_response_time) as avg_frt,
+ AVG(avg_response_time) as avg_resp_time,
+ AVG(total_hold_time) as avg_hold_time,
+ AVG(resolution_time) as avg_resolution_time,
+ AVG(user_resolution_time) as avg_user_resolution_time
+ FROM `tabIssue`
+ WHERE
+ name IN %(issues)s
+ GROUP BY {0}
+ """.format(field), {'issues': issues}, as_dict=1)
+
+ for entry in data:
+ value = entry.get(field)
+ if not value:
+ value = _('Not Specified')
+
+ for metric in metrics_list:
+ self.issue_summary_data.setdefault(value, frappe._dict()).setdefault(metric, 0.0)
+
+ self.issue_summary_data[value]['avg_response_time'] = entry.get('avg_resp_time') or 0.0
+ self.issue_summary_data[value]['avg_first_response_time'] = entry.get('avg_frt') or 0.0
+ self.issue_summary_data[value]['avg_hold_time'] = entry.get('avg_hold_time') or 0.0
+ self.issue_summary_data[value]['avg_resolution_time'] = entry.get('avg_resolution_time') or 0.0
+ self.issue_summary_data[value]['avg_user_resolution_time'] = entry.get('avg_user_resolution_time') or 0.0
+
+ def get_chart_data(self):
+ self.chart = []
+
+ labels = []
+ open_issues = []
+ replied_issues = []
+ resolved_issues = []
+ closed_issues = []
+
+ entity = self.filters.based_on
+ entity_field = self.field_map.get(entity)
+ if entity == 'Assigned To':
+ entity_field = 'user'
+
+ for entry in self.data:
+ labels.append(entry.get(entity_field))
+ open_issues.append(entry.get('open'))
+ replied_issues.append(entry.get('replied'))
+ resolved_issues.append(entry.get('resolved'))
+ closed_issues.append(entry.get('closed'))
+
+ self.chart = {
+ 'data': {
+ 'labels': labels[:30],
+ 'datasets': [
+ {
+ 'name': 'Open',
+ 'values': open_issues[:30]
+ },
+ {
+ 'name': 'Replied',
+ 'values': replied_issues[:30]
+ },
+ {
+ 'name': 'Resolved',
+ 'values': resolved_issues[:30]
+ },
+ {
+ 'name': 'Closed',
+ 'values': closed_issues[:30]
+ }
+ ]
+ },
+ 'type': 'bar',
+ 'barOptions': {
+ 'stacked': True
+ }
+ }
+
+ def get_report_summary(self):
+ self.report_summary = []
+
+ open_issues = 0
+ replied = 0
+ resolved = 0
+ closed = 0
+
+ for entry in self.data:
+ open_issues += entry.get('open')
+ replied += entry.get('replied')
+ resolved += entry.get('resolved')
+ closed += entry.get('closed')
+
+ self.report_summary = [
+ {
+ 'value': open_issues,
+ 'indicator': 'Red',
+ 'label': _('Open'),
+ 'datatype': 'Int',
+ },
+ {
+ 'value': replied,
+ 'indicator': 'Grey',
+ 'label': _('Replied'),
+ 'datatype': 'Int',
+ },
+ {
+ 'value': resolved,
+ 'indicator': 'Green',
+ 'label': _('Resolved'),
+ 'datatype': 'Int',
+ },
+ {
+ 'value': closed,
+ 'indicator': 'Green',
+ 'label': _('Closed'),
+ 'datatype': 'Int',
+ }
+ ]
+
diff --git a/erpnext/support/workspace/support/support.json b/erpnext/support/workspace/support/support.json
new file mode 100644
index 0000000..01a8676
--- /dev/null
+++ b/erpnext/support/workspace/support/support.json
@@ -0,0 +1,186 @@
+{
+ "category": "Modules",
+ "charts": [],
+ "creation": "2020-03-02 15:48:23.224699",
+ "developer_mode_only": 0,
+ "disable_user_customization": 0,
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "extends_another_page": 0,
+ "hide_custom": 0,
+ "icon": "support",
+ "idx": 0,
+ "is_standard": 1,
+ "label": "Support",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Issues",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Issue",
+ "link_to": "Issue",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Issue Type",
+ "link_to": "Issue Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Issue Priority",
+ "link_to": "Issue Priority",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance Schedule",
+ "link_to": "Maintenance Schedule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Maintenance Visit",
+ "link_to": "Maintenance Visit",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Service Level Agreement",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Service Level Agreement",
+ "link_to": "Service Level Agreement",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Warranty",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Warranty Claim",
+ "link_to": "Warranty Claim",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Serial No",
+ "link_to": "Serial No",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Support Settings",
+ "link_to": "Support Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Reports",
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Issue",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "First Response Time for Issues",
+ "link_to": "First Response Time for Issues",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2020-12-01 13:38:37.073482",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Support",
+ "owner": "Administrator",
+ "pin_to_bottom": 0,
+ "pin_to_top": 0,
+ "shortcuts": [
+ {
+ "color": "Yellow",
+ "format": "{} Assigned",
+ "label": "Issue",
+ "link_to": "Issue",
+ "stats_filter": "{\n \"_assign\": [\"like\", '%' + frappe.session.user + '%'],\n \"status\": \"Open\"\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Maintenance Visit",
+ "link_to": "Maintenance Visit",
+ "type": "DocType"
+ },
+ {
+ "label": "Service Level Agreement",
+ "link_to": "Service Level Agreement",
+ "type": "DocType"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/config/__init__.py b/erpnext/telephony/__init__.py
similarity index 100%
rename from erpnext/config/__init__.py
rename to erpnext/telephony/__init__.py
diff --git a/erpnext/config/__init__.py b/erpnext/telephony/doctype/__init__.py
similarity index 100%
copy from erpnext/config/__init__.py
copy to erpnext/telephony/doctype/__init__.py
diff --git a/erpnext/communication/doctype/call_log/__init__.py b/erpnext/telephony/doctype/call_log/__init__.py
similarity index 100%
rename from erpnext/communication/doctype/call_log/__init__.py
rename to erpnext/telephony/doctype/call_log/__init__.py
diff --git a/erpnext/telephony/doctype/call_log/call_log.js b/erpnext/telephony/doctype/call_log/call_log.js
new file mode 100644
index 0000000..e7afa0b
--- /dev/null
+++ b/erpnext/telephony/doctype/call_log/call_log.js
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Call Log', {
+ refresh: function(frm) {
+ frm.events.setup_recording_audio_control(frm);
+ const incoming_call = frm.doc.type == 'Incoming';
+ frm.add_custom_button(incoming_call ? __('Callback'): __('Call Again'), () => {
+ const number = incoming_call ? frm.doc.from : frm.doc.to;
+ frappe.phone_call.handler(number, frm);
+ });
+ },
+ setup_recording_audio_control(frm) {
+ const recording_wrapper = frm.get_field('recording_html').$wrapper;
+ if (!frm.doc.recording_url || frm.doc.recording_url == 'null') {
+ recording_wrapper.empty();
+ } else {
+ recording_wrapper.addClass('input-max-width');
+ recording_wrapper.html(`
+ <audio
+ controls
+ src="${frm.doc.recording_url}">
+ </audio>
+ `);
+ }
+ }
+});
diff --git a/erpnext/communication/doctype/call_log/call_log.json b/erpnext/telephony/doctype/call_log/call_log.json
similarity index 60%
rename from erpnext/communication/doctype/call_log/call_log.json
rename to erpnext/telephony/doctype/call_log/call_log.json
index 31e79f1..1d6c39e 100644
--- a/erpnext/communication/doctype/call_log/call_log.json
+++ b/erpnext/telephony/doctype/call_log/call_log.json
@@ -5,35 +5,27 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
+ "call_details_section",
"id",
"from",
"to",
- "column_break_3",
- "received_by",
"medium",
- "caller_information",
- "contact",
- "contact_name",
- "column_break_10",
+ "start_time",
+ "end_time",
+ "column_break_4",
+ "type",
"customer",
- "lead",
- "lead_name",
- "section_break_5",
"status",
"duration",
- "recording_url"
+ "recording_url",
+ "recording_html",
+ "section_break_11",
+ "summary",
+ "section_break_19",
+ "links"
],
"fields": [
{
- "fieldname": "column_break_3",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "label": "Call Details"
- },
- {
"fieldname": "id",
"fieldtype": "Data",
"label": "ID",
@@ -50,6 +42,7 @@
{
"fieldname": "to",
"fieldtype": "Data",
+ "in_list_view": 1,
"label": "To",
"read_only": 1
},
@@ -58,13 +51,13 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
- "options": "Ringing\nIn Progress\nCompleted\nMissed",
+ "options": "Ringing\nIn Progress\nCompleted\nFailed\nBusy\nNo Answer\nQueued\nCanceled",
"read_only": 1
},
{
"description": "Call Duration in seconds",
"fieldname": "duration",
- "fieldtype": "Int",
+ "fieldtype": "Duration",
"in_list_view": 1,
"label": "Duration",
"read_only": 1
@@ -72,8 +65,8 @@
{
"fieldname": "recording_url",
"fieldtype": "Data",
- "label": "Recording URL",
- "read_only": 1
+ "hidden": 1,
+ "label": "Recording URL"
},
{
"fieldname": "medium",
@@ -82,51 +75,52 @@
"read_only": 1
},
{
- "fieldname": "received_by",
- "fieldtype": "Link",
- "label": "Received By",
- "options": "Employee",
+ "fieldname": "type",
+ "fieldtype": "Select",
+ "label": "Type",
+ "options": "Incoming\nOutgoing",
"read_only": 1
},
{
- "fieldname": "caller_information",
+ "fieldname": "recording_html",
+ "fieldtype": "HTML",
+ "label": "Recording HTML"
+ },
+ {
+ "fieldname": "section_break_19",
"fieldtype": "Section Break",
- "label": "Caller Information"
+ "label": "Reference"
},
{
- "fieldname": "contact",
- "fieldtype": "Link",
- "label": "Contact",
- "options": "Contact",
- "read_only": 1
+ "fieldname": "links",
+ "fieldtype": "Table",
+ "label": "Links",
+ "options": "Dynamic Link"
},
{
- "fieldname": "lead",
- "fieldtype": "Link",
- "label": "Lead ",
- "options": "Lead",
- "read_only": 1
- },
- {
- "fetch_from": "contact.name",
- "fieldname": "contact_name",
- "fieldtype": "Data",
- "hidden": 1,
- "in_list_view": 1,
- "label": "Contact Name",
- "read_only": 1
- },
- {
- "fieldname": "column_break_10",
+ "fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
- "fetch_from": "lead.lead_name",
- "fieldname": "lead_name",
- "fieldtype": "Data",
- "hidden": 1,
- "in_list_view": 1,
- "label": "Lead Name",
+ "fieldname": "summary",
+ "fieldtype": "Small Text"
+ },
+ {
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Call Summary"
+ },
+ {
+ "fieldname": "start_time",
+ "fieldtype": "Datetime",
+ "label": "Start Time",
+ "read_only": 1
+ },
+ {
+ "fieldname": "end_time",
+ "fieldtype": "Datetime",
+ "label": "End Time",
"read_only": 1
},
{
@@ -135,14 +129,19 @@
"label": "Customer",
"options": "Customer",
"read_only": 1
+ },
+ {
+ "fieldname": "call_details_section",
+ "fieldtype": "Section Break",
+ "label": "Call Details"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-08-25 17:08:34.085731",
+ "modified": "2021-02-08 14:23:28.744844",
"modified_by": "Administrator",
- "module": "Communication",
+ "module": "Telephony",
"name": "Call Log",
"owner": "Administrator",
"permissions": [
@@ -163,8 +162,8 @@
"role": "Employee"
}
],
- "sort_field": "modified",
- "sort_order": "ASC",
+ "sort_field": "creation",
+ "sort_order": "DESC",
"title_field": "from",
"track_changes": 1,
"track_views": 1
diff --git a/erpnext/telephony/doctype/call_log/call_log.py b/erpnext/telephony/doctype/call_log/call_log.py
new file mode 100644
index 0000000..4d553df
--- /dev/null
+++ b/erpnext/telephony/doctype/call_log/call_log.py
@@ -0,0 +1,176 @@
+# -*- 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 erpnext.crm.doctype.utils import get_scheduled_employees_for_popup, strip_number
+from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
+from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links
+
+from erpnext.crm.doctype.lead.lead import get_lead_with_phone_number
+
+END_CALL_STATUSES = ['No Answer', 'Completed', 'Busy', 'Failed']
+ONGOING_CALL_STATUSES = ['Ringing', 'In Progress']
+
+
+class CallLog(Document):
+ def validate(self):
+ deduplicate_dynamic_links(self)
+
+ def before_insert(self):
+ """Add lead(third party person) links to the document.
+ """
+ lead_number = self.get('from') if self.is_incoming_call() else self.get('to')
+ lead_number = strip_number(lead_number)
+
+ contact = get_contact_with_phone_number(strip_number(lead_number))
+ if contact:
+ self.add_link(link_type='Contact', link_name=contact)
+
+ lead = get_lead_with_phone_number(lead_number)
+ if lead:
+ self.add_link(link_type='Lead', link_name=lead)
+
+ def after_insert(self):
+ self.trigger_call_popup()
+
+ def on_update(self):
+ def _is_call_missed(doc_before_save, doc_after_save):
+ # FIXME: This works for Exotel but not for all telepony providers
+ return doc_before_save.to != doc_after_save.to and doc_after_save.status not in END_CALL_STATUSES
+
+ def _is_call_ended(doc_before_save, doc_after_save):
+ return doc_before_save.status not in END_CALL_STATUSES and self.status in END_CALL_STATUSES
+
+ doc_before_save = self.get_doc_before_save()
+ if not doc_before_save: return
+
+ if _is_call_missed(doc_before_save, self):
+ frappe.publish_realtime('call_{id}_missed'.format(id=self.id), self)
+ self.trigger_call_popup()
+
+ if _is_call_ended(doc_before_save, self):
+ frappe.publish_realtime('call_{id}_ended'.format(id=self.id), self)
+
+ def is_incoming_call(self):
+ return self.type == 'Incoming'
+
+ def add_link(self, link_type, link_name):
+ self.append('links', {
+ 'link_doctype': link_type,
+ 'link_name': link_name
+ })
+
+ def trigger_call_popup(self):
+ if self.is_incoming_call():
+ scheduled_employees = get_scheduled_employees_for_popup(self.medium)
+ employee_emails = get_employees_with_number(self.to)
+
+ # check if employees with matched number are scheduled to receive popup
+ emails = set(scheduled_employees).intersection(employee_emails)
+
+ if frappe.conf.developer_mode:
+ self.add_comment(text=f"""
+ Scheduled Employees: {scheduled_employees}
+ Matching Employee: {employee_emails}
+ Show Popup To: {emails}
+ """)
+
+ if employee_emails and not emails:
+ self.add_comment(text=_("No employee was scheduled for call popup"))
+
+ for email in emails:
+ frappe.publish_realtime('show_call_popup', self, user=email)
+
+
+@frappe.whitelist()
+def add_call_summary(call_log, summary):
+ doc = frappe.get_doc('Call Log', call_log)
+ doc.add_comment('Comment', frappe.bold(_('Call Summary')) + '<br><br>' + summary)
+
+def get_employees_with_number(number):
+ number = strip_number(number)
+ if not number: return []
+
+ employee_emails = frappe.cache().hget('employees_with_number', number)
+ if employee_emails: return employee_emails
+
+ employees = frappe.get_all('Employee', filters={
+ 'cell_number': ['like', '%{}%'.format(number)],
+ 'user_id': ['!=', '']
+ }, fields=['user_id'])
+
+ employee_emails = [employee.user_id for employee in employees]
+ frappe.cache().hset('employees_with_number', number, employee_emails)
+
+ return employee_emails
+
+def link_existing_conversations(doc, state):
+ """
+ Called from hooks on creation of Contact or Lead to link all the existing conversations.
+ """
+ if doc.doctype != 'Contact': return
+ try:
+ numbers = [d.phone for d in doc.phone_nos]
+
+ for number in numbers:
+ number = strip_number(number)
+ if not number: continue
+ logs = frappe.db.sql_list("""
+ SELECT cl.name FROM `tabCall Log` cl
+ LEFT JOIN `tabDynamic Link` dl
+ ON cl.name = dl.parent
+ WHERE (cl.`from` like %(phone_number)s or cl.`to` like %(phone_number)s)
+ GROUP BY cl.name
+ HAVING SUM(
+ CASE
+ WHEN dl.link_doctype = %(doctype)s AND dl.link_name = %(docname)s
+ THEN 1
+ ELSE 0
+ END
+ )=0
+ """, dict(
+ phone_number='%{}'.format(number),
+ docname=doc.name,
+ doctype = doc.doctype
+ )
+ )
+
+ for log in logs:
+ call_log = frappe.get_doc('Call Log', log)
+ call_log.add_link(link_type=doc.doctype, link_name=doc.name)
+ call_log.save()
+ frappe.db.commit()
+ except Exception:
+ frappe.log_error(title=_('Error during caller information update'))
+
+def get_linked_call_logs(doctype, docname):
+ # content will be shown in timeline
+ logs = frappe.get_all('Dynamic Link', fields=['parent'], filters={
+ 'parenttype': 'Call Log',
+ 'link_doctype': doctype,
+ 'link_name': docname
+ })
+
+ logs = set([log.parent for log in logs])
+
+ logs = frappe.get_all('Call Log', fields=['*'], filters={
+ 'name': ['in', logs]
+ })
+
+ timeline_contents = []
+ for log in logs:
+ log.show_call_button = 0
+ timeline_contents.append({
+ 'icon': 'call',
+ 'is_card': True,
+ 'creation': log.creation,
+ 'template': 'call_link',
+ 'template_data': log
+ })
+
+ return timeline_contents
+
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/telephony/doctype/call_log/test_call_log.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/telephony/doctype/call_log/test_call_log.py
index 2ad7984..faa6304 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/telephony/doctype/call_log/test_call_log.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestCallLog(unittest.TestCase):
pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/telephony/doctype/incoming_call_handling_schedule/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/telephony/doctype/incoming_call_handling_schedule/__init__.py
diff --git a/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.json b/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.json
new file mode 100644
index 0000000..6d46b4e
--- /dev/null
+++ b/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.json
@@ -0,0 +1,60 @@
+{
+ "actions": [],
+ "creation": "2020-11-19 11:15:54.967710",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "day_of_week",
+ "from_time",
+ "to_time",
+ "agent_group"
+ ],
+ "fields": [
+ {
+ "fieldname": "day_of_week",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Day Of Week",
+ "options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday",
+ "reqd": 1
+ },
+ {
+ "default": "9:00:00",
+ "fieldname": "from_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "From Time",
+ "reqd": 1
+ },
+ {
+ "default": "17:00:00",
+ "fieldname": "to_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "To Time",
+ "reqd": 1
+ },
+ {
+ "fieldname": "agent_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Agent Group",
+ "options": "Employee Group",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-11-19 11:15:54.967710",
+ "modified_by": "Administrator",
+ "module": "Telephony",
+ "name": "Incoming Call Handling Schedule",
+ "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/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py b/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py
new file mode 100644
index 0000000..fcf2974
--- /dev/null
+++ b/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class IncomingCallHandlingSchedule(Document):
+ pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/telephony/doctype/incoming_call_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/telephony/doctype/incoming_call_settings/__init__.py
diff --git a/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js
new file mode 100644
index 0000000..1bcc846
--- /dev/null
+++ b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.js
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+function time_to_seconds(time_str) {
+ // Convert time string of format HH:MM:SS into seconds.
+ let seq = time_str.split(':');
+ seq = seq.map((n) => parseInt(n));
+ return (seq[0]*60*60) + (seq[1]*60) + seq[2];
+}
+
+function number_sort(array, ascending=true) {
+ let array_copy = [...array];
+ if (ascending) {
+ array_copy.sort((a, b) => a-b); // ascending order
+ } else {
+ array_copy.sort((a, b) => b-a); // descending order
+ }
+ return array_copy;
+}
+
+function groupby(items, key) {
+ // Group the list of items using the given key.
+ const obj = {};
+ items.forEach((item) => {
+ if (item[key] in obj) {
+ obj[item[key]].push(item);
+ } else {
+ obj[item[key]] = [item];
+ }
+ });
+ return obj;
+}
+
+function check_timeslot_overlap(ts1, ts2) {
+ /// Timeslot is a an array of length 2 ex: [from_time, to_time]
+ /// time in timeslot is an integer represents number of seconds.
+ if ((ts1[0] < ts2[0] && ts1[1] <= ts2[0]) || (ts1[0] >= ts2[1] && ts1[1] > ts2[1])) {
+ return false;
+ }
+ return true;
+}
+
+function validate_call_schedule(schedule) {
+ validate_call_schedule_timeslot(schedule);
+ validate_call_schedule_overlaps(schedule);
+}
+
+function validate_call_schedule_timeslot(schedule) {
+ // Make sure that to time slot is ahead of from time slot.
+ let errors = [];
+
+ for (let row in schedule) {
+ let record = schedule[row];
+ let from_time_in_secs = time_to_seconds(record.from_time);
+ let to_time_in_secs = time_to_seconds(record.to_time);
+ if (from_time_in_secs >= to_time_in_secs) {
+ errors.push(__('Call Schedule Row {0}: To time slot should always be ahead of From time slot.', [row]));
+ }
+ }
+
+ if (errors.length > 0) {
+ frappe.throw(errors.join("<br/>"));
+ }
+}
+
+function is_call_schedule_overlapped(day_schedule) {
+ // Check if any time slots are overlapped in a day schedule.
+ let timeslots = [];
+ day_schedule.forEach((record)=> {
+ timeslots.push([time_to_seconds(record.from_time), time_to_seconds(record.to_time)]);
+ });
+
+ if (timeslots.length < 2) {
+ return false;
+ }
+
+ timeslots = number_sort(timeslots);
+
+ // Sorted timeslots will be in ascending order if not overlapped.
+ for (let i=1; i < timeslots.length; i++) {
+ if (check_timeslot_overlap(timeslots[i-1], timeslots[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function validate_call_schedule_overlaps(schedule) {
+ let group_by_day = groupby(schedule, 'day_of_week');
+ for (const [day, day_schedule] of Object.entries(group_by_day)) {
+ if (is_call_schedule_overlapped(day_schedule)) {
+ frappe.throw(__('Please fix overlapping time slots for {0}', [day]));
+ }
+ }
+}
+
+frappe.ui.form.on('Incoming Call Settings', {
+ validate(frm) {
+ validate_call_schedule(frm.doc.call_handling_schedule);
+ }
+});
+
diff --git a/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.json b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.json
new file mode 100644
index 0000000..3ffb3e4
--- /dev/null
+++ b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.json
@@ -0,0 +1,82 @@
+{
+ "actions": [],
+ "autoname": "Prompt",
+ "creation": "2020-11-19 10:37:20.734245",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "call_routing",
+ "column_break_2",
+ "greeting_message",
+ "agent_busy_message",
+ "agent_unavailable_message",
+ "section_break_6",
+ "call_handling_schedule"
+ ],
+ "fields": [
+ {
+ "default": "Sequential",
+ "fieldname": "call_routing",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Call Routing",
+ "options": "Sequential\nSimultaneous"
+ },
+ {
+ "fieldname": "greeting_message",
+ "fieldtype": "Data",
+ "label": "Greeting Message"
+ },
+ {
+ "fieldname": "agent_busy_message",
+ "fieldtype": "Data",
+ "label": "Agent Busy Message"
+ },
+ {
+ "fieldname": "agent_unavailable_message",
+ "fieldtype": "Data",
+ "label": "Agent Unavailable Message"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "call_handling_schedule",
+ "fieldtype": "Table",
+ "label": "Call Handling Schedule",
+ "options": "Incoming Call Handling Schedule",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-11-19 11:17:14.527862",
+ "modified_by": "Administrator",
+ "module": "Telephony",
+ "name": "Incoming Call Settings",
+ "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/telephony/doctype/incoming_call_settings/incoming_call_settings.py b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.py
new file mode 100644
index 0000000..2b2008a
--- /dev/null
+++ b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.py
@@ -0,0 +1,63 @@
+# -*- 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 datetime import datetime
+from typing import Tuple
+from frappe import _
+
+class IncomingCallSettings(Document):
+ def validate(self):
+ """List of validations
+ * Make sure that to time slot is ahead of from time slot in call schedule
+ * Make sure that no overlapping timeslots for a given day
+ """
+ self.validate_call_schedule_timeslot(self.call_handling_schedule)
+ self.validate_call_schedule_overlaps(self.call_handling_schedule)
+
+ def validate_call_schedule_timeslot(self, schedule: list):
+ """ Make sure that to time slot is ahead of from time slot.
+ """
+ errors = []
+ for record in schedule:
+ from_time = self.time_to_seconds(record.from_time)
+ to_time = self.time_to_seconds(record.to_time)
+ if from_time >= to_time:
+ errors.append(
+ _('Call Schedule Row {0}: To time slot should always be ahead of From time slot.').format(record.idx)
+ )
+
+ if errors:
+ frappe.throw('<br/>'.join(errors))
+
+ def validate_call_schedule_overlaps(self, schedule: list):
+ """Check if any time slots are overlapped in a day schedule.
+ """
+ week_days = set([each.day_of_week for each in schedule])
+
+ for day in week_days:
+ timeslots = [(record.from_time, record.to_time) for record in schedule if record.day_of_week==day]
+
+ # convert time in timeslot into an integer represents number of seconds
+ timeslots = sorted(map(lambda seq: tuple(map(self.time_to_seconds, seq)), timeslots))
+ if len(timeslots) < 2: continue
+
+ for i in range(1, len(timeslots)):
+ if self.check_timeslots_overlap(timeslots[i-1], timeslots[i]):
+ frappe.throw(_('Please fix overlapping time slots for {0}.').format(day))
+
+ @staticmethod
+ def check_timeslots_overlap(ts1: Tuple[int, int], ts2: Tuple[int, int]) -> bool:
+ if (ts1[0] < ts2[0] and ts1[1] <= ts2[0]) or (ts1[0] >= ts2[1] and ts1[1] > ts2[1]):
+ return False
+ return True
+
+ @staticmethod
+ def time_to_seconds(time: str) -> int:
+ """Convert time string of format HH:MM:SS into seconds
+ """
+ date_time = datetime.strptime(time, "%H:%M:%S")
+ return date_time - datetime(1900, 1, 1)
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py
similarity index 78%
copy from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
copy to erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py
index 2ad7984..c058c11 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestIncomingCallSettings(unittest.TestCase):
pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/telephony/doctype/voice_call_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/telephony/doctype/voice_call_settings/__init__.py
diff --git a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py b/erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py
similarity index 79%
rename from erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
rename to erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py
index 2ad7984..85d6add 100644
--- a/erpnext/non_profit/doctype/membership_settings/test_membership_settings.py
+++ b/erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py
@@ -6,5 +6,5 @@
# import frappe
import unittest
-class TestMembershipSettings(unittest.TestCase):
+class TestVoiceCallSettings(unittest.TestCase):
pass
diff --git a/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.js b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.js
new file mode 100644
index 0000000..4a61b61
--- /dev/null
+++ b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Voice Call Settings', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.json b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.json
new file mode 100644
index 0000000..25e55a2
--- /dev/null
+++ b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.json
@@ -0,0 +1,124 @@
+{
+ "actions": [],
+ "autoname": "field:user",
+ "creation": "2020-12-08 16:52:40.590146",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "user",
+ "call_receiving_device",
+ "column_break_3",
+ "greeting_message",
+ "agent_busy_message",
+ "agent_unavailable_message"
+ ],
+ "fields": [
+ {
+ "fieldname": "user",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "User",
+ "options": "User",
+ "permlevel": 1,
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "greeting_message",
+ "fieldtype": "Data",
+ "label": "Greeting Message"
+ },
+ {
+ "fieldname": "agent_busy_message",
+ "fieldtype": "Data",
+ "label": "Agent Busy Message"
+ },
+ {
+ "fieldname": "agent_unavailable_message",
+ "fieldtype": "Data",
+ "label": "Agent Unavailable Message"
+ },
+ {
+ "default": "Computer",
+ "fieldname": "call_receiving_device",
+ "fieldtype": "Select",
+ "label": "Call Receiving Device",
+ "options": "Computer\nPhone"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-12-14 18:49:34.600194",
+ "modified_by": "Administrator",
+ "module": "Telephony",
+ "name": "Voice Call Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "All",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "permlevel": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "permlevel": 2,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "permlevel": 2,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "All",
+ "share": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py
new file mode 100644
index 0000000..ad3bbf1
--- /dev/null
+++ b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py
@@ -0,0 +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 frappe
+from frappe.model.document import Document
+
+class VoiceCallSettings(Document):
+ pass
diff --git a/erpnext/templates/emails/birthday_reminder.html b/erpnext/templates/emails/birthday_reminder.html
new file mode 100644
index 0000000..12cdf1e
--- /dev/null
+++ b/erpnext/templates/emails/birthday_reminder.html
@@ -0,0 +1,25 @@
+<div class="gray-container text-center">
+ <div>
+ {% for person in birthday_persons %}
+ {% if person.image %}
+ <img
+ class="avatar-frame standard-image"
+ src="{{ person.image }}"
+ style="{{ css_style or '' }}"
+ title="{{ person.name }}">
+ </span>
+ {% else %}
+ <span
+ class="avatar-frame standard-image"
+ style="{{ css_style or '' }}"
+ title="{{ person.name }}">
+ {{ frappe.utils.get_abbr(person.name) }}
+ </span>
+ {% endif %}
+ {% endfor %}
+ </div>
+ <div style="margin-top: 15px">
+ <span>{{ reminder_text }}</span>
+ <p class="text-muted">{{ message }}</p>
+ </div>
+</div>
\ No newline at end of file
diff --git a/erpnext/templates/emails/request_for_quotation.html b/erpnext/templates/emails/request_for_quotation.html
index b4dfb88..812939a 100644
--- a/erpnext/templates/emails/request_for_quotation.html
+++ b/erpnext/templates/emails/request_for_quotation.html
@@ -1,11 +1,24 @@
-<h3>{{_("Request for Quotation")}}</h3>
+<h4>{{_("Request for Quotation")}}</h4>
+<p>{{ supplier_salutation if supplier_salutation else ''}} {{ supplier_name }},</p>
<p>{{ message }}</p>
+
+<p>{{_("The Request for Quotation can be accessed by clicking on the following button")}}:</p>
+<p>
+ <button style="border: 1px solid #15c; padding: 6px; border-radius: 5px; background-color: white;">
+ <a href="{{ rfq_link }}" style="color: #15c; text-decoration:none;" target="_blank">Submit your Quotation</a>
+ </button>
+</p><br>
+
+<p>{{_("Regards")}},<br>
+{{ user_fullname }}</p><br>
+
{% if update_password_link %}
-<p>{{_("Please click on the following link to set your new password")}}:</p>
-<p><a href="{{ update_password_link }}">{{ update_password_link }}</a></p>
-{% else %}
-<p>{{_("The request for quotation can be accessed by clicking on the following link")}}:</p>
-<p><a href="{{ rfq_link }}">Submit your Quotation</a></p>
-{% endif %}
-<p>{{_("Thank you")}},<br>
-{{ user_fullname }}</p>
+
+<p>{{_("Please click on the following button to set your new password")}}:</p>
+<p>
+ <button style="border: 1px solid #15c; padding: 4px; border-radius: 5px; background-color: white;">
+ <a href="{{ update_password_link }}" style="color: #15c; font-size: 12px; text-decoration:none;" target="_blank">{{_("Update Password") }}</a>
+ </button>
+</p>
+
+{% endif %}
\ No newline at end of file
diff --git a/erpnext/templates/generators/item/item.html b/erpnext/templates/generators/item/item.html
index d3691a6..135982d 100644
--- a/erpnext/templates/generators/item/item.html
+++ b/erpnext/templates/generators/item/item.html
@@ -3,21 +3,25 @@
{% block title %} {{ title }} {% endblock %}
{% block breadcrumbs %}
+<div class="item-breadcrumbs small text-muted">
{% include "templates/includes/breadcrumbs.html" %}
+</div>
{% endblock %}
{% block page_content %}
-{% from "erpnext/templates/includes/macros.html" import product_image %}
-<div class="item-content">
- <div class="product-page-content" itemscope itemtype="http://schema.org/Product">
- <div class="row mb-5">
- {% include "templates/generators/item/item_image.html" %}
- {% include "templates/generators/item/item_details.html" %}
+<div class="product-container">
+ {% from "erpnext/templates/includes/macros.html" import product_image %}
+ <div class="item-content">
+ <div class="product-page-content" itemscope itemtype="http://schema.org/Product">
+ <div class="row mb-5">
+ {% include "templates/generators/item/item_image.html" %}
+ {% include "templates/generators/item/item_details.html" %}
+ </div>
+
+ {% include "templates/generators/item/item_specifications.html" %}
+
+ {{ doc.website_content or '' }}
</div>
-
- {% include "templates/generators/item/item_specifications.html" %}
-
- {{ doc.website_content or '' }}
</div>
</div>
{% endblock %}
diff --git a/erpnext/templates/generators/item/item_add_to_cart.html b/erpnext/templates/generators/item/item_add_to_cart.html
index dbf15de..f5adbf0 100644
--- a/erpnext/templates/generators/item/item_add_to_cart.html
+++ b/erpnext/templates/generators/item/item_add_to_cart.html
@@ -6,10 +6,10 @@
<div class="item-cart row mt-2" data-variant-item-code="{{ item_code }}">
<div class="col-md-12">
{% if cart_settings.show_price and product_info.price %}
- <h4>
+ <div class="product-price">
{{ product_info.price.formatted_price_sales_uom }}
- <small class="text-muted">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small>
- </h4>
+ <small class="formatted-price">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small>
+ </div>
{% else %}
{{ _("Unit of Measurement") }} : {{ product_info.uom }}
{% endif %}
@@ -17,11 +17,11 @@
{% if cart_settings.show_stock_availability %}
<div>
{% if product_info.in_stock == 0 %}
- <span class="text-danger">
+ <span class="text-danger no-stock">
{{ _('Not in stock') }}
</span>
{% elif product_info.in_stock == 1 %}
- <span class="text-success">
+ <span class="text-success has-stock">
{{ _('In stock') }}
{% if product_info.show_stock_qty and product_info.stock_qty %}
({{ product_info.stock_qty[0][0] }})
@@ -30,7 +30,7 @@
{% endif %}
</div>
{% endif %}
- <div class="mt-3">
+ <div class="mt-5 mb-5">
{% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
<a href="/cart"
class="btn btn-light btn-view-in-cart {% if not product_info.qty %}hidden{% endif %}"
@@ -40,8 +40,13 @@
</a>
<button
data-item-code="{{item_code}}"
- class="btn btn-outline-primary btn-add-to-cart {% if product_info.qty %}hidden{% endif %}"
+ class="btn btn-primary btn-add-to-cart {% if product_info.qty %}hidden{% endif %} w-100"
>
+ <span class="mr-2">
+ <svg class="icon icon-md">
+ <use href="#icon-assets"></use>
+ </svg>
+ </span>
{{ _("Add to Cart") }}
</button>
{% endif %}
diff --git a/erpnext/templates/generators/item/item_configure.html b/erpnext/templates/generators/item/item_configure.html
index 73f9ec9..b61ac73 100644
--- a/erpnext/templates/generators/item/item_configure.html
+++ b/erpnext/templates/generators/item/item_configure.html
@@ -1,9 +1,9 @@
{% if shopping_cart and shopping_cart.cart_settings.enabled %}
{% set cart_settings = shopping_cart.cart_settings %}
-<div class="mt-3">
+<div class="mt-5 mb-6">
{% if cart_settings.enable_variants | int %}
- <button class="btn btn-primary btn-configure"
+ <button class="btn btn-primary-light btn-configure"
data-item-code="{{ doc.name }}"
data-item-name="{{ doc.item_name }}"
>
diff --git a/erpnext/templates/generators/item/item_configure.js b/erpnext/templates/generators/item/item_configure.js
index 5fd9011..8eadb84 100644
--- a/erpnext/templates/generators/item/item_configure.js
+++ b/erpnext/templates/generators/item/item_configure.js
@@ -187,42 +187,55 @@
}
get_html_for_item_found({ filtered_items_count, filtered_items, exact_match, product_info }) {
- const exact_match_message = __('1 exact match.');
- const one_item = exact_match.length === 1 ?
- exact_match[0] :
- filtered_items_count === 1 ?
- filtered_items[0] : '';
+ const one_item = exact_match.length === 1
+ ? exact_match[0]
+ : filtered_items_count === 1
+ ? filtered_items[0]
+ : '';
const item_add_to_cart = one_item ? `
- <div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
- <div>
- <div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
- </div>
- <a href data-action="btn_add_to_cart" data-item-code="${one_item}">
- ${__('Add to cart')}
- </a>
- </div>
- `: '';
+ <button data-item-code="${one_item}"
+ class="btn btn-primary btn-add-to-cart w-100"
+ data-action="btn_add_to_cart"
+ >
+ <span class="mr-2">
+ ${frappe.utils.icon('assets', 'md')}
+ </span>
+ ${__("Add to Cart")}s
+ </button>
+ ` : '';
const items_found = filtered_items_count === 1 ?
__('{0} item found.', [filtered_items_count]) :
__('{0} items found.', [filtered_items_count]);
- const item_found_status = `
- <div class="alert alert-warning d-flex justify-content-between align-items-center" role="alert">
- <span>
- ${exact_match.length === 1 ? '' : items_found}
- ${exact_match.length === 1 ? `<span>${exact_match_message}</span>` : ''}
- </span>
- <a href data-action="btn_clear_values">
- ${__('Clear values')}
+ /* eslint-disable indent */
+ const item_found_status = exact_match.length === 1
+ ? `<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
+ <div><div>
+ ${one_item}
+ ${product_info && product_info.price
+ ? '(' + product_info.price.formatted_price_sales_uom + ')'
+ : ''
+ }
+ </div></div>
+ <a href data-action="btn_clear_values" data-item-code="${one_item}">
+ ${__('Clear Values')}
</a>
- </div>
- `;
+ </div>`
+ : `<div class="alert alert-warning d-flex justify-content-between align-items-center" role="alert">
+ <span>
+ ${items_found}
+ </span>
+ <a href data-action="btn_clear_values">
+ ${__('Clear values')}
+ </a>
+ </div>`;
+ /* eslint-disable indent */
return `
- ${item_add_to_cart}
${item_found_status}
+ ${item_add_to_cart}
`;
}
@@ -254,8 +267,8 @@
}
append_status_area() {
- this.dialog.$status_area = $('<div class="status-area">');
- this.dialog.$wrapper.find('.modal-body').prepend(this.dialog.$status_area);
+ this.dialog.$status_area = $('<div class="status-area mt-5">');
+ this.dialog.$wrapper.find('.modal-body').append(this.dialog.$status_area);
this.dialog.$wrapper.on('click', '[data-action]', (e) => {
e.preventDefault();
const $target = $(e.currentTarget);
@@ -263,7 +276,7 @@
const method = this[action];
method.call(this, e);
});
- this.dialog.$body.css({ maxHeight: '75vh', overflow: 'auto', overflowX: 'hidden' });
+ this.dialog.$wrapper.addClass('item-configurator-dialog');
}
get_next_attribute_and_values(selected_attributes) {
diff --git a/erpnext/templates/generators/item/item_details.html b/erpnext/templates/generators/item/item_details.html
index 4cbecb0..3b77585 100644
--- a/erpnext/templates/generators/item/item_details.html
+++ b/erpnext/templates/generators/item/item_details.html
@@ -1,14 +1,21 @@
-<div class="col-md-8">
+<div class="col-md-7 product-details">
<!-- title -->
-<h1 itemprop="name">
+<h1 class="product-title" itemprop="name">
{{ item_name }}
</h1>
-<p class="text-muted">
+<p class="product-code">
<span>{{ _("Item Code") }}:</span>
<span itemprop="productID">{{ doc.name }}</span>
</p>
+{% if has_variants %}
+ <!-- configure template -->
+ {% include "templates/generators/item/item_configure.html" %}
+{% else %}
+ <!-- add variant to cart -->
+ {% include "templates/generators/item/item_add_to_cart.html" %}
+{% endif %}
<!-- description -->
-<div itemprop="description">
+<div class="product-description" itemprop="description">
{% if frappe.utils.strip_html(doc.web_long_description or '') %}
{{ doc.web_long_description | safe }}
{% elif frappe.utils.strip_html(doc.description or '') %}
@@ -17,12 +24,4 @@
{{ _("No description given") }}
{% endif %}
</div>
-
-{% if has_variants %}
- <!-- configure template -->
- {% include "templates/generators/item/item_configure.html" %}
-{% else %}
- <!-- add variant to cart -->
- {% include "templates/generators/item/item_add_to_cart.html" %}
-{% endif %}
</div>
diff --git a/erpnext/templates/generators/item/item_image.html b/erpnext/templates/generators/item/item_image.html
index 5d46a45..39a30d0 100644
--- a/erpnext/templates/generators/item/item_image.html
+++ b/erpnext/templates/generators/item/item_image.html
@@ -1,42 +1,42 @@
-<div class="col-md-4 h-100">
-{% if slides %}
-{{ product_image(slides[0].image, 'product-image') }}
-<div class="item-slideshow">
- {% for item in slides %}
- <img class="item-slideshow-image mt-2 {% if loop.first %}active{% endif %}"
- src="{{ item.image }}" alt="{{ item.heading }}">
- {% endfor %}
-</div>
-<!-- Simple image slideshow -->
-<script>
- frappe.ready(() => {
- $('.page_content').on('click', '.item-slideshow-image', (e) => {
- const $img = $(e.currentTarget);
- const link = $img.prop('src');
- const $product_image = $('.product-image');
- $product_image.find('a').prop('href', link);
- $product_image.find('img').prop('src', link);
+<div class="col-md-5 h-100 d-flex">
+ {% if slides %}
+ <div class="item-slideshow d-flex flex-column mr-3">
+ {% for item in slides %}
+ <img class="item-slideshow-image mb-2 {% if loop.first %}active{% endif %}"
+ src="{{ item.image }}" alt="{{ item.heading }}">
+ {% endfor %}
+ </div>
+ {{ product_image(slides[0].image, 'product-image') }}
+ <!-- Simple image slideshow -->
+ <script>
+ frappe.ready(() => {
+ $('.page_content').on('click', '.item-slideshow-image', (e) => {
+ const $img = $(e.currentTarget);
+ const link = $img.prop('src');
+ const $product_image = $('.product-image');
+ $product_image.find('a').prop('href', link);
+ $product_image.find('img').prop('src', link);
- $('.item-slideshow-image').removeClass('active');
- $img.addClass('active');
- });
- })
-</script>
-{% else %}
-{{ product_image(website_image or image or 'no-image.jpg', alt=website_image_alt or item_name) }}
-{% endif %}
+ $('.item-slideshow-image').removeClass('active');
+ $img.addClass('active');
+ });
+ })
+ </script>
+ {% else %}
+ {{ product_image(website_image or image or 'no-image.jpg', alt=website_image_alt or item_name) }}
+ {% endif %}
-<!-- Simple image preview -->
+ <!-- Simple image preview -->
-<div class="image-zoom-view" style="display: none;">
- <button type="button" class="close" aria-label="Close">
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
- stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x">
- <line x1="18" y1="6" x2="6" y2="18"></line>
- <line x1="6" y1="6" x2="18" y2="18"></line>
- </svg>
- </button>
-</div>
+ <div class="image-zoom-view" style="display: none;">
+ <button type="button" class="close" aria-label="Close">
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x">
+ <line x1="18" y1="6" x2="6" y2="18"></line>
+ <line x1="6" y1="6" x2="18" y2="18"></line>
+ </svg>
+ </button>
+ </div>
</div>
<style>
.website-image {
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index 40a064f..393c3a4 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -1,38 +1,139 @@
{% extends "templates/web.html" %}
-{% block header %}<h1>{{ name }}</h1>{% endblock %}
+{% block header %}
+<!-- <h2>{{ title }}</h2> -->
+{% endblock header %}
+
+{% block script %}
+<script type="text/javascript" src="/all-products/index.js"></script>
+{% endblock %}
{% block page_content %}
<div class="item-group-content" itemscope itemtype="http://schema.org/Product">
<div class="item-group-slideshow">
{% if slideshow %}<!-- slideshow -->
- {% include "templates/includes/slideshow.html" %}
+ {{ web_block(
+ "Hero Slider",
+ values=slideshow,
+ add_container=0,
+ add_top_padding=0,
+ add_bottom_padding=0,
+ ) }}
{% endif %}
+ <h2 class="mt-3">{{ title }}</h2>
{% if description %}<!-- description -->
- <div class="mb-3" itemprop="description">{{ description or ""}}</div>
+ <div class="item-group-description text-muted mb-5" itemprop="description">{{ description or ""}}</div>
{% endif %}
</div>
<div class="row">
- <div class="col-md-8">
- {% if items %}
- <div id="search-list">
- {% for i in range(0, page_length) %}
- {% if items[i] %}
- {%- set item = items[i] %}
+ <div class="col-12 order-2 col-md-9 order-md-2 item-card-group-section">
+ <div class="row products-list">
+ {% if items %}
+ {% for item in items %}
{% include "erpnext/www/all-products/item_row.html" %}
- {% endif %}
+ {% endfor %}
+ {% else %}
+ {% include "erpnext/www/all-products/not_found.html" %}
+ {% endif %}
+ </div>
+ </div>
+ <div class="col-12 order-1 col-md-3 order-md-1">
+ <div class="collapse d-md-block mr-4 filters-section" id="product-filters">
+ <div class="d-flex justify-content-between align-items-center mb-5 title-section">
+ <div class="mb-4 filters-title" > {{ _('Filters') }} </div>
+ <a class="mb-4 clear-filters" href="/{{ doc.route }}">{{ _('Clear All') }}</a>
+ </div>
+ {% for field_filter in field_filters %}
+ {%- set item_field = field_filter[0] %}
+ {%- set values = field_filter[1] %}
+ <div class="mb-4 filter-block pb-5">
+ <div class="filter-label mb-3">{{ item_field.label }}</div>
+
+ {% if values | len > 20 %}
+ <!-- show inline filter if values more than 20 -->
+ <input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
+ {% endif %}
+
+ {% if values %}
+ <div class="filter-options">
+ {% for value in values %}
+ <div class="checkbox" data-value="{{ value }}">
+ <label for="{{value}}">
+ <input type="checkbox"
+ class="product-filter field-filter"
+ id="{{value}}"
+ data-filter-name="{{ item_field.fieldname }}"
+ data-filter-value="{{ value }}"
+ >
+ <span class="label-area">{{ value }}</span>
+ </label>
+ </div>
+ {% endfor %}
+ </div>
+ {% else %}
+ <i class="text-muted">{{ _('No values') }}</i>
+ {% endif %}
+ </div>
+ {% endfor %}
+
+ {% for attribute in attribute_filters %}
+ <div class="mb-4 filter-block pb-5">
+ <div class="filter-label mb-3">{{ attribute.name}}</div>
+ {% if values | len > 20 %}
+ <!-- show inline filter if values more than 20 -->
+ <input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
+ {% endif %}
+
+ {% if attribute.item_attribute_values %}
+ <div class="filter-options">
+ {% for attr_value in attribute.item_attribute_values %}
+ <div class="checkbox">
+ <label data-value="{{ value }}">
+ <input type="checkbox"
+ class="product-filter attribute-filter"
+ id="{{attr_value.name}}"
+ data-attribute-name="{{ attribute.name }}"
+ data-attribute-value="{{ attr_value.attribute_value }}"
+ {% if attr_value.checked %} checked {% endif %}>
+ <span class="label-area">{{ attr_value.attribute_value }}</span>
+ </label>
+ </div>
+ {% endfor %}
+ </div>
+ {% else %}
+ <i class="text-muted">{{ _('No values') }}</i>
+ {% endif %}
+ </div>
{% endfor %}
</div>
- <div class="item-group-nav-buttons">
- {% if frappe.form_dict.start|int > 0 %}
- <a class="btn btn-outline-secondary" href="/{{ pathname }}?start={{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</a>
- {% endif %}
- {% if items|length > page_length %}
- <a class="btn btn-outline-secondary" href="/{{ pathname }}?start={{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</a>
- {% endif %}
- </div>
- {% else %}
- <div class="text-muted">{{ _("No items listed") }}.</div>
+
+ <script>
+ frappe.ready(() => {
+ $('.product-filter-filter').on('keydown', frappe.utils.debounce((e) => {
+ const $input = $(e.target);
+ const keyword = ($input.val() || '').toLowerCase();
+ const $filter_options = $input.next('.filter-options');
+
+ $filter_options.find('.custom-control').show();
+ $filter_options.find('.custom-control').each((i, el) => {
+ const $el = $(el);
+ const value = $el.data('value').toLowerCase();
+ if (!value.includes(keyword)) {
+ $el.hide();
+ }
+ });
+ }, 300));
+ })
+ </script>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-12">
+ {% if frappe.form_dict.start|int > 0 %}
+ <button class="btn btn-outline-secondary btn-prev" data-start="{{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</button>
+ {% endif %}
+ {% if items|length >= page_length %}
+ <button class="btn btn-outline-secondary btn-next" data-start="{{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</button>
{% endif %}
</div>
</div>
diff --git a/erpnext/templates/generators/job_opening.html b/erpnext/templates/generators/job_opening.html
index f92e72e..c562db3 100644
--- a/erpnext/templates/generators/job_opening.html
+++ b/erpnext/templates/generators/job_opening.html
@@ -13,10 +13,21 @@
{%- if description -%}
<div>{{ description }}</div>
{% endif %}
+
+{%- if publish_salary_range -%}
+<div><b>{{_("Salary range per month")}}: </b>{{ frappe.format_value(frappe.utils.flt(lower_range), currency=currency) }} - {{ frappe.format_value(frappe.utils.flt(upper_range), currency=currency) }}</div>
+{% endif %}
+
<p style='margin-top: 30px'>
- <a class='btn btn-primary'
+ {%- if job_application_route -%}
+ <a class='btn btn-primary'
+ href='/{{job_application_route}}?new=1&job_title={{ doc.name }}'>
+ {{ _("Apply Now") }}</a>
+ {% else %}
+ <a class='btn btn-primary'
href='/job_application?new=1&job_title={{ doc.name }}'>
{{ _("Apply Now") }}</a>
+ {% endif %}
</p>
{% endblock %}
diff --git a/erpnext/templates/includes/address_row.html b/erpnext/templates/includes/address_row.html
index dadd2df..6d4dd54 100644
--- a/erpnext/templates/includes/address_row.html
+++ b/erpnext/templates/includes/address_row.html
@@ -2,7 +2,7 @@
<a href="/addresses?name={{ doc.name | urlencode }}" class="no-underline text-reset">
<div class="row">
<div class="col-3">
- <span class="indicator {{ "red" if doc.address_type=="Office" else "green" if doc.address_type=="Billing" else "blue" if doc.address_type=="Shipping" else "darkgrey" }}">{{ doc.address_title }}</span>
+ <span class="indicator {{ "red" if doc.address_type=="Office" else "green" if doc.address_type=="Billing" else "blue" if doc.address_type=="Shipping" else "gray" }}">{{ doc.address_title }}</span>
</div>
<div class="col-2"> {{ _(doc.address_type) }} </div>
<div class="col-2"> {{ doc.city }} </div>
diff --git a/erpnext/templates/includes/cart.js b/erpnext/templates/includes/cart.js
index c6dfd35..c390cd1 100644
--- a/erpnext/templates/includes/cart.js
+++ b/erpnext/templates/includes/cart.js
@@ -14,7 +14,7 @@
},
bind_events: function() {
- shopping_cart.bind_address_select();
+ shopping_cart.bind_address_picker_dialog();
shopping_cart.bind_place_order();
shopping_cart.bind_request_quotation();
shopping_cart.bind_change_qty();
@@ -23,28 +23,78 @@
shopping_cart.bind_coupon_code();
},
- bind_address_select: function() {
- $(".cart-addresses").on('click', '.address-card', function(e) {
- const $card = $(e.currentTarget);
- const address_type = $card.closest('[data-address-type]').attr('data-address-type');
- const address_name = $card.closest('[data-address-name]').attr('data-address-name');
- return frappe.call({
- type: "POST",
- method: "erpnext.shopping_cart.cart.update_cart_address",
- freeze: true,
- args: {
- address_type,
- address_name
- },
- callback: function(r) {
- if(!r.exc) {
- $(".cart-tax-items").html(r.message.taxes);
- }
- }
- });
+ bind_address_picker_dialog: function() {
+ const d = this.get_update_address_dialog();
+ this.parent.find('.btn-change-address').on('click', (e) => {
+ const type = $(e.currentTarget).parents('.address-container').attr('data-address-type');
+ $(d.get_field('address_picker').wrapper).html(
+ this.get_address_template(type)
+ );
+ d.show();
});
},
+ get_update_address_dialog() {
+ let d = new frappe.ui.Dialog({
+ title: "Select Address",
+ fields: [{
+ 'fieldtype': 'HTML',
+ 'fieldname': 'address_picker',
+ }],
+ primary_action_label: __('Set Address'),
+ primary_action: () => {
+ const $card = d.$wrapper.find('.address-card.active');
+ const address_type = $card.closest('[data-address-type]').attr('data-address-type');
+ const address_name = $card.closest('[data-address-name]').attr('data-address-name');
+ frappe.call({
+ type: "POST",
+ method: "erpnext.shopping_cart.cart.update_cart_address",
+ freeze: true,
+ args: {
+ address_type,
+ address_name
+ },
+ callback: function(r) {
+ d.hide();
+ if (!r.exc) {
+ $(".cart-tax-items").html(r.message.taxes);
+ shopping_cart.parent.find(
+ `.address-container[data-address-type="${address_type}"]`
+ ).html(r.message.address);
+ }
+ }
+ });
+ }
+ });
+
+ return d;
+ },
+
+ get_address_template(type) {
+ return {
+ shipping: `<div class="mb-3" data-section="shipping-address">
+ <div class="row no-gutters" data-fieldname="shipping_address_name">
+ {% for address in shipping_addresses %}
+ <div class="mr-3 mb-3 w-100" data-address-name="{{address.name}}" data-address-type="shipping"
+ {% if doc.shipping_address_name == address.name %} data-active {% endif %}>
+ {% include "templates/includes/cart/address_picker_card.html" %}
+ </div>
+ {% endfor %}
+ </div>
+ </div>`,
+ billing: `<div class="mb-3" data-section="billing-address">
+ <div class="row no-gutters" data-fieldname="customer_address">
+ {% for address in billing_addresses %}
+ <div class="mr-3 mb-3 w-100" data-address-name="{{address.name}}" data-address-type="billing"
+ {% if doc.shipping_address_name == address.name %} data-active {% endif %}>
+ {% include "templates/includes/cart/address_picker_card.html" %}
+ </div>
+ {% endfor %}
+ </div>
+ </div>`,
+ }[type];
+ },
+
bind_place_order: function() {
$(".btn-place-order").on("click", function() {
shopping_cart.place_order(this);
@@ -221,6 +271,7 @@
frappe.ready(function() {
$(".cart-icon").hide();
+ shopping_cart.parent = $(".cart-container");
shopping_cart.bind_events();
});
diff --git a/erpnext/templates/includes/cart/address_card.html b/erpnext/templates/includes/cart/address_card.html
index 646210e..667144b 100644
--- a/erpnext/templates/includes/cart/address_card.html
+++ b/erpnext/templates/includes/cart/address_card.html
@@ -1,12 +1,17 @@
<div class="card address-card h-100">
- <div class="check" style="position: absolute; right: 15px; top: 15px;">
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
+ <div class="btn btn-sm btn-default btn-change-address" style="position: absolute; right: 0; top: 0;">
+ {{ _('Change') }}
</div>
- <div class="card-body">
- <h5 class="card-title">{{ address.title }}</h5>
- <p class="card-text text-muted">
+ <div class="card-body p-0">
+ <div class="card-title">{{ address.title }}</div>
+ <div class="card-text mb-2">
{{ address.display }}
- </p>
- <a href="/addresses?name={{address.name}}" class="card-link">{{ _('Edit') }}</a>
+ </div>
+ <a href="/addresses?name={{address.name}}" class="card-link">
+ <svg class="icon icon-sm">
+ <use href="#icon-edit"></use>
+ </svg>
+ {{ _('Edit') }}
+ </a>
</div>
</div>
diff --git a/erpnext/templates/includes/cart/address_picker_card.html b/erpnext/templates/includes/cart/address_picker_card.html
new file mode 100644
index 0000000..2334ea2
--- /dev/null
+++ b/erpnext/templates/includes/cart/address_picker_card.html
@@ -0,0 +1,12 @@
+<div class="card address-card h-100">
+ <div class="check" style="position: absolute; right: 15px; top: 15px;">
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
+ </div>
+ <div class="card-body">
+ <h5 class="card-title">{{ address.title }}</h5>
+ <p class="card-text text-muted">
+ {{ address.display }}
+ </p>
+ <a href="/addresses?name={{address.name}}" class="card-link">{{ _('Edit') }}</a>
+ </div>
+</div>
\ No newline at end of file
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index aa25c88..84a9430 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -14,31 +14,39 @@
</div>
</div>
{% endif %}
-<div class="mb-3" data-section="shipping-address">
- <h6 class="text-uppercase">{{ _("Shipping Address") }}</h6>
+<div class="mb-3 frappe-card p-5" data-section="shipping-address">
+ <h6>{{ _("Shipping Address") }}</h6>
+ <hr>
+ {% for address in shipping_addresses %}
+ {% if doc.shipping_address_name == address.name %}
<div class="row no-gutters" data-fieldname="shipping_address_name">
- {% for address in shipping_addresses %}
- <div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" data-address-type="shipping" {% if doc.shipping_address_name == address.name %} data-active {% endif %}>
- {% include "templates/includes/cart/address_card.html" %}
- </div>
- {% endfor %}
+ <div class="w-100 address-container" data-address-name="{{address.name}}" data-address-type="shipping" data-active>
+ {% include "templates/includes/cart/address_card.html" %}
+ </div>
</div>
+ {% endif %}
+ {% endfor %}
</div>
-<div class="mb-3" data-section="billing-address">
- <h6 class="text-uppercase">{{ _("Billing Address") }}</h6>
- <div class="row no-gutters" data-fieldname="customer_address">
- {% for address in billing_addresses %}
- <div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" data-address-type="billing" {% if doc.customer_address == address.name %} data-active {% endif %}>
- {% include "templates/includes/cart/address_card.html" %}
- </div>
- {% endfor %}
- </div>
+<div class="checkbox ml-1 mb-2">
+ <label for="input_same_billing">
+ <input type="checkbox" id="input_same_billing" checked>
+ <span class="label-area">{{ _('Billing Address is same as Shipping Address') }}</span>
+ </label>
</div>
-<div class="custom-control custom-checkbox">
- <input type="checkbox" class="custom-control-input" id="input_same_billing" checked>
- <label class="custom-control-label" for="input_same_billing">{{ _('Billing Address is same as Shipping Address') }}</label>
+<div class="mb-3 frappe-card p-5" data-section="billing-address">
+ <h6>{{ _("Billing Address") }}</h6>
+ <hr>
+ {% for address in billing_addresses %}
+ {% if doc.customer_address == address.name %}
+ <div class="row no-gutters" data-fieldname="customer_address">
+ <div class="w-100 address-container" data-address-name="{{address.name}}" data-address-type="billing" data-active>
+ {% include "templates/includes/cart/address_card.html" %}
+ </div>
+ </div>
+ {% endif %}
+ {% endfor %}
</div>
-<button class="btn btn-outline-primary btn-sm mt-3 btn-new-address">{{ _("Add a new address") }}</button>
+<button class="btn btn-outline-primary btn-sm mt-1 btn-new-address bg-white">{{ _("Add a new address") }}</button>
<script>
frappe.ready(() => {
diff --git a/erpnext/templates/includes/cart/cart_address_picker.html b/erpnext/templates/includes/cart/cart_address_picker.html
new file mode 100644
index 0000000..72cc5f5
--- /dev/null
+++ b/erpnext/templates/includes/cart/cart_address_picker.html
@@ -0,0 +1,4 @@
+<div class="mb-3 frappe-card p-5" data-section="shipping-address">
+ <h6>{{ _("Shipping Address") }}</h6>
+</div>
+
diff --git a/erpnext/templates/includes/cart/cart_items.html b/erpnext/templates/includes/cart/cart_items.html
index ca5744b..75441c4 100644
--- a/erpnext/templates/includes/cart/cart_items.html
+++ b/erpnext/templates/includes/cart/cart_items.html
@@ -1,15 +1,15 @@
{% for d in doc.items %}
<tr data-name="{{ d.name }}">
<td>
- <div class="font-weight-bold">
+ <div class="item-title mb-1">
{{ d.item_name }}
</div>
- <div>
+ <div class="item-subtitle">
{{ d.item_code }}
</div>
{%- set variant_of = frappe.db.get_value('Item', d.item_code, 'variant_of') %}
{% if variant_of %}
- <span class="text-muted">
+ <span class="item-subtitle">
{{ _('Variant of') }} <a href="{{frappe.db.get_value('Item', variant_of, 'route')}}">{{ variant_of }}</a>
</span>
{% endif %}
@@ -20,20 +20,20 @@
<td class="text-right">
<div class="input-group number-spinner">
<span class="input-group-prepend d-none d-sm-inline-block">
- <button class="btn btn-outline-secondary cart-btn" data-dir="dwn">–</button>
+ <button class="btn cart-btn" data-dir="dwn">–</button>
</span>
- <input class="form-control text-right cart-qty border-secondary" value="{{ d.get_formatted('qty') }}" data-item-code="{{ d.item_code }}">
+ <input class="form-control text-center cart-qty" value="{{ d.get_formatted('qty') }}" data-item-code="{{ d.item_code }}">
<span class="input-group-append d-none d-sm-inline-block">
- <button class="btn btn-outline-secondary cart-btn" data-dir="up">+</button>
+ <button class="btn cart-btn" data-dir="up">+</button>
</span>
</div>
</td>
{% if cart_settings.enable_checkout %}
- <td class="text-right">
+ <td class="text-right item-subtotal">
<div>
{{ d.get_formatted('amount') }}
</div>
- <span class="text-muted">
+ <span class="item-rate">
{{ _('Rate:') }} {{ d.get_formatted('rate') }}
</span>
</td>
diff --git a/erpnext/templates/includes/footer/footer_extension.html b/erpnext/templates/includes/footer/footer_extension.html
index 6171b61..c7f0d06 100644
--- a/erpnext/templates/includes/footer/footer_extension.html
+++ b/erpnext/templates/includes/footer/footer_extension.html
@@ -1,12 +1,12 @@
{% if not hide_footer_signup %}
<div class="input-group">
- <input type="text" class="form-control border-secondary"
+ <input type="text" class="form-control"
id="footer-subscribe-email"
placeholder="{{ _('Your email address...') }}"
aria-label="{{ _('Your email address...') }}"
aria-describedby="footer-subscribe-button">
<div class="input-group-append">
- <button class="btn btn-sm btn-outline-secondary"
+ <button class="btn btn-sm btn-default"
type="button" id="footer-subscribe-button">{{ _("Get Updates") }}</button>
</div>
</div>
diff --git a/erpnext/templates/includes/issue_row.html b/erpnext/templates/includes/issue_row.html
index ff868fa..a04f558 100644
--- a/erpnext/templates/includes/issue_row.html
+++ b/erpnext/templates/includes/issue_row.html
@@ -1,8 +1,8 @@
<div class="web-list-item transaction-list-item">
<a href="/issues?name={{ doc.name }}" class="no-underline">
- <div class="row py-4 border-bottom">
+ <div class="row py-4">
<div class="col-3 d-flex align-items-center">
- {% set indicator = 'red' if doc.status == 'Open' else 'darkgrey' %}
+ {% set indicator = 'red' if doc.status == 'Open' else 'gray' %}
{% set indicator = 'green' if doc.status == 'Closed' else indicator %}
<span class="d-inline-flex indicator {{ indicator }}"></span>
{{ doc.name }}
@@ -10,7 +10,7 @@
<div class="col-5 text-muted">
{{ doc.subject }}</div>
<div class="col-2 d-flex align-items-center text-muted">
- {% set indicator = 'red' if doc.status == 'Open' else 'darkgrey' %}
+ {% set indicator = 'red' if doc.status == 'Open' else 'gray' %}
{% set indicator = 'green' if doc.status == 'Closed' else indicator %}
{% set indicator = 'orange' if doc.status == 'Open' and doc.priority == 'Medium' else indicator %}
{% set indicator = 'yellow' if doc.status == 'Open' and doc.priority == 'Low' else indicator %}
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index ea6b00f..c44bfb5 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -7,10 +7,10 @@
</div>
{% endmacro %}
-{% macro product_image(website_image, css_class="", alt="") %}
- <div class="border text-center rounded h-100 {{ css_class }}" style="overflow: hidden;">
+{% macro product_image(website_image, css_class="product-image", alt="") %}
+ <div class="border text-center rounded {{ css_class }}" style="overflow: hidden;">
<img itemprop="image" class="website-image h-100 w-100" alt="{{ alt }}" src="{{ frappe.utils.quoted(website_image or 'no-image.jpg') | abs_url }}">
- </div>
+ </div>
{% endmacro %}
{% macro media_image(website_image, name, css_class="") %}
@@ -18,13 +18,13 @@
{% if not website_image -%}
<div class="sidebar-standard-image"> <div class="standard-image" style="background-color: rgb(250, 251, 252);">{{name}}</div> </div>
{%- endif %}
- {% if website_image -%}
+ {% if website_image -%}
<a href="{{ frappe.utils.quoted(website_image) }}">
<img itemprop="image" src="{{ frappe.utils.quoted(website_image) | abs_url }}"
class="img-responsive img-thumbnail sidebar-image" style="min-height:100%; min-width:100%;">
</a>
- {%- endif %}
- </div>
+ {%- endif %}
+ </div>
{% endmacro %}
{% macro render_homepage_section(section) %}
@@ -40,7 +40,7 @@
<div class="col-md-{{ section.column_value }} mb-4">
<div class="card h-100 justify-content-between">
{% if card.image %}
- <div class="website-image-lazy" data-class="card-img-top h-100" data-src="{{ card.image }}" data-alt="{{ card.title }}"></div>
+ <div class="website-image-lazy" data-class="card-img-top h-75" data-src="{{ card.image }}" data-alt="{{ card.title }}"></div>
{% endif %}
<div class="card-body">
<h5 class="card-title">{{ card.title }}</h5>
@@ -57,4 +57,67 @@
</section>
{% endif %}
-{% endmacro %}
\ No newline at end of file
+{% endmacro %}
+
+{%- macro item_card(title, image, url, description, rate, category, is_featured=False, is_full_width=False, align="Left") -%}
+{%- set align_items_class = resolve_class({
+ 'align-items-end': align == 'Right',
+ 'align-items-center': align == 'Center',
+ 'align-items-start': align == 'Left',
+}) -%}
+{%- set col_size = 3 if is_full_width else 4 -%}
+{% if is_featured %}
+<div class="col-sm-{{ col_size*2 }} item-card">
+ <div class="card featured-item {{ align_items_class }}">
+ {% if image %}
+ <div class="row no-gutters">
+ <div class="col-md-6">
+ <img class="card-img" src="{{ image }}" alt="{{ title }}">
+ </div>
+ <div class="col-md-6">
+ {{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+ </div>
+ </div>
+ {% else %}
+ <div class="col-md-12">
+ {{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+ </div>
+ {% endif %}
+ </div>
+</div>
+{% else %}
+<div class="col-sm-{{ col_size }} item-card">
+ <div class="card {{ align_items_class }}">
+ {% if image %}
+ <div class="card-img-container">
+ <img class="card-img" src="{{ image }}" alt="{{ title }}">
+ </div>
+ {% else %}
+ <div class="card-img-top no-image">
+ {{ frappe.utils.get_abbr(title) }}
+ </div>
+ {% endif %}
+ {{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+ </div>
+</div>
+{% endif %}
+{%- endmacro -%}
+
+{%- macro item_card_body(title, description, url, rate, category, is_featured, align) -%}
+{%- set align_class = resolve_class({
+ 'text-right': align == 'Right',
+ 'text-center': align == 'Center' and not is_featured,
+ 'text-left': align == 'Left' or is_featured,
+}) -%}
+<div class="card-body {{ align_class }}">
+ <div class="product-title">{{ title or '' }}</div>
+ {% if is_featured %}
+ <div class="product-price">{{ rate or '' }}</div>
+ <div class="product-description ellipsis">{{ description or '' }}</div>
+ {% else %}
+ <div class="product-category">{{ category or '' }}</div>
+ <div class="product-price">{{ rate or '' }}</div>
+ {% endif %}
+</div>
+<a href="/{{ url or '#' }}" class="stretched-link"></a>
+{%- endmacro -%}
\ No newline at end of file
diff --git a/erpnext/templates/includes/navbar/navbar_items.html b/erpnext/templates/includes/navbar/navbar_items.html
index 4daf0e7..133d99e 100644
--- a/erpnext/templates/includes/navbar/navbar_items.html
+++ b/erpnext/templates/includes/navbar/navbar_items.html
@@ -2,9 +2,11 @@
{% block navbar_right_extension %}
<li class="shopping-cart cart-icon hidden">
- <a href="/cart" class="nav-link">
- {{ _("Cart") }}
- <span class="badge badge-primary" id="cart-count"></span>
+ <a class="nav-link" href="/cart">
+ <svg class="icon icon-lg">
+ <use href="#icon-assets"></use>
+ </svg>
+ <span class="badge badge-primary cart-badge" id="cart-count"></span>
</a>
</li>
{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/includes/order/order_taxes.html b/erpnext/templates/includes/order/order_taxes.html
index ebec838..d2c458e 100644
--- a/erpnext/templates/includes/order/order_taxes.html
+++ b/erpnext/templates/includes/order/order_taxes.html
@@ -29,12 +29,12 @@
{{ _("Discount") }}
</th>
<th class="text-right tot_quotation_discount">
- {% set tot_quotation_discount = [] %}
- {%- for item in doc.items -%}
- {% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
- * item.discount_percentage) / 100)) %}{% endif %}
- {% endfor %}
- {{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
+ {% set tot_quotation_discount = [] %}
+ {%- for item in doc.items -%}
+ {% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
+ * item.discount_percentage) / 100)) %}{% endif %}
+ {% endfor %}
+ {{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
</th>
</tr>
{% endif %}
@@ -47,51 +47,52 @@
{{ _("Total Amount") }}
</th>
<th class="text-right">
- <span>
- {% set total_amount = [] %}
- {%- for item in doc.items -%}
- {% if total_amount.append((item.price_list_rate * item.qty)) %}{% endif %}
- {% endfor %}
- {{ frappe.utils.fmt_money((total_amount | sum),currency=doc.currency) }}
- </span>
+ <span>
+ {% set total_amount = [] %}
+ {%- for item in doc.items -%}
+ {% if total_amount.append((item.price_list_rate * item.qty)) %}{% endif %}
+ {% endfor %}
+ {{ frappe.utils.fmt_money((total_amount | sum),currency=doc.currency) }}
+ </span>
</th>
</tr>
<tr>
- <th class="text-right" colspan="2">
- {{ _("Applied Coupon Code") }}
- </th>
- <th class="text-right">
- <span>
- {%- for row in frappe.get_all(doctype="Coupon Code",
- fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
- <span>{{ row.coupon_code }}</span>
- {% endfor %}
- </span>
- </th>
+ <th class="text-right" colspan="2">
+ {{ _("Applied Coupon Code") }}
+ </th>
+ <th class="text-right">
+ <span>
+ {%- for row in frappe.get_all(doctype="Coupon Code",
+ fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
+ <span>{{ row.coupon_code }}</span>
+ {% endfor %}
+ </span>
+ </th>
</tr>
<tr>
- <th class="text-right" colspan="2">
- {{ _("Discount") }}
- </th>
- <th class="text-right">
- <span>
- {% set tot_SO_discount = [] %}
- {%- for item in doc.items -%}
- {% if tot_SO_discount.append((((item.price_list_rate * item.qty)
- * item.discount_percentage) / 100)) %}{% endif %}
- {% endfor %}
- {{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
- </span>
- </th>
+ <th class="text-right" colspan="2">
+ {{ _("Discount") }}
+ </th>
+ <th class="text-right">
+ <span>
+ {% set tot_SO_discount = [] %}
+ {%- for item in doc.items -%}
+ {% if tot_SO_discount.append((((item.price_list_rate * item.qty)
+ * item.discount_percentage) / 100)) %}{% endif %}
+ {% endfor %}
+ {{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
+ </span>
+ </th>
</tr>
{% endif %}
{% endif %}
<tr>
- <th class="text-right" colspan="2">
+ <th></th>
+ <th class="item-grand-total">
{{ _("Grand Total") }}
</th>
- <th class="text-right">
+ <th class="text-right item-grand-total">
{{ doc.get_formatted("grand_total") }}
</th>
</tr>
diff --git a/erpnext/templates/includes/products_as_list.html b/erpnext/templates/includes/products_as_list.html
index 88910d0..9bf9fd9 100644
--- a/erpnext/templates/includes/products_as_list.html
+++ b/erpnext/templates/includes/products_as_list.html
@@ -1,4 +1,4 @@
-{% from "erpnext/templates/includes/macros.html" import product_image_square %}
+{% from "erpnext/templates/includes/macros.html" import item_card, item_card_body %}
<a class="product-link product-list-link" href="{{ route|abs_url }}">
<div class='row'>
diff --git a/erpnext/templates/includes/projects/project_row.html b/erpnext/templates/includes/projects/project_row.html
index 73c83ef..4c8c40d 100644
--- a/erpnext/templates/includes/projects/project_row.html
+++ b/erpnext/templates/includes/projects/project_row.html
@@ -15,7 +15,7 @@
</div>
</div>
{% else %}
- <span class="indicator {{ "red" if doc.status=="Open" else "darkgrey" }}">
+ <span class="indicator {{ "red" if doc.status=="Open" else "gray" }}">
{{ doc.status }}</span>
{% endif %}
</div>
diff --git a/erpnext/templates/includes/projects/project_tasks.html b/erpnext/templates/includes/projects/project_tasks.html
index 94c692c..50b9f4b 100644
--- a/erpnext/templates/includes/projects/project_tasks.html
+++ b/erpnext/templates/includes/projects/project_tasks.html
@@ -3,7 +3,7 @@
<a class="no-decoration task-link {{ task.css_seen }}" href="/tasks?name={{ task.name }}">
<div class='row project-item'>
<div class='col-xs-9'>
- <span class="indicator {{ "red" if task.status=="Open" else "green" if task.status=="Closed" else "darkgrey" }}" title="{{ task.status }}" > {{ task.subject }}</span>
+ <span class="indicator {{ "red" if task.status=="Open" else "green" if task.status=="Closed" else "gray" }}" title="{{ task.status }}" > {{ task.subject }}</span>
<div class="small text-muted item-timestamp"
title="{{ frappe.utils.pretty_date(task.modified) }}">
{{ _("modified") }} {{ frappe.utils.pretty_date(task.modified) }}
@@ -16,9 +16,9 @@
</span>
{% else %}
<span class="avatar avatar-small standard-image" title="Assigned to {{ task.todo.owner }}">
-
+
</span>
- {% endif %}
+ {% endif %}
{% endif %} </div>
<div class='col-xs-2'>
<span class="pull-right list-comment-count small {{ "text-extra-muted" if task.comment_count==0 else "text-muted" }}">
diff --git a/erpnext/templates/includes/projects/project_timesheets.html b/erpnext/templates/includes/projects/project_timesheets.html
index fb3806c..05a07c1 100644
--- a/erpnext/templates/includes/projects/project_timesheets.html
+++ b/erpnext/templates/includes/projects/project_timesheets.html
@@ -3,19 +3,19 @@
<a class="no-decoration timesheet-link {{ timesheet.css_seen }}" href="/timesheet/{{ timesheet.info.name}}">
<div class='row project-item'>
<div class='col-xs-10'>
- <span class="indicator {{ "blue" if timesheet.info.status=="Submitted" else "red" if timesheet.info.status=="Draft" else "darkgrey" }}" title="{{ timesheet.info.status }}" > {{ timesheet.info.name }} </span>
+ <span class="indicator {{ "blue" if timesheet.info.status=="Submitted" else "red" if timesheet.info.status=="Draft" else "gray" }}" title="{{ timesheet.info.status }}" > {{ timesheet.info.name }} </span>
<div class="small text-muted item-timestamp">
{{ _("From") }} {{ frappe.format_date(timesheet.from_time) }} {{ _("to") }} {{ frappe.format_date(timesheet.to_time) }}
</div>
</div>
<div class='col-xs-1' style="margin-right:-30px;">
<span class="avatar avatar-small" title="{{ timesheet.info.modified_by }}"> <img src="{{ timesheet.info.user_image }}" style="display:flex;"></span>
- </div>
+ </div>
<div class='col-xs-1'>
<span class="pull-right list-comment-count small {{ "text-extra-muted" if timesheet.comment_count==0 else "text-muted" }}">
<i class="octicon octicon-comment-discussion"></i>
{{ timesheet.info.comment_count }}
- </span>
+ </span>
</div>
</div>
</a>
diff --git a/erpnext/templates/includes/timesheet/timesheet_row.html b/erpnext/templates/includes/timesheet/timesheet_row.html
index 4852f59..0f9cc77 100644
--- a/erpnext/templates/includes/timesheet/timesheet_row.html
+++ b/erpnext/templates/includes/timesheet/timesheet_row.html
@@ -1,7 +1,7 @@
<div class="web-list-item transaction-list-item">
<div class="row">
<div class="col-xs-3">
- <span class='indicator {{ "red" if doc.status=="Cancelled" else "green" if doc.status=="Billed" else "blue" if doc.status=="Submitted" else "darkgrey" }} small'>
+ <span class='indicator {{ "red" if doc.status=="Cancelled" else "green" if doc.status=="Billed" else "blue" if doc.status=="Submitted" else "gray" }} small'>
{{ doc.name }}
</span>
</div>
diff --git a/erpnext/templates/includes/transaction_row.html b/erpnext/templates/includes/transaction_row.html
index fd4835e..930d0c2 100644
--- a/erpnext/templates/includes/transaction_row.html
+++ b/erpnext/templates/includes/transaction_row.html
@@ -1,7 +1,7 @@
<div class="web-list-item transaction-list-item">
<div class="row">
<div class="col-sm-4">
- <span class="indicator small {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
+ <span class="indicator small {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "gray") }}">
{{ doc.name }}</span>
<div class="small text-muted transaction-time"
title="{{ frappe.utils.format_datetime(doc.modified, "medium") }}">
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index 3033d15..ea34371 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -2,7 +2,7 @@
{% block title %} {{ _("Shopping Cart") }} {% endblock %}
-{% block header %}<h1>{{ _("Shopping Cart") }}</h1>{% endblock %}
+{% block header %}<h3 class="shopping-cart-header mt-2 mb-6">{{ _("Shopping Cart") }}</h1>{% endblock %}
<!--
{% block script %}
@@ -18,94 +18,122 @@
{% from "templates/includes/macros.html" import item_name_and_description %}
+{% if doc.items %}
<div class="cart-container">
- <div id="cart-error" class="alert alert-danger" style="display: none;"></div>
+ <div class="row m-0">
+ <div class="col-md-8 frappe-card p-5">
+ <div>
+ <div id="cart-error" class="alert alert-danger" style="display: none;"></div>
+ <div class="cart-items-header">
+ {{ _('Items') }}
+ </div>
+ <table class="table mt-3 cart-table">
+ <thead>
+ <tr>
+ <th width="60%">{{ _('Item') }}</th>
+ <th width="20%">{{ _('Quantity') }}</th>
+ {% if cart_settings.enable_checkout %}
+ <th width="20%" class="text-right">{{ _('Subtotal') }}</th>
+ {% endif %}
+ </tr>
+ </thead>
+ <tbody class="cart-items">
+ {% include "templates/includes/cart/cart_items.html" %}
+ </tbody>
+ {% if cart_settings.enable_checkout %}
+ <tfoot class="cart-tax-items">
+ {% include "templates/includes/order/order_taxes.html" %}
+ </tfoot>
+ {% endif %}
+ </table>
+ </div>
+ <div class="row">
+ <div class="col-4">
+ {% if cart_settings.enable_checkout %}
+ <a class="btn btn-outline-primary" href="/orders">
+ {{ _('See past orders') }}
+ </a>
+ {% else %}
+ <a class="btn btn-outline-primary" href="/quotations">
+ {{ _('See past quotations') }}
+ </a>
+ {% endif %}
+ </div>
+ <div class="col-8">
+ {% if doc.items %}
+ <div class="place-order-container">
+ <a class="btn btn-primary-light mr-2" href="/all-products">
+ {{ _("Continue Shopping") }}
+ </a>
+ {% if cart_settings.enable_checkout %}
+ <button class="btn btn-primary btn-place-order" type="button">
+ {{ _("Place Order") }}
+ </button>
+ {% else %}
+ <button class="btn btn-primary btn-request-for-quotation" type="button">
+ {{ _("Request for Quotation") }}
+ </button>
+ {% endif %}
+ </div>
+ {% endif %}
+ </div>
+ </div>
- {% if doc.items %}
- <table class="table table-bordered mt-3">
- <thead>
- <tr>
- <th width="60%">{{ _('Item') }}</th>
- <th width="20%" class="text-right">{{ _('Quantity') }}</th>
- {% if cart_settings.enable_checkout %}
- <th width="20%" class="text-right">{{ _('Subtotal') }}</th>
- {% endif %}
- </tr>
- </thead>
- <tbody class="cart-items">
- {% include "templates/includes/cart/cart_items.html" %}
- </tbody>
- {% if cart_settings.enable_checkout %}
- <tfoot class="cart-tax-items">
- {% include "templates/includes/order/order_taxes.html" %}
- </tfoot>
- {% endif %}
- </table>
- {% else %}
- <p class="text-muted">{{ _('Your cart is Empty') }}</p>
- {% endif %}
- {% if doc.items %}
- <div class="place-order-container">
- {% if cart_settings.enable_checkout %}
- <button class="btn btn-primary btn-place-order" type="button">
- {{ _("Place Order") }}
- </button>
- {% else %}
- <button class="btn btn-primary btn-request-for-quotation" type="button">
- {{ _("Request for Quotation") }}
- </button>
+ {% if doc.items %}
+ {% if doc.tc_name %}
+ <div class="terms-and-conditions-link">
+ <a href class="link-terms-and-conditions" data-terms-name="{{ doc.tc_name }}">
+ {{ _("Terms and Conditions") }}
+ </a>
+ <script>
+ frappe.ready(() => {
+ $('.link-terms-and-conditions').click((e) => {
+ e.preventDefault();
+ const $link = $(e.target);
+ const terms_name = $link.attr('data-terms-name');
+ show_terms_and_conditions(terms_name);
+ })
+ });
+ function show_terms_and_conditions(terms_name) {
+ frappe.call('erpnext.shopping_cart.cart.get_terms_and_conditions', { terms_name })
+ .then(r => {
+ frappe.msgprint({
+ title: terms_name,
+ message: r.message
+ });
+ });
+ }
+ </script>
+ </div>
{% endif %}
</div>
- {% endif %}
- {% if doc.items %}
- {% if doc.tc_name %}
- <div class="terms-and-conditions-link">
- <a href class="link-terms-and-conditions" data-terms-name="{{ doc.tc_name }}">
- {{ _("Terms and Conditions") }}
- </a>
- <script>
- frappe.ready(() => {
- $('.link-terms-and-conditions').click((e) => {
- e.preventDefault();
- const $link = $(e.target);
- const terms_name = $link.attr('data-terms-name');
- show_terms_and_conditions(terms_name);
- })
- });
- function show_terms_and_conditions(terms_name) {
- frappe.call('erpnext.shopping_cart.cart.get_terms_and_conditions', { terms_name })
- .then(r => {
- frappe.msgprint({
- title: terms_name,
- message: r.message
- });
- });
- }
- </script>
+ <div class="col-md-4">
+ <div class="cart-addresses">
+ {% include "templates/includes/cart/cart_address.html" %}
+ </div>
</div>
- {% endif %}
-
- <div class="cart-addresses mt-5">
- {% include "templates/includes/cart/cart_address.html" %}
+ {% endif %}
</div>
- {% endif %}
</div>
-
-<div class="row mt-5">
- <div class="col-12">
- {% if cart_settings.enable_checkout %}
- <a href="/orders">
+{% else %}
+<div class="cart-empty frappe-card">
+ <div class="cart-empty-state">
+ <img src="/assets/erpnext/images/ui-states/cart-empty-state.png" alt="Empty State">
+ </div>
+ <div class="cart-empty-message mt-4">{{ _('Your cart is Empty') }}</p>
+ {% if cart_settings.enable_checkout %}
+ <a class="btn btn-outline-primary" href="/orders">
{{ _('See past orders') }}
</a>
{% else %}
- <a href="/quotations">
+ <a class="btn btn-outline-primary" href="/quotations">
{{ _('See past quotations') }}
</a>
- {% endif %}
- </div>
+ {% endif %}
</div>
+{% endif %}
{% endblock %}
diff --git a/erpnext/templates/pages/material_request_info.html b/erpnext/templates/pages/material_request_info.html
index 9d18989..0c2772e 100644
--- a/erpnext/templates/pages/material_request_info.html
+++ b/erpnext/templates/pages/material_request_info.html
@@ -20,12 +20,12 @@
<div class="row transaction-subheading">
<div class="col-xs-6">
- <span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
+ <span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "gray") }}">
{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }}
</span>
</div>
<div class="col-xs-6 text-muted text-right small">
- {{ frappe.utils.formatdate(doc.transaction_date, 'medium') }}
+ {{ frappe.utils.format_date(doc.transaction_date, 'medium') }}
</div>
</div>
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 01b5f6d..07dd676 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -8,7 +8,7 @@
{% block title %}{{ doc.name }}{% endblock %}
{% block header %}
- <h1 class="m-0">{{ doc.name }}</h1>
+ <h2 class="m-0">{{ doc.name }}</h2>
{% endblock %}
{% block header_actions %}
@@ -33,7 +33,7 @@
<div class="row transaction-subheading">
<div class="col-6">
- <span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
+ <span class="indicator-pill {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
{% if doc.doctype == "Quotation" and not doc.docstatus %}
{{ _("Pending") }}
{% else %}
@@ -41,11 +41,11 @@
{% endif %}
</span>
</div>
- <div class="col-6 text-muted text-right small">
- {{ frappe.utils.formatdate(doc.transaction_date, 'medium') }}
+ <div class="col-6 text-muted text-right small pt-3">
+ {{ frappe.utils.format_date(doc.transaction_date, 'medium') }}
{% if doc.valid_till %}
<p>
- {{ _("Valid Till") }}: {{ frappe.utils.formatdate(doc.valid_till, 'medium') }}
+ {{ _("Valid Till") }}: {{ frappe.utils.format_date(doc.valid_till, 'medium') }}
</p>
{% endif %}
</div>
@@ -66,38 +66,39 @@
{% endif %}
<div class="order-container">
-
<!-- items -->
- <div class="order-item-table">
- <div class="row order-items order-item-header text-muted">
- <div class="col-sm-6 col-6 h6 text-uppercase">
+ <table class="order-item-table w-100 table">
+ <thead class="order-items order-item-header">
+ <th width="60%">
{{ _("Item") }}
- </div>
- <div class="col-sm-3 col-xs-3 text-right h6 text-uppercase">
+ </th>
+ <th width="20%" class="text-right">
{{ _("Quantity") }}
- </div>
- <div class="col-sm-3 col-xs-3 text-right h6 text-uppercase">
+ </th>
+ <th width="20%" class="text-right">
{{ _("Amount") }}
- </div>
- </div>
+ </th>
+ </thead>
+ <tbody>
{% for d in doc.items %}
- <div class="row order-items">
- <div class="col-sm-6 col-6">
+ <tr class="order-items">
+ <td>
{{ item_name_and_description(d) }}
- </div>
- <div class="col-sm-3 col-xs-3 text-right">
+ </td>
+ <td class="text-right">
{{ d.qty }}
{% if d.delivered_qty is defined and d.delivered_qty != None %}
<p class="text-muted small">{{ _("Delivered") }} {{ d.delivered_qty }}</p>
{% endif %}
- </div>
- <div class="col-sm-3 col-xs-3 text-right">
+ </td>
+ <td class="text-right">
{{ d.get_formatted("amount") }}
<p class="text-muted small">{{ _("Rate:") }} {{ d.get_formatted("rate") }}</p>
- </div>
- </div>
+ </td>
+ </tr>
{% endfor %}
- </div>
+ </tbody>
+ </table>
<!-- taxes -->
<div class="order-taxes d-flex justify-content-end">
<table>
diff --git a/erpnext/templates/pages/rfq.html b/erpnext/templates/pages/rfq.html
index 5b27a94..6e2edb6 100644
--- a/erpnext/templates/pages/rfq.html
+++ b/erpnext/templates/pages/rfq.html
@@ -77,13 +77,13 @@
<div class="web-list-item transaction-list-item quotations" idx="{{d.name}}">
<div class="row">
<div class="col-sm-6">
- <span class="indicator darkgrey">{{d.name}}</span>
+ <span class="indicator gray">{{d.name}}</span>
</div>
<div class="col-sm-3">
- <span class="small darkgrey">{{d.status}}</span>
+ <span class="small gray">{{d.status}}</span>
</div>
<div class="col-sm-3">
- <span class="small darkgrey">{{d.transaction_date}}</span>
+ <span class="small gray">{{d.transaction_date}}</span>
</div>
</div>
<a class="transaction-item-link" href="/quotations/{{d.name}}">Link</a>
diff --git a/erpnext/templates/print_formats/includes/item_table_description.html b/erpnext/templates/print_formats/includes/item_table_description.html
index 070cca5..7569e50 100644
--- a/erpnext/templates/print_formats/includes/item_table_description.html
+++ b/erpnext/templates/print_formats/includes/item_table_description.html
@@ -1,7 +1,7 @@
-{%- set compact = doc.flags.compact_item_print -%}
-{%- set compact_fields = doc.flags.compact_item_fields -%}
+{%- set compact = print_settings.compact_item_print -%}
+{%- set compact_fields = parent_doc.flags.compact_item_fields -%}
{%- set display_columns = visible_columns|map(attribute="fieldname")| list -%}
-{%- set columns = doc.flags.format_columns(display_columns, compact_fields) -%}
+{%- set columns = parent_doc.flags.format_columns(display_columns, compact_fields) -%}
{% if doc.in_format_data("image") and doc.get("image") and "image" in display_columns -%}
<div class="pull-left" style="max-width: 40%; margin-right: 10px;">
@@ -11,11 +11,11 @@
<div>
{% if doc.in_format_data("item_code") and "item_code" in display_columns -%}
- <div class="primary">
- {% if compact %}<strong>{% endif %}
- {{ _(doc.item_code) }}
- {% if compact %}</strong>{% endif %}
+ {% if compact %}
+ <div class="primary compact-item">
+ {{ _(doc.item_code) }}
</div>
+ {% endif %}
{%- endif %}
{%- if doc.in_format_data("item_name") and "item_name" in display_columns and
diff --git a/erpnext/templates/print_formats/includes/item_table_qty.html b/erpnext/templates/print_formats/includes/item_table_qty.html
index ecaaef4..8e68f1c 100644
--- a/erpnext/templates/print_formats/includes/item_table_qty.html
+++ b/erpnext/templates/print_formats/includes/item_table_qty.html
@@ -1,4 +1,4 @@
-{% set qty_first=frappe.db.get_single_value("Print Settings", "print_uom_after_quantity") %}
+{% set qty_first=print_settings.print_uom_after_quantity %}
{% if qty_first %}
{{ doc.get_formatted("qty", doc) }}
{% if (doc.uom and not doc.is_print_hide("uom")) %} {{ _(doc.uom) }}
diff --git a/erpnext/templates/print_formats/includes/items.html b/erpnext/templates/print_formats/includes/items.html
new file mode 100644
index 0000000..55598e7
--- /dev/null
+++ b/erpnext/templates/print_formats/includes/items.html
@@ -0,0 +1,37 @@
+{%- if data -%}
+ {%- set visible_columns = get_visible_columns(doc.get(df.fieldname),
+ table_meta, df) -%}
+ <div {{ fieldmeta(df) }}>
+ <table class="table table-bordered table-condensed">
+ <thead>
+ <tr>
+ <th style="width: 40px" class="table-sr">{{ _("Sr") }}</th>
+ {% for tdf in visible_columns %}
+ {% if (data and not print_settings.compact_item_print) or tdf.fieldname in doc.flags.compact_item_fields %}
+ <th style="width: {{ get_width(tdf) }};" class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
+ {{ _(tdf.label) }}</th>
+ {% endif %}
+ {% endfor %}
+ </tr>
+ </thead>
+ <tbody>
+ {% for d in data %}
+ <tr>
+ <td class="table-sr">{{ d.idx }}</td>
+ {% for tdf in visible_columns %}
+ {% if not print_settings.compact_item_print or tdf.fieldname in doc.flags.compact_item_fields %}
+ <td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
+ {% if doc.child_print_templates %}
+ {%- set child_templates = doc.child_print_templates.get(df.fieldname) %}
+ <div class="value">{{ print_value(tdf, d, doc, visible_columns, child_templates) }}</div></td>
+ {% else %}
+ <div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
+{%- endif -%}
diff --git a/erpnext/templates/print_formats/includes/taxes.html b/erpnext/templates/print_formats/includes/taxes.html
index 6e984f3..1935542 100644
--- a/erpnext/templates/print_formats/includes/taxes.html
+++ b/erpnext/templates/print_formats/includes/taxes.html
@@ -17,13 +17,13 @@
{{ render_discount_amount(doc) }}
{%- endif -%}
{%- for charge in data -%}
- {%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
+ {%- if (charge.tax_amount or print_settings.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
<div class="row">
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
- <label>{{ charge.get_formatted("description") }}</label></div>
+ <label>{{ charge.get_formatted("description") }}</label>
+ </div>
<div class="col-xs-7 text-right">
- {{ frappe.format_value(frappe.utils.flt(charge.tax_amount),
- table_meta.get_field("tax_amount"), doc, currency=doc.currency) }}
+ {{ charge.get_formatted('tax_amount', doc) }}
</div>
</div>
{%- endif -%}
diff --git a/erpnext/tests/test_search.py b/erpnext/tests/test_search.py
index 566495f..f60e5e4 100644
--- a/erpnext/tests/test_search.py
+++ b/erpnext/tests/test_search.py
@@ -6,13 +6,13 @@
class TestSearch(unittest.TestCase):
# Search for the word "cond", part of the word "conduire" (Lead) in french.
def test_contact_search_in_foreign_language(self):
- frappe.local.lang = 'fr'
- output = filter_dynamic_link_doctypes("DocType", "cond", "name", 0, 20, {
- 'fieldtype': 'HTML',
- 'fieldname': 'contact_html'
- })
- result = [['found' for x in y if x=="Lead"] for y in output]
- self.assertTrue(['found'] in result)
-
- def tearDown(self):
- frappe.local.lang = 'en'
\ No newline at end of file
+ try:
+ frappe.local.lang = 'fr'
+ output = filter_dynamic_link_doctypes("DocType", "cond", "name", 0, 20, {
+ 'fieldtype': 'HTML',
+ 'fieldname': 'contact_html'
+ })
+ result = [['found' for x in y if x=="Lead"] for y in output]
+ self.assertTrue(['found'] in result)
+ finally:
+ frappe.local.lang = 'en'
diff --git a/erpnext/translations/af.csv b/erpnext/translations/af.csv
index 7269bd7..45435d8 100644
--- a/erpnext/translations/af.csv
+++ b/erpnext/translations/af.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Werklike tipe belasting kan nie in Itemkoers in ry {0} ingesluit word nie.,
Add,Voeg,
Add / Edit Prices,Voeg pryse by,
-Add All Suppliers,Voeg alle verskaffers by,
Add Comment,Voeg kommentaar by,
Add Customers,Voeg kliënte by,
Add Employees,Voeg werknemers by,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Kan nie aftrek as die kategorie vir 'Waardasie' of 'Vaulering en Totaal' is nie.,
"Cannot delete Serial No {0}, as it is used in stock transactions","Kan nie reeksnommer {0} uitvee nie, aangesien dit in voorraadtransaksies gebruik word",
Cannot enroll more than {0} students for this student group.,Kan nie meer as {0} studente vir hierdie studente groep inskryf nie.,
-Cannot find Item with this barcode,Kan geen item met hierdie strepieskode vind nie,
Cannot find active Leave Period,Kan nie aktiewe verlofperiode vind nie,
Cannot produce more Item {0} than Sales Order quantity {1},Kan nie meer item {0} produseer as hoeveelheid van die bestelling {1},
Cannot promote Employee with status Left,Kan nie werknemer bevorder met status links nie,
Cannot refer row number greater than or equal to current row number for this Charge type,Kan nie rynommer groter as of gelyk aan huidige rynommer vir hierdie Laai tipe verwys nie,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Kan lading tipe nie as 'Op vorige rybedrag' of 'Op vorige ry totale' vir eerste ry kies nie,
-Cannot set a received RFQ to No Quote,Kan nie 'n RFQ vir geen kwotasie opstel nie,
Cannot set as Lost as Sales Order is made.,Kan nie as verlore gestel word nie aangesien verkoopsbestelling gemaak is.,
Cannot set authorization on basis of Discount for {0},Kan nie magtiging instel op grond van Korting vir {0},
Cannot set multiple Item Defaults for a company.,Kan nie verskeie itemvoorkeure vir 'n maatskappy stel nie.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Kostes word opgedateer in Aankoopontvangste teen elke item,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Kostes sal proporsioneel verdeel word op grond van die hoeveelheid of hoeveelheid van die produk, soos per u keuse",
-Chart Of Accounts,Grafiek van rekeninge,
Chart of Cost Centers,Grafiek van kostesentrums,
Check all,Kyk alles,
Checkout,Uitteken,
@@ -581,7 +577,6 @@
Compensatory Off,Kompenserende Off,
Compensatory leave request days not in valid holidays,Vergoedingsverlof versoek dae nie in geldige vakansiedae,
Complaint,klagte,
-Completed Qty can not be greater than 'Qty to Manufacture',Voltooide hoeveelheid kan nie groter wees as 'Hoeveelheid om te vervaardig' nie,
Completion Date,voltooiingsdatum,
Computer,rekenaar,
Condition,toestand,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Skep en bestuur daaglikse, weeklikse en maandelikse e-posverdelings.",
Create customer quotes,Skep kliënte kwotasies,
Create rules to restrict transactions based on values.,Skep reëls om transaksies gebaseer op waardes te beperk.,
-Created By,Gemaak deur,
Created {0} scorecards for {1} between: ,Geskep {0} telkaarte vir {1} tussen:,
Creating Company and Importing Chart of Accounts,Skep 'n maatskappy en voer rekeningrekeninge in,
Creating Fees,Fooie skep,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Werknemeroordrag kan nie voor die Oordragdatum ingedien word nie,
Employee cannot report to himself.,Werknemer kan nie aan homself rapporteer nie.,
Employee relieved on {0} must be set as 'Left',Werknemer verlig op {0} moet gestel word as 'Links',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Werknemerstatus kan nie op 'Links' gestel word nie, aangesien die volgende werknemers tans aan hierdie werknemer rapporteer:",
Employee {0} already submited an apllication {1} for the payroll period {2},Werknemer {0} het reeds 'n aantekening {1} ingedien vir die betaalperiode {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Werknemer {0} het reeds aansoek gedoen vir {1} tussen {2} en {3}:,
Employee {0} has no maximum benefit amount,Werknemer {0} het geen maksimum voordeelbedrag nie,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Vir ry {0}: Gee beplande hoeveelheid,
"For {0}, only credit accounts can be linked against another debit entry",Vir {0} kan slegs kredietrekeninge gekoppel word teen 'n ander debietinskrywing,
"For {0}, only debit accounts can be linked against another credit entry",Vir {0} kan slegs debietrekeninge gekoppel word teen 'n ander kredietinskrywing,
-Form View,Form View,
Forum Activity,Forum Aktiwiteit,
Free item code is not selected,Gratis itemkode word nie gekies nie,
Freight and Forwarding Charges,Vrag en vragkoste,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Verlof kan nie voor {0} toegeken word nie, aangesien verlofbalans reeds in die toekomstige verlofrekordrekord {1} oorgedra is.",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Verlof kan nie voor {0} toegepas / gekanselleer word nie, aangesien verlofbalans reeds in die toekomstige verlofrekordrekord {1} oorgedra is.",
Leave of type {0} cannot be longer than {1},Verlof van tipe {0} kan nie langer wees as {1},
-Leave the field empty to make purchase orders for all suppliers,Los die veld leeg om bestellings vir alle verskaffers te maak,
Leaves,blare,
Leaves Allocated Successfully for {0},Blare suksesvol toegeken vir {0},
Leaves has been granted sucessfully,Blare is suksesvol toegeken,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Geen items met die materiaal om te vervaardig,
No Items with Bill of Materials.,Geen voorwerpe met materiaalbriewe nie.,
No Permission,Geen toestemming nie,
-No Quote,Geen kwotasie nie,
No Remarks,Geen opmerkings,
No Result to submit,Geen resultaat om in te dien nie,
No Salary Structure assigned for Employee {0} on given date {1},Geen Salarisstruktuur toegeken vir Werknemer {0} op gegewe datum {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Oorvleuelende toestande tussen:,
Owner,Eienaar,
PAN,PAN,
-PO already created for all sales order items,Pos reeds geskep vir alle verkope bestellingsitems,
POS,POS,
POS Profile,POS Profiel,
POS Profile is required to use Point-of-Sale,POS-profiel is nodig om Punt van Verkope te gebruik,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Kies asseblief die laastipe eers,
Please select Company,Kies asseblief Maatskappy,
Please select Company and Designation,Kies asseblief Maatskappy en Aanwysing,
-Please select Company and Party Type first,Kies asseblief eers Maatskappy- en Partytipe,
Please select Company and Posting Date to getting entries,Kies asseblief Maatskappy en Posdatum om inskrywings te kry,
Please select Company first,Kies asseblief Maatskappy eerste,
Please select Completion Date for Completed Asset Maintenance Log,Kies asseblief Voltooiingsdatum vir voltooide bateonderhoudslog,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Ry {0}: UOM Gesprekfaktor is verpligtend,
Row {0}: select the workstation against the operation {1},Ry {0}: kies die werkstasie teen die operasie {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Ry {0}: {1} Serial nommers benodig vir item {2}. U het {3} verskaf.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Ry {0}: {1} is nodig om die openings {2} fakture te skep,
Row {0}: {1} must be greater than 0,Ry {0}: {1} moet groter as 0 wees,
Row {0}: {1} {2} does not match with {3},Ry {0}: {1} {2} stem nie ooreen met {3},
Row {0}:Start Date must be before End Date,Ry {0}: Begindatum moet voor Einddatum wees,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Stuur Grant Review Email,
Send Now,Stuur nou,
Send SMS,Stuur SMS,
-Send Supplier Emails,Stuur verskaffer e-pos,
Send mass SMS to your contacts,Stuur massa-SMS na jou kontakte,
Sensitivity,sensitiwiteit,
Sent,gestuur,
-Serial #,Serie #,
Serial No and Batch,Serial No and Batch,
Serial No is mandatory for Item {0},Volgnummer is verpligtend vir item {0},
Serial No {0} does not belong to Batch {1},Reeksnommer {0} hoort nie by bondel {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Die naam van u maatskappy waarvoor u hierdie stelsel opstel.,
The number of shares and the share numbers are inconsistent,Die aantal aandele en die aandele is onbestaanbaar,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Die betaling gateway rekening in plan {0} verskil van die betaling gateway rekening in hierdie betaling versoek,
-The request for quotation can be accessed by clicking on the following link,Die versoek om kwotasie kan verkry word deur op die volgende skakel te kliek,
The selected BOMs are not for the same item,Die gekose BOM's is nie vir dieselfde item nie,
The selected item cannot have Batch,Die gekose item kan nie Batch hê nie,
The seller and the buyer cannot be the same,Die verkoper en die koper kan nie dieselfde wees nie,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Die totale bedrag vir komponent van buigsame voordele {0} mag nie minder wees as die maksimum voordele nie {1},
Total hours: {0},Totale ure: {0},
Total leaves allocated is mandatory for Leave Type {0},"Totale blare wat toegeken is, is verpligtend vir Verlof Tipe {0}",
-Total weightage assigned should be 100%. It is {0},Totale gewig toegeken moet 100% wees. Dit is {0},
Total working hours should not be greater than max working hours {0},Totale werksure moet nie groter wees nie as maksimum werksure {0},
Total {0} ({1}),Totaal {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Totale {0} vir alle items is nul, mag u verander word "Versprei koste gebaseer op '",
@@ -3316,7 +3299,6 @@
What do you need help with?,Waarmee het jy hulp nodig?,
What does it do?,Wat doen dit?,
Where manufacturing operations are carried.,Waar vervaardigingsbedrywighede uitgevoer word.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Terwyl u rekening vir kindermaatskappy {0} skep, word ouerrekening {1} nie gevind nie. Skep asseblief die ouerrekening in die ooreenstemmende COA",
White,wit,
Wire Transfer,Elektroniese oorbetaling,
WooCommerce Products,WooCommerce Produkte,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} variante geskep.,
{0} {1} created,{0} {1} geskep,
{0} {1} does not exist,{0} {1} bestaan nie,
-{0} {1} does not exist.,{0} {1} bestaan nie.,
{0} {1} has been modified. Please refresh.,{0} {1} is gewysig. Herlaai asseblief.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} is nie ingedien nie, sodat die aksie nie voltooi kan word nie",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} word geassosieer met {2}, maar Partyrekening is {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} bestaan nie,
{0}: {1} not found in Invoice Details table,{0}: {1} word nie in die faktuurbesonderhede-tabel gevind nie,
{} of {},{} van {},
+Assigned To,Toevertrou aan,
Chat,chat,
Completed By,Voltooi deur,
Conditions,voorwaardes,
@@ -3506,7 +3488,9 @@
Merge with existing,Voeg saam met bestaande,
Office,kantoor,
Orientation,geaardheid,
+Parent,Ouer,
Passive,passiewe,
+Payment Failed,Betaling misluk,
Percent,persent,
Permanent,permanente,
Personal,persoonlike,
@@ -3544,7 +3528,6 @@
Company field is required,Ondernemingsveld word vereis,
Creating Dimensions...,Skep dimensies ...,
Duplicate entry against the item code {0} and manufacturer {1},Dupliseer inskrywing teen die itemkode {0} en vervaardiger {1},
-Import Chart Of Accounts from CSV / Excel files,Voer rekeningkaart uit CSV / Excel-lêers in,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,"Ongeldige GSTIN! Die invoer wat u ingevoer het, stem nie ooreen met die GSTIN-formaat vir UIN-houers of OIDAR-diensverskaffers wat nie inwoon nie",
Invoice Grand Total,Faktuur groot totaal,
Last carbon check date cannot be a future date,Die laaste datum vir koolstoftoets kan nie 'n toekoms wees nie,
@@ -3556,6 +3539,7 @@
Show {0},Wys {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Spesiale karakters behalwe "-", "#", ".", "/", "{" En "}" word nie toegelaat in die naamreekse nie",
Target Details,Teikenbesonderhede,
+{0} already has a Parent Procedure {1}.,{0} het reeds 'n ouerprosedure {1}.,
API,API,
Annual,jaarlikse,
Approved,goedgekeur,
@@ -3572,6 +3556,8 @@
No data to export,Geen data om uit te voer nie,
Portrait,Portret,
Print Heading,Drukopskrif,
+Scheduler Inactive,Skeduleerder onaktief,
+Scheduler is inactive. Cannot import data.,Planner is onaktief. Kan nie data invoer nie.,
Show Document,Wys dokument,
Show Traceback,Wys terugsporing,
Video,video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Skep kwaliteitsinspeksie vir item {0},
Creating Accounts...,Skep rekeninge ...,
Creating bank entries...,Skep tans bankinskrywings ...,
-Creating {0},Skep {0},
Credit limit is already defined for the Company {0},Kredietlimiet is reeds gedefinieër vir die maatskappy {0},
Ctrl + Enter to submit,Ctrl + Enter om in te dien,
Ctrl+Enter to submit,Ctrl + Enter om in te dien,
@@ -3921,7 +3906,6 @@
Plaid public token error,Geplaaste openbare tekenfout,
Plaid transactions sync error,Gesinkroniseerfout in plaidtransaksies,
Please check the error log for details about the import errors,Kontroleer die foutlogboek vir meer inligting oor die invoerfoute,
-Please click on the following link to set your new password,Klik asseblief op die volgende skakel om u nuwe wagwoord te stel,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Skep asseblief <b>DATEV-instellings</b> vir die maatskappy <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Skep 'n aanpassingsjoernaalinskrywing vir bedrag {0},
Please do not create more than 500 items at a time,Moenie meer as 500 items op 'n slag skep nie,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Die datum van vrylating moet in die toekoms wees,
Relieving Date must be greater than or equal to Date of Joining,Verligtingsdatum moet groter wees as of gelyk wees aan die Datum van aansluiting,
Rename,hernoem,
+Rename Not Allowed,Hernoem nie toegelaat nie,
Repayment Method is mandatory for term loans,Terugbetalingsmetode is verpligtend vir termynlenings,
Repayment Start Date is mandatory for term loans,Aanvangsdatum vir terugbetaling is verpligtend vir termynlenings,
Report Item,Rapporteer item,
@@ -4043,7 +4028,6 @@
Select All,Kies Alles,
Select Difference Account,Kies Verskilrekening,
Select a Default Priority.,Kies 'n standaardprioriteit.,
-Select a Supplier from the Default Supplier List of the items below.,Kies 'n verskaffer uit die standaardverskafferlys van die onderstaande items.,
Select a company,Kies 'n maatskappy,
Select finance book for the item {0} at row {1},Kies finansieringsboek vir die item {0} op ry {1},
Select only one Priority as Default.,Kies slegs een prioriteit as verstek.,
@@ -4247,7 +4231,6 @@
Actual ,werklike,
Add to cart,Voeg by die winkelwagen,
Budget,begroting,
-Chart Of Accounts Importer,Invoerder van rekeningrekeninge,
Chart of Accounts,Tabel van rekeninge,
Customer database.,Kliënt databasis.,
Days Since Last order,Dae sedert die laaste bestelling,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Einddatum kan nie minder wees as die begin datum nie,
For Default Supplier (Optional),Vir Standaardverskaffer (opsioneel),
From date cannot be greater than To date,Vanaf datum kan nie groter wees as Datum,
-Get items from,Kry items van,
Group by,Groep By,
In stock,In voorraad,
Item name,Item naam,
@@ -4532,32 +4514,22 @@
Accounts Settings,Rekeninge Instellings,
Settings for Accounts,Instellings vir rekeninge,
Make Accounting Entry For Every Stock Movement,Maak Rekeningkundige Inskrywing Vir Elke Voorraadbeweging,
-"If enabled, the system will post accounting entries for inventory automatically.","Indien geaktiveer, sal die stelsel outomaties rekeningkundige inskrywings vir voorraad plaas.",
-Accounts Frozen Upto,Rekeninge Bevrore Upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Rekeningkundige inskrywing wat tot op hierdie datum gevries is, kan niemand toelaat / verander nie, behalwe die rol wat hieronder gespesifiseer word.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Rol toegelaat om bevrore rekeninge in te stel en Bevrore Inskrywings te wysig,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Gebruikers met hierdie rol word toegelaat om gevriesde rekeninge te stel en rekeningkundige inskrywings teen bevrore rekeninge te skep / te verander,
Determine Address Tax Category From,Bepaal adresbelastingkategorie vanaf,
-Address used to determine Tax Category in transactions.,Adres wat gebruik word om belastingkategorie in transaksies te bepaal.,
Over Billing Allowance (%),Toelae oor fakturering (%),
-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 for $110.,"Persentasie waarop u toegelaat word om meer te betaal teen die bestelde bedrag. Byvoorbeeld: As die bestelwaarde $ 100 is vir 'n artikel en die verdraagsaamheid as 10% is, kan u $ 110 faktureer.",
Credit Controller,Kredietbeheerder,
-Role that is allowed to submit transactions that exceed credit limits set.,Rol wat toegelaat word om transaksies voor te lê wat groter is as kredietlimiete.,
Check Supplier Invoice Number Uniqueness,Kontroleer Verskaffer-faktuurnommer Uniekheid,
Make Payment via Journal Entry,Betaal via Joernaal Inskrywing,
Unlink Payment on Cancellation of Invoice,Ontkoppel betaling met kansellasie van faktuur,
-Unlink Advance Payment on Cancelation of Order,Ontkoppel vooruitbetaling by kansellasie van bestelling,
Book Asset Depreciation Entry Automatically,Boekbate-waardeverminderinginskrywing outomaties,
Automatically Add Taxes and Charges from Item Tax Template,Belasting en heffings word outomaties bygevoeg vanaf die itembelastingsjabloon,
Automatically Fetch Payment Terms,Haal betalingsvoorwaardes outomaties aan,
-Show Inclusive Tax In Print,Wys Inklusiewe Belasting In Druk,
Show Payment Schedule in Print,Wys betalingskedule in druk,
Currency Exchange Settings,Geldruilinstellings,
Allow Stale Exchange Rates,Staaf wisselkoerse toe,
Stale Days,Stale Days,
Report Settings,Verslaginstellings,
Use Custom Cash Flow Format,Gebruik aangepaste kontantvloeiformaat,
-Only select if you have setup Cash Flow Mapper documents,Kies slegs as u instellings vir kontantvloeimappers opstel,
Allowed To Transact With,Toegelaat om mee te doen,
SWIFT number,SWIFT-nommer,
Branch Code,Takkode,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS kliënt groep,
POS Field,POS veld,
POS Item Group,POS Item Group,
-[Select],[Kies],
Company Address,Maatskappyadres,
Update Stock,Werk Voorraad,
Ignore Pricing Rule,Ignoreer prysreël,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Verskaffer Naming By,
Default Supplier Group,Verstekverskaffergroep,
Default Buying Price List,Verstek kooppryslys,
-Maintain same rate throughout purchase cycle,Handhaaf dieselfde koers deur die hele aankoopsiklus,
-Allow Item to be added multiple times in a transaction,Laat item toe om verskeie kere in 'n transaksie te voeg,
Backflush Raw Materials of Subcontract Based On,Backflush Grondstowwe van Subkontraktering gebaseer op,
Material Transferred for Subcontract,Materiaal oorgedra vir subkontrakteur,
Over Transfer Allowance (%),Toelaag vir oordrag (%),
@@ -5540,7 +5509,6 @@
Current Stock,Huidige voorraad,
PUR-RFQ-.YYYY.-,PUR-VOK-.YYYY.-,
For individual supplier,Vir individuele verskaffer,
-Supplier Detail,Verskaffer Detail,
Link to Material Requests,Skakel na materiaalversoeke,
Message for Supplier,Boodskap vir Verskaffer,
Request for Quotation Item,Versoek vir kwotasie-item,
@@ -6481,7 +6449,6 @@
Appraisal Template,Appraisal Template,
For Employee Name,Vir Werknemer Naam,
Goals,Doelwitte,
-Calculate Total Score,Bereken totale telling,
Total Score (Out of 5),Totale telling (uit 5),
"Any other remarks, noteworthy effort that should go in the records.","Enige ander opmerkings, noemenswaardige poging wat in die rekords moet plaasvind.",
Appraisal Goal,Evalueringsdoel,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Rede vir vertrek,
Leave Encashed?,Verlaten verlaat?,
Encashment Date,Bevestigingsdatum,
-Exit Interview Details,Afhanklike onderhoudsbesonderhede,
-Held On,Aangehou,
-Reason for Resignation,Rede vir bedanking,
-Better Prospects,Beter vooruitsigte,
-Health Concerns,Gesondheid Kommer,
New Workplace,Nuwe werkplek,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Terugbetaalde bedrag,
@@ -6740,10 +6702,7 @@
Employee Settings,Werknemer instellings,
Retirement Age,Aftree-ouderdom,
Enter retirement age in years,Gee aftree-ouderdom in jare,
-Employee Records to be created by,Werknemersrekords wat geskep moet word deur,
-Employee record is created using selected field. ,Werknemer rekord is geskep met behulp van geselekteerde veld.,
Stop Birthday Reminders,Stop verjaardag herinnerings,
-Don't send Employee Birthday Reminders,Moenie Werknemer Verjaarsdag Herinnerings stuur nie,
Expense Approver Mandatory In Expense Claim,Uitgawe Goedkeuring Verpligte Uitgawe Eis,
Payroll Settings,Loonstaatinstellings,
Leave,Verlaat,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Verlaat Goedkeuring Verpligtend In Verlof Aansoek,
Show Leaves Of All Department Members In Calendar,Toon blare van alle Departementslede in die Jaarboek,
Auto Leave Encashment,Verlaat omhulsel outomaties,
-Restrict Backdated Leave Application,Beperk aansoeke vir die verouderde verlof,
Hiring Settings,Instellings huur,
Check Vacancies On Job Offer Creation,Kyk na vakatures met die skep van werksaanbiedinge,
Identification Document Type,Identifikasiedokument Tipe,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Vervaardigingsinstellings,
Raw Materials Consumption,Verbruik van grondstowwe,
Allow Multiple Material Consumption,Laat veelvuldige materiaalverbruik toe,
-Allow multiple Material Consumption against a Work Order,Laat veelvuldige materiaalverbruik toe teen 'n werkorder,
Backflush Raw Materials Based On,Backflush Grondstowwe gebaseer op,
Material Transferred for Manufacture,Materiaal oorgedra vir Vervaardiging,
Capacity Planning,Kapasiteitsbeplanning,
Disable Capacity Planning,Skakel kapasiteitsbeplanning uit,
Allow Overtime,Laat Oortyd toe,
-Plan time logs outside Workstation Working Hours.,Beplan tydstamme buite werkstasie werksure.,
Allow Production on Holidays,Laat produksie toe op vakansie,
Capacity Planning For (Days),Kapasiteitsbeplanning vir (Dae),
-Try planning operations for X days in advance.,Probeer beplanningsaktiwiteite vir X dae van vooraf.,
-Time Between Operations (in mins),Tyd tussen bedrywighede (in mins),
-Default 10 mins,Verstek 10 minute,
Default Warehouses for Production,Standaard pakhuise vir produksie,
Default Work In Progress Warehouse,Verstek werk in voortgang Warehouse,
Default Finished Goods Warehouse,Standaard voltooide goedere pakhuis,
Default Scrap Warehouse,Standaard skroot pakhuis,
-Over Production for Sales and Work Order,Oorproduksie vir verkoops- en werkbestelling,
Overproduction Percentage For Sales Order,Oorproduksie persentasie vir verkoopsbestelling,
Overproduction Percentage For Work Order,Oorproduksie Persentasie Vir Werk Orde,
Other Settings,Ander instellings,
Update BOM Cost Automatically,Dateer BOM koste outomaties op,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Werk BOM koste outomaties via Scheduler, gebaseer op die jongste waarderings koers / prys lys koers / laaste aankoop koers van grondstowwe.",
Material Request Plan Item,Materiaal Versoek Plan Item,
Material Request Type,Materiaal Versoek Tipe,
Material Issue,Materiële Uitgawe,
@@ -7603,10 +7554,6 @@
Quality Goal,Kwaliteit doel,
Monitoring Frequency,Monitor frekwensie,
Weekday,weekdag,
-January-April-July-October,Januarie-April-Julie-Oktober,
-Revision and Revised On,Hersiening en hersien op,
-Revision,hersiening,
-Revised On,Hersien op,
Objectives,doelwitte,
Quality Goal Objective,Kwaliteit Doelwit,
Objective,Doel,
@@ -7619,7 +7566,6 @@
Processes,prosesse,
Quality Procedure Process,Kwaliteit prosedure proses,
Process Description,Prosesbeskrywing,
-Child Procedure,Kinderprosedure,
Link existing Quality Procedure.,Koppel die bestaande kwaliteitsprosedure.,
Additional Information,Bykomende inligting,
Quality Review Objective,Doel van gehaltehersiening,
@@ -7787,15 +7733,9 @@
Default Customer Group,Verstek kliënt groep,
Default Territory,Standaard Territorium,
Close Opportunity After Days,Sluit geleentheid na dae,
-Auto close Opportunity after 15 days,Vakansie sluit geleentheid na 15 dae,
Default Quotation Validity Days,Standaard Kwotasie Geldigheidsdae,
Sales Update Frequency,Verkope Update Frekwensie,
-How often should project and company be updated based on Sales Transactions.,Hoe gereeld moet projek en maatskappy opgedateer word gebaseer op verkoops transaksies.,
Each Transaction,Elke transaksie,
-Allow user to edit Price List Rate in transactions,Laat gebruiker toe om Pryslyskoers te wysig in transaksies,
-Allow multiple Sales Orders against a Customer's Purchase Order,Laat meerdere verkope bestellings toe teen 'n kliënt se aankoopbestelling,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Valideer Verkoopprys vir Item teen Aankoopprys of Waardasietarief,
-Hide Customer's Tax Id from Sales Transactions,Versteek Kliënt se Belasting-ID van Verkoopstransaksies,
SMS Center,Sms sentrum,
Send To,Stuur na,
All Contact,Alle Kontak,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Vervaardigers gebruik in items,
Limited to 12 characters,Beperk tot 12 karakters,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Stel pakhuis,
-Sets 'For Warehouse' in each row of the Items table.,Stel 'Vir pakhuis' in elke ry van die Artikeltabel in.,
-Requested For,Gevra vir,
Partially Ordered,Gedeeltelik bestel,
Transferred,oorgedra,
% Ordered,% Bestel,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Standaard Voorraad UOM,
Sample Retention Warehouse,Sample Retention Warehouse,
Default Valuation Method,Verstekwaardasiemetode,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Persentasie wat u mag ontvang of meer lewer teen die hoeveelheid bestel. Byvoorbeeld: As jy 100 eenhede bestel het. en u toelae is 10%, dan mag u 110 eenhede ontvang.",
-Action if Quality inspection is not submitted,Optrede indien kwaliteitsinspeksie nie ingedien word nie,
Show Barcode Field,Toon strepieskode veld,
Convert Item Description to Clean HTML,Omskep itembeskrywing om HTML skoon te maak,
-Auto insert Price List rate if missing,Voer outomaties pryslys in indien dit ontbreek,
Allow Negative Stock,Laat negatiewe voorraad toe,
Automatically Set Serial Nos based on FIFO,Stel Serial Nos outomaties gebaseer op FIFO,
-Set Qty in Transactions based on Serial No Input,Stel aantal in Transaksies gebaseer op Serial No Input,
Auto Material Request,Auto Materiaal Versoek,
-Raise Material Request when stock reaches re-order level,Verhoog Materiaal Versoek wanneer voorraad bereik herbestellingsvlak bereik,
-Notify by Email on creation of automatic Material Request,Stel per e-pos in kennis van die skepping van outomatiese materiaalversoek,
Inter Warehouse Transfer Settings,Inter Warehouse-oordraginstellings,
-Allow Material Transfer From Delivery Note and Sales Invoice,Laat materiaaloordrag toe vanaf afleweringsnota en verkoopsfaktuur,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Laat materiaaloordrag toe vanaf aankoopbewys en aankoopfaktuur,
Freeze Stock Entries,Vries Voorraadinskrywings,
Stock Frozen Upto,Voorraad Bevrore Upto,
-Freeze Stocks Older Than [Days],Vries Voorrade Ouer As [Dae],
-Role Allowed to edit frozen stock,Rol Toegestaan om gevriesde voorraad te wysig,
Batch Identification,Batch Identification,
Use Naming Series,Gebruik Naming Series,
Naming Series Prefix,Benaming van die reeksreeks,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Aankoopontvangstendense,
Purchase Register,Aankoopregister,
Quotation Trends,Aanhalingstendense,
-Quoted Item Comparison,Genoteerde Item Vergelyking,
Received Items To Be Billed,Items ontvang om gefaktureer te word,
Qty to Order,Hoeveelheid om te bestel,
Requested Items To Be Transferred,Gevraagde items wat oorgedra moet word,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Kies pakhuis vir materiaalversoeke,
Transfer Materials For Warehouse {0},Oordragmateriaal vir pakhuis {0},
Production Plan Material Request Warehouse,Produksieplan Materiaalversoekpakhuis,
-Set From Warehouse,Stel vanaf pakhuis,
-Source Warehouse (Material Transfer),Bronpakhuis (materiaaloordrag),
Sets 'Source Warehouse' in each row of the items table.,Stel 'Bronpakhuis' in elke ry van die artikeltabel in.,
Sets 'Target Warehouse' in each row of the items table.,Stel 'Target Warehouse' in elke ry van die artikeltabel in.,
Show Cancelled Entries,Wys gekanselleerde inskrywings,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Diens ontvang, maar nie gefaktureer nie",
Deferred Accounting Settings,Uitgestelde rekeningkundige instellings,
Book Deferred Entries Based On,Boek uitgestelde inskrywings gebaseer op,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","As 'Maande' gekies word, word die vaste bedrag vir elke maand as uitgestelde inkomste of uitgawe geboek, ongeag die aantal dae in 'n maand. Dit sal oorweeg word as uitgestelde inkomste of uitgawes vir 'n hele maand nie bespreek word nie.",
Days,Dae,
Months,Maande,
Book Deferred Entries Via Journal Entry,Boek uitgestelde inskrywings via joernaalinskrywing,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"As dit nie gemerk is nie, sal GL-inskrywings geskep word om uitgestelde inkomste / uitgawes te bespreek",
Submit Journal Entries,Dien joernaalinskrywings in,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"As dit nie gemerk is nie, word die joernaalinskrywings in 'n konseptoestand gestoor en moet dit handmatig ingedien word",
Enable Distributed Cost Center,Aktiveer verspreide kostesentrum,
@@ -8901,8 +8823,6 @@
Is Inter State,Is Interstaat,
Purchase Details,Aankoopbesonderhede,
Depreciation Posting Date,Datum van afskrywing,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Bestelling benodig vir aankoop van fakture en ontvangsbewyse,
-Purchase Receipt Required for Purchase Invoice Creation,Aankoopbewys benodig vir die skep van aankoopfakture,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",Die verskaffersnaam word standaard ingestel volgens die opgegeven verskaffersnaam. As u wil hê dat verskaffers deur a genoem moet word,
choose the 'Naming Series' option.,kies die opsie 'Naamreeks'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Stel die standaardpryslys op wanneer u 'n nuwe aankooptransaksie skep. Itempryse word uit hierdie pryslys gehaal.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Is inkomstebelasting komponent,
Component properties and references ,Komponenteienskappe en verwysings,
Additional Salary ,Bykomende salaris,
-Condtion and formula,Kondisie en formule,
Unmarked days,Ongemerkte dae,
Absent Days,Afwesige dae,
Conditions and Formula variable and example,Voorwaardes en formule veranderlike en voorbeeld,
Feedback By,Terugvoer deur,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Vervaardigingsafdeling,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Verkooporder benodig vir die maak van fakture en afleweringsnotas,
-Delivery Note Required for Sales Invoice Creation,Afleweringsnota benodig vir die skep van verkoopsfakture,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",Die kliëntnaam word standaard ingestel volgens die volledige naam wat ingevoer is. As u wil hê dat klante deur 'n,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Stel die standaardpryslys op wanneer u 'n nuwe verkoopstransaksie skep. Itempryse word uit hierdie pryslys gehaal.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","As hierdie opsie 'Ja' is ingestel, sal ERPNext u verhinder om 'n verkoopfaktuur of afleweringsnota te maak sonder om eers 'n bestelling te skep. Hierdie konfigurasie kan vir 'n bepaalde klant oorskry word deur die 'Laat skepping van faktuur sonder verkooporder' in die kliënt-hoof aan te skakel.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} is suksesvol by al die geselekteerde onderwerpe gevoeg.,
Topics updated,Onderwerpe is opgedateer,
Academic Term and Program,Akademiese termyn en program,
-Last Stock Transaction for item {0} was on {1}.,Laaste voorraadtransaksie vir item {0} was op {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Voorraadtransaksies vir item {0} kan nie voor hierdie tyd gepos word nie.,
Please remove this item and try to submit again or update the posting time.,Verwyder hierdie item en probeer weer om dit in te dien of die tyd van die plasing op te dateer.,
Failed to Authenticate the API key.,Kon nie die API-sleutel verifieer nie.,
Invalid Credentials,Ongeldige magtigingsbewyse,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Gaan u Plaid-kliënt-ID en geheime waardes na,
Bank transaction creation error,Fout met die skep van banktransaksies,
Unit of Measurement,Eenheid van mate,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Ry # {}: die verkoopkoers vir item {} is laer as die {}. Verkoopprys moet ten minste {} wees,
Fiscal Year {0} Does Not Exist,Fiskale jaar {0} bestaan nie,
Row # {0}: Returned Item {1} does not exist in {2} {3},Ry # {0}: Teruggestuurde item {1} bestaan nie in {2} {3},
Valuation type charges can not be marked as Inclusive,Kostes van waardasie kan nie as Inklusief gemerk word nie,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Die responstyd vir {0} prioriteit in ry {1} kan nie langer wees as die resolusietyd nie.,
{0} is not enabled in {1},{0} is nie geaktiveer in {1},
Group by Material Request,Groepeer volgens materiaalversoek,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Ry {0}: Vir verskaffer {0} word e-posadres vereis om e-pos te stuur,
Email Sent to Supplier {0},E-pos gestuur aan verskaffer {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",Die toegang tot die versoek vir 'n kwotasie vanaf die portaal is uitgeskakel. Skakel dit in Portaalinstellings in om toegang te verleen.,
Supplier Quotation {0} Created,Kwotasie van verskaffer {0} geskep,
Valid till Date cannot be before Transaction Date,Geldige bewerkingsdatum kan nie voor transaksiedatum wees nie,
+Unlink Advance Payment on Cancellation of Order,Ontkoppel vooruitbetaling by kansellasie van bestelling,
+"Simple Python Expression, Example: territory != 'All Territories'","Eenvoudige Python-uitdrukking, Voorbeeld: gebied! = 'Alle gebiede'",
+Sales Contributions and Incentives,Verkoopsbydraes en aansporings,
+Sourced by Supplier,Van verskaffer verkry,
+Total weightage assigned should be 100%.<br>It is {0},Die totale gewigstoekenning moet 100% wees.<br> Dit is {0},
+Account {0} exists in parent company {1}.,Rekening {0} bestaan in moedermaatskappy {1}.,
+"To overrule this, enable '{0}' in company {1}",Skakel '{0}' in die maatskappy {1} in om dit te oorheers.,
+Invalid condition expression,Ongeldige toestandsuitdrukking,
+Please Select a Company First,Kies eers 'n maatskappy,
+Please Select Both Company and Party Type First,Kies asseblief eers die maatskappy en die partytjie,
+Provide the invoice portion in percent,Verskaf die faktuurgedeelte in persent,
+Give number of days according to prior selection,Gee die aantal dae volgens voorafgaande keuse,
+Email Details,E-posbesonderhede,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Kies 'n groet vir die ontvanger. Bv. Mnr., Me., Ens.",
+Preview Email,Voorskou e-pos,
+Please select a Supplier,Kies 'n verskaffer,
+Supplier Lead Time (days),Leveringstyd (dae),
+"Home, Work, etc.","Huis, werk, ens.",
+Exit Interview Held On,Uitgangsonderhoud gehou,
+Condition and formula,Toestand en formule,
+Sets 'Target Warehouse' in each row of the Items table.,Stel 'Target Warehouse' in elke ry van die Items-tabel.,
+Sets 'Source Warehouse' in each row of the Items table.,Stel 'Bronpakhuis' in elke ry van die Artikeltabel in.,
+POS Register,POS-register,
+"Can not filter based on POS Profile, if grouped by POS Profile","Kan nie gebaseer op POS-profiel filter nie, indien dit gegroepeer is volgens POS-profiel",
+"Can not filter based on Customer, if grouped by Customer","Kan nie op grond van die klant filter nie, indien dit volgens die klant gegroepeer is",
+"Can not filter based on Cashier, if grouped by Cashier","Kan nie filter op grond van Kassier nie, indien dit gegroepeer is volgens Kassier",
+Payment Method,Betalings metode,
+"Can not filter based on Payment Method, if grouped by Payment Method","Kan nie op grond van die betaalmetode filter nie, indien dit gegroepeer is volgens die betaalmetode",
+Supplier Quotation Comparison,Vergelyking tussen kwotasies van verskaffers,
+Price per Unit (Stock UOM),Prys per eenheid (voorraad UOM),
+Group by Supplier,Groepeer volgens verskaffer,
+Group by Item,Groepeer volgens item,
+Remember to set {field_label}. It is required by {regulation}.,Onthou om {field_label} in te stel. Dit word deur {regulasie} vereis.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Inskrywingsdatum kan nie voor die begindatum van die akademiese jaar wees nie {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Inskrywingsdatum kan nie na die einddatum van die akademiese termyn {0} wees nie,
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Inskrywingsdatum kan nie voor die begindatum van die akademiese termyn {0} wees nie,
+Future Posting Not Allowed,Toekomstige plasing word nie toegelaat nie,
+"To enable Capital Work in Progress Accounting, ","Om rekeningkundige kapitaalwerk moontlik te maak,",
+you must select Capital Work in Progress Account in accounts table,u moet Capital Work in Progress-rekening in die rekeningtabel kies,
+You can also set default CWIP account in Company {},U kan ook die standaard CWIP-rekening instel in die maatskappy {},
+The Request for Quotation can be accessed by clicking on the following button,Toegang tot die versoek vir 'n kwotasie is deur op die volgende knoppie te klik,
+Regards,Groete,
+Please click on the following button to set your new password,Klik op die volgende knoppie om u nuwe wagwoord in te stel,
+Update Password,Wagwoord op te dateer,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Ry # {}: die verkoopkoers vir item {} is laer as die {}. Verkoop {} moet ten minste {} wees,
+You can alternatively disable selling price validation in {} to bypass this validation.,U kan ook die validering van verkooppryse in {} deaktiveer om hierdie validering te omseil.,
+Invalid Selling Price,Ongeldige verkoopprys,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Adres moet aan 'n maatskappy gekoppel word. Voeg asseblief 'n ry vir Company in die skakeltabel.,
+Company Not Linked,Maatskappy nie gekoppel nie,
+Import Chart of Accounts from CSV / Excel files,Voer rekeningrekeninge in vanaf CSV / Excel-lêers,
+Completed Qty cannot be greater than 'Qty to Manufacture',Voltooide hoeveelheid kan nie groter wees as 'hoeveelheid om te vervaardig',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Ry {0}: Vir verskaffer {1} word e-posadres vereis om 'n e-pos te stuur,
+"If enabled, the system will post accounting entries for inventory automatically","As dit geaktiveer is, sal die stelsel outomaties rekeningkundige inskrywings vir voorraad plaas",
+Accounts Frozen Till Date,Rekeninge Bevrore tot op datum,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"Rekeningkundige inskrywings word tot op hierdie datum gevries. Niemand kan inskrywings skep of wysig nie, behalwe gebruikers met die onderstaande rol",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Rol toegelaat om bevrore rekeninge op te stel en bevrore inskrywings te wysig,
+Address used to determine Tax Category in transactions,Adres wat gebruik word om belastingkategorie in transaksies te bepaal,
+"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 ","Die persentasie waarop u toegelaat word om meer te faktureer teen die bedrag wat u bestel. As die bestelwaarde byvoorbeeld $ 100 vir 'n artikel is en die toleransie op 10% gestel word, mag u tot $ 110 faktureer",
+This role is allowed to submit transactions that exceed credit limits,Hierdie rol word toegelaat om transaksies in te dien wat die kredietlimiete oorskry,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","As 'Maande' gekies word, word 'n vaste bedrag vir elke maand as uitgestelde inkomste of uitgawe geboek, ongeag die aantal dae in 'n maand. Dit sal oorweeg word as uitgestelde inkomste of uitgawes vir 'n hele maand nie bespreek word nie",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","As dit nie gemerk is nie, sal direkte GL-inskrywings geskep word om uitgestelde inkomste of uitgawes te bespreek",
+Show Inclusive Tax in Print,Toon inklusiewe belasting in druk,
+Only select this if you have set up the Cash Flow Mapper documents,Kies dit slegs as u die Cash Flow Mapper-dokumente opgestel het,
+Payment Channel,Betalingskanaal,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Is 'n bestelling nodig vir die skep van fakture en ontvangsbewyse?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Is aankoopbewys nodig vir die skep van aankoopfakture?,
+Maintain Same Rate Throughout the Purchase Cycle,Handhaaf dieselfde koers gedurende die aankoopsiklus,
+Allow Item To Be Added Multiple Times in a Transaction,Laat toe dat items meerdere kere bygevoeg word in 'n transaksie,
+Suppliers,Verskaffers,
+Send Emails to Suppliers,Stuur e-posse na verskaffers,
+Select a Supplier,Kies 'n verskaffer,
+Cannot mark attendance for future dates.,Kan nie bywoning vir toekomstige datums merk nie.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Wil u die bywoning bywerk?<br> Aanwesig: {0}<br> Afwesig: {1},
+Mpesa Settings,Mpesa-instellings,
+Initiator Name,Inisieerder Naam,
+Till Number,Tot nommer,
+Sandbox,Sandbak,
+ Online PassKey,Aanlyn PassKey,
+Security Credential,Sekuriteitsbewys,
+Get Account Balance,Kry rekeningbalans,
+Please set the initiator name and the security credential,Stel die naam van die inisieerder en die sekuriteitsbewys in,
+Inpatient Medication Entry,Toelating tot medikasie vir binnepasiënte,
+HLC-IME-.YYYY.-,HLC-IME-.JJJJ.-,
+Item Code (Drug),Itemkode (dwelm),
+Medication Orders,Medisyne bestellings,
+Get Pending Medication Orders,Kry hangende medisyne-bestellings,
+Inpatient Medication Orders,Mediese bestellings vir binnepasiënte,
+Medication Warehouse,Medikasiepakhuis,
+Warehouse from where medication stock should be consumed,Pakhuis vanwaar medisyne gebruik moet word,
+Fetching Pending Medication Orders,Haal hangende medisyne-bestellings op,
+Inpatient Medication Entry Detail,Inskrywingsdetail vir binnemedikasie,
+Medication Details,Medikasiebesonderhede,
+Drug Code,Dwelmkode,
+Drug Name,Dwelmsnaam,
+Against Inpatient Medication Order,Teen medikasiebevel vir binnepasiënte,
+Against Inpatient Medication Order Entry,Tegniese bestellings vir medikasie vir binnepasiënte,
+Inpatient Medication Order,Medikasiebevel vir binnepasiënte,
+HLC-IMO-.YYYY.-,HLC-IMO-.JJJJ.-,
+Total Orders,Totale bestellings,
+Completed Orders,Voltooide bestellings,
+Add Medication Orders,Voeg medisyne bestellings by,
+Adding Order Entries,Bestelinskrywings byvoeg,
+{0} medication orders completed,{0} medisyne-bestellings voltooi,
+{0} medication order completed,{0} medisyne-bestelling voltooi,
+Inpatient Medication Order Entry,Invoer vir medikasie vir binnepasiënte,
+Is Order Completed,Is bestelling voltooi,
+Employee Records to Be Created By,Werknemersrekords om deur te skep,
+Employee records are created using the selected field,Werknemersrekords word met behulp van die geselekteerde veld geskep,
+Don't send employee birthday reminders,Moenie werknemers se verjaardagaanmanings stuur nie,
+Restrict Backdated Leave Applications,Beperk teruggedateerde verlofaansoeke,
+Sequence ID,Volgorde ID,
+Sequence Id,Volgorde Id,
+Allow multiple material consumptions against a Work Order,Laat veelvuldige materiële verbruik teen 'n werkorder toe,
+Plan time logs outside Workstation working hours,Beplan tydlêers buite werksure vir werkstasies,
+Plan operations X days in advance,Beplan bedrywighede X dae voor die tyd,
+Time Between Operations (Mins),Tyd tussen bewerkings (min.),
+Default: 10 mins,Verstek: 10 minute,
+Overproduction for Sales and Work Order,Oorproduksie vir verkope en werkbestelling,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Werk BOM-koste outomaties op via die skeduleerder, gebaseer op die nuutste waardasietarief / pryslyskoers / laaste aankoopprys van grondstowwe",
+Purchase Order already created for all Sales Order items,Aankooporder wat reeds vir alle verkooporderitems gemaak is,
+Select Items,Kies Items,
+Against Default Supplier,Teen verstekverskaffer,
+Auto close Opportunity after the no. of days mentioned above,Geleentheid outomaties sluit na die nr. van die dae hierbo genoem,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Is verkoopsorder benodig vir die skep van verkoopsfakture en afleweringsnotas?,
+Is Delivery Note Required for Sales Invoice Creation?,Is afleweringsnota nodig vir die skep van verkoopsfakture?,
+How often should Project and Company be updated based on Sales Transactions?,Hoe gereeld moet Projek en Maatskappy op grond van verkoopstransaksies opgedateer word?,
+Allow User to Edit Price List Rate in Transactions,Laat gebruikers toe om pryslystrate in transaksies te wysig,
+Allow Item to Be Added Multiple Times in a Transaction,Laat toe dat items meerdere kere bygevoeg word in 'n transaksie,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Laat veelvuldige verkope bestellings toe teen 'n klant se bestelling,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Valideer verkoopprys vir artikel teen aankoopprys of waardasie,
+Hide Customer's Tax ID from Sales Transactions,Versteek die belasting-ID van die klant van die verkoopstransaksies,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Die persentasie wat u mag ontvang of meer aflewer teen die hoeveelheid wat u bestel. As u byvoorbeeld 100 eenhede bestel het, en u toelae 10% is, mag u 110 eenhede ontvang.",
+Action If Quality Inspection Is Not Submitted,Optrede as kwaliteitsinspeksie nie ingedien word nie,
+Auto Insert Price List Rate If Missing,Voeg pryslyskoers outomaties in indien ontbreek,
+Automatically Set Serial Nos Based on FIFO,Stel serienummers outomaties op grond van EIEU,
+Set Qty in Transactions Based on Serial No Input,Stel hoeveelheid in transaksies op basis van reeksinvoer nie,
+Raise Material Request When Stock Reaches Re-order Level,Verhoog die materiaalversoek wanneer die voorraad die herbestellingsvlak bereik,
+Notify by Email on Creation of Automatic Material Request,Stel dit per e-pos in kennis oor die skep van outomatiese materiaalversoek,
+Allow Material Transfer from Delivery Note to Sales Invoice,Laat materiaaloordrag toe van afleweringsnota na verkoopsfaktuur,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Laat materiaaloordrag toe van aankoopbewys na aankoopfaktuur,
+Freeze Stocks Older Than (Days),Vriesvoorrade ouer as (dae),
+Role Allowed to Edit Frozen Stock,Rol toegelaat om bevrore voorraad te wysig,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,"Die bedrag wat nie toegeken is nie, is groter as die bedrag wat die banktransaksie nie toeken nie",
+Payment Received,Betaling ontvang,
+Attendance cannot be marked outside of Academic Year {0},Bywoning kan nie buite die akademiese jaar {0} gemerk word nie,
+Student is already enrolled via Course Enrollment {0},Student is reeds ingeskryf via kursusinskrywing {0},
+Attendance cannot be marked for future dates.,Bywoning kan nie gemerk word vir toekomstige datums nie.,
+Please add programs to enable admission application.,Voeg asseblief programme by om die aansoek om toelating moontlik te maak.,
+The following employees are currently still reporting to {0}:,Die volgende werknemers meld tans nog aan by {0}:,
+Please make sure the employees above report to another Active employee.,Maak asseblief seker dat die werknemers hierbo aan 'n ander aktiewe werknemer rapporteer.,
+Cannot Relieve Employee,Kan nie werknemer ontslaan nie,
+Please enter {0},Voer asseblief {0} in,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Kies 'n ander betaalmetode. Mpesa ondersteun nie transaksies in die geldeenheid '{0}',
+Transaction Error,Transaksiefout,
+Mpesa Express Transaction Error,Mpesa Express-transaksiefout,
+"Issue detected with Mpesa configuration, check the error logs for more details","Probleem opgespoor met Mpesa-konfigurasie, kyk na die foutlêers vir meer besonderhede",
+Mpesa Express Error,Mpesa Express-fout,
+Account Balance Processing Error,Verwerking van rekeningbalansfout,
+Please check your configuration and try again,Gaan u konfigurasie na en probeer weer,
+Mpesa Account Balance Processing Error,Verwerking van Mpesa-rekeningbalansfout,
+Balance Details,Balansbesonderhede,
+Current Balance,Huidige balaans,
+Available Balance,Beskikbare balans,
+Reserved Balance,Gereserveerde balans,
+Uncleared Balance,Onduidelike balans,
+Payment related to {0} is not completed,Betaling wat verband hou met {0} is nie voltooi nie,
+Row #{}: Item Code: {} is not available under warehouse {}.,Ry # {}: Itemkode: {} is nie beskikbaar onder pakhuis {} nie.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Ry # {}: voorraadhoeveelheid nie genoeg vir artikelkode: {} onder pakhuis {}. Beskikbare hoeveelheid {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Ry # {}: kies 'n reeksnommer en 'n bondel teenoor item: {} of verwyder dit om die transaksie te voltooi.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Ry # {}: Geen reeksnommer is gekies teenoor item nie: {}. Kies een of verwyder dit om die transaksie te voltooi.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Ry # {}: Geen groep gekies teenoor item nie: {}. Kies 'n groep of verwyder dit om die transaksie te voltooi.,
+Payment amount cannot be less than or equal to 0,Betalingsbedrag kan nie kleiner as of gelyk aan 0 wees nie,
+Please enter the phone number first,Voer eers die telefoonnommer in,
+Row #{}: {} {} does not exist.,Ry # {}: {} {} bestaan nie.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Ry # {0}: {1} is nodig om die openingsfakture {2} te skep,
+You had {} errors while creating opening invoices. Check {} for more details,Daar was {} foute tydens die skep van openingsfakture. Gaan na {} vir meer besonderhede,
+Error Occured,Fout het voorgekom,
+Opening Invoice Creation In Progress,Die opening van die skep van fakture aan die gang,
+Creating {} out of {} {},Skep tans {} uit {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Serienommer: {0}) kan nie verbruik word nie, aangesien dit gereserveer is vir die volledige bestelling {1}.",
+Item {0} {1},Item {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Laaste voorraadtransaksie vir item {0} onder pakhuis {1} was op {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Voorraadtransaksies vir item {0} onder pakhuis {1} kan nie voor hierdie tyd gepos word nie.,
+Posting future stock transactions are not allowed due to Immutable Ledger,"As gevolg van Onveranderlike Grootboek, word toekomstige aandeletransaksies nie toegelaat nie",
+A BOM with name {0} already exists for item {1}.,'N BOM met die naam {0} bestaan reeds vir item {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Het jy die item hernoem? Kontak administrateur / tegniese ondersteuning,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Op ry # {0}: die volgorde-ID {1} mag nie kleiner wees as die vorige ryvolg-ID {2},
+The {0} ({1}) must be equal to {2} ({3}),Die {0} ({1}) moet gelyk wees aan {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, voltooi die bewerking {1} voor die bewerking {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Kan nie verseker dat aflewering per reeksnr. Nie, aangesien artikel {0} bygevoeg word met en sonder versekering deur afleweringnr.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Item {0} het geen reeksnommer nie. Slegs geassosialiseerde items kan afgelewer word op grond van reeksnr,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Geen aktiewe BOM vir item {0} gevind nie. Aflewering per reeksnommer kan nie verseker word nie,
+No pending medication orders found for selected criteria,Geen hangende medikasiebestellings vir geselekteerde kriteria gevind nie,
+From Date cannot be after the current date.,Vanaf datum kan nie na die huidige datum wees nie.,
+To Date cannot be after the current date.,To Date kan nie na die huidige datum wees nie.,
+From Time cannot be after the current time.,Van tyd kan nie na die huidige tyd wees nie.,
+To Time cannot be after the current time.,To Time kan nie na die huidige tyd wees nie.,
+Stock Entry {0} created and ,Voorraadinskrywing {0} geskep en,
+Inpatient Medication Orders updated successfully,Mediese bestellings vir binnepasiënte is suksesvol opgedateer,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Ry {0}: kan nie inskrywingsmedikasie-inskrywing skep teen die gekanselleerde bestelling vir binnepasiëntmedikasie nie {1},
+Row {0}: This Medication Order is already marked as completed,Ry {0}: hierdie medisyne-bestelling is reeds as voltooi gemerk,
+Quantity not available for {0} in warehouse {1},Hoeveelheid nie beskikbaar vir {0} in pakhuis {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Aktiveer asseblief Laat negatiewe voorraad toe in voorraadinstellings of skep voorraadinskrywing om voort te gaan.,
+No Inpatient Record found against patient {0},Geen pasiëntrekord gevind teen pasiënt nie {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Daar bestaan reeds 'n medikasiebevel vir binnepasiënte {0} teen pasiëntontmoeting {1}.,
+Allow In Returns,Laat opbrengste toe,
+Hide Unavailable Items,Versteek nie-beskikbare items,
+Apply Discount on Discounted Rate,Pas afslag toe op afslag,
+Therapy Plan Template,Terapieplan-sjabloon,
+Fetching Template Details,Haal sjabloonbesonderhede op,
+Linked Item Details,Gekoppelde itembesonderhede,
+Therapy Types,Terapie tipes,
+Therapy Plan Template Detail,Terapieplan sjabloonbesonderhede,
+Non Conformance,Nie-ooreenstemming,
+Process Owner,Proses eienaar,
+Corrective Action,Korrektiewe aksie,
+Preventive Action,Voorkomende aksie,
+Problem,Probleem,
+Responsible,Verantwoordelik,
+Completion By,Voltooiing deur,
+Process Owner Full Name,Proses eienaar se volle naam,
+Right Index,Regte indeks,
+Left Index,Linkse indeks,
+Sub Procedure,Subprosedure,
+Passed,Geslaag,
+Print Receipt,Drukbewys,
+Edit Receipt,Wysig kwitansie,
+Focus on search input,Fokus op soekinsette,
+Focus on Item Group filter,Fokus op Item Group filter,
+Checkout Order / Submit Order / New Order,Afhandeling Bestelling / Dien Bestelling / Nuwe Bestelling in,
+Add Order Discount,Bestel afslag byvoeg,
+Item Code: {0} is not available under warehouse {1}.,Itemkode: {0} is nie beskikbaar onder pakhuis {1} nie.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Reeksnommers nie beskikbaar vir item {0} onder pakhuis {1} nie. Probeer om die pakhuis te verander.,
+Fetched only {0} available serial numbers.,Slegs {0} beskikbare reeksnommers gekry.,
+Switch Between Payment Modes,Skakel tussen betaalmetodes,
+Enter {0} amount.,Voer {0} bedrag in.,
+You don't have enough points to redeem.,U het nie genoeg punte om af te los nie.,
+You can redeem upto {0}.,U kan tot {0} gebruik.,
+Enter amount to be redeemed.,Voer die bedrag in wat afgelos moet word.,
+You cannot redeem more than {0}.,U kan nie meer as {0} gebruik nie.,
+Open Form View,Maak vormaansig oop,
+POS invoice {0} created succesfully,POS-faktuur {0} suksesvol geskep,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Voorraadhoeveelheid nie genoeg vir artikelkode: {0} onder pakhuis {1}. Beskikbare hoeveelheid {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Serienommer: {0} is reeds oorgedra na 'n ander POS-faktuur.,
+Balance Serial No,Saldo Reeksnr,
+Warehouse: {0} does not belong to {1},Pakhuis: {0} behoort nie tot {1},
+Please select batches for batched item {0},Kies groepe vir 'n partytjie-item {0},
+Please select quantity on row {0},Kies hoeveelheid in ry {0},
+Please enter serial numbers for serialized item {0},Voer die reeksnommers in vir die reeks-item {0},
+Batch {0} already selected.,Bondel {0} reeds gekies.,
+Please select a warehouse to get available quantities,Kies 'n pakhuis om beskikbare hoeveelhede te kry,
+"For transfer from source, selected quantity cannot be greater than available quantity",Vir oordrag vanaf die bron kan die gekose hoeveelheid nie groter wees as die beskikbare hoeveelheid nie,
+Cannot find Item with this Barcode,Kan nie item met hierdie strepieskode vind nie,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} is verpligtend. Miskien word valuta-rekord nie vir {1} tot {2} geskep nie,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} het bates wat daaraan gekoppel is, ingedien. U moet die bates kanselleer om die aankoopopbrengs te skep.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Kan nie hierdie dokument kanselleer nie, want dit is gekoppel aan die ingediende bate {0}. Kanselleer dit asseblief om voort te gaan.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ry # {}: Reeksnr. {} Is reeds oorgedra na 'n ander POS-faktuur. Kies 'n geldige reeksnr.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ry # {}: reeksnommers. {} Is reeds in 'n ander POS-faktuur oorgedra. Kies 'n geldige reeksnr.,
+Item Unavailable,Item nie beskikbaar nie,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Ry # {}: reeksnommer {} kan nie teruggestuur word nie, aangesien dit nie op die oorspronklike faktuur gedoen is nie {}",
+Please set default Cash or Bank account in Mode of Payment {},Stel die verstek kontant- of bankrekening in die betaalmetode {},
+Please set default Cash or Bank account in Mode of Payments {},Stel asseblief die standaard kontant- of bankrekening in die modus van betalings {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Maak seker dat die {} rekening 'n balansstaatrekening is. U kan die ouerrekening in 'n balansrekening verander of 'n ander rekening kies.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Maak seker dat die {} rekening 'n betaalbare rekening is. Verander die rekeningtipe na Betaalbaar of kies 'n ander rekening.,
+Row {}: Expense Head changed to {} ,Ry {}: Onkostekop verander na {},
+because account {} is not linked to warehouse {} ,omdat rekening {} nie aan pakhuis gekoppel is nie {},
+or it is not the default inventory account,of dit is nie die standaardvoorraadrekening nie,
+Expense Head Changed,Uitgawehoof verander,
+because expense is booked against this account in Purchase Receipt {},omdat die onkoste teen hierdie rekening in die aankoopbewys {} bespreek word,
+as no Purchase Receipt is created against Item {}. ,aangesien geen aankoopbewys teen item {} geskep word nie.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Dit word gedoen om rekeningkunde te hanteer vir gevalle waar aankoopbewys na aankoopfaktuur geskep word,
+Purchase Order Required for item {},Bestelling benodig vir item {},
+To submit the invoice without purchase order please set {} ,Stel die {} in om die faktuur sonder 'n bestelling in te dien,
+as {} in {},soos in {},
+Mandatory Purchase Order,Verpligte bestelling,
+Purchase Receipt Required for item {},Aankoopbewys benodig vir item {},
+To submit the invoice without purchase receipt please set {} ,Stel die {} in om die faktuur sonder aankoopbewys in te dien.,
+Mandatory Purchase Receipt,Verpligte aankoopbewys,
+POS Profile {} does not belongs to company {},POS-profiel {} behoort nie tot die maatskappy nie {},
+User {} is disabled. Please select valid user/cashier,Gebruiker {} is gedeaktiveer. Kies 'n geldige gebruiker / kassier,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Ry # {}: oorspronklike faktuur {} van retourfaktuur {} is {}.,
+Original invoice should be consolidated before or along with the return invoice.,Die oorspronklike faktuur moet voor of saam met die retoervaktuur gekonsolideer word.,
+You can add original invoice {} manually to proceed.,U kan oorspronklike fakture {} handmatig byvoeg om voort te gaan.,
+Please ensure {} account is a Balance Sheet account. ,Maak seker dat die {} rekening 'n balansstaatrekening is.,
+You can change the parent account to a Balance Sheet account or select a different account.,U kan die ouerrekening in 'n balansrekening verander of 'n ander rekening kies.,
+Please ensure {} account is a Receivable account. ,Maak seker dat die {} rekening 'n ontvangbare rekening is.,
+Change the account type to Receivable or select a different account.,Verander die rekeningtipe na Ontvangbaar of kies 'n ander rekening.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} kan nie gekanselleer word nie omdat die verdienste van die Lojaliteitspunte afgelos is. Kanselleer eers die {} Nee {},
+already exists,bestaan alreeds,
+POS Closing Entry {} against {} between selected period,POS-sluitingsinskrywing {} teen {} tussen die gekose periode,
+POS Invoice is {},POS-faktuur is {},
+POS Profile doesn't matches {},POS-profiel stem nie ooreen nie {},
+POS Invoice is not {},POS-faktuur is nie {},
+POS Invoice isn't created by user {},POS-faktuur word nie deur gebruiker {} geskep nie,
+Row #{}: {},Ry # {}: {},
+Invalid POS Invoices,Ongeldige POS-fakture,
+Please add the account to root level Company - {},Voeg die rekening by die maatskappy se wortelvlak - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Terwyl u 'n rekening vir Child Company {0} skep, word die ouerrekening {1} nie gevind nie. Skep asseblief die ouerrekening in ooreenstemmende COA",
+Account Not Found,Rekening nie gevind nie,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Terwyl u 'n rekening vir Child Company {0} skep, word die ouerrekening {1} as 'n grootboekrekening gevind.",
+Please convert the parent account in corresponding child company to a group account.,Skakel asseblief die ouerrekening in die ooreenstemmende kindermaatskappy om na 'n groeprekening.,
+Invalid Parent Account,Ongeldige ouerrekening,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Om dit te hernoem, is slegs toegelaat via moedermaatskappy {0}, om wanverhouding te voorkom.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","As u {0} {1} hoeveelhede van die artikel {2} het, sal die skema {3} op die item toegepas word.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","As u {0} {1} die waarde van item {2} het, sal die skema {3} op die item toegepas word.",
+"As the field {0} is enabled, the field {1} is mandatory.","Aangesien die veld {0} geaktiveer is, is die veld {1} verpligtend.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Aangesien die veld {0} geaktiveer is, moet die waarde van die veld {1} meer as 1 wees.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Kan nie reeksnommer {0} van die artikel {1} lewer nie, aangesien dit gereserveer is vir die volledige bestelling {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",Verkooporder {0} het 'n bespreking vir die artikel {1}. U kan slegs gereserveerde {1} teen {0} aflewer.,
+{0} Serial No {1} cannot be delivered,{0} Reeksnr. {1} kan nie afgelewer word nie,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Ry {0}: Item uit die onderkontrak is verpligtend vir die grondstof {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Aangesien daar voldoende grondstowwe is, is materiaalversoek nie nodig vir pakhuis {0} nie.",
+" If you still want to proceed, please enable {0}.",Skakel {0} aan as u nog steeds wil voortgaan.,
+The item referenced by {0} - {1} is already invoiced,Die item waarna verwys word deur {0} - {1} word reeds gefaktureer,
+Therapy Session overlaps with {0},Terapiesessie oorvleuel met {0},
+Therapy Sessions Overlapping,Terapiesessies oorvleuel,
+Therapy Plans,Terapieplanne,
+"Item Code, warehouse, quantity are required on row {0}","Itemkode, pakhuis, hoeveelheid word in ry {0} vereis",
+Get Items from Material Requests against this Supplier,Kry items uit materiaalversoeke teen hierdie verskaffer,
+Enable European Access,Aktiveer Europese toegang,
+Creating Purchase Order ...,Skep tans bestelling ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",Kies 'n verskaffer uit die verstekverskaffers van die onderstaande items. By seleksie sal 'n bestelling slegs gemaak word teen items wat tot die geselekteerde verskaffer behoort.,
+Row #{}: You must select {} serial numbers for item {}.,Ry # {}: u moet {} reeksnommers vir item {} kies.,
diff --git a/erpnext/translations/am.csv b/erpnext/translations/am.csv
index accc23f..554b0a5 100644
--- a/erpnext/translations/am.csv
+++ b/erpnext/translations/am.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},ትክክለኛው ዓይነት የግብር ረድፍ ውስጥ ንጥል ተመን ውስጥ ሊካተቱ አይችሉም {0},
Add,አክል,
Add / Edit Prices,/ አርትዕ ዋጋዎች አክል,
-Add All Suppliers,ሁሉንም አቅራቢዎች አክል,
Add Comment,አስተያየት ያክሉ,
Add Customers,ደንበኞች ያክሉ,
Add Employees,ሰራተኞችን አክል,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',በምድብ «ግምቱ 'ወይም' Vaulation እና ጠቅላላ 'ነው ጊዜ ቀነሰ አይቻልም,
"Cannot delete Serial No {0}, as it is used in stock transactions",መሰረዝ አይቻልም መለያ የለም {0}: ይህ የአክሲዮን ግብይቶች ላይ የዋለው እንደ,
Cannot enroll more than {0} students for this student group.,ይህ ተማሪ ቡድን {0} ተማሪዎች በላይ መመዝገብ አይችልም.,
-Cannot find Item with this barcode,በዚህ የአሞሌ ኮድን ንጥል ነገር ማግኘት አልተቻለም ፡፡,
Cannot find active Leave Period,ንቁ የቆየውን ጊዜ ማግኘት አይቻልም,
Cannot produce more Item {0} than Sales Order quantity {1},የሽያጭ ትዕዛዝ ብዛት የበለጠ ንጥል {0} ማፍራት የማይችሉ {1},
Cannot promote Employee with status Left,በአስተዳዳሪ ሁኔታ ወደ ሠራተኛ ማስተዋወቅ አይቻልም,
Cannot refer row number greater than or equal to current row number for this Charge type,ይህ የክፍያ ዓይነት የአሁኑ ረድፍ ቁጥር ይበልጣል ወይም እኩል ረድፍ ቁጥር ሊያመለክት አይችልም,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,የመጀመሪያውን ረድፍ ለ 'ቀዳሚ ረድፍ ጠቅላላ ላይ' 'ቀዳሚ የረድፍ መጠን ላይ' እንደ ክፍያ አይነት መምረጥ ወይም አይቻልም,
-Cannot set a received RFQ to No Quote,የተቀበሉት አር.ኤም.ፒ. ወደ "ምንም" የለም,
Cannot set as Lost as Sales Order is made.,የሽያጭ ትዕዛዝ ነው እንደ የጠፋ እንደ ማዘጋጀት አልተቻለም.,
Cannot set authorization on basis of Discount for {0},ለ ቅናሽ ላይ የተመሠረተ ፈቃድ ማዘጋጀት አይቻልም {0},
Cannot set multiple Item Defaults for a company.,የአንድ ኩባንያ ብዙ ንጥል ነባሪዎችን ማዘጋጀት አይቻልም.,
@@ -521,7 +518,6 @@
Chargeble,ቻርጅ,
Charges are updated in Purchase Receipt against each item,ክፍያዎች እያንዳንዱ ንጥል ላይ የግዢ ደረሰኝ ውስጥ መዘመን ነው,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","ክፍያዎች ተመጣጣኝ መጠን በእርስዎ ምርጫ መሠረት, ንጥል ብዛት ወይም መጠን ላይ በመመርኮዝ መሰራጨት ይሆናል",
-Chart Of Accounts,መለያዎች ገበታ,
Chart of Cost Centers,ወጪ ማዕከላት ገበታ,
Check all,ሁሉንም ይመልከቱ,
Checkout,ጨርሰህ ውጣ,
@@ -581,7 +577,6 @@
Compensatory Off,የማካካሻ አጥፋ,
Compensatory leave request days not in valid holidays,ተቀባይነት ባላቸው በዓላት ውስጥ ክፍያ የማይሰጥ የቀን የጥበቃ ቀን ጥያቄ,
Complaint,ቅሬታ,
-Completed Qty can not be greater than 'Qty to Manufacture',ይልቅ 'ብዛት ለማምረት' ተጠናቋል ብዛት የበለጠ መሆን አይችልም,
Completion Date,ማጠናቀቂያ ቀን,
Computer,ኮምፕዩተር,
Condition,ሁኔታ,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","ይፍጠሩ እና, ዕለታዊ ሳምንታዊ እና ወርሃዊ የኢሜይል ዜናዎች ያስተዳድሩ.",
Create customer quotes,የደንበኛ ጥቅሶችን ፍጠር,
Create rules to restrict transactions based on values.,እሴቶች ላይ የተመሠረተ ግብይቶችን ለመገደብ ደንቦች ይፍጠሩ.,
-Created By,የተፈጠረ,
Created {0} scorecards for {1} between: ,በ {1} መካከል {0} የካታኬት ካርዶች በ:,
Creating Company and Importing Chart of Accounts,ኩባኒያን መፍጠር እና የመለያዎች ገበታ ማስመጣት ፡፡,
Creating Fees,ክፍያዎች በመፍጠር,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,የተቀጣሪ ዝውውሩ ከመሸጋገሪያ ቀን በፊት መቅረብ አይችልም,
Employee cannot report to himself.,የተቀጣሪ ራሱን ሪፖርት አይችልም.,
Employee relieved on {0} must be set as 'Left',{0} መዘጋጀት አለበት ላይ እፎይታ ሠራተኛ 'ግራ' እንደ,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,የሚከተሉት ሠራተኞች በአሁኑ ወቅት ለዚህ ሠራተኛ ሪፖርት እያደረጉ ስለሆነ የሰራተኛ ሁኔታ ወደ 'ግራ' መደረግ አይችልም ፡፡,
Employee {0} already submited an apllication {1} for the payroll period {2},ተቀጣሪ {0} ለደመወዙ ጊዜ {,
Employee {0} has already applied for {1} between {2} and {3} : ,ተቀጣሪ {0} ቀድሞውኑ በ {2} እና በ {3} መካከል በ {1} አመልክቷል:,
Employee {0} has no maximum benefit amount,ተቀጣሪ / ሰራተኛ {0} ከፍተኛውን ጥቅም የለውም,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,ለረድፍ {0}: የታቀዱ qty አስገባ,
"For {0}, only credit accounts can be linked against another debit entry",{0}: ብቻ የክሬዲት መለያዎች ሌላ ዴቢት ግቤት ላይ የተገናኘ ሊሆን ይችላል,
"For {0}, only debit accounts can be linked against another credit entry",{0}: ብቻ ዴቢት መለያዎች ሌላ ክሬዲት ግቤት ላይ የተገናኘ ሊሆን ይችላል,
-Form View,የቅፅ እይታ,
Forum Activity,የውይይት መድረክ,
Free item code is not selected,የነፃ ንጥል ኮድ አልተመረጠም።,
Freight and Forwarding Charges,ጭነት እና ማስተላለፍ ክፍያዎች,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","በፊት የተመደበ አይችልም ይተዉት {0}, ፈቃድ ቀሪ አስቀድሞ የማስቀመጫ-በሚተላለፈው ወደፊት ፈቃድ አመዳደብ መዝገብ ውስጥ ቆይቷል እንደ {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",ፈቃድ ቀሪ አስቀድሞ የማስቀመጫ-በሚተላለፈው ወደፊት ፈቃድ አመዳደብ መዝገብ ውስጥ ቆይቷል እንደ በፊት {0} ቀርቷል / መተግበር አይችልም ተወው {1},
Leave of type {0} cannot be longer than {1},አይነት ፈቃድ {0} በላይ ሊሆን አይችልም {1},
-Leave the field empty to make purchase orders for all suppliers,ለሁሉም አቅራቢዎች የግዢ ትዕዛዞችን ለማድረግ መስኩን ባዶ ይተዉት,
Leaves,ቅጠሎች,
Leaves Allocated Successfully for {0},ለ በተሳካ ሁኔታ የተመደበ ማምለኩን {0},
Leaves has been granted sucessfully,ቅጠሎች በተሳካ ሁኔታ ተሰጥተዋል,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,ዕቃዎች መካከል ቢል ጋር ምንም ንጥሎች ለማምረት,
No Items with Bill of Materials.,በቢል ቁሳቁሶች ከቁጥሮች ጋር ምንም ዕቃዎች የሉም ፡፡,
No Permission,ምንም ፍቃድ,
-No Quote,ምንም መግለጫ የለም,
No Remarks,ምንም መግለጫዎች,
No Result to submit,ለማስገባት ምንም ውጤት የለም,
No Salary Structure assigned for Employee {0} on given date {1},በተሰጠው ቀን {0} ላይ ለተቀጠረ ተቀጣሪ {0} የተመደበ ደመወዝ,
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,መካከል ተገኝቷል ከተደራቢ ሁኔታ:,
Owner,ባለቤት,
PAN,PAN,
-PO already created for all sales order items,ፖስታው ቀድሞውኑ ለሁሉም የሽያጭ ነገዶች እቃዎች ተፈጥሯል,
POS,POS,
POS Profile,POS መገለጫ,
POS Profile is required to use Point-of-Sale,POS የመሸጫ ቦታን ለመጠቀም POS የመጠየቅ ግዴታ አለበት,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,በመጀመሪያ የክፍያ አይነት ይምረጡ,
Please select Company,ኩባንያ ይምረጡ,
Please select Company and Designation,እባክዎ ኩባንያ እና ዲዛይን ይምረጡ,
-Please select Company and Party Type first,በመጀመሪያ ኩባንያ እና የፓርቲ አይነት ይምረጡ,
Please select Company and Posting Date to getting entries,እባክዎ ግቤቶችን ለመመዝገብ እባክዎ ኩባንያ እና የድረ-ገጽ ቀንን ይምረጡ,
Please select Company first,መጀመሪያ ኩባንያ እባክዎ ይምረጡ,
Please select Completion Date for Completed Asset Maintenance Log,እባክዎን ለተጠናቀቀው የንብረት ጥገና ምዝግብ ማስታወሻ ቀነ-ገደብ ይምረጡ,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,ረድፍ {0}: UOM የልወጣ ምክንያት የግዴታ ነው,
Row {0}: select the workstation against the operation {1},ረድፍ {0}: ከግዜው ላይ {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,ረድፍ {0}: {1} የቁጥር ቁጥሮች ለ Item {2} ያስፈልጋሉ. {3} ሰጥተሃል.,
-Row {0}: {1} is required to create the Opening {2} Invoices,ረድፍ {0}: ክፍት {2} ደረሰኞችን ለመፍጠር {1} ያስፈልጋል,
Row {0}: {1} must be greater than 0,ረድፍ {0}: {1} ከ 0 በላይ መሆን አለበት,
Row {0}: {1} {2} does not match with {3},ረድፍ {0}: {1} {2} ጋር አይዛመድም {3},
Row {0}:Start Date must be before End Date,ረድፍ {0}: የመጀመሪያ ቀን ከመጨረሻ ቀን በፊት መሆን አለበት,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,የእርዳታ ግምገማን ኢሜይል ላክ,
Send Now,አሁን ላክ,
Send SMS,ኤስ ኤም ኤስ ላክ,
-Send Supplier Emails,አቅራቢው ኢሜይሎች ላክ,
Send mass SMS to your contacts,የመገናኛ ኤስ የእርስዎን እውቂያዎች ላክ,
Sensitivity,ትብነት,
Sent,ተልኳል,
-Serial #,ተከታታይ #,
Serial No and Batch,ተከታታይ የለም እና ባች,
Serial No is mandatory for Item {0},ተከታታይ ምንም ንጥል ግዴታ ነው {0},
Serial No {0} does not belong to Batch {1},Serial No {0} የቡድን {1} አይደለም,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,የእርስዎን ኩባንያ ስም ስለ እናንተ ይህ ሥርዓት ማዋቀር ነው.,
The number of shares and the share numbers are inconsistent,የአክሲዮኖች ቁጥር እና የማካካሻ ቁጥሮች ወጥ ናቸው,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,የክፍያ ዕቅድ ክፍያ በእቅድ {0} ውስጥ በዚህ የክፍያ ጥያቄ ውስጥ ካለው የክፍያ በር መለያ የተለየ ነው።,
-The request for quotation can be accessed by clicking on the following link,ጥቅስ ለማግኘት ጥያቄው በሚከተለው አገናኝ ላይ ጠቅ በማድረግ ሊደረስባቸው ይችላሉ,
The selected BOMs are not for the same item,የተመረጡት BOMs ተመሳሳይ ንጥል አይደሉም,
The selected item cannot have Batch,የተመረጠው ንጥል ባች ሊኖረው አይችልም,
The seller and the buyer cannot be the same,ሻጩ እና ገዢው ተመሳሳይ መሆን አይችሉም,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},አጠቃላይ ተለዋዋጭ የድጋፍ አካል መጠን {0} ከከፍተኛው ጥቅሞች በታች መሆን የለበትም {1},
Total hours: {0},ጠቅላላ ሰዓት: {0},
Total leaves allocated is mandatory for Leave Type {0},ጠቅላላ ቅጠሎች የተመደቡበት አይነት {0},
-Total weightage assigned should be 100%. It is {0},100% መሆን አለበት የተመደበ ጠቅላላ weightage. ይህ ነው {0},
Total working hours should not be greater than max working hours {0},ጠቅላላ የሥራ ሰዓቶች ከፍተኛ የሥራ ሰዓት በላይ መሆን የለበትም {0},
Total {0} ({1}),ጠቅላላ {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","ጠቅላላ {0} ሁሉም ንጥሎች እናንተ 'ላይ የተመሠረተ ክፍያዎች ያሰራጩ' መቀየር አለበት ሊሆን ይችላል, ዜሮ ነው",
@@ -3316,7 +3299,6 @@
What do you need help with?,ምን ጋር እርዳታ የሚያስፈልጋቸው ለምንድን ነው?,
What does it do?,ምን ያደርጋል?,
Where manufacturing operations are carried.,"ባለማምረታቸው, ቀዶ የት ተሸክመው ነው.",
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",ለህፃናት ኩባንያ {0} መለያ በሚፈጥሩበት ጊዜ ፣ የወላጅ መለያ {1} አልተገኘም። እባክዎን የወላጅ መለያ ተጓዳኝ COA ን ይፍጠሩ።,
White,ነጭ,
Wire Transfer,የሃዋላ ገንዘብ መላኪያ,
WooCommerce Products,WooCommerce ምርቶች።,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} ፈጣሪዎች ተፈጥረዋል.,
{0} {1} created,{0} {1} ተፈጥሯል,
{0} {1} does not exist,{0} {1} የለም,
-{0} {1} does not exist.,{0} {1} የለም.,
{0} {1} has been modified. Please refresh.,{0} {1} ተቀይሯል. እባክዎ ያድሱ.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} እርምጃ ሊጠናቀቅ አልቻለም, ስለዚህ ገብቷል አልተደረገም",
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1} ከ {2} ጋር የተያያዘ ነው ነገር ግን የፓርቲ መለያ {3},
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} ነው አይደለም አለ,
{0}: {1} not found in Invoice Details table,{0}: {1} የደረሰኝ ዝርዝሮች ሠንጠረዥ ውስጥ አልተገኘም,
{} of {},{} ከ {},
+Assigned To,የተመደበ,
Chat,ውይይት,
Completed By,ተጠናቅቋል,
Conditions,ሁኔታዎች,
@@ -3506,7 +3488,9 @@
Merge with existing,ነባር ጋር አዋህድ,
Office,ቢሮ,
Orientation,አቀማመጥ,
+Parent,ወላጅ,
Passive,የማይሠራ,
+Payment Failed,ክፍያ አልተሳካም,
Percent,መቶኛ,
Permanent,ቋሚ,
Personal,የግል,
@@ -3544,7 +3528,6 @@
Company field is required,የኩባንያው መስክ ያስፈልጋል።,
Creating Dimensions...,ልኬቶችን በመፍጠር ላይ ...,
Duplicate entry against the item code {0} and manufacturer {1},በእቃ ኮዱ {0} እና በአምራቹ {1} ላይ የተባዛ ግቤት,
-Import Chart Of Accounts from CSV / Excel files,የመለያዎች ገበታዎችን ከ CSV / የ Excel ፋይሎች ያስመጡ።,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,ልክ ያልሆነ GSTIN! ያስገባኸው ግቤት ለ UIN Holders ወይም ነዋሪ ላልሆኑ OIDAR አገልግሎት አቅራቢዎች ከ GSTIN ቅርጸት ጋር አይጣጣምም ፡፡,
Invoice Grand Total,የክፍያ መጠየቂያ ግራንድ አጠቃላይ።,
Last carbon check date cannot be a future date,የመጨረሻው የካርቦን ፍተሻ ቀን የወደፊት ቀን ሊሆን አይችልም።,
@@ -3556,6 +3539,7 @@
Show {0},አሳይ {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",ከ "-" ፣ "#" ፣ "፣" ፣ "/" ፣ "{" እና "}" በስተቀር ልዩ ቁምፊዎች ከመለያ መሰየሚያ አይፈቀድም,
Target Details,የ Detailsላማ ዝርዝሮች።,
+{0} already has a Parent Procedure {1}.,{0} ቀድሞውኑ የወላጅ አሰራር ሂደት አለው {1}።,
API,ኤ ፒ አይ,
Annual,ዓመታዊ,
Approved,ጸድቋል,
@@ -3572,6 +3556,8 @@
No data to export,ወደ ውጭ ለመላክ ምንም ውሂብ የለም።,
Portrait,ፎቶግራፍ,
Print Heading,አትም HEADING,
+Scheduler Inactive,መርሐግብር አስያዥ ንቁ ያልሆነ።,
+Scheduler is inactive. Cannot import data.,መርሐግብር አስያዥ ንቁ አይደለም። ውሂብ ማስመጣት አልተቻለም።,
Show Document,ሰነድ አሳይ።,
Show Traceback,Traceback አሳይ።,
Video,ቪዲዮ ፡፡,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},ለእቃው ጥራት ምርመራን ይፍጠሩ {0},
Creating Accounts...,መለያዎችን በመፍጠር ላይ ...,
Creating bank entries...,የባንክ ግቤቶችን በመፍጠር ላይ ...,
-Creating {0},{0} በመፍጠር ላይ,
Credit limit is already defined for the Company {0},የብድር መጠን ለድርጅቱ ቀድሞውኑ ተገልጻል {0},
Ctrl + Enter to submit,ለማስገባት Ctrl + ያስገቡ,
Ctrl+Enter to submit,ለማስገባት Ctrl + Enter ይጫኑ,
@@ -3921,7 +3906,6 @@
Plaid public token error,የተዘበራረቀ የህዝብ የምስጋና የምስክር ወረቀት,
Plaid transactions sync error,የተዘዋወሩ ግብይቶች የማመሳሰል ስህተት።,
Please check the error log for details about the import errors,እባክዎን ስለማስመጣት ስህተቶች ዝርዝር ለማግኘት የስህተት ምዝግብ ማስታወሻውን ይመልከቱ ፡፡,
-Please click on the following link to set your new password,አዲሱን የይለፍ ቃል ለማዘጋጀት በሚከተለው አገናኝ ላይ ጠቅ ያድርጉ,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,እባክዎ <b>ለኩባንያ የ DATEV ቅንብሮችን</b> ይፍጠሩ <b>{}</b> ።,
Please create adjustment Journal Entry for amount {0} ,እባክዎ ለቁጥር {0} ማስተካከያ ጆርናል ግቤት ይፍጠሩ,
Please do not create more than 500 items at a time,እባክዎን በአንድ ጊዜ ከ 500 በላይ እቃዎችን አይፍጠሩ ፡፡,
@@ -3997,6 +3981,7 @@
Release date must be in the future,የሚለቀቅበት ቀን ለወደፊቱ መሆን አለበት።,
Relieving Date must be greater than or equal to Date of Joining,የመልሶ ማግኛ ቀን ከተቀላቀለበት ቀን የሚበልጥ ወይም እኩል መሆን አለበት,
Rename,ዳግም ሰይም,
+Rename Not Allowed,ዳግም መሰየም አልተፈቀደም።,
Repayment Method is mandatory for term loans,የመክፈያ ዘዴ ለጊዜ ብድሮች አስገዳጅ ነው,
Repayment Start Date is mandatory for term loans,የመክፈያ መጀመሪያ ቀን ለአበዳሪ ብድሮች አስገዳጅ ነው,
Report Item,ንጥል ሪፖርት ያድርጉ ፡፡,
@@ -4043,7 +4028,6 @@
Select All,ሁሉንም ምረጥ,
Select Difference Account,የልዩ መለያ ይምረጡ።,
Select a Default Priority.,ነባሪ ቅድሚያ ይምረጡ።,
-Select a Supplier from the Default Supplier List of the items below.,ከዚህ በታች ካሉት ነገሮች ነባሪ አቅራቢ ዝርዝር አቅራቢን ይምረጡ ፡፡,
Select a company,ኩባንያ ይምረጡ።,
Select finance book for the item {0} at row {1},ለዕቃው ፋይናንስ መጽሐፍ ይምረጡ {0} ረድፍ {1},
Select only one Priority as Default.,እንደ ነባሪ አንድ ቅድሚያ የሚሰጠውን ይምረጡ።,
@@ -4247,7 +4231,6 @@
Actual ,ትክክለኛ,
Add to cart,ወደ ግዢው ቅርጫት ጨምር,
Budget,ባጀት,
-Chart Of Accounts Importer,የመለያዎች አስመጪ ገበታ።,
Chart of Accounts,የአድራሻዎች ዝርዝር,
Customer database.,የደንበኛ ውሂብ ጎታ.,
Days Since Last order,የመጨረሻ ትዕዛዝ ጀምሮ ቀናት,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,የማብቂያ ቀን ከመጀመሪያ ቀን ያነሰ መሆን አይችልም,
For Default Supplier (Optional),ነባሪ አቅራቢ (አማራጭ),
From date cannot be greater than To date,ቀን ቀን ወደ በላይ ሊሆን አይችልም ከ,
-Get items from,ከ ንጥሎችን ያግኙ,
Group by,ቡድን በ,
In stock,ለሽያጭ የቀረበ እቃ,
Item name,ንጥል ስም,
@@ -4532,32 +4514,22 @@
Accounts Settings,ቅንብሮች መለያዎች,
Settings for Accounts,መለያዎች ቅንብሮች,
Make Accounting Entry For Every Stock Movement,እያንዳንዱ የአክሲዮን ንቅናቄ ለ በአካውንቲንግ የሚመዘገብ አድርግ,
-"If enabled, the system will post accounting entries for inventory automatically.","የነቃ ከሆነ, ስርዓት በራስ ሰር ክምችት ለ የሂሳብ ግቤቶች መለጠፍ ነው.",
-Accounts Frozen Upto,Frozen እስከሁለት መለያዎች,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","ከዚህ ቀን ድረስ በበረዶ ዲግሪ ግቤት, ማንም / ማድረግ ከዚህ በታች በተጠቀሰው ሚና በስተቀር ግቤት መቀየር ይችላል.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,ሚና Frozen መለያዎች & አርትዕ Frozen ግቤቶችን አዘጋጅ የሚፈቀድለት,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,ይህን ሚና ያላቸው ተጠቃሚዎች የታሰሩ መለያዎች ላይ የሂሳብ ግቤቶች የታሰሩ መለያዎች ማዘጋጀት እና ለመፍጠር ቀይር / የተፈቀደላቸው,
Determine Address Tax Category From,የአድራሻ ግብር ምድብ ከ,
-Address used to determine Tax Category in transactions.,በግብይቶች ውስጥ የግብር ምድብን ለመለየት የሚያገለግል አድራሻ።,
Over Billing Allowance (%),ከሂሳብ አበል በላይ (%),
-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 for $110.,በሚታዘዘው መጠን ላይ ተጨማሪ ሂሳብ እንዲከፍሉ ተፈቅዶልዎታል። ለምሳሌ-የትእዛዝ ዋጋ ለአንድ ነገር $ 100 ዶላር ከሆነ እና መቻቻል 10% ሆኖ ከተቀናበረ $ 110 እንዲከፍሉ ይፈቀድልዎታል።,
Credit Controller,የብድር መቆጣጠሪያ,
-Role that is allowed to submit transactions that exceed credit limits set.,ካልተዋቀረ የብድር ገደብ መብለጥ መሆኑን ግብይቶችን ማቅረብ አይፈቀድም ነው ሚና.,
Check Supplier Invoice Number Uniqueness,ማጣሪያ አቅራቢው የደረሰኝ ቁጥር ልዩ,
Make Payment via Journal Entry,ጆርናል Entry በኩል ክፍያ አድርግ,
Unlink Payment on Cancellation of Invoice,የደረሰኝ ስረዛ ላይ ክፍያ አታገናኝ,
-Unlink Advance Payment on Cancelation of Order,በትዕዛዝ መተላለፍ ላይ የቅድሚያ ክፍያ ክፍያን አያላቅቁ።,
Book Asset Depreciation Entry Automatically,መጽሐፍ የንብረት ዋጋ መቀነስ Entry ሰር,
Automatically Add Taxes and Charges from Item Tax Template,ከእቃው ግብር አብነት ግብርን እና ክፍያዎች በራስ-ሰር ያክሉ።,
Automatically Fetch Payment Terms,የክፍያ ውሎችን በራስ-ሰር ያውጡ።,
-Show Inclusive Tax In Print,Inclusive Tax In Print ውስጥ አሳይ,
Show Payment Schedule in Print,የክፍያ ዕቅድ በ Print ውስጥ አሳይ,
Currency Exchange Settings,የምንዛሬ ልውውጥ ቅንብሮች,
Allow Stale Exchange Rates,የተለመዱ ትውልዶች ፍቀድ,
Stale Days,የቆዳ ቀናቶች,
Report Settings,ሪፖርት ቅንብሮችን ሪፖርት አድርግ,
Use Custom Cash Flow Format,ብጁ የገንዘብ ፍሰት ቅርጸት ተጠቀም,
-Only select if you have setup Cash Flow Mapper documents,የ "Cash Flow Mapper" ሰነዶች ካለህ ብቻ ምረጥ,
Allowed To Transact With,ለማስተላለፍ የተፈቀደለት,
SWIFT number,SWIFT ቁጥር,
Branch Code,የቅርንጫፍ ኮድ,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS የደንበኛ ቡድን,
POS Field,POS መስክ,
POS Item Group,POS ንጥል ቡድን,
-[Select],[ምረጥ],
Company Address,የኩባንያ አድራሻ,
Update Stock,አዘምን Stock,
Ignore Pricing Rule,የዋጋ አሰጣጥ ደንብ ችላ,
@@ -5495,8 +5466,6 @@
Supplier Naming By,በ አቅራቢው አሰያየም,
Default Supplier Group,ነባሪ የአቅራቢ ቡድን,
Default Buying Price List,ነባሪ መግዛትና ዋጋ ዝርዝር,
-Maintain same rate throughout purchase cycle,የግዢ ዑደት ውስጥ ተመሳሳይ መጠን ይኑራችሁ,
-Allow Item to be added multiple times in a transaction,ንጥል አንድ ግብይት ውስጥ በርካታ ጊዜያት መታከል ፍቀድ,
Backflush Raw Materials of Subcontract Based On,የቢሮ ውጣ ውረጅ ቁሳቁስ,
Material Transferred for Subcontract,ለንዐስ ኮንትራቱ የተሸጋገሩ ቁሳቁሶች,
Over Transfer Allowance (%),ከ የማስተላለፍ አበል (%),
@@ -5540,7 +5509,6 @@
Current Stock,የአሁኑ የአክሲዮን,
PUR-RFQ-.YYYY.-,PUR-RFQ-yYYY.-,
For individual supplier,ግለሰብ አቅራቢ ለ,
-Supplier Detail,በአቅራቢዎች ዝርዝር,
Link to Material Requests,ወደ ቁሳዊ ጥያቄዎች አገናኝ,
Message for Supplier,አቅራቢ ለ መልዕክት,
Request for Quotation Item,ትዕምርተ ንጥል ጥያቄ,
@@ -6481,7 +6449,6 @@
Appraisal Template,ግምገማ አብነት,
For Employee Name,የሰራተኛ ስም ለ,
Goals,ግቦች,
-Calculate Total Score,አጠቃላይ ነጥብ አስላ,
Total Score (Out of 5),(5 ውጪ) አጠቃላይ ነጥብ,
"Any other remarks, noteworthy effort that should go in the records.","ሌሎች ማንኛውም አስተያየት, መዝገቦች ውስጥ መሄድ ዘንድ ትኩረት የሚስብ ጥረት.",
Appraisal Goal,ግምገማ ግብ,
@@ -6599,11 +6566,6 @@
Reason for Leaving,የምትሄድበት ምክንያት,
Leave Encashed?,Encashed ይውጡ?,
Encashment Date,Encashment ቀን,
-Exit Interview Details,መውጫ ቃለ ዝርዝሮች,
-Held On,የተያዙ ላይ,
-Reason for Resignation,ሥራ መልቀቅ ለ ምክንያት,
-Better Prospects,የተሻለ ተስፋ,
-Health Concerns,የጤና ሰጋት,
New Workplace,አዲስ በሥራ ቦታ,
HR-EAD-.YYYY.-,ሃ-ኤአር-ያዮያን.-,
Returned Amount,የተመለሰው መጠን,
@@ -6740,10 +6702,7 @@
Employee Settings,የሰራተኛ ቅንብሮች,
Retirement Age,ጡረታ ዕድሜ,
Enter retirement age in years,ዓመታት ውስጥ ጡረታ ዕድሜ ያስገቡ,
-Employee Records to be created by,ሠራተኛ መዛግብት መፈጠር አለበት,
-Employee record is created using selected field. ,የተቀጣሪ መዝገብ የተመረጠው መስክ በመጠቀም የተፈጠረ ነው.,
Stop Birthday Reminders,አቁም የልደት ቀን አስታዋሾች,
-Don't send Employee Birthday Reminders,የተቀጣሪ የልደት አስታዋሾች አትላክ,
Expense Approver Mandatory In Expense Claim,የወጪ ፍቃድ አስገዳጅ በክፍያ ጥያቄ,
Payroll Settings,ከደመወዝ ክፍያ ቅንብሮች,
Leave,ተወው,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,ፈቃድ ሰጪ አመልካች ትተው ማመልከቻ ማመልከቻ,
Show Leaves Of All Department Members In Calendar,በቀን መቁጠሪያ ውስጥ የሁሉም የመጓጓዣ አባላት ቅጠሎች ያሳዩ,
Auto Leave Encashment,ራስ-ሰር ማጠናከሪያ,
-Restrict Backdated Leave Application,የተለቀቀውን የመልቀቂያ ማመልከቻን ገድብ,
Hiring Settings,የቅጥር ቅንጅቶች,
Check Vacancies On Job Offer Creation,በሥራ አቅርቦት ፈጠራ ላይ ክፍት ቦታዎችን ይፈትሹ ፡፡,
Identification Document Type,የመታወቂያ ሰነድ ዓይነት,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,ማኑፋክቸሪንግ ቅንብሮች,
Raw Materials Consumption,ጥሬ ዕቃዎች ፍጆታ,
Allow Multiple Material Consumption,በርካታ የቁሳቁሶችን ፍቃድን ይፍቀዱ,
-Allow multiple Material Consumption against a Work Order,ከአንድ የስራ ትዕዛዝ በላይ ብዙ ቁሳቁሶችን ይፍቀዱ,
Backflush Raw Materials Based On,Backflush ጥሬ እቃዎች ላይ የተመረኮዘ ላይ,
Material Transferred for Manufacture,ቁሳዊ ማምረት ለ ተላልፈዋል,
Capacity Planning,የአቅም ዕቅድ,
Disable Capacity Planning,የአቅም ማቀድን ያሰናክሉ,
Allow Overtime,የትርፍ ሰዓት ፍቀድ,
-Plan time logs outside Workstation Working Hours.,ከገቢር የሥራ ሰዓት ውጪ ጊዜ መዝገቦች ያቅዱ.,
Allow Production on Holidays,በዓላት ላይ ምርት ፍቀድ,
Capacity Planning For (Days),(ቀኖች) ያህል አቅም ዕቅድ,
-Try planning operations for X days in advance.,አስቀድሞ X ቀኖች ለ ቀዶ ዕቅድ ይሞክሩ.,
-Time Between Operations (in mins),(ደቂቃዎች ውስጥ) ክወናዎች መካከል ሰዓት,
-Default 10 mins,10 ደቂቃ ነባሪ,
Default Warehouses for Production,ለምርት ነባሪ መጋዘኖች,
Default Work In Progress Warehouse,የሂደት መጋዘን ውስጥ ነባሪ ሥራ,
Default Finished Goods Warehouse,ነባሪ ጨርሷል ዕቃዎች መጋዘን,
Default Scrap Warehouse,ነባሪ የስዕል መለጠፊያ መጋዘን,
-Over Production for Sales and Work Order,ለሽያጭ እና ለሥራ ትዕዛዝ ከ ምርት በላይ,
Overproduction Percentage For Sales Order,የሽያጭ ምርት በመቶኛ ለሽያጭ ትእዛዝ,
Overproduction Percentage For Work Order,ለስራ ቅደም ተከተል የማካካሻ ምርቶች መቶኛ,
Other Settings,ሌሎች ቅንብሮች,
Update BOM Cost Automatically,የቤቶች ዋጋ በራስ-ሰር ያዘምኑ,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",በቅርብ ጊዜ የተመን ዋጋ / የዋጋ ዝርዝር / በመጨረሻው የጥሬ ዕቃ ዋጋ ላይ በመመርኮዝ የወኪል ማስተካከያውን በጊዜ መርሐግብር በኩል በራስሰር ያስከፍላል.,
Material Request Plan Item,የቁሳዊ እሴት ጥያቄ እቅድ,
Material Request Type,ቁሳዊ ጥያቄ አይነት,
Material Issue,ቁሳዊ ችግር,
@@ -7603,10 +7554,6 @@
Quality Goal,ጥራት ያለው ግብ።,
Monitoring Frequency,ድግግሞሽ መቆጣጠር።,
Weekday,የሳምንቱ ቀናት።,
-January-April-July-October,ከጥር - ኤፕሪል-ሐምሌ-ጥቅምት ፡፡,
-Revision and Revised On,ክለሳ እና ገምጋሚ ፡፡,
-Revision,ክለሳ,
-Revised On,ተሻሽሎ በርቷል,
Objectives,ዓላማዎች ፡፡,
Quality Goal Objective,ጥራት ያለው ግብ ግብ ፡፡,
Objective,ዓላማ።,
@@ -7619,7 +7566,6 @@
Processes,ሂደቶች,
Quality Procedure Process,የጥራት ሂደት,
Process Description,የሂደት መግለጫ,
-Child Procedure,የሕፃናት አሠራር,
Link existing Quality Procedure.,አሁን ያለውን የጥራት አሠራር ያገናኙ ፡፡,
Additional Information,ተጭማሪ መረጃ,
Quality Review Objective,የጥራት ግምገማ ዓላማ።,
@@ -7787,15 +7733,9 @@
Default Customer Group,ነባሪ የደንበኛ ቡድን,
Default Territory,ነባሪ ግዛት,
Close Opportunity After Days,ቀናት በኋላ ዝጋ አጋጣሚ,
-Auto close Opportunity after 15 days,15 ቀናት በኋላ ራስ የቅርብ አጋጣሚ,
Default Quotation Validity Days,ነባሪ ትዕዛዝ ዋጋ መስጫ ቀናት,
Sales Update Frequency,የሽያጭ የማሻሻያ ድግግሞሽ,
-How often should project and company be updated based on Sales Transactions.,በሽርክም ትራንስፖርቶች መሠረት ፕሮጀክቱ እና ኩባንያው በየስንት ጊዜ ማዘመን አለባቸው.,
Each Transaction,እያንዳንዱ ግብይት,
-Allow user to edit Price List Rate in transactions,የተጠቃሚ ግብይቶችን የዋጋ ዝርዝር ተመን አርትዕ ለማድረግ ፍቀድ,
-Allow multiple Sales Orders against a Customer's Purchase Order,አንድ የደንበኛ የግዢ ትዕዛዝ ላይ በርካታ የሽያጭ ትዕዛዞች ፍቀድ,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,የግዢ Rate ወይም ግምቱ ተመን ላይ ንጥል ለ ሽያጭ ዋጋ Validate,
-Hide Customer's Tax Id from Sales Transactions,የሽያጭ ግብይቶች ከ የደንበኛ የግብር መታወቂያ ደብቅ,
SMS Center,ኤስ ኤም ኤስ ማዕከል,
Send To,ወደ ላክ,
All Contact,ሁሉም እውቂያ,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,ንጥሎች ውስጥ ጥቅም ላይ አምራቾች,
Limited to 12 characters,12 ቁምፊዎች የተገደበ,
MAT-MR-.YYYY.-,ት እሚል-ያሲ-ያዮያን.-,
-Set Warehouse,መጋዘን ያዘጋጁ,
-Sets 'For Warehouse' in each row of the Items table.,በእቃዎቹ ሰንጠረዥ በእያንዳንዱ ረድፍ ‹ለመጋዘን› ያዘጋጃል ፡፡,
-Requested For,ለ ተጠይቋል,
Partially Ordered,በከፊል የታዘዘ,
Transferred,ተላልፈዋል,
% Ordered,% የዕቃው መረጃ,
@@ -8407,24 +8344,14 @@
Default Stock UOM,ነባሪ የክምችት UOM,
Sample Retention Warehouse,የናሙና ማቆያ መደብር,
Default Valuation Method,ነባሪ ዋጋ ትመና ዘዴው,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,መቶኛ መቀበል ወይም አዘዘ መጠን ላይ ተጨማሪ ማድረስ ይፈቀዳል. ለምሳሌ: 100 ቤቶች ትእዛዝ ከሆነ. እና በል ከዚያም 110 ቤቶች ለመቀበል የተፈቀደላቸው 10% ነው.,
-Action if Quality inspection is not submitted,የጥራት ምርመራ ካልተደረገ እርምጃ,
Show Barcode Field,አሳይ ባርኮድ መስክ,
Convert Item Description to Clean HTML,የኤች ቲ ኤም ኤል ን የእርሳስ መግለጫ ቀይር,
-Auto insert Price List rate if missing,ራስ-ያስገቡ ዋጋ ዝርዝር መጠን ይጎድለዋል ከሆነ,
Allow Negative Stock,አሉታዊ የአክሲዮን ፍቀድ,
Automatically Set Serial Nos based on FIFO,በራስ-ሰር FIFO ላይ የተመሠረተ ቁጥሮች መለያ አዘጋጅ,
-Set Qty in Transactions based on Serial No Input,በ Serial No Entput ላይ በመመርኮዝ ስንት ግምት ያዘጋጁ,
Auto Material Request,ራስ-ሐሳብ ያለው ጥያቄ,
-Raise Material Request when stock reaches re-order level,የአክሲዮን ዳግም-ትዕዛዝ ደረጃ ላይ ሲደርስ የቁሳዊ ጥያቄ ላይ አንሥታችሁ,
-Notify by Email on creation of automatic Material Request,ራስ-ሰር የቁስ ጥያቄ መፍጠር ላይ በኢሜይል አሳውቅ,
Inter Warehouse Transfer Settings,የኢንተር መጋዘን ማስተላለፍ ቅንብሮች,
-Allow Material Transfer From Delivery Note and Sales Invoice,ከመላኪያ ማስታወሻ እና ከሽያጭ ደረሰኝ ላይ ቁሳቁስ ማስተላለፍን ይፍቀዱ,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,የቁሳቁስ ሽግግር ከግዢ ደረሰኝ እና የግዢ ደረሰኝ ይፍቀዱ,
Freeze Stock Entries,አርጋ Stock ግቤቶችን,
Stock Frozen Upto,የክምችት Frozen እስከሁለት,
-Freeze Stocks Older Than [Days],እሰር አክሲዮኖች የቆየ ይልቅ [ቀኖች],
-Role Allowed to edit frozen stock,ሚና የታሰረው የአክሲዮን አርትዕ ማድረግ ተፈቅዷል,
Batch Identification,የቡድን መለያ,
Use Naming Series,ስም መስጠት ስሞችን ተጠቀም,
Naming Series Prefix,የሶስት ቅንጅቶችን ስም በማውጣት ላይ,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,የግዢ ደረሰኝ በመታየት ላይ ያሉ,
Purchase Register,የግዢ ይመዝገቡ,
Quotation Trends,በትዕምርተ ጥቅስ አዝማሚያዎች,
-Quoted Item Comparison,የተጠቀሰ ንጥል ንጽጽር,
Received Items To Be Billed,ተቀብሏል ንጥሎች እንዲከፍሉ ለማድረግ,
Qty to Order,ለማዘዝ ብዛት,
Requested Items To Be Transferred,ተጠይቋል ንጥሎች መወሰድ,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,ለቁሳዊ ጥያቄዎች መጋዘን ይምረጡ,
Transfer Materials For Warehouse {0},ቁሳቁሶችን ለመጋዘን ያስተላልፉ {0},
Production Plan Material Request Warehouse,የምርት እቅድ ቁሳቁስ ጥያቄ መጋዘን,
-Set From Warehouse,ከመጋዘን ተዘጋጅ,
-Source Warehouse (Material Transfer),ምንጭ መጋዘን (ቁሳቁስ ማስተላለፍ),
Sets 'Source Warehouse' in each row of the items table.,በእያንዲንደ የእቃ ሰንጠረ tableች ረድፍ ውስጥ ‹ምንጭ መጋዘን› ያዘጋጃሌ ፡፡,
Sets 'Target Warehouse' in each row of the items table.,በእያንዲንደ የጠረጴዛዎች ረድፍ ውስጥ ‹ዒላማ መጋዘን› ያዘጋጃሌ ፡፡,
Show Cancelled Entries,የተሰረዙ ግቤቶችን አሳይ,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,አገልግሎት ተቀበለ ግን አልተከፈለም,
Deferred Accounting Settings,የዘገየ የሂሳብ አያያዝ ቅንብሮች,
Book Deferred Entries Based On,በመጽሐፍ ላይ ተመስርተው የተዘገዩ ግቤዎች,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","ወሮች" ከተመረጠ ከዚያ የተወሰነ መጠን በአንድ ወር ውስጥ የቀኖች ብዛት ምንም ይሁን ምን ለእያንዳንዱ ወር እንደዘገየ ገቢ ወይም ወጪ ይቆጠራሉ። የተዘገዘ ገቢ ወይም ወጪ ለአንድ ወር በሙሉ ካልተያዘ ይረጋገጣል።,
Days,ቀናት,
Months,ወሮች,
Book Deferred Entries Via Journal Entry,የመጽሔት መዘግየት ግቤቶች በጆርናል መግቢያ በኩል,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,ይህ ካልተመረመረ ቀጥታ የ GL ግቤቶች የተዘገዘ ገቢ / ወጪን ለማስያዝ ይፈጠራሉ,
Submit Journal Entries,የጆርናል ግቤቶችን ያስገቡ,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,ይህ ካልተመረመረ የጆርናል ግቤቶች በረቂቅ ሁኔታ ውስጥ ይቀመጣሉ እና በእጅ መቅረብ አለባቸው,
Enable Distributed Cost Center,የተሰራጨ የወጪ ማዕከልን ያንቁ,
@@ -8901,8 +8823,6 @@
Is Inter State,የኢንተር ግዛት ነው,
Purchase Details,የግዢ ዝርዝሮች,
Depreciation Posting Date,የዋጋ ቅናሽ መለጠፊያ ቀን,
-Purchase Order Required for Purchase Invoice & Receipt Creation,ለግዢ መጠየቂያ እና ደረሰኝ ፈጠራ የግዢ ትዕዛዝ ያስፈልጋል,
-Purchase Receipt Required for Purchase Invoice Creation,የግዢ ደረሰኝ ለመፍጠር የግዢ ደረሰኝ ያስፈልጋል,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",በነባሪነት የአቅራቢው ስም እንደገባው በአቅራቢው ስም ይዋቀራል ፡፡ አቅራቢዎች በ ሀ እንዲሰየሙ ከፈለጉ,
choose the 'Naming Series' option.,የ “ስያሜ ተከታታይ” ን ይምረጡ።,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,አዲስ የግዢ ግብይት ሲፈጥሩ ነባሪውን የዋጋ ዝርዝር ያዋቅሩ። የእቃ ዋጋዎች ከዚህ የዋጋ ዝርዝር ውስጥ ይፈለጋሉ።,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,የገቢ ግብር አካል ነው,
Component properties and references ,የአካል ክፍሎች እና ማጣቀሻዎች,
Additional Salary ,ተጨማሪ ደመወዝ,
-Condtion and formula,መጨናነቅ እና ቀመር,
Unmarked days,ምልክት ያልተደረገባቸው ቀናት,
Absent Days,የቀሩ ቀናት,
Conditions and Formula variable and example,ሁኔታዎች እና የቀመር ተለዋዋጭ እና ምሳሌ,
Feedback By,ግብረመልስ በ,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY.-MM. - ዲ.ዲ.-,
Manufacturing Section,የማምረቻ ክፍል,
-Sales Order Required for Sales Invoice & Delivery Note Creation,ለሽያጭ መጠየቂያ እና አቅርቦት የማስረከቢያ ማስታወሻ የሽያጭ ትዕዛዝ ያስፈልጋል,
-Delivery Note Required for Sales Invoice Creation,የመላኪያ ማስታወሻ ለሽያጭ መጠየቂያ ደረሰኝ ፈጠራ ያስፈልጋል,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",በነባሪነት የደንበኛው ስም እንደገባው ሙሉ ስም ይዋቀራል ፡፡ ደንበኞች በ ሀ እንዲሰየሙ ከፈለጉ,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,አዲስ የሽያጭ ግብይት ሲፈጥሩ ነባሪውን የዋጋ ዝርዝር ያዋቅሩ። የእቃ ዋጋዎች ከዚህ የዋጋ ዝርዝር ውስጥ ይፈለጋሉ።,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",ይህ አማራጭ ‹አዎ› ከተዋቀረ ERPNext በመጀመሪያ የሽያጭ ትዕዛዝ ሳይፈጥሩ የሽያጭ መጠየቂያ መጠየቂያ ወይም የማስረከቢያ ማስታወሻ እንዳይፈጥሩ ይከለክልዎታል ፡፡ በደንበኛው ማስተር ውስጥ የ ‹የሽያጭ መጠየቂያ መጠየቂያ ያለ የሽያጭ ትዕዛዝ ፍቀድ› አመልካች ሳጥንን በማንቃት ይህ ውቅር ለአንድ የተወሰነ ደንበኛ ሊተካ ይችላል ፡፡,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} በተሳካ ሁኔታ ወደ ሁሉም በተመረጡት ርዕሶች ታክሏል,
Topics updated,ርዕሶች ዘምነዋል,
Academic Term and Program,የትምህርት ጊዜ እና ፕሮግራም,
-Last Stock Transaction for item {0} was on {1}.,ለንጥል {0} የመጨረሻው የአክሲዮን ግብይት በ {1} ላይ ነበር።,
-Stock Transactions for Item {0} cannot be posted before this time.,የንጥል ክምችት ግብይቶች {0} ከዚህ ጊዜ በፊት መለጠፍ አይቻልም።,
Please remove this item and try to submit again or update the posting time.,እባክዎ ይህንን ንጥል ያስወግዱ እና እንደገና ለማስገባት ይሞክሩ ወይም የመለጠፍ ጊዜውን ያዘምኑ።,
Failed to Authenticate the API key.,የኤፒአይ ቁልፍን ማረጋገጥ አልተሳካም።,
Invalid Credentials,ልክ ያልሆኑ ምስክርነቶች,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,እባክዎ የፕላድ ደንበኛ መታወቂያዎን እና ሚስጥራዊ እሴቶችዎን ያረጋግጡ,
Bank transaction creation error,የባንክ ግብይት መፍጠር ስህተት,
Unit of Measurement,የመለኪያ አሃድ,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},ረድፍ # {}: ለንጥል የመሸጥ መጠን {} ከእሱ ያነሰ ነው። የመሸጥ መጠን ቢያንስ ቢያንስ መሆን አለበት {},
Fiscal Year {0} Does Not Exist,የበጀት ዓመት {0} የለም,
Row # {0}: Returned Item {1} does not exist in {2} {3},ረድፍ # {0}: የተመለሰ ንጥል {1} በ {2} {3} ውስጥ የለም,
Valuation type charges can not be marked as Inclusive,የዋጋ አሰጣጥ አይነት ክፍያዎች ሁሉን ያካተተ ሆኖ ምልክት ሊደረግባቸው አይቻልም,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,የምላሽ ጊዜ ለ {0} በተከታታይ ቅድሚያ የሚሰጠው {1} ከመፍትሔው ጊዜ ሊበልጥ አይችልም።,
{0} is not enabled in {1},{0} በ {1} ውስጥ አልነቃም,
Group by Material Request,በቁሳዊ ጥያቄ በቡድን,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",ረድፍ {0} ለአቅራቢው {0} ኢሜል ለመላክ የኢሜል አድራሻ ያስፈልጋል,
Email Sent to Supplier {0},ለአቅራቢ ኢሜይል ተልኳል {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",ከመግቢያው የጥቆማ ጥያቄ መዳረሻ ተሰናክሏል ፡፡ መዳረሻን ለመፍቀድ በ Portal ቅንብሮች ውስጥ ያንቁት።,
Supplier Quotation {0} Created,የአቅራቢ ጥቅስ {0} ተፈጥሯል,
Valid till Date cannot be before Transaction Date,እስከዛሬ ድረስ የሚሰራ ከግብይት ቀን በፊት መሆን አይችልም,
+Unlink Advance Payment on Cancellation of Order,በትእዛዝ ስረዛ ላይ የቅድሚያ ክፍያ ግንኙነትን ያላቅቁ,
+"Simple Python Expression, Example: territory != 'All Territories'",ቀላል የፓይዘን መግለጫ ፣ ምሳሌ: ክልል! = 'ሁሉም ግዛቶች',
+Sales Contributions and Incentives,የሽያጭ አስተዋፅዖዎች እና ማበረታቻዎች,
+Sourced by Supplier,በአቅራቢው ተነስቷል,
+Total weightage assigned should be 100%.<br>It is {0},የተመደበው አጠቃላይ ክብደት 100% መሆን አለበት ፡፡<br> እሱ {0} ነው,
+Account {0} exists in parent company {1}.,መለያ {0} በወላጅ ኩባንያ ውስጥ አለ {1}።,
+"To overrule this, enable '{0}' in company {1}",ይህንን ለመሻር በኩባንያው ውስጥ {0} ን ያንቁ {1},
+Invalid condition expression,ልክ ያልሆነ ሁኔታ መግለጫ,
+Please Select a Company First,እባክዎ መጀመሪያ አንድ ኩባንያ ይምረጡ,
+Please Select Both Company and Party Type First,እባክዎ መጀመሪያ ሁለቱንም ኩባንያ እና የድግስ ዓይነት ይምረጡ,
+Provide the invoice portion in percent,የክፍያ መጠየቂያውን ክፍል በመቶኛ ያቅርቡ,
+Give number of days according to prior selection,በቀድሞው ምርጫ መሠረት የቀናትን ቁጥር ይስጡ,
+Email Details,የኢሜል ዝርዝሮች,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.",ለተቀባዩ ሰላምታ ይምረጡ ፡፡ ለምሳሌ ሚስተር ወይዘሮ ወ.ዘ.ተ.,
+Preview Email,ኢሜል ቅድመ እይታ,
+Please select a Supplier,እባክዎ አቅራቢ ይምረጡ,
+Supplier Lead Time (days),የአቅራቢ መሪ ጊዜ (ቀናት),
+"Home, Work, etc.",ቤት ፣ ሥራ ፣ ወዘተ,
+Exit Interview Held On,መውጫ ቃለ መጠይቅ በርቷል,
+Condition and formula,ሁኔታ እና ቀመር,
+Sets 'Target Warehouse' in each row of the Items table.,በእያንዲንደ የእቃ ሰንጠረ rowች ረድፍ ውስጥ ‹ዒላማ መጋዘን› ያዘጋጃሌ ፡፡,
+Sets 'Source Warehouse' in each row of the Items table.,በእያንዲንደ የእቃ ሰንጠረ rowች ረድፍ ውስጥ ‹ምንጭ መጋዘን› ያዘጋጃሌ ፡፡,
+POS Register,POS ይመዝገቡ,
+"Can not filter based on POS Profile, if grouped by POS Profile",በ POS መገለጫ ከተመደቡ በ POS መገለጫ ላይ ተመስርተው ማጣሪያ ማድረግ አይቻልም,
+"Can not filter based on Customer, if grouped by Customer",በደንበኛው ከተመደበ በደንበኛው ላይ የተመሠረተ ማጣሪያ ማድረግ አይቻልም,
+"Can not filter based on Cashier, if grouped by Cashier",በገንዘብ ተቀባዩ ከተመደቡ በገንዘብ ተቀባይ ላይ የተመሠረተ ማጣራት አይቻልም,
+Payment Method,የክፍያ ዘዴ,
+"Can not filter based on Payment Method, if grouped by Payment Method",በክፍያ ዘዴ ከተመደቡ በክፍያ ዘዴው መሠረት ማጣሪያ ማድረግ አይቻልም,
+Supplier Quotation Comparison,የአቅራቢዎች ጥቅስ ንፅፅር,
+Price per Unit (Stock UOM),ዋጋ በአንድ ክፍል (ክምችት UOM),
+Group by Supplier,በአቅራቢ ቡድን,
+Group by Item,በንጥል በቡድን,
+Remember to set {field_label}. It is required by {regulation}.,{Field_label} ን ማቀናበርን ያስታውሱ። በ {ደንብ} ይፈለጋል።,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},የምዝገባ ቀን ከአካዳሚክ አመቱ መጀመሪያ ቀን በፊት መሆን አይችልም {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},የመመዝገቢያ ቀን ከትምህርታዊ ጊዜ ማብቂያ ቀን በኋላ መሆን አይችልም {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},የምዝገባ ቀን ከትምህርቱ ዘመን መጀመሪያ ቀን በፊት መሆን አይችልም {0},
+Future Posting Not Allowed,የወደፊቱ መለጠፍ አልተፈቀደም,
+"To enable Capital Work in Progress Accounting, ",በሂሳብ አያያዝ ውስጥ የካፒታል ሥራን ለማንቃት ፣,
+you must select Capital Work in Progress Account in accounts table,በሂሳብ ሰንጠረዥ ውስጥ በሂሳብ መዝገብ ውስጥ ካፒታል ሥራን መምረጥ አለብዎት,
+You can also set default CWIP account in Company {},እንዲሁም ነባሪ የ CWIP መለያ በኩባንያ ውስጥ ማቀናበር ይችላሉ {},
+The Request for Quotation can be accessed by clicking on the following button,የጥያቄ ጥያቄ የሚከተለውን ቁልፍ በመጫን ማግኘት ይቻላል,
+Regards,ከሰላምታ ጋር,
+Please click on the following button to set your new password,አዲሱን የይለፍ ቃልዎን ለማዘጋጀት እባክዎ በሚከተለው ቁልፍ ላይ ጠቅ ያድርጉ,
+Update Password,የይለፍ ቃል ያዘምኑ,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},ረድፍ # {}-ለንጥል የመሸጥ መጠን {} ከእርሷ ያነሰ ነው። መሸጥ {} ቢያንስ ቢያንስ መሆን አለበት {},
+You can alternatively disable selling price validation in {} to bypass this validation.,ይህንን ማረጋገጫ ለማለፍ በ {} ውስጥ የሽያጭ ዋጋ ማረጋገጫውን በአማራጭ ማሰናከል ይችላሉ።,
+Invalid Selling Price,ልክ ያልሆነ የሽያጭ ዋጋ,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,አድራሻ ከኩባንያ ጋር መገናኘት አለበት ፡፡ እባክዎ በአገናኝስ ሰንጠረዥ ውስጥ ለኩባንያ አንድ ረድፍ ያክሉ።,
+Company Not Linked,ኩባንያ አልተያያዘም,
+Import Chart of Accounts from CSV / Excel files,የመለያዎች ገበታ ከ CSV / Excel ፋይሎች ያስመጡ,
+Completed Qty cannot be greater than 'Qty to Manufacture',የተጠናቀቀው ኪቲ ከ ‹Qty to Manufacturere› ሊበልጥ አይችልም ፡፡,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",ረድፍ {0} ለአቅራቢ {1} ኢሜል ለመላክ የኢሜል አድራሻ ያስፈልጋል,
+"If enabled, the system will post accounting entries for inventory automatically",ከነቃ ሲስተሙ ለሂሳብ ዝርዝር የሂሳብ መዝገብ ግቤቶችን በራስ-ሰር ይለጥፋል,
+Accounts Frozen Till Date,መለያዎች የቀዘቀዙ እስከ ቀን,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,የሂሳብ ምዝገባዎች ምዝገባዎች እስከዚህ ቀን ድረስ ቀዝቅዘዋል። ከዚህ በታች ከተጠቀሰው ሚና ጋር ከተጠቃሚዎች በስተቀር ግቤቶችን ማንም መፍጠር ወይም ማሻሻል አይችልም,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,የቀዘቀዙ መለያዎችን ለማዘጋጀት እና የቀዘቀዙ ግቤቶችን ለማርትዕ የተፈቀደ ሚና,
+Address used to determine Tax Category in transactions,በግብይቶች ውስጥ የግብር ምድብን ለመወሰን የሚያገለግል አድራሻ,
+"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 ",ከታዘዘው መጠን የበለጠ እንዲከፍሉ የተፈቀደልዎ መቶኛ። ለምሳሌ ፣ የትእዛዝ ዋጋ ለአንድ ነገር $ 100 ከሆነ እና መቻቻል 10% ሆኖ ከተቀመጠ እስከ 110 ዶላር ድረስ እንዲከፍሉ ይፈቀድልዎታል,
+This role is allowed to submit transactions that exceed credit limits,ይህ ሚና ከብድር ገደቦች በላይ የሆኑ ግብይቶችን እንዲያቀርብ ይፈቀድለታል,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",“ወሮች” ከተመረጠ በአንድ ወር ውስጥ ያሉት ቀናት ብዛት ምንም ይሁን ምን አንድ የተወሰነ መጠን እንደ ተዘገዘ ገቢ ወይም ወጪ በወር ይመዘገባል። የተዘገዘ ገቢ ወይም ወጪ ለአንድ ወር በሙሉ ካልተያዘ ይረጋገጣል,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",ይህ ቁጥጥር ካልተደረገበት የቀዘቀዘ ገቢን ወይም ወጪን ለማስያዝ ቀጥተኛ የ GL ግቤቶች ይፈጠራሉ,
+Show Inclusive Tax in Print,በህትመት ውስጥ ሁሉን አቀፍ ግብርን አሳይ,
+Only select this if you have set up the Cash Flow Mapper documents,የገንዘብ ፍሰት ካርታ ሰነዶችን ካዘጋጁ ብቻ ይህንን ይምረጡ,
+Payment Channel,የክፍያ ሰርጥ,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,የግዢ መጠየቂያ እና ደረሰኝ ፈጠራ የግዢ ትዕዛዝ ያስፈልጋል?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,የግዢ ደረሰኝ ለመፍጠር የግዢ ደረሰኝ ያስፈልጋል?,
+Maintain Same Rate Throughout the Purchase Cycle,በግዢው ዑደት ውስጥ ሁሉ ተመሳሳይ ተመን ይኑርዎት,
+Allow Item To Be Added Multiple Times in a Transaction,ንጥል በአንድ ግብይት ውስጥ ብዙ ጊዜ እንዲታከል ይፍቀዱ,
+Suppliers,አቅራቢዎች,
+Send Emails to Suppliers,ለአቅራቢዎች ኢሜሎችን ይላኩ,
+Select a Supplier,አቅራቢ ይምረጡ,
+Cannot mark attendance for future dates.,ለወደፊቱ ቀናት መገኘትን ምልክት ማድረግ አይቻልም።,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},ተገኝነትን ማዘመን ይፈልጋሉ?<br> ያቅርቡ: {0}<br> የለም: {1},
+Mpesa Settings,Mpesa ቅንብሮች,
+Initiator Name,የመነሻ ስም,
+Till Number,እስከ ቁጥር,
+Sandbox,ማጠሪያ,
+ Online PassKey,በመስመር ላይ PassKey,
+Security Credential,የደህንነት ማረጋገጫ,
+Get Account Balance,የሂሳብ ሚዛን ያግኙ,
+Please set the initiator name and the security credential,እባክዎን የአስጀማሪውን ስም እና የደህንነት ማረጋገጫውን ያዘጋጁ,
+Inpatient Medication Entry,የታካሚ መድኃኒት መግቢያ,
+HLC-IME-.YYYY.-,ኤች.ሲ.ኤል-አይኤም-.YYYY.-,
+Item Code (Drug),የእቃ ኮድ (መድሃኒት),
+Medication Orders,የመድኃኒት ትዕዛዞች,
+Get Pending Medication Orders,በመጠባበቅ ላይ ያሉ የሕክምና ትዕዛዞችን ያግኙ,
+Inpatient Medication Orders,የታካሚ መድኃኒት ማዘዣዎች,
+Medication Warehouse,የመድኃኒት መጋዘን,
+Warehouse from where medication stock should be consumed,የመድኃኒት ክምችት ከሚበላበት መጋዘን,
+Fetching Pending Medication Orders,በመጠባበቅ ላይ ያሉ የሕክምና ትዕዛዞችን ማምጣት,
+Inpatient Medication Entry Detail,የታካሚ ህክምና መድሃኒት ዝርዝር ዝርዝር,
+Medication Details,የመድኃኒት ዝርዝሮች,
+Drug Code,የመድኃኒት ኮድ,
+Drug Name,የመድኃኒት ስም,
+Against Inpatient Medication Order,በሆስፒታሎች የመድኃኒት ማዘዣ ላይ,
+Against Inpatient Medication Order Entry,በሆስፒታሎች የመድኃኒት ማዘዣ መግቢያ ላይ,
+Inpatient Medication Order,የታካሚ መድኃኒት ማዘዣ,
+HLC-IMO-.YYYY.-,ኤች.ሲ.ኤል-አይሞ-.YYYY.-,
+Total Orders,ጠቅላላ ትዕዛዞች,
+Completed Orders,የተጠናቀቁ ትዕዛዞች,
+Add Medication Orders,የመድኃኒት ትዕዛዞችን ያክሉ,
+Adding Order Entries,የትዕዛዝ ግቤቶችን በማከል ላይ,
+{0} medication orders completed,{0} የመድኃኒት ትዕዛዞች ተጠናቅቀዋል,
+{0} medication order completed,{0} የመድኃኒት ትዕዛዝ ተጠናቅቋል,
+Inpatient Medication Order Entry,የታካሚ መድኃኒት ማዘዣ መግቢያ,
+Is Order Completed,ትዕዛዝ ተጠናቅቋል,
+Employee Records to Be Created By,እንዲፈጠሩ የሰራተኛ መዝገቦች በ,
+Employee records are created using the selected field,የሰራተኛ መዝገቦች በተመረጠው መስክ በመጠቀም ይፈጠራሉ,
+Don't send employee birthday reminders,የሰራተኛ የልደት ቀን ማስታወሻዎችን አይላኩ,
+Restrict Backdated Leave Applications,ጊዜ ያለፈበት ፈቃድ መተግበሪያዎችን ይገድቡ,
+Sequence ID,የቅደም ተከተል መታወቂያ,
+Sequence Id,የቅደም ተከተል መታወቂያ,
+Allow multiple material consumptions against a Work Order,በስራ ትዕዛዝ ላይ በርካታ የቁሳቁስ ፍጆታዎች ይፍቀዱ,
+Plan time logs outside Workstation working hours,ከሥራ መስሪያ የሥራ ሰዓት ውጭ የጊዜ ምዝግብ ማስታወሻዎችን ያቅዱ,
+Plan operations X days in advance,ሥራዎችን ከ X ቀናት በፊት ያቅዱ,
+Time Between Operations (Mins),በኦፕሬሽንስ (ማይንስ) መካከል ያለው ጊዜ,
+Default: 10 mins,ነባሪ: 10 ደቂቃዎች,
+Overproduction for Sales and Work Order,ለሽያጭ እና ለሥራ ትዕዛዝ ትርፍ ምርት,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",በመጨረሻው የዋጋ ተመን / የዋጋ ዝርዝር ተመን / ጥሬ ዕቃዎች የመጨረሻ ግዢ ዋጋ ላይ በመመርኮዝ የ BOM ወጪን በራስ-ሰር በፕሮግራም በኩል ያዘምኑ,
+Purchase Order already created for all Sales Order items,ለሁሉም የሽያጭ ትዕዛዝ ዕቃዎች አስቀድሞ የተፈጠረ የግዢ ትዕዛዝ,
+Select Items,ንጥሎችን ይምረጡ,
+Against Default Supplier,በነባሪ አቅራቢ ላይ,
+Auto close Opportunity after the no. of days mentioned above,ከቁጥር በኋላ በራስ-ሰር ዕድል ይዝጉ። ከላይ የተጠቀሱትን ቀናት,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,የሽያጭ መጠየቂያ እና የማስረከቢያ ማስታወሻ መፍጠር የሽያጭ ትዕዛዝ ያስፈልጋል?,
+Is Delivery Note Required for Sales Invoice Creation?,ለሽያጭ መጠየቂያ ደረሰኝ ፈጠራ የማስረከቢያ ማስታወሻ ይፈለጋል?,
+How often should Project and Company be updated based on Sales Transactions?,በሽያጭ ግብይቶች ላይ በመመርኮዝ ፕሮጀክት እና ኩባንያ ምን ያህል ጊዜ መዘመን አለባቸው?,
+Allow User to Edit Price List Rate in Transactions,በተጠቃሚዎች ውስጥ የዋጋ ዝርዝር ተመን እንዲያርትዕ ለተጠቃሚ ይፍቀዱለት,
+Allow Item to Be Added Multiple Times in a Transaction,ንጥል በአንድ ግብይት ውስጥ ብዙ ጊዜ እንዲታከል ይፍቀዱ,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,በደንበኞች ግዢ ትዕዛዝ ላይ ብዙ የሽያጭ ትዕዛዞችን ይፍቀዱ,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,ለግዢ ዋጋ ወይም የዋጋ ተመን ለእቃው የሽያጭ ዋጋን ያረጋግጡ,
+Hide Customer's Tax ID from Sales Transactions,የደንበኞችን የግብር መታወቂያ ከሽያጭ ግብይቶች ይደብቁ,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.",ከታዘዘው ብዛት የበለጠ እንዲቀበሉ ወይም እንዲያቀርቡ የተፈቀደልዎ መቶኛ። ለምሳሌ ፣ 100 አሃዶችን ካዘዙ እና አበልዎ 10% ከሆነ ከዚያ 110 ክፍሎችን ለመቀበል ይፈቀድልዎታል።,
+Action If Quality Inspection Is Not Submitted,እርምጃ የጥራት ምርመራ ካልተላለፈ,
+Auto Insert Price List Rate If Missing,ከጎደለ ራስ-ሰር የዋጋ ዝርዝር ተመን ያስገቡ,
+Automatically Set Serial Nos Based on FIFO,በ FIFO ላይ የተመሠረተ ተከታታይ ቁጥሮችን በራስ-ሰር ያዘጋጁ,
+Set Qty in Transactions Based on Serial No Input,በተከታታይ ግብዓት ላይ በመመስረት ግብይቶችን Qty ያቀናብሩ,
+Raise Material Request When Stock Reaches Re-order Level,ክምችት እንደገና ሲታዘዝ የቁሳዊ ጥያቄን ከፍ ያድርጉ,
+Notify by Email on Creation of Automatic Material Request,የራስ-ሰር ቁሳቁስ ጥያቄን በመፍጠር በኢሜል ያሳውቁ,
+Allow Material Transfer from Delivery Note to Sales Invoice,ከመላኪያ ማስታወሻ ወደ ሽያጭ መጠየቂያ ደረሰኝ ቁሳቁስ ማስተላለፍ ይፍቀዱ,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,የቁሳቁስ ሽግግር ከግዢ ደረሰኝ እስከ የግዢ ደረሰኝ ይፍቀዱ,
+Freeze Stocks Older Than (Days),ከቀኖች የበለጠ የቀዘቀዙ አክሲዮኖች,
+Role Allowed to Edit Frozen Stock,የቀዘቀዘ ክምችት ለማርትዕ የተፈቀደ ሚና,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,ያልተመደበው የክፍያ ግቤት መጠን {0} ከባንኩ ግብይት ያልተመደበ መጠን ይበልጣል,
+Payment Received,ክፍያ ደርሷል,
+Attendance cannot be marked outside of Academic Year {0},መገኘት ከትምህርታዊ ዓመት {0} ውጭ ምልክት ሊደረግበት አይችልም,
+Student is already enrolled via Course Enrollment {0},ተማሪ ቀድሞውኑ በኮርስ ምዝገባ በኩል ተመዝግቧል {0},
+Attendance cannot be marked for future dates.,ለወደፊቱ ቀናት መገኘትን ምልክት ማድረግ አይቻልም ፡፡,
+Please add programs to enable admission application.,የመግቢያ ማመልከቻን ለማንቃት እባክዎ ፕሮግራሞችን ያክሉ።,
+The following employees are currently still reporting to {0}:,የሚከተሉት ሰራተኞች በአሁኑ ጊዜ ለ {0} ሪፖርት እያደረጉ ነው-,
+Please make sure the employees above report to another Active employee.,እባክዎ ከላይ ያሉት ሠራተኞች ለሌላ ንቁ ሠራተኛ ሪፖርት ማድረጉን ያረጋግጡ ፡፡,
+Cannot Relieve Employee,ሰራተኛን ማቃለል አልተቻለም,
+Please enter {0},እባክዎ ያስገቡ {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',እባክዎ ሌላ የመክፈያ ዘዴ ይምረጡ። Mpesa በ ‹{0}› ምንዛሬ ውስጥ ግብይቶችን አይደግፍም,
+Transaction Error,የግብይት ስህተት,
+Mpesa Express Transaction Error,Mpesa Express የግብይት ስህተት,
+"Issue detected with Mpesa configuration, check the error logs for more details",በ Mpesa ውቅር የተገኘ ችግር ፣ ለተጨማሪ ዝርዝሮች የስህተት ምዝግብ ማስታወሻዎችን ይፈትሹ,
+Mpesa Express Error,የፓፒሳ ኤክስፕረስ ስህተት,
+Account Balance Processing Error,የመለያ ሚዛን ማስኬድ ስህተት,
+Please check your configuration and try again,እባክዎ ውቅርዎን ይፈትሹ እና እንደገና ይሞክሩ,
+Mpesa Account Balance Processing Error,የፓፒሳ ሂሳብ ሚዛን ማስኬድ ስህተት,
+Balance Details,ሚዛናዊ ዝርዝሮች,
+Current Balance,የአሁኑ ሒሳብ,
+Available Balance,የሚገኝ ሚዛን,
+Reserved Balance,የተጠበቀ ሚዛን,
+Uncleared Balance,ያልተስተካከለ ሚዛን,
+Payment related to {0} is not completed,ከ {0} ጋር የተገናኘ ክፍያ አልተጠናቀቀም,
+Row #{}: Item Code: {} is not available under warehouse {}.,ረድፍ # {} ንጥል ኮድ {} በመጋዘን ስር አይገኝም {}።,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,ረድፍ # {}: ለዕቃው ኮድ በቂ ያልሆነ የአክሲዮን ብዛት {} ከመጋዘን በታች {}። የሚገኝ ብዛት {},
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,ረድፍ # {}: እባክዎ ተከታታይ ቁጥርን ይምረጡ እና በንጥል ላይ ድምርን ይምረጡ ፦ {} ወይም ግብይቱን ለማጠናቀቅ ያስወግዱት።,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,ረድፍ # {}: በንጥል ላይ ምንም የመለያ ቁጥር አልተመረጠም: {}. ግብይቱን ለማጠናቀቅ እባክዎ አንዱን ይምረጡ ወይም ያስወግዱት።,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,ረድፍ # {}: በንጥል ላይ ምንም ስብስብ አልተመረጠም {}። ግብይቱን ለማጠናቀቅ እባክዎ አንድ ቡድን ይምረጡ ወይም ያስወግዱት።,
+Payment amount cannot be less than or equal to 0,የክፍያ መጠን ከ 0 በታች ወይም እኩል ሊሆን አይችልም,
+Please enter the phone number first,እባክዎን መጀመሪያ የስልክ ቁጥሩን ያስገቡ,
+Row #{}: {} {} does not exist.,ረድፍ # {}: {} {} የለም።,
+Row #{0}: {1} is required to create the Opening {2} Invoices,ረድፍ # {0}: የመክፈቻ {2} ደረሰኞችን ለመፍጠር {1} ያስፈልጋል,
+You had {} errors while creating opening invoices. Check {} for more details,የመክፈቻ መጠየቂያዎችን ሲፈጥሩ {} ስህተቶች ነበሩዎት። ለተጨማሪ ዝርዝሮች {} ን ይፈትሹ,
+Error Occured,ስህተት ተከስቷል,
+Opening Invoice Creation In Progress,የክፍያ መጠየቂያ ፈጠራ በሂደት ላይ,
+Creating {} out of {} {},{} ከ {} {} መፍጠር,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(ተከታታይ ቁጥር: {0}) ወደ ሙሉ ሙላ የሽያጭ ትዕዛዝ የተስተካከለ ስለሆነ ሊወሰድ አይችልም {1}።,
+Item {0} {1},ንጥል {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,የመጨረሻው የንጥል ግብይት ግብይት {0} ከመጋዘን በታች {1} በ {2} ላይ ነበር።,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,ለእቃው የአክሲዮን ግብይቶች {0} ከመጋዘን በታች {1} ከዚህ ጊዜ በፊት መለጠፍ አይቻልም።,
+Posting future stock transactions are not allowed due to Immutable Ledger,ለወደፊቱ የማይለዋወጥ ሌደር ምክንያት የወደፊት የአክሲዮን ግብይቶችን መለጠፍ አይፈቀድም,
+A BOM with name {0} already exists for item {1}.,ስም ያለው BOM {0} አስቀድሞ ለንጥል {1} አለ።,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} ንጥሉን ቀይረውታል? እባክዎን የአስተዳዳሪ / ቴክ ድጋፍን ያነጋግሩ,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},በረድፍ # {0} ላይ - የቅደም ተከተል መታወቂያ {1} ከቀዳሚው ረድፍ ቅደም ተከተል መታወቂያ በታች መሆን አይችልም {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) ከ {2} ({3}) ጋር እኩል መሆን አለበት,
+"{0}, complete the operation {1} before the operation {2}.",{0} ፣ ከቀዶ ጥገናው በፊት {1} ክዋኔውን ያጠናቅቁ {2}።,
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,ንጥል {0} በመደመር እና በመረጃ አቅርቦት ማድረጉን ማረጋገጥ ስለ ተጨመረ በ Serial No ማድረስን ማረጋገጥ አልተቻለም,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,ንጥል {0} በተከታታይ ቁጥር የለውም በመለያ ቁጥር ላይ በመመስረት መላኪያ ሊኖራቸው የሚችለው በተከታታይ የተሰሩ ንጥሎች ብቻ ናቸው,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,ለንጥል {0} ምንም ንቁ BOM አልተገኘም። ማድረስ በተከታታይ ቁጥር ማረጋገጥ አይቻልም,
+No pending medication orders found for selected criteria,ለተመረጡት መመዘኛዎች በመጠባበቅ ላይ ያሉ የመድኃኒት ትዕዛዞች አልተገኙም,
+From Date cannot be after the current date.,ከቀን ከአሁኑ ቀን በኋላ መሆን አይችልም።,
+To Date cannot be after the current date.,እስከዛሬ ከአሁኑ ቀን በኋላ መሆን አይችልም።,
+From Time cannot be after the current time.,ከጊዜው ከአሁኑ ሰዓት በኋላ ሊሆን አይችልም ፡፡,
+To Time cannot be after the current time.,ለጊዜ ከአሁኑ ሰዓት በኋላ ሊሆን አይችልም ፡፡,
+Stock Entry {0} created and ,የአክሲዮን ግቤት {0} ተፈጥሯል እና,
+Inpatient Medication Orders updated successfully,የታካሚ መድኃኒት ማዘዣ ትዕዛዞች በተሳካ ሁኔታ ተዘምነዋል,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},ረድፍ {0} ፦ ከተሰረዘ የታመመ የመድኃኒት ማዘዣ ትእዛዝ ጋር የታካሚ መድኃኒት ግቤት መፍጠር አልተቻለም {1},
+Row {0}: This Medication Order is already marked as completed,ረድፍ {0} ይህ የመድኃኒት ትእዛዝ አስቀድሞ እንደተጠናቀቀ ምልክት ተደርጎበታል,
+Quantity not available for {0} in warehouse {1},ብዛት ለ {0} መጋዘን ውስጥ {1} አይገኝም,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,እባክዎ በክምችት ቅንብሮች ውስጥ አሉታዊ ክምችት ይፍቀዱ ወይም ለመቀጠል የአክሲዮን ግባ ይፍጠሩ።,
+No Inpatient Record found against patient {0},በታካሚው {0} ላይ ምንም የታካሚ መዝገብ አልተገኘም,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,የታካሚ ገጠመኝን {0} የታካሚ ገጠመኝ መድኃኒት {1} ቀድሞውኑ አለ።,
+Allow In Returns,ተመላሽ አድርግ,
+Hide Unavailable Items,የማይገኙ ዕቃዎችን ደብቅ,
+Apply Discount on Discounted Rate,በቅናሽ ዋጋ ላይ ቅናሽ ይተግብሩ,
+Therapy Plan Template,ቴራፒ እቅድ አብነት,
+Fetching Template Details,የአብነት ዝርዝሮችን በማምጣት ላይ,
+Linked Item Details,የተገናኙ ንጥል ዝርዝሮች,
+Therapy Types,የሕክምና ዓይነቶች,
+Therapy Plan Template Detail,ቴራፒ እቅድ አብነት ዝርዝር,
+Non Conformance,ያልሆነ አፈፃፀም,
+Process Owner,የሂደት ባለቤት,
+Corrective Action,የማስተካከያ እርምጃ,
+Preventive Action,የመከላከያ እርምጃ,
+Problem,ችግር,
+Responsible,ኃላፊነት የሚሰማው,
+Completion By,ማጠናቀቂያ በ,
+Process Owner Full Name,የሂደት ባለቤት ሙሉ ስም,
+Right Index,የቀኝ ማውጫ,
+Left Index,የግራ ማውጫ,
+Sub Procedure,ንዑስ አሠራር,
+Passed,አል .ል,
+Print Receipt,ደረሰኝ ያትሙ,
+Edit Receipt,ደረሰኝ ያርትዑ,
+Focus on search input,በፍለጋ ግብዓት ላይ ያተኩሩ,
+Focus on Item Group filter,በእቃ ቡድን ማጣሪያ ላይ ያተኩሩ,
+Checkout Order / Submit Order / New Order,የመውጫ ክፍያ ትዕዛዝ / ትዕዛዝ ያስገቡ / አዲስ ትዕዛዝ,
+Add Order Discount,የትእዛዝ ቅናሽ ያክሉ,
+Item Code: {0} is not available under warehouse {1}.,የእቃ ኮድ {0} በመጋዘን ስር አይገኝም {1}።,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,ተከታታይ ቁጥሮች ለንጥል {0} በመጋዘን ስር {1} አይገኙም። እባክዎን መጋዝን ለመቀየር ይሞክሩ።,
+Fetched only {0} available serial numbers.,የተገኙት {0} ተከታታይ ቁጥሮች ብቻ ተገኝተዋል።,
+Switch Between Payment Modes,በክፍያ ሁነታዎች መካከል ይቀያይሩ,
+Enter {0} amount.,{0} መጠን ያስገቡ።,
+You don't have enough points to redeem.,ለማስመለስ በቂ ነጥቦች የሉዎትም።,
+You can redeem upto {0}.,እስከ {0} ድረስ ማስመለስ ይችላሉ,
+Enter amount to be redeemed.,ለማስመለስ መጠን ያስገቡ።,
+You cannot redeem more than {0}.,ከ {0} በላይ ማስመለስ አይችሉም።,
+Open Form View,የቅጽ እይታን ይክፈቱ,
+POS invoice {0} created succesfully,የ POS ደረሰኝ {0} በተሳካ ሁኔታ ፈጠረ,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,ለንጥል ኮድ በቂ ያልሆነ የአክሲዮን ብዛት {0} ከመጋዘን በታች {1}። የሚገኝ ብዛት {2}።,
+Serial No: {0} has already been transacted into another POS Invoice.,የመለያ ቁጥር {0} ቀድሞውኑ ወደ ሌላ POS ደረሰኝ ተቀይሯል።,
+Balance Serial No,ሚዛን ተከታታይ ቁጥር,
+Warehouse: {0} does not belong to {1},መጋዘን {0} የ {1} አይደለም,
+Please select batches for batched item {0},እባክዎን ለተጣራ ንጥል ስብስቦችን ይምረጡ {0},
+Please select quantity on row {0},እባክዎ በረድፍ {0} ላይ ብዛትን ይምረጡ,
+Please enter serial numbers for serialized item {0},እባክዎ ለተከታታይ ንጥል {0} ተከታታይ ቁጥሮች ያስገቡ,
+Batch {0} already selected.,ባች {0} ቀድሞውኑ ተመርጧል።,
+Please select a warehouse to get available quantities,የሚገኙ መጠኖችን ለማግኘት እባክዎ መጋዘን ይምረጡ,
+"For transfer from source, selected quantity cannot be greater than available quantity",ከምንጭ ለማስተላለፍ የተመረጠው ብዛት ከሚገኘው ብዛት ሊበልጥ አይችልም,
+Cannot find Item with this Barcode,በዚህ ባርኮድ አማካኝነት ንጥል ማግኘት አልተቻለም,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} ግዴታ ነው ምናልባት የምንዛሬ ልውውጥ መዝገብ ለ {1} እስከ {2} አልተፈጠረም,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} ከሱ ጋር የተገናኙ ንብረቶችን አስገብቷል። የግዢ ተመላሽ ለመፍጠር ንብረቶቹን መሰረዝ ያስፈልግዎታል።,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,ይህ ሰነድ ከቀረበው ንብረት {0} ጋር የተገናኘ በመሆኑ መሰረዝ አልተቻለም። ለመቀጠል እባክዎ ይሰርዙት።,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,ረድፍ # {}: የመለያ ቁጥር {} ቀድሞውኑ ወደ ሌላ POS ደረሰኝ ተቀይሯል። እባክዎ ትክክለኛ ተከታታይ ቁጥር ይምረጡ።,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,ረድፍ # {}: ተከታታይ ቁጥሮች {} ቀድሞውኑ ወደ ሌላ POS ደረሰኝ ተቀይሯል። እባክዎ ትክክለኛ ተከታታይ ቁጥር ይምረጡ።,
+Item Unavailable,ንጥል አይገኝም,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},ረድፍ # {}: ተከታታይ ቁጥር {} በመጀመሪያው የክፍያ መጠየቂያ ውስጥ ስለማይነካ መመለስ አይቻልም {},
+Please set default Cash or Bank account in Mode of Payment {},እባክዎ ነባሪ ጥሬ ገንዘብ ወይም የባንክ ሂሳብ በክፍያ ሁኔታ ውስጥ ያዘጋጁ {},
+Please set default Cash or Bank account in Mode of Payments {},እባክዎን ነባሪ ጥሬ ገንዘብ ወይም የባንክ ሂሳብ በክፍያዎች ሁኔታ ያዘጋጁ {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,እባክዎ {} መለያ የሂሳብ ሚዛን መለያ መሆኑን ያረጋግጡ። የወላጅ ሂሳብን ወደ ሚዛናዊ ሉህ መለያ መለወጥ ወይም የተለየ መለያ መምረጥ ይችላሉ።,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,እባክዎ {} መለያ የሚከፈልበት መለያ መሆኑን ያረጋግጡ። የመለያውን ዓይነት ወደ ተከፈለ ይለውጡ ወይም የተለየ መለያ ይምረጡ።,
+Row {}: Expense Head changed to {} ,ረድፍ {}: የወጪ ጭንቅላት ወደ {} ተለውጧል,
+because account {} is not linked to warehouse {} ,ምክንያቱም መለያ {} ከመጋዘን ጋር አልተያያዘም {},
+or it is not the default inventory account,ወይም ነባሪው የመለያ ሂሳብ አይደለም,
+Expense Head Changed,የወጪ ጭንቅላት ተቀየረ,
+because expense is booked against this account in Purchase Receipt {},ምክንያቱም በግዢ ደረሰኝ {} ውስጥ በዚህ ሂሳብ ላይ ወጪ ተይ becauseል,
+as no Purchase Receipt is created against Item {}. ,በእቃው ላይ ምንም የግዢ ደረሰኝ ስለማይፈጠር {}።,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,ይህ ከግዢ ደረሰኝ በኋላ የግዢ ደረሰኝ ሲፈጠር ለጉዳዮች የሂሳብ አያያዝን ለመቆጣጠር ነው,
+Purchase Order Required for item {},ለንጥል የግዢ ትዕዛዝ ያስፈልጋል {},
+To submit the invoice without purchase order please set {} ,የክፍያ መጠየቂያውን ያለግዢ ትዕዛዝ ለማስገባት እባክዎ ያዘጋጁ {},
+as {} in {},እንደ {} በ {},
+Mandatory Purchase Order,የግዴታ የግዢ ትዕዛዝ,
+Purchase Receipt Required for item {},የግዢ ደረሰኝ ለንጥል ያስፈልጋል {},
+To submit the invoice without purchase receipt please set {} ,የክፍያ መጠየቂያ ደረሰኝ ያለ ግዢ ደረሰኝ ለማስገባት እባክዎ ያዘጋጁ {},
+Mandatory Purchase Receipt,የግዴታ የግዢ ደረሰኝ,
+POS Profile {} does not belongs to company {},የ POS መገለጫ {} የድርጅት አይደለም {},
+User {} is disabled. Please select valid user/cashier,ተጠቃሚው {} ተሰናክሏል እባክዎ ትክክለኛ ተጠቃሚ / ገንዘብ ተቀባይ ይምረጡ,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,ረድፍ # {}: የመጀመሪያው የክፍያ መጠየቂያ {} የመመለሻ መጠየቂያ {} {} ነው።,
+Original invoice should be consolidated before or along with the return invoice.,ኦሪጅናል የክፍያ መጠየቂያ ከመመለሻ መጠየቂያ በፊት ወይም አብሮ መጠናከር አለበት ፡፡,
+You can add original invoice {} manually to proceed.,ለመቀጠል የመጀመሪያውን የክፍያ መጠየቂያ {} በእጅ ማከል ይችላሉ።,
+Please ensure {} account is a Balance Sheet account. ,እባክዎ {} መለያ የሂሳብ ሚዛን መለያ መሆኑን ያረጋግጡ።,
+You can change the parent account to a Balance Sheet account or select a different account.,የወላጅ ሂሳብን ወደ ሚዛናዊ ሉህ መለያ መለወጥ ወይም የተለየ መለያ መምረጥ ይችላሉ።,
+Please ensure {} account is a Receivable account. ,እባክዎ {} መለያ ተቀባይነት ያለው መለያ መሆኑን ያረጋግጡ።,
+Change the account type to Receivable or select a different account.,የመለያውን ዓይነት ወደ ደረሰኝ ይለውጡ ወይም የተለየ መለያ ይምረጡ።,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},የተገኘው የታማኝነት ነጥቦች ስለተመለሱ {} መሰረዝ አይቻልም። መጀመሪያ {} አይ {} ን ሰርዝ,
+already exists,አስቀድሞ አለ,
+POS Closing Entry {} against {} between selected period,በተመረጠው ጊዜ መካከል የ POS መዝጊያ መግቢያ {} ከ {} ጋር,
+POS Invoice is {},POS ደረሰኝ {} ነው,
+POS Profile doesn't matches {},የ POS መገለጫ ከ {} ጋር አይዛመድም,
+POS Invoice is not {},POS ደረሰኝ {} አይደለም,
+POS Invoice isn't created by user {},POS ደረሰኝ በተጠቃሚ አልተፈጠረም {},
+Row #{}: {},ረድፍ # {}: {},
+Invalid POS Invoices,ልክ ያልሆኑ የ POS ደረሰኞች,
+Please add the account to root level Company - {},እባክዎ መለያውን ወደ ስር ደረጃ ኩባንያ ያክሉ - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",ለህፃናት ኩባንያ {0} መለያ በሚፈጥሩበት ጊዜ ፣ የወላጅ መለያ {1} አልተገኘም። እባክዎን በተጓዳኝ COA ውስጥ የወላጅ መለያ ይፍጠሩ,
+Account Not Found,መለያ አልተገኘም,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",ለህፃናት ኩባንያ {0} መለያ በሚፈጥሩበት ጊዜ ፣ የወላጅ መለያ {1} እንደ የሂሳብ መዝገብ መዝገብ ተገኝቷል።,
+Please convert the parent account in corresponding child company to a group account.,እባክዎ በተዛማጅ ልጅ ኩባንያ ውስጥ ያለውን የወላጅ መለያ ወደ ቡድን መለያ ይለውጡ።,
+Invalid Parent Account,ልክ ያልሆነ የወላጅ መለያ,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",ዳግም መሰየምን የተሳሳተ ላለመሆን ለመከላከል በወላጅ ኩባንያ {0} በኩል ብቻ ነው የሚፈቀደው።,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",እርስዎ {0} {1} የእቃው ብዛት {2} ከሆነ ፣ መርሃግብሩ {3} በእቃው ላይ ይተገበራል።,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",እርስዎ {0} {1} ዋጋ ያለው ዋጋ {2} ከሆነ ፣ መርሃግብሩ {3} በእቃው ላይ ይተገበራል።,
+"As the field {0} is enabled, the field {1} is mandatory.",መስኩ {0} እንደነቃ ፣ መስኩ {1} ግዴታ ነው።,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",መስኩ {0} እንደነቃ ፣ የመስኩ {1} ዋጋ ከ 1 በላይ መሆን አለበት።,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},የመለያ ቁጥር {1} ንጥል {1} ን ለመሙላት የሽያጭ ትዕዛዝ የተያዘ ስለሆነ ማቅረብ አይቻልም {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",የሽያጭ ትዕዛዝ {0} ለንጥል {1} ቦታ ማስያዝ አለው ፣ እርስዎ የተያዙትን በ {1} በ {0} ብቻ ሊያደርሱ ይችላሉ።,
+{0} Serial No {1} cannot be delivered,{0} ተከታታይ ቁጥር {1} ማድረስ አይቻልም,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},ረድፍ {0} ለንዑስ ግብይት የተቀናበረ ንጥል አስገዳጅ ነው {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",በቂ ጥሬ ዕቃዎች ስላሉት ቁሳቁስ መጋዘን ለ መጋዘን {0} አያስፈልግም።,
+" If you still want to proceed, please enable {0}.",አሁንም መቀጠል ከፈለጉ እባክዎ {0} ን ያንቁ።,
+The item referenced by {0} - {1} is already invoiced,የተጠቀሰው ንጥል በ {0} - {1} አስቀድሞ ደረሰኝ ተደርጓል,
+Therapy Session overlaps with {0},ቴራፒ ክፍለ-ጊዜ ከ {0} ጋር ይደራረባል,
+Therapy Sessions Overlapping,ቴራፒ ክፍለ-ጊዜዎች መደራረብ,
+Therapy Plans,የሕክምና ዕቅዶች,
+"Item Code, warehouse, quantity are required on row {0}",የእቃ ኮድ ፣ መጋዘን ፣ ብዛት በረድፍ {0} ላይ ያስፈልጋሉ,
+Get Items from Material Requests against this Supplier,በዚህ አቅራቢ ላይ እቃዎችን ከቁሳዊ ጥያቄዎች ያግኙ,
+Enable European Access,የአውሮፓ መዳረሻን ያንቁ,
+Creating Purchase Order ...,የግዢ ትዕዛዝ በመፍጠር ላይ ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",ከዚህ በታች ካሉ ዕቃዎች ነባሪ አቅራቢዎች አቅራቢ ይምረጡ። በምርጫ ወቅት ለተመረጠው አቅራቢ ብቻ በሆኑ ዕቃዎች ላይ የግዢ ትዕዛዝ ይደረጋል።,
+Row #{}: You must select {} serial numbers for item {}.,ረድፍ # {}: {} ለንጥል ተከታታይ ቁጥሮች {} መምረጥ አለብዎት።,
diff --git a/erpnext/translations/ar.csv b/erpnext/translations/ar.csv
index f586a44..91a9da9 100644
--- a/erpnext/translations/ar.csv
+++ b/erpnext/translations/ar.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},نوع الضريبة الفعلي لا يمكن تضمينه في معدل الصنف في الصف {0},
Add,إضافة,
Add / Edit Prices,إضافة و تعديل الأسعار,
-Add All Suppliers,إضافة جميع الموردين,
Add Comment,أضف تعليق,
Add Customers,إضافة العملاء,
Add Employees,إضافة موظفين,
@@ -318,10 +317,10 @@
Auto repeat document updated,تكرار تلقائي للمستندات المحدثة,
Automotive,سيارات,
Available,متاح,
-Available Leaves,المغادارت المتوفرة,
+Available Leaves,المغادارت والاجازات المتاحة,
Available Qty,الكمية المتاحة,
Available Selling,المبيعات المتاحة,
-Available for use date is required,مطلوب متاح لتاريخ الاستخدام,
+Available for use date is required,مطلوب تاريخ متاح للاستخدام,
Available slots,الفتحات المتاحة,
Available {0},متاح {0},
Available-for-use Date should be after purchase date,يجب أن يكون التاريخ متاحًا بعد تاريخ الشراء,
@@ -331,16 +330,16 @@
Avg. Buying Price List Rate,متوسط قائمة أسعار الشراء,
Avg. Selling Price List Rate,متوسط قائمة أسعار البيع,
Avg. Selling Rate,متوسط معدل البيع,
-BOM,فاتورة المواد,
-BOM Browser,BOM متصفح,
-BOM No,رقم قائمة المواد,
-BOM Rate,سعر قائمة المواد,
+BOM,قائمة مكونات المواد,
+BOM Browser,قائمة مكونات المواد متصفح,
+BOM No,رقم قائمة مكونات المواد,
+BOM Rate,سعر او معدل قائمة مكونات المواد,
BOM Stock Report,تقرير مخزون فاتورة المواد,
BOM and Manufacturing Quantity are required,مطلوب، قائمة مكونات المواد و كمية التصنيع,
BOM does not contain any stock item,فاتورة الموارد لا تحتوي على أي صنف مخزون,
BOM {0} does not belong to Item {1},قائمة المواد {0} لا تنتمي إلى الصنف {1},
-BOM {0} must be active,فاتورة المواد {0} يجب أن تكون نشطة\n<br>\nBOM {0} must be active,
-BOM {0} must be submitted,فاتورة المواد {0} يجب أن تكون مسجلة\n<br>\nBOM {0} must be submitted,
+BOM {0} must be active,قائمة مكونات المواد {0} يجب أن تكون نشطة\n<br>\nBOM {0} must be active,
+BOM {0} must be submitted,قائمة مكونات المواد {0} يجب أن تكون مسجلة\n<br>\nBOM {0} must be submitted,
Balance,الموازنة,
Balance (Dr - Cr),الرصيد (مدين - دائن),
Balance ({0}),الرصيد ({0}),
@@ -389,21 +388,21 @@
Bill No,رقم الفاتورة,
Bill of Materials,فاتورة المواد,
Bill of Materials (BOM),قوائم المواد,
-Billable Hours,ساعات للفوترة,
-Billed,توصف,
+Billable Hours,ساعات قابلة للفوترة,
+Billed,تمت الفوترة,
Billed Amount,القيمة المقدم فاتورة بها,
Billing,الفواتير,
-Billing Address,عنوان تقديم الفواتير,
+Billing Address,العنوان الذي ترسل به الفواتير,
Billing Address is same as Shipping Address,عنوان الفواتير هو نفس عنوان الشحن,
Billing Amount,قيمة الفواتير,
-Billing Status,الحالة الفواتير,
+Billing Status,حالة الفواتير,
Billing currency must be equal to either default company's currency or party account currency,يجب أن تكون عملة الفوترة مساوية لعملة الشركة الافتراضية أو عملة حساب الطرف,
Bills raised by Suppliers.,فواتير حولت من قبل الموردين.,
Bills raised to Customers.,فواتير حولت للزبائن.,
Biotechnology,التكنولوجيا الحيوية,
Birthday Reminder,تذكير عيد ميلاد,
Black,أسود,
-Blanket Orders from Costumers.,أوامر بطانية من العملاء.,
+Blanket Orders from Costumers.,أوامر شراء شاملة من العملاء.,
Block Invoice,حظر الفاتورة,
Boms,قوائم المواد,
Bonus Payment Date cannot be a past date,لا يمكن أن يكون تاريخ الدفع المكافأ تاريخًا سابقًا,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',لا يمكن خصمها عند الفئة ' التقييم ' أو ' التقييم والمجموع '\n<br>\nCannot deduct when category is for 'Valuation' or 'Valuation and Total',
"Cannot delete Serial No {0}, as it is used in stock transactions",لا يمكن حذف الرقم التسلسلي {0}، لانه يتم استخدامها في قيود المخزون,
Cannot enroll more than {0} students for this student group.,لا يمكن تسجيل أكثر من {0} طلاب لمجموعة الطلاب هذه.,
-Cannot find Item with this barcode,لا يمكن العثور على العنصر مع هذا الرمز الشريطي,
Cannot find active Leave Period,لا يمكن ايجاد فترة الاجازة النشطة,
Cannot produce more Item {0} than Sales Order quantity {1},لا يمكن أن تنتج المزيد من البند {0} اكثر من كمية طلب المبيعات {1},
Cannot promote Employee with status Left,لا يمكن ترقية موظف بحالة مغادرة,
Cannot refer row number greater than or equal to current row number for this Charge type,لا يمكن أن يشير رقم الصف أكبر من أو يساوي رقم الصف الحالي لهذا النوع المسؤول,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"لا يمكن تحديد نوع التهمة باسم ' في الصف السابق المبلغ ' أو ' في السابق صف إجمالي "" ل لصف الأول",
-Cannot set a received RFQ to No Quote,لا يمكن تعيين رفق وردت إلى أي اقتباس,
Cannot set as Lost as Sales Order is made.,لا يمكن أن تعين كخسارة لأنه تم تقديم أمر البيع. <br>Cannot set as Lost as Sales Order is made.,
Cannot set authorization on basis of Discount for {0},لا يمكن تحديد التخويل على أساس الخصم ل {0},
Cannot set multiple Item Defaults for a company.,لا يمكن تعيين عدة عناصر افتراضية لأي شركة.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,تحديث الرسوم في اضافة المشتريات لكل صنف,
"Charges will be distributed proportionately based on item qty or amount, as per your selection",وسيتم توزيع تستند رسوم متناسب على الكمية البند أو كمية، حسب اختيارك,
-Chart Of Accounts,الشجرة المحاسبية,
Chart of Cost Centers,دليل مراكز التكلفة,
Check all,حدد الكل,
Checkout,دفع,
@@ -581,7 +577,6 @@
Compensatory Off,تعويض,
Compensatory leave request days not in valid holidays,أيام طلب الإجازة التعويضية ليست في أيام العطل الصالحة,
Complaint,شكوى,
-Completed Qty can not be greater than 'Qty to Manufacture',"الكمية المصنعة لا يمكن أن تكون أكبر من ""كمية التصنيع""",
Completion Date,تاريخ الانتهاء,
Computer,الحاسوب,
Condition,الحالة,
@@ -627,7 +622,7 @@
Cost Centers,مراكز التكلفة,
Cost Updated,تم تحديث التكلفة\n<br>\nCost Updated,
Cost as on,التكلفة كما في,
-Cost of Delivered Items,تكلفة البنود المسلمة,
+Cost of Delivered Items,تكلفة السلع والمواد المسلمة,
Cost of Goods Sold,تكلفة البضاعة المباعة,
Cost of Issued Items,تكلفة المواد المصروفة,
Cost of New Purchase,تكلفة الشراء الجديد,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.",إنشاء وإدارة البريد الإلكتروني يوميا وأسبوعية وشهرية .,
Create customer quotes,إنشاء عروض مسعرة للزبائن,
Create rules to restrict transactions based on values.,إنشاء قواعد لتقييد المعاملات على أساس القيم.,
-Created By,منشئه بواسطه,
Created {0} scorecards for {1} between: ,تم إنشاء {0} بطاقات الأداء {1} بين:,
Creating Company and Importing Chart of Accounts,إنشاء شركة واستيراد مخطط الحسابات,
Creating Fees,إنشاء الرسوم,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,لا يمكن تقديم نقل الموظف قبل تاريخ النقل,
Employee cannot report to himself.,الموظف لا يمكن أن يقدم تقريرا إلى نفسه.\n<br>\nEmployee cannot report to himself.,
Employee relieved on {0} must be set as 'Left',الموظف الذي ترك العمل في {0} يجب أن يتم تحديده ' مغادر ',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,لا يمكن تعيين حالة الموظف على "يسار" لأن الموظفين التاليين يقومون حاليًا بإبلاغ هذا الموظف:,
Employee {0} already submited an apllication {1} for the payroll period {2},قام الموظف {0} بالفعل بإرسال apllication {1} لفترة المرتبات {2},
Employee {0} has already applied for {1} between {2} and {3} : ,الموظف {0} قد طبق بالفعل على {1} بين {2} و {3}:,
Employee {0} has no maximum benefit amount,الموظف {0} ليس لديه الحد الأقصى لمبلغ الاستحقاق,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,بالنسبة إلى الصف {0}: أدخل الكمية المخطط لها,
"For {0}, only credit accounts can be linked against another debit entry","ل {0}, فقط الحسابات الدائنة ممكن أن تكون مقابل مدخل مدين أخر.\n<br>\nFor {0}, only credit accounts can be linked against another debit entry",
"For {0}, only debit accounts can be linked against another credit entry","ل {0}, فقط حسابات المدينة يمكن أن تكون مقابل مدخل دائن أخر.\n<br>\nFor {0}, only debit accounts can be linked against another credit entry",
-Form View,عرض النموذج,
Forum Activity,نشاط المنتدى,
Free item code is not selected,لم يتم تحديد رمز العنصر المجاني,
Freight and Forwarding Charges,رسوم الشحن,
@@ -1300,7 +1292,7 @@
Integrated Tax,ضريبة متكاملة,
Inter-State Supplies,اللوازم بين الدول,
Interest Amount,مبلغ الفائدة,
-Interests,الإهتمامات,
+Interests,الإهتمامات او الفوائد,
Intern,المتدرب,
Internet Publishing,نشر على شبكة الإنترنت,
Intra-State Supplies,اللوازم داخل الدولة,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",لا يمكن تخصيص اجازة قبل {0}، لان رصيد الإجازات قد تم تحوبله الي سجل تخصيص اجازات مستقبلي {1},
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",الاجازة لا يمكن تطبيقها او إلغائها قبل {0}، لان رصيد الإجازات قد تم تحويله الي سجل تخصيص إجازات مستقبلي {1},
Leave of type {0} cannot be longer than {1},يجب أن لا يتجاوز عدد أيام اﻹجازة من نوع {0} عدد {1} يوم.\n<br>\nLeave of type {0} cannot be longer than {1},
-Leave the field empty to make purchase orders for all suppliers,اترك الحقل فارغًا لإجراء أوامر الشراء لجميع الموردين,
Leaves,الاجازات,
Leaves Allocated Successfully for {0},تم تخصيص اﻹجازات بنجاح ل {0}\n<br>\nLeaves Allocated Successfully for {0},
Leaves has been granted sucessfully,تم منح الأوراق بنجاح,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,لا توجد بنود في قائمة المواد للتصنيع,
No Items with Bill of Materials.,لا توجد عناصر مع جدول المواد.,
No Permission,لا يوجد تصريح,
-No Quote,لا اقتباس,
No Remarks,لا ملاحظات,
No Result to submit,لا توجد نتيجة لإرسال,
No Salary Structure assigned for Employee {0} on given date {1},لا يتم تحديد هيكل الراتب للموظف {0} في تاريخ معين {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,الشروط المتداخله التي تم العثور عليها بين:\n<br>\nOverlapping conditions found between:,
Owner,مالك,
PAN,مقلاة,
-PO already created for all sales order items,PO تم إنشاؤها بالفعل لجميع عناصر أمر المبيعات,
POS,نقطة البيع,
POS Profile,الملف الشخصي لنقطة البيع,
POS Profile is required to use Point-of-Sale,مطلوب بوس الشخصي لاستخدام نقطة البيع,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,يرجى تحديد نوع الرسوم أولا,
Please select Company,الرجاء اختيار شركة \n<br>\nPlease select Company,
Please select Company and Designation,يرجى تحديد الشركة والتسمية,
-Please select Company and Party Type first,يرجى تحديد الشركة ونوع الطرف المعني أولا,
Please select Company and Posting Date to getting entries,يرجى تحديد الشركة وتاريخ النشر للحصول على إدخالات,
Please select Company first,الرجاء تحديد الشركة أولا\n<br>\nPlease select Company first,
Please select Completion Date for Completed Asset Maintenance Log,يرجى تحديد تاريخ الانتهاء لاستكمال سجل صيانة الأصول,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,الصف {0}: عامل تحويل UOM إلزامي\n<br>\nRow {0}: UOM Conversion Factor is mandatory,
Row {0}: select the workstation against the operation {1},الصف {0}: حدد محطة العمل مقابل العملية {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,الصف {0}: {1} الأرقام التسلسلية المطلوبة للبند {2}. لقد قدمت {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,الصف {0}: {1} مطلوب لإنشاء الفواتير الافتتاحية {2},
Row {0}: {1} must be greater than 0,الصف {0}: يجب أن يكون {1} أكبر من 0,
Row {0}: {1} {2} does not match with {3},الصف {0}: {1} {2} لا يتطابق مع {3},
Row {0}:Start Date must be before End Date,الصف {0}: يجب أن يكون تاريخ البدء أقل من تاريخ الانتهاء\n<br>\nRow {0}:Start Date must be before End Date,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,إرسال بريد إلكتروني منح مراجعة,
Send Now,أرسل الآن,
Send SMS,SMS أرسل رسالة,
-Send Supplier Emails,إرسال رسائل البريد الإلكتروني مزود,
Send mass SMS to your contacts,إرسال SMS الشامل لجهات الاتصال الخاصة بك,
Sensitivity,حساسية,
Sent,أرسلت,
-Serial #,المسلسل #,
Serial No and Batch,الرقم التسلسلي والدفعة,
Serial No is mandatory for Item {0},رقم المسلسل إلزامي القطعة ل {0},
Serial No {0} does not belong to Batch {1},المسلسل لا {0} لا ينتمي إلى الدفعة {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,اسم الشركة التي كنت تقوم بإعداد هذا النظام.,
The number of shares and the share numbers are inconsistent,عدد الأسهم وأعداد الأسهم غير متناسقة,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,يختلف حساب بوابة الدفع في الخطة {0} عن حساب بوابة الدفع في طلب الدفع هذا,
-The request for quotation can be accessed by clicking on the following link,طلب للحصول على الاقتباس يمكن الوصول إليها من خلال النقر على الرابط التالي,
The selected BOMs are not for the same item,قواائم المواد المحددة ليست لنفس البند,
The selected item cannot have Batch,العنصر المحدد لا يمكن أن يكون دفعة,
The seller and the buyer cannot be the same,البائع والمشتري لا يمكن أن يكون هو نفسه,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},يجب ألا يقل إجمالي مبلغ الفائدة المرنة {0} عن الحد الأقصى للمنافع {1},
Total hours: {0},مجموع الساعات: {0},
Total leaves allocated is mandatory for Leave Type {0},إجمالي الإجازات المخصصة إلزامي لنوع الإجازة {0},
-Total weightage assigned should be 100%. It is {0},يجب أن يكون مجموع الترجيح تعيين 100 ٪ . فمن {0},
Total working hours should not be greater than max working hours {0},عدد ساعات العمل الكلي يجب ألا يكون أكثر من العدد الأقصى لساعات العمل {0},
Total {0} ({1}),إجمالي {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","إجمالي {0} لجميع العناصر هو صفر، قد يكون عليك تغيير 'توزيع الرسوم على أساس'\n<br>\nTotal {0} for all items is zero, may be you should change 'Distribute Charges Based On'",
@@ -3316,7 +3299,6 @@
What do you need help with?,ما الذى تحتاج المساعدة به؟,
What does it do?,مجال عمل الشركة؟,
Where manufacturing operations are carried.,حيث تتم عمليات التصنيع.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",أثناء إنشاء حساب لشركة تابعة {0} ، لم يتم العثور على الحساب الأصل {1}. يرجى إنشاء الحساب الأصل في شهادة توثيق البرامج المقابلة,
White,أبيض,
Wire Transfer,حوالة مصرفية,
WooCommerce Products,منتجات WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,تم إنشاء المتغيرات {0}.,
{0} {1} created,{0} {1} إنشاء,
{0} {1} does not exist,{0} {1} غير موجود\n<br>\n{0} {1} does not exist,
-{0} {1} does not exist.,{0} {1} غير موجود.,
{0} {1} has been modified. Please refresh.,تم تعديل {0} {1}، يرجى تحديث الصفحة من المتصفح,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} لم يتم إرسالها، ولذلك لا يمكن إكمال الإجراء,
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1} مرتبط ب {2}، ولكن حساب الطرف هو {3},
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} غير موجود,
{0}: {1} not found in Invoice Details table,{0}: {1} غير موجود في جدول تفاصيل الفواتير,
{} of {},{} من {},
+Assigned To,كلف إلى,
Chat,الدردشة,
Completed By,اكتمل بواسطة,
Conditions,الظروف,
@@ -3506,7 +3488,9 @@
Merge with existing,دمج مع الحالي,
Office,مكتب,
Orientation,توجيه,
+Parent,رقم الاب,
Passive,غير فعال,
+Payment Failed,عملية الدفع فشلت,
Percent,في المئة,
Permanent,دائم,
Personal,الشخصية,
@@ -3544,7 +3528,6 @@
Company field is required,حقل الشركة مطلوب,
Creating Dimensions...,إنشاء الأبعاد ...,
Duplicate entry against the item code {0} and manufacturer {1},إدخال مكرر مقابل رمز العنصر {0} والشركة المصنعة {1},
-Import Chart Of Accounts from CSV / Excel files,استيراد الرسم البياني للحسابات من ملفات CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN غير صالح! لا يتطابق الإدخال الذي أدخلته مع تنسيق GSTIN لحاملي UIN أو مزودي خدمة OIDAR غير المقيمين,
Invoice Grand Total,الفاتورة الكبرى المجموع,
Last carbon check date cannot be a future date,لا يمكن أن يكون تاريخ فحص الكربون الأخير تاريخًا مستقبلاً,
@@ -3556,6 +3539,7 @@
Show {0},عرض {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",الأحرف الخاصة باستثناء "-" ، "#" ، "." ، "/" ، "{" و "}" غير مسموح في سلسلة التسمية,
Target Details,تفاصيل الهدف,
+{0} already has a Parent Procedure {1}.,{0} يحتوي بالفعل على إجراء الأصل {1}.,
API,API,
Annual,سنوي,
Approved,موافق عليه,
@@ -3572,6 +3556,8 @@
No data to export,لا توجد بيانات للتصدير,
Portrait,صورة,
Print Heading,طباعة الرأسية,
+Scheduler Inactive,المجدول غير نشط,
+Scheduler is inactive. Cannot import data.,المجدول غير نشط. لا يمكن استيراد البيانات.,
Show Document,عرض المستند,
Show Traceback,إظهار التتبع,
Video,فيديو,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},إنشاء فحص الجودة للعنصر {0},
Creating Accounts...,إنشاء حسابات ...,
Creating bank entries...,إنشاء إدخالات بنكية ...,
-Creating {0},إنشاء {0},
Credit limit is already defined for the Company {0},تم تحديد حد الائتمان بالفعل للشركة {0},
Ctrl + Enter to submit,Ctrl + Enter للتقديم,
Ctrl+Enter to submit,Ctrl + Enter للإرسال,
@@ -3830,7 +3815,7 @@
Loading...,تحميل ...,
Loan Amount exceeds maximum loan amount of {0} as per proposed securities,يتجاوز مبلغ القرض الحد الأقصى لمبلغ القرض {0} وفقًا للأوراق المالية المقترحة,
Loan Applications from customers and employees.,طلبات القروض من العملاء والموظفين.,
-Loan Disbursement,صرف قرض,
+Loan Disbursement,إنفاق تمويل,
Loan Processes,عمليات القرض,
Loan Security,ضمان القرض,
Loan Security Pledge,تعهد ضمان القرض,
@@ -3921,7 +3906,6 @@
Plaid public token error,خطأ رمزي عام منقوش,
Plaid transactions sync error,خطأ في مزامنة المعاملات المنقوشة,
Please check the error log for details about the import errors,الرجاء التحقق من سجل الأخطاء للحصول على تفاصيل حول أخطاء الاستيراد,
-Please click on the following link to set your new password,الرجاء الضغط على الرابط التالي لتعيين كلمة المرور الجديدة,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,الرجاء إنشاء <b>إعدادات DATEV</b> للشركة <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,الرجاء إنشاء تعديل إدخال دفتر اليومية للمبلغ {0},
Please do not create more than 500 items at a time,يرجى عدم إنشاء أكثر من 500 عنصر في وقت واحد,
@@ -3997,6 +3981,7 @@
Release date must be in the future,يجب أن يكون تاريخ الإصدار في المستقبل,
Relieving Date must be greater than or equal to Date of Joining,يجب أن يكون تاريخ التخفيف أكبر من أو يساوي تاريخ الانضمام,
Rename,إعادة تسمية,
+Rename Not Allowed,إعادة تسمية غير مسموح به,
Repayment Method is mandatory for term loans,طريقة السداد إلزامية للقروض لأجل,
Repayment Start Date is mandatory for term loans,تاريخ بدء السداد إلزامي للقروض لأجل,
Report Item,بلغ عن شيء,
@@ -4043,7 +4028,6 @@
Select All,تحديد الكل,
Select Difference Account,حدد حساب الفرق,
Select a Default Priority.,حدد أولوية افتراضية.,
-Select a Supplier from the Default Supplier List of the items below.,حدد موردًا من قائمة الموردين الافتراضية للعناصر أدناه.,
Select a company,اختر شركة,
Select finance book for the item {0} at row {1},حدد دفتر تمويل للعنصر {0} في الصف {1},
Select only one Priority as Default.,حدد أولوية واحدة فقط كإعداد افتراضي.,
@@ -4247,7 +4231,6 @@
Actual ,فعلي,
Add to cart,أضف إلى السلة,
Budget,ميزانية,
-Chart Of Accounts Importer,الرسم البياني للحسابات المستورد,
Chart of Accounts,الشجرة المحاسبية,
Customer database.,قاعدة بيانات العملاء.,
Days Since Last order,الأيام منذ آخر طلب,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,تاريخ النهاية لا يمكن أن يكون اقل من تاريخ البدء\n<br>\nEnd Date can not be less than Start Date,
For Default Supplier (Optional),للمورد الافتراضي (اختياري),
From date cannot be greater than To date,(من تاريخ) لا يمكن أن يكون أكبر (الي التاريخ),
-Get items from,الحصول على البنود من,
Group by,المجموعة حسب,
In stock,في المخزن,
Item name,اسم السلعة,
@@ -4532,32 +4514,22 @@
Accounts Settings,إعدادات الحسابات,
Settings for Accounts,إعدادات الحسابات,
Make Accounting Entry For Every Stock Movement,اعمل قيد محاسبي لكل حركة للمخزون,
-"If enabled, the system will post accounting entries for inventory automatically.",إذا تم التمكين، سيقوم النظام بترحيل القيود المحاسبية الخاصة بالمخزون تلقائيا.,
-Accounts Frozen Upto,حسابات مجمدة حتى,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",القيود المحاسبية مجمده حتى هذا التاريخ، لا أحد يستطيع أن ينشئ أو يعدل القييد باستثناء الدور المحدد أدناه.,
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,الدور الوظيفي يسمح له بتجميد الحسابات و تعديل القيود المجمدة,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,يسمح للمستخدمين مع هذا الدور لضبط الحسابات المجمدة و إنشاء / تعديل القيود المحاسبية على حسابات مجمدة,
Determine Address Tax Category From,تحديد عنوان ضريبة الفئة من,
-Address used to determine Tax Category in transactions.,العنوان المستخدم لتحديد الفئة الضريبية في المعاملات.,
Over Billing Allowance (%),زيادة الفواتير المسموح بها (٪),
-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 for $110.,النسبة المئوية المسموح لك بدفعها أكثر مقابل المبلغ المطلوب. على سبيل المثال: إذا كانت قيمة الطلبية 100 دولار للعنصر وتم تعيين التسامح على 10 ٪ ، فيُسمح لك بدفع فاتورة بمبلغ 110 دولارات.,
Credit Controller,مراقب الرصيد دائن,
-Role that is allowed to submit transactions that exceed credit limits set.,الدور الوظيفي الذي يسمح له بتقديم المعاملات التي تتجاوز حدود الدين المحددة.,
Check Supplier Invoice Number Uniqueness,التحقق من رقم الفتورة المرسلة من المورد مميز (ليس متكرر),
Make Payment via Journal Entry,قم بالدفع عن طريق قيد دفتر اليومية,
Unlink Payment on Cancellation of Invoice,إلغاء ربط الدفع على إلغاء الفاتورة,
-Unlink Advance Payment on Cancelation of Order,إلغاء ربط الدفع المقدم عند إلغاء الطلب,
Book Asset Depreciation Entry Automatically,كتاب اهلاك الأُصُول المدخلة تلقائيا,
Automatically Add Taxes and Charges from Item Tax Template,إضافة الضرائب والرسوم تلقائيا من قالب الضريبة البند,
Automatically Fetch Payment Terms,جلب شروط الدفع تلقائيًا,
-Show Inclusive Tax In Print,عرض الضريبة الشاملة في الطباعة,
Show Payment Schedule in Print,عرض جدول الدفع في الطباعة,
Currency Exchange Settings,إعدادات صرف العملات,
Allow Stale Exchange Rates,السماح لأسعار الصرف الثابتة,
Stale Days,أيام قديمة,
Report Settings,إعدادات التقرير,
Use Custom Cash Flow Format,استخدم تنسيق التدفق النقدي المخصص,
-Only select if you have setup Cash Flow Mapper documents,حدد فقط إذا كان لديك إعداد مخطط مخطط التدفق النقدي,
Allowed To Transact With,سمح للاعتماد مع,
SWIFT number,رقم سويفت,
Branch Code,رمز الفرع,
@@ -4940,7 +4912,6 @@
POS Customer Group,مجموعة عملاء نقطة البيع,
POS Field,نقاط البيع الميدانية,
POS Item Group,مجموعة المواد لنقطة البيع,
-[Select],[اختر ],
Company Address,عنوان الشركة,
Update Stock,تحديث المخزون,
Ignore Pricing Rule,تجاهل (قاعدة التسعير),
@@ -5495,8 +5466,6 @@
Supplier Naming By,المورد تسمية بواسطة,
Default Supplier Group,مجموعة الموردين الافتراضية,
Default Buying Price List,قائمة اسعار الشراء الافتراضية,
-Maintain same rate throughout purchase cycle,الحفاظ على نفس السعر طوال دورة الشراء,
-Allow Item to be added multiple times in a transaction,السماح بإضافة صنف لأكثر من مرة في عملية تجارية,
Backflush Raw Materials of Subcontract Based On,Backflush المواد الخام من العقد من الباطن,
Material Transferred for Subcontract,المواد المنقولة للعقود من الباطن,
Over Transfer Allowance (%),بدل النقل (٪),
@@ -5540,7 +5509,6 @@
Current Stock,المخزون الحالية,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,عن مورد فردي,
-Supplier Detail,المورد التفاصيل,
Link to Material Requests,رابط لطلبات المواد,
Message for Supplier,رسالة لمزود,
Request for Quotation Item,طلب تسعيرة البند,
@@ -6481,7 +6449,6 @@
Appraisal Template,قالب التقييم,
For Employee Name,لاسم الموظف,
Goals,الأهداف,
-Calculate Total Score,حساب النتيجة الإجمالية,
Total Score (Out of 5),مجموع نقاط (من 5),
"Any other remarks, noteworthy effort that should go in the records.",أي ملاحظات أخرى، وجهود جديرة بالذكر يجب أن تدون في السجلات.,
Appraisal Goal,الغاية من التقييم,
@@ -6599,11 +6566,6 @@
Reason for Leaving,سبب ترك العمل,
Leave Encashed?,إجازات مصروفة نقداً؟,
Encashment Date,تاريخ التحصيل,
-Exit Interview Details,تفاصيل مقابلة مغادرة الشركة,
-Held On,عقدت في,
-Reason for Resignation,سبب الاستقالة,
-Better Prospects,آفاق أفضل,
-Health Concerns,شؤون صحية,
New Workplace,مكان العمل الجديد,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,المبلغ المرتجع,
@@ -6740,10 +6702,7 @@
Employee Settings,إعدادات الموظف,
Retirement Age,سن التقاعد,
Enter retirement age in years,أدخل سن التقاعد بالسنوات,
-Employee Records to be created by,سجلات الموظفين المراد إنشاؤها من قبل,
-Employee record is created using selected field. ,يتم إنشاء سجل الموظف باستخدام الحقل المحدد.,
Stop Birthday Reminders,ايقاف التذكير بأعياد الميلاد,
-Don't send Employee Birthday Reminders,عدم ارسال تذكير للموضفين بأعياد الميلاد,
Expense Approver Mandatory In Expense Claim,الموافقة على المصروفات إلزامية في مطالبة النفقات,
Payroll Settings,إعدادات دفع الرواتب,
Leave,غادر,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,إجازة الموافقة إلزامية في طلب الإجازة,
Show Leaves Of All Department Members In Calendar,إظهار أوراق جميع أعضاء القسم في التقويم,
Auto Leave Encashment,إجازة مغادرة السيارات,
-Restrict Backdated Leave Application,تقييد طلب الإجازة المتأخرة,
Hiring Settings,إعدادات التوظيف,
Check Vacancies On Job Offer Creation,التحقق من الوظائف الشاغرة عند إنشاء عرض العمل,
Identification Document Type,نوع وثيقة التعريف,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,إعدادات التصنيع,
Raw Materials Consumption,استهلاك المواد الخام,
Allow Multiple Material Consumption,السماح باستهلاك المواد المتعددة,
-Allow multiple Material Consumption against a Work Order,السماح باستهلاك المواد المتعددة مقابل طلب العمل,
Backflush Raw Materials Based On,Backflush المواد الخام مبني على,
Material Transferred for Manufacture,المواد المنقولة لغرض صناعة,
Capacity Planning,القدرة على التخطيط,
Disable Capacity Planning,تعطيل تخطيط القدرات,
Allow Overtime,تسمح العمل الإضافي,
-Plan time logs outside Workstation Working Hours.,تخطيط سجلات الوقت خارج ساعات العمل محطة العمل.,
Allow Production on Holidays,السماح الإنتاج على عطلات,
Capacity Planning For (Days),القدرة على التخطيط لل(أيام),
-Try planning operations for X days in advance.,محاولة التخطيط لعمليات لX أيام مقدما.,
-Time Between Operations (in mins),الوقت بين العمليات (في دقيقة),
-Default 10 mins,افتراضي 10 دقيقة,
Default Warehouses for Production,المستودعات الافتراضية للإنتاج,
Default Work In Progress Warehouse,افتراضي العمل في مستودع التقدم,
Default Finished Goods Warehouse,المخزن الافتراضي للبضائع التامة الصنع,
Default Scrap Warehouse,مستودع الخردة الافتراضي,
-Over Production for Sales and Work Order,أكثر من الإنتاج للمبيعات وأمر العمل,
Overproduction Percentage For Sales Order,نسبة الإنتاج الزائد لأمر المبيعات,
Overproduction Percentage For Work Order,نسبة الإنتاج الزائد لأمر العمل,
Other Settings,اعدادات اخرى,
Update BOM Cost Automatically,تحديث بوم التكلفة تلقائيا,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",تحديث تكلفة بوم تلقائيا عبر جدولة، استنادا إلى أحدث معدل التقييم / سعر قائمة معدل / آخر معدل شراء المواد الخام.,
Material Request Plan Item,المادة طلب خطة البند,
Material Request Type,نوع طلب المواد,
Material Issue,صرف مواد,
@@ -7603,10 +7554,6 @@
Quality Goal,هدف الجودة,
Monitoring Frequency,مراقبة التردد,
Weekday,يوم من أيام الأسبوع,
-January-April-July-October,من يناير إلى أبريل ويوليو وأكتوبر,
-Revision and Revised On,مراجعة وتنقيح,
-Revision,مراجعة,
-Revised On,المنقحة في,
Objectives,الأهداف,
Quality Goal Objective,هدف جودة الهدف,
Objective,موضوعي,
@@ -7619,7 +7566,6 @@
Processes,العمليات,
Quality Procedure Process,عملية إجراءات الجودة,
Process Description,وصف العملية,
-Child Procedure,إجراء الطفل,
Link existing Quality Procedure.,ربط إجراءات الجودة الحالية.,
Additional Information,معلومة اضافية,
Quality Review Objective,هدف مراجعة الجودة,
@@ -7787,15 +7733,9 @@
Default Customer Group,المجموعة الافتراضية العملاء,
Default Territory,الإقليم الافتراضي,
Close Opportunity After Days,فرصة قريبة بعد يوم,
-Auto close Opportunity after 15 days,اغلاق تلقائي للفرص بعد 15 يوما,
Default Quotation Validity Days,عدد أيام صلاحية عرض الأسعار الافتراضي,
Sales Update Frequency,تردد تحديث المبيعات,
-How often should project and company be updated based on Sales Transactions.,كم مرة يجب تحديث المشروع والشركة استنادًا إلى معاملات المبيعات.,
Each Transaction,كل عملية,
-Allow user to edit Price List Rate in transactions,تسمح للمستخدم لتحرير الأسعار قائمة قيم في المعاملات,
-Allow multiple Sales Orders against a Customer's Purchase Order,السماح بعدة أوامر البيع ضد طلب شراء العميل,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,تحقق من سعر البيع للالبند ضد سعر الشراء أو معدل التقييم,
-Hide Customer's Tax Id from Sales Transactions,إخفاء المعرف الضريبي للعملاء من معاملات مبيعات,
SMS Center,مركز رسائل SMS,
Send To,أرسل إلى,
All Contact,جميع جهات الاتصال,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,الشركات المصنعة المستخدمة في الاصناف,
Limited to 12 characters,تقتصر على 12 حرفا,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,تعيين المستودع,
-Sets 'For Warehouse' in each row of the Items table.,يعيّن "للمستودع" في كل صف من جدول السلع.,
-Requested For,طلب لل,
Partially Ordered,طلبت جزئيًا,
Transferred,نقل,
% Ordered,٪ تم طلبها,
@@ -8407,24 +8344,14 @@
Default Stock UOM,افتراضي وحدة قياس السهم,
Sample Retention Warehouse,مستودع الاحتفاظ بالعينات,
Default Valuation Method,أسلوب التقييم الافتراضي,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,النسبة المئوية يسمح لك لتلقي أو تقديم المزيد من ضد الكمية المطلوبة. على سبيل المثال: إذا كنت قد أمرت 100 وحدة. و10٪ ثم يسمح بدل الخاص بك لتلقي 110 وحدة.,
-Action if Quality inspection is not submitted,الإجراء إذا لم يتم تقديم فحص الجودة,
Show Barcode Field,مشاهدة الباركود الميدان,
Convert Item Description to Clean HTML,تحويل وصف السلعة لتنظيف هتمل,
-Auto insert Price List rate if missing,إدراج تلقائي لقائمة الأسعار إن لم تكن موجودة,
Allow Negative Stock,السماح بالقيم السالبة للمخزون,
Automatically Set Serial Nos based on FIFO,حدد الرقم التسلسلي بناءً على FIFO,
-Set Qty in Transactions based on Serial No Input,تعيين الكمية في المعاملات استناداً إلى Serial No Input,
Auto Material Request,طلب مواد تلقائي,
-Raise Material Request when stock reaches re-order level,رفع طلب المواد عند الأسهم تصل إلى مستوى إعادة الطلب,
-Notify by Email on creation of automatic Material Request,إبلاغ عن طريق البريد الإلكتروني عند انشاء طلب مواد تلقائي,
Inter Warehouse Transfer Settings,إعدادات نقل المستودعات الداخلية,
-Allow Material Transfer From Delivery Note and Sales Invoice,السماح بنقل المواد من مذكرة التسليم وفاتورة المبيعات,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,السماح بنقل المواد من إيصال الشراء وفاتورة الشراء,
Freeze Stock Entries,تجميد مقالات المالية,
Stock Frozen Upto,المخزون المجمدة لغاية,
-Freeze Stocks Older Than [Days],تجميد الأرصدة أقدم من [ أيام],
-Role Allowed to edit frozen stock,صلاحية السماح بتحرير الأسهم المجمدة,
Batch Identification,تحديد الدفعة,
Use Naming Series,استخدام سلسلة التسمية,
Naming Series Prefix,بادئة سلسلة التسمية,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,شراء اتجاهات الإيصال,
Purchase Register,سجل شراء,
Quotation Trends,مؤشرات المناقصة,
-Quoted Item Comparison,مقارنة بند المناقصة,
Received Items To Be Billed,العناصر الواردة إلى أن توصف,
Qty to Order,الكمية للطلب,
Requested Items To Be Transferred,العناصر المطلوبة على أن يتم تحويلها,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,حدد المستودع لطلبات المواد,
Transfer Materials For Warehouse {0},نقل المواد للمستودع {0},
Production Plan Material Request Warehouse,مستودع طلب مواد خطة الإنتاج,
-Set From Warehouse,تعيين من المستودع,
-Source Warehouse (Material Transfer),مستودع المصدر (نقل المواد),
Sets 'Source Warehouse' in each row of the items table.,يعيّن "مستودع المصدر" في كل صف من جدول العناصر.,
Sets 'Target Warehouse' in each row of the items table.,يعيّن "المستودع المستهدف" في كل صف من جدول العناصر.,
Show Cancelled Entries,إظهار الإدخالات الملغاة,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,تم استلام الخدمة ولكن لم يتم دفع الفاتورة,
Deferred Accounting Settings,إعدادات المحاسبة المؤجلة,
Book Deferred Entries Based On,حجز إدخالات مؤجلة على أساس,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",إذا تم تحديد "الأشهر" ، فسيتم حجز المبلغ الثابت كإيرادات أو مصروفات مؤجلة لكل شهر بغض النظر عن عدد الأيام في الشهر. سيتم تقسيمها بالتناسب إذا لم يتم حجز الإيرادات أو المصروفات المؤجلة لمدة شهر كامل.,
Days,أيام,
Months,الشهور,
Book Deferred Entries Via Journal Entry,كتاب مؤجل إدخالات عن طريق إدخال دفتر اليومية,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,إذا كان هذا غير محدد ، فسيتم إنشاء إدخالات دفتر الأستاذ العام المباشرة لحجز الإيرادات / المصاريف المؤجلة,
Submit Journal Entries,إرسال إدخالات دفتر اليومية,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,إذا كان هذا غير محدد ، فسيتم حفظ إدخالات دفتر اليومية في حالة المسودة وسيتعين إرسالها يدويًا,
Enable Distributed Cost Center,تمكين مركز التكلفة الموزعة,
@@ -8901,8 +8823,6 @@
Is Inter State,هو Inter State,
Purchase Details,تفاصيل شراء,
Depreciation Posting Date,تاريخ ترحيل الإهلاك,
-Purchase Order Required for Purchase Invoice & Receipt Creation,أمر الشراء مطلوب لإنشاء فاتورة الشراء والإيصال,
-Purchase Receipt Required for Purchase Invoice Creation,مطلوب إيصال الشراء لإنشاء فاتورة الشراء,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",بشكل افتراضي ، يتم تعيين اسم المورد وفقًا لاسم المورد الذي تم إدخاله. إذا كنت تريد تسمية الموردين بواسطة أ,
choose the 'Naming Series' option.,اختر خيار "سلسلة التسمية".,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,تكوين قائمة الأسعار الافتراضية عند إنشاء معاملة شراء جديدة. سيتم جلب أسعار العناصر من قائمة الأسعار هذه.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,هو مكون ضريبة الدخل,
Component properties and references ,خصائص المكونات والمراجع,
Additional Salary ,الراتب الإضافي,
-Condtion and formula,الشرط والصيغة,
Unmarked days,أيام غير محددة,
Absent Days,أيام الغياب,
Conditions and Formula variable and example,متغير الشروط والصيغة والمثال,
Feedback By,ردود الفعل من,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,قسم التصنيع,
-Sales Order Required for Sales Invoice & Delivery Note Creation,مطلوب أمر المبيعات لإنشاء فاتورة المبيعات وإشعار التسليم,
-Delivery Note Required for Sales Invoice Creation,مطلوب مذكرة التسليم لإنشاء فاتورة المبيعات,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",بشكل افتراضي ، يتم تعيين اسم العميل وفقًا للاسم الكامل الذي تم إدخاله. إذا كنت تريد تسمية العملاء بواسطة أ,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,تكوين قائمة الأسعار الافتراضية عند إنشاء معاملة مبيعات جديدة. سيتم جلب أسعار العناصر من قائمة الأسعار هذه.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",إذا تم تكوين هذا الخيار "نعم" ، سيمنعك ERPNext من إنشاء فاتورة مبيعات أو مذكرة تسليم دون إنشاء أمر مبيعات أولاً. يمكن تجاوز هذا التكوين لعميل معين عن طريق تمكين مربع الاختيار "السماح بإنشاء فاتورة المبيعات بدون طلب مبيعات" في مدير العميل.,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,تمت إضافة {0} {1} إلى كافة الموضوعات المحددة بنجاح.,
Topics updated,تم تحديث المواضيع,
Academic Term and Program,الفصل الدراسي والبرنامج,
-Last Stock Transaction for item {0} was on {1}.,كانت آخر معاملة مخزون للعنصر {0} في {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,لا يمكن ترحيل معاملات المخزون الخاصة بالعنصر {0} قبل هذا الوقت.,
Please remove this item and try to submit again or update the posting time.,يرجى إزالة هذا العنصر ومحاولة الإرسال مرة أخرى أو تحديث وقت النشر.,
Failed to Authenticate the API key.,فشل مصادقة مفتاح API.,
Invalid Credentials,بيانات الاعتماد غير صالحة,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,يرجى التحقق من معرّف عميل Plaid والقيم السرية,
Bank transaction creation error,خطأ في إنشاء معاملة البنك,
Unit of Measurement,وحدة قياس,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Row # {}: معدل بيع العنصر {} أقل من {}. يجب أن يكون معدل البيع على الأقل {},
Fiscal Year {0} Does Not Exist,السنة المالية {0} غير موجودة,
Row # {0}: Returned Item {1} does not exist in {2} {3},الصف رقم {0}: العنصر الذي تم إرجاعه {1} غير موجود في {2} {3},
Valuation type charges can not be marked as Inclusive,لا يمكن تحديد رسوم نوع التقييم على أنها شاملة,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,لا يمكن أن يكون وقت الاستجابة {0} للأولوية في الصف {1} أكبر من وقت الحل.,
{0} is not enabled in {1},{0} غير ممكّن في {1},
Group by Material Request,تجميع حسب طلب المواد,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",الصف {0}: للمورد {0} ، عنوان البريد الإلكتروني مطلوب لإرسال بريد إلكتروني,
Email Sent to Supplier {0},تم إرسال بريد إلكتروني إلى المورد {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",تم تعطيل الوصول إلى طلب عرض الأسعار من البوابة. للسماح بالوصول ، قم بتمكينه في إعدادات البوابة.,
Supplier Quotation {0} Created,تم إنشاء عرض أسعار المورد {0},
Valid till Date cannot be before Transaction Date,صالح حتى التاريخ لا يمكن أن يكون قبل تاريخ المعاملة,
+Unlink Advance Payment on Cancellation of Order,إلغاء ربط الدفع المسبق عند إلغاء الطلب,
+"Simple Python Expression, Example: territory != 'All Territories'",تعبير بايثون بسيط ، مثال: إقليم! = "كل الأقاليم",
+Sales Contributions and Incentives,مساهمات وحوافز المبيعات,
+Sourced by Supplier,مصدرها المورد,
+Total weightage assigned should be 100%.<br>It is {0},يجب أن يكون الوزن الإجمالي المخصص 100٪.<br> إنه {0},
+Account {0} exists in parent company {1}.,الحساب {0} موجود في الشركة الأم {1}.,
+"To overrule this, enable '{0}' in company {1}",لإلغاء هذا ، قم بتمكين "{0}" في الشركة {1},
+Invalid condition expression,تعبير شرط غير صالح,
+Please Select a Company First,الرجاء تحديد شركة أولاً,
+Please Select Both Company and Party Type First,الرجاء تحديد نوع الشركة والحزب أولاً,
+Provide the invoice portion in percent,قم بتوفير جزء الفاتورة بالنسبة المئوية,
+Give number of days according to prior selection,أعط عدد الأيام حسب الاختيار المسبق,
+Email Details,تفاصيل البريد الإلكتروني,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.",حدد تحية للمتلقي. على سبيل المثال السيد ، السيدة ، إلخ.,
+Preview Email,معاينة البريد الإلكتروني,
+Please select a Supplier,الرجاء اختيار مورد,
+Supplier Lead Time (days),مهلة المورد (أيام),
+"Home, Work, etc.",المنزل والعمل وما إلى ذلك.,
+Exit Interview Held On,أجريت مقابلة الخروج,
+Condition and formula,الشرط والصيغة,
+Sets 'Target Warehouse' in each row of the Items table.,يعيّن "المستودع المستهدف" في كل صف من جدول السلع.,
+Sets 'Source Warehouse' in each row of the Items table.,يعيّن "مستودع المصدر" في كل صف من جدول السلع.,
+POS Register,سجل نقاط البيع,
+"Can not filter based on POS Profile, if grouped by POS Profile",لا يمكن التصفية بناءً على ملف تعريف نقطة البيع ، إذا تم تجميعها حسب ملف تعريف نقطة البيع,
+"Can not filter based on Customer, if grouped by Customer",لا يمكن التصفية بناءً على العميل ، إذا تم تجميعه بواسطة العميل,
+"Can not filter based on Cashier, if grouped by Cashier",لا يمكن التصفية على أساس Cashier ، إذا تم تجميعها بواسطة Cashier,
+Payment Method,طريقة الدفع او السداد,
+"Can not filter based on Payment Method, if grouped by Payment Method",لا يمكن التصفية بناءً على طريقة الدفع ، إذا تم تجميعها حسب طريقة الدفع,
+Supplier Quotation Comparison,مقارنة عروض أسعار الموردين,
+Price per Unit (Stock UOM),السعر لكل وحدة (المخزون UOM),
+Group by Supplier,تجميع حسب المورد,
+Group by Item,تجميع حسب البند,
+Remember to set {field_label}. It is required by {regulation}.,تذكر أن تقوم بتعيين {field_label}. مطلوب بموجب {لائحة}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},لا يمكن أن يكون تاريخ التسجيل قبل تاريخ بدء العام الأكاديمي {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},لا يمكن أن يكون تاريخ التسجيل بعد تاريخ انتهاء الفصل الدراسي {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},لا يمكن أن يكون تاريخ التسجيل قبل تاريخ بدء الفصل الدراسي {0},
+Future Posting Not Allowed,النشر في المستقبل غير مسموح به,
+"To enable Capital Work in Progress Accounting, ",لتمكين محاسبة الأعمال الرأسمالية الجارية ،,
+you must select Capital Work in Progress Account in accounts table,يجب عليك تحديد حساب رأس المال قيد التقدم في جدول الحسابات,
+You can also set default CWIP account in Company {},يمكنك أيضًا تعيين حساب CWIP الافتراضي في الشركة {},
+The Request for Quotation can be accessed by clicking on the following button,يمكن الوصول إلى طلب عرض الأسعار من خلال النقر على الزر التالي,
+Regards,مع تحياتي,
+Please click on the following button to set your new password,الرجاء النقر فوق الزر التالي لتعيين كلمة المرور الجديدة,
+Update Password,تطوير كلمة السر,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Row # {}: معدل بيع العنصر {} أقل من {}. يجب بيع {} على الأقل {},
+You can alternatively disable selling price validation in {} to bypass this validation.,يمكنك بدلاً من ذلك تعطيل التحقق من سعر البيع في {} لتجاوز هذا التحقق.,
+Invalid Selling Price,سعر البيع غير صالح,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,يجب ربط العنوان بشركة. الرجاء إضافة صف للشركة في جدول الروابط.,
+Company Not Linked,شركة غير مرتبطة,
+Import Chart of Accounts from CSV / Excel files,استيراد مخطط الحسابات من ملفات CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',لا يمكن أن تكون الكمية المكتملة أكبر من "الكمية إلى التصنيع",
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",الصف {0}: للمورد {1} ، مطلوب عنوان البريد الإلكتروني لإرسال بريد إلكتروني,
+"If enabled, the system will post accounting entries for inventory automatically",في حالة التمكين ، سيقوم النظام بترحيل إدخالات المحاسبة للمخزون تلقائيًا,
+Accounts Frozen Till Date,الحسابات المجمدة حتى تاريخ,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,تم تجميد قيود المحاسبة حتى هذا التاريخ. لا يمكن لأي شخص إنشاء أو تعديل الإدخالات باستثناء المستخدمين الذين لديهم الدور المحدد أدناه,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,الدور مسموح به لتعيين حسابات مجمدة وتعديل الإدخالات المجمدة,
+Address used to determine Tax Category in transactions,العنوان المستخدم لتحديد فئة الضريبة في المعاملات,
+"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 ",النسبة المئوية المسموح لك بدفعها مقابل المبلغ المطلوب. على سبيل المثال ، إذا كانت قيمة الأمر 100 دولار أمريكي لأحد العناصر ، وتم تعيين التفاوت بنسبة 10٪ ، فيُسمح لك بدفع ما يصل إلى 110 دولارات أمريكية.,
+This role is allowed to submit transactions that exceed credit limits,يُسمح لهذا الدور بإرسال المعاملات التي تتجاوز حدود الائتمان,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",إذا تم تحديد "الأشهر" ، فسيتم حجز مبلغ ثابت كإيرادات أو مصروفات مؤجلة لكل شهر بغض النظر عن عدد الأيام في الشهر. سيتم تقسيمها إذا لم يتم حجز الإيرادات أو المصاريف المؤجلة لمدة شهر كامل,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",إذا لم يتم تحديد ذلك ، فسيتم إنشاء إدخالات دفتر الأستاذ العام المباشرة لحجز الإيرادات أو المصاريف المؤجلة,
+Show Inclusive Tax in Print,عرض الضرائب الشاملة في المطبوعات,
+Only select this if you have set up the Cash Flow Mapper documents,حدد هذا فقط إذا كنت قد قمت بإعداد مستندات مخطط التدفق النقدي,
+Payment Channel,قناة الدفع,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,هل طلب الشراء مطلوب لإنشاء فاتورة الشراء والإيصال؟,
+Is Purchase Receipt Required for Purchase Invoice Creation?,هل إيصال الشراء مطلوب لإنشاء فاتورة الشراء؟,
+Maintain Same Rate Throughout the Purchase Cycle,حافظ على نفس السعر طوال دورة الشراء,
+Allow Item To Be Added Multiple Times in a Transaction,السماح بإضافة العنصر عدة مرات في المعاملة,
+Suppliers,الموردين,
+Send Emails to Suppliers,إرسال رسائل البريد الإلكتروني إلى الموردين,
+Select a Supplier,حدد المورد,
+Cannot mark attendance for future dates.,لا يمكن تحديد الحضور للتواريخ المستقبلية.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},هل تريد تحديث الحضور؟<br> الحاضر: {0}<br> غائب: {1},
+Mpesa Settings,إعدادات Mpesa,
+Initiator Name,اسم البادئ,
+Till Number,حتى رقم,
+Sandbox,صندوق الرمل,
+ Online PassKey,مفتاح المرور عبر الإنترنت,
+Security Credential,الاعتماد الأمني,
+Get Account Balance,احصل على رصيد الحساب,
+Please set the initiator name and the security credential,يرجى تعيين اسم البادئ وبيانات اعتماد الأمان,
+Inpatient Medication Entry,إدخال الأدوية للمرضى الداخليين,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),كود البند (المخدرات),
+Medication Orders,أوامر الدواء,
+Get Pending Medication Orders,احصل على طلبات الأدوية المعلقة,
+Inpatient Medication Orders,طلبات الأدوية للمرضى الداخليين,
+Medication Warehouse,مستودع الأدوية,
+Warehouse from where medication stock should be consumed,المستودع الذي يجب استهلاك مخزون الأدوية منه,
+Fetching Pending Medication Orders,إحضار أوامر الأدوية المعلقة,
+Inpatient Medication Entry Detail,تفاصيل إدخال الأدوية للمرضى الداخليين,
+Medication Details,تفاصيل الدواء,
+Drug Code,كود الدواء,
+Drug Name,اسم الدواء,
+Against Inpatient Medication Order,ضد طلب الأدوية للمرضى الداخليين,
+Against Inpatient Medication Order Entry,ضد إدخال طلب الأدوية للمرضى الداخليين,
+Inpatient Medication Order,طلب الأدوية للمرضى الداخليين,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,إجمالي الطلبات,
+Completed Orders,الطلبات المكتملة,
+Add Medication Orders,أضف طلبات الأدوية,
+Adding Order Entries,إضافة إدخالات الطلب,
+{0} medication orders completed,تم إكمال {0} من طلبات الأدوية,
+{0} medication order completed,اكتمل طلب الدواء {0},
+Inpatient Medication Order Entry,إدخال طلب الأدوية للمرضى الداخليين,
+Is Order Completed,هل اكتمل الطلب,
+Employee Records to Be Created By,سجلات الموظفين التي سيتم إنشاؤها بواسطة,
+Employee records are created using the selected field,يتم إنشاء سجلات الموظفين باستخدام الحقل المحدد,
+Don't send employee birthday reminders,لا ترسل تذكيرات عيد ميلاد الموظف,
+Restrict Backdated Leave Applications,تقييد طلبات الإجازة القديمة,
+Sequence ID,معرف التسلسل,
+Sequence Id,معرف التسلسل,
+Allow multiple material consumptions against a Work Order,السماح باستهلاكات متعددة للمواد مقابل طلب العمل,
+Plan time logs outside Workstation working hours,سجلات وقت الخطة خارج ساعات عمل محطة العمل,
+Plan operations X days in advance,خطط العمليات قبل X من الأيام,
+Time Between Operations (Mins),الوقت بين العمليات (بالدقائق),
+Default: 10 mins,الافتراضي: 10 دقائق,
+Overproduction for Sales and Work Order,زيادة الإنتاج للمبيعات وطلب العمل,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",قم بتحديث تكلفة قائمة المواد تلقائيًا عبر المجدول ، استنادًا إلى أحدث معدل تقييم / سعر قائمة الأسعار / آخر سعر شراء للمواد الخام,
+Purchase Order already created for all Sales Order items,تم إنشاء أمر الشراء بالفعل لجميع بنود أوامر المبيعات,
+Select Items,اختيار العناصر,
+Against Default Supplier,ضد المورد الافتراضي,
+Auto close Opportunity after the no. of days mentioned above,فرصة الإغلاق التلقائي بعد لا. من الأيام المذكورة أعلاه,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,هل طلب المبيعات مطلوب لإنشاء فاتورة المبيعات ومذكرة التسليم؟,
+Is Delivery Note Required for Sales Invoice Creation?,هل مطلوب مذكرة التسليم لإنشاء فاتورة المبيعات؟,
+How often should Project and Company be updated based on Sales Transactions?,كم مرة يجب تحديث المشروع والشركة بناءً على معاملات المبيعات؟,
+Allow User to Edit Price List Rate in Transactions,السماح للمستخدم بتحرير سعر قائمة الأسعار في المعاملات,
+Allow Item to Be Added Multiple Times in a Transaction,السماح بإضافة العنصر عدة مرات في المعاملة,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,السماح بأوامر مبيعات متعددة مقابل طلب الشراء الخاص بالعميل,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,تحقق من صحة سعر البيع للسلعة مقابل معدل الشراء أو معدل التقييم,
+Hide Customer's Tax ID from Sales Transactions,إخفاء المعرّف الضريبي للعميل من معاملات المبيعات,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.",النسبة المئوية المسموح لك باستلامها أو تسليم المزيد مقابل الكمية المطلوبة. على سبيل المثال ، إذا كنت قد طلبت 100 وحدة ، وكان مخصصك 10٪ ، فيُسمح لك باستلام 110 وحدة.,
+Action If Quality Inspection Is Not Submitted,الإجراء إذا لم يتم تقديم استقصاء الجودة,
+Auto Insert Price List Rate If Missing,إدراج سعر قائمة الأسعار تلقائيًا إذا كان مفقودًا,
+Automatically Set Serial Nos Based on FIFO,قم بتعيين الأرقام التسلسلية تلقائيًا استنادًا إلى ما يرد أولاً يصرف أولاً,
+Set Qty in Transactions Based on Serial No Input,قم بتعيين الكمية في المعاملات بناءً على عدم إدخال تسلسلي,
+Raise Material Request When Stock Reaches Re-order Level,رفع طلب المواد عندما يصل المخزون إلى مستوى إعادة الطلب,
+Notify by Email on Creation of Automatic Material Request,الإخطار عن طريق البريد الإلكتروني عند إنشاء طلب المواد تلقائيًا,
+Allow Material Transfer from Delivery Note to Sales Invoice,السماح بنقل المواد من مذكرة التسليم إلى فاتورة المبيعات,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,السماح بنقل المواد من إيصال الشراء إلى فاتورة الشراء,
+Freeze Stocks Older Than (Days),تجميد المخزونات أقدم من (أيام),
+Role Allowed to Edit Frozen Stock,الدور المسموح به لتحرير المخزون المجمد,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,المبلغ غير المخصص لإدخال الدفع {0} أكبر من المبلغ غير المخصص للمعاملة المصرفية,
+Payment Received,تم استلام الدفعة,
+Attendance cannot be marked outside of Academic Year {0},لا يمكن وضع علامة على الحضور خارج العام الدراسي {0},
+Student is already enrolled via Course Enrollment {0},تم تسجيل الطالب بالفعل عن طريق التسجيل في الدورة التدريبية {0},
+Attendance cannot be marked for future dates.,لا يمكن تحديد الحضور للتواريخ المستقبلية.,
+Please add programs to enable admission application.,الرجاء إضافة برامج لتمكين تطبيق القبول.,
+The following employees are currently still reporting to {0}:,لا يزال الموظفون التالي ذكرهم يتبعون حاليًا {0}:,
+Please make sure the employees above report to another Active employee.,يرجى التأكد من أن الموظفين أعلاه يقدمون تقارير إلى موظف نشط آخر.,
+Cannot Relieve Employee,لا يمكن إعفاء الموظف,
+Please enter {0},الرجاء إدخال {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',الرجاء تحديد طريقة دفع أخرى. لا تدعم Mpesa المعاملات بالعملة "{0}",
+Transaction Error,خطأ في المعاملة,
+Mpesa Express Transaction Error,خطأ معاملة Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details",تم اكتشاف مشكلة في تكوين Mpesa ، تحقق من سجلات الأخطاء لمزيد من التفاصيل,
+Mpesa Express Error,خطأ Mpesa Express,
+Account Balance Processing Error,خطأ في معالجة رصيد الحساب,
+Please check your configuration and try again,يرجى التحقق من التكوين الخاص بك وحاول مرة أخرى,
+Mpesa Account Balance Processing Error,خطأ في معالجة رصيد حساب Mpesa,
+Balance Details,تفاصيل الرصيد,
+Current Balance,الرصيد الحالي,
+Available Balance,الرصيد المتوفر,
+Reserved Balance,رصيد محجوز,
+Uncleared Balance,رصيد غير مصفى,
+Payment related to {0} is not completed,الدفع المتعلق بـ {0} لم يكتمل,
+Row #{}: Item Code: {} is not available under warehouse {}.,الصف # {}: رمز العنصر: {} غير متوفر ضمن المستودع {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,الصف # {}: كمية المخزون غير كافية لرمز الصنف: {} تحت المستودع {}. الكمية المتوفرة {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,الصف # {}: الرجاء تحديد رقم تسلسلي ودفعة مقابل العنصر: {} أو إزالته لإكمال المعاملة.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,الصف # {}: لم يتم تحديد رقم تسلسلي مقابل العنصر: {}. يرجى تحديد واحد أو إزالته لإكمال الصفقة.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,الصف رقم {}: لم يتم تحديد دُفعة مقابل العنصر: {}. يرجى تحديد دفعة أو إزالتها لإكمال المعاملة.,
+Payment amount cannot be less than or equal to 0,لا يمكن أن يكون مبلغ الدفعة أقل من أو يساوي 0,
+Please enter the phone number first,الرجاء إدخال رقم الهاتف أولاً,
+Row #{}: {} {} does not exist.,الصف رقم {}: {} {} غير موجود.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,الصف رقم {0}: {1} مطلوب لإنشاء فواتير الافتتاح {2},
+You had {} errors while creating opening invoices. Check {} for more details,كان لديك {} من الأخطاء أثناء إنشاء الفواتير الافتتاحية. تحقق من {} لمزيد من التفاصيل,
+Error Occured,حدث خطأ,
+Opening Invoice Creation In Progress,جاري إنشاء الفاتورة الافتتاحية,
+Creating {} out of {} {},إنشاء {} من {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(الرقم التسلسلي: {0}) لا يمكن استهلاكه لأنه محجوز لملء طلب المبيعات {1}.,
+Item {0} {1},العنصر {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,كانت آخر معاملة مخزون للبند {0} تحت المستودع {1} في {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,لا يمكن ترحيل معاملات المخزون للبند {0} تحت المستودع {1} قبل هذا الوقت.,
+Posting future stock transactions are not allowed due to Immutable Ledger,لا يُسمح بترحيل معاملات الأسهم المستقبلية بسبب دفتر الأستاذ غير القابل للتغيير,
+A BOM with name {0} already exists for item {1}.,يوجد BOM بالاسم {0} بالفعل للعنصر {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} هل أعدت تسمية العنصر؟ يرجى الاتصال بالدعم الفني / المسؤول,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},في الصف # {0}: لا يمكن أن يكون معرف التسلسل {1} أقل من معرف تسلسل الصف السابق {2},
+The {0} ({1}) must be equal to {2} ({3}),يجب أن يكون {0} ({1}) مساويًا لـ {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.",{0} ، أكمل العملية {1} قبل العملية {2}.,
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,لا يمكن ضمان التسليم بواسطة Serial No حيث أن العنصر {0} مضاف مع وبدون ضمان التسليم بواسطة Serial No.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,لا يحتوي العنصر {0} على رقم مسلسل. يمكن فقط تسليم العناصر المسلسلة بناءً على الرقم التسلسلي,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,لم يتم العثور على BOM نشط للعنصر {0}. لا يمكن ضمان التسليم عن طريق الرقم التسلسلي,
+No pending medication orders found for selected criteria,لم يتم العثور على طلبات الأدوية المعلقة للمعايير المحددة,
+From Date cannot be after the current date.,لا يمكن أن يكون من تاريخ بعد التاريخ الحالي.,
+To Date cannot be after the current date.,لا يمكن أن يكون "To Date" بعد التاريخ الحالي.,
+From Time cannot be after the current time.,من وقت لا يمكن أن يكون بعد الوقت الحالي.,
+To Time cannot be after the current time.,لا يمكن أن يكون الوقت بعد الوقت الحالي.,
+Stock Entry {0} created and ,تم إنشاء إدخال المخزون {0} و,
+Inpatient Medication Orders updated successfully,تم تحديث طلبات الأدوية للمرضى الداخليين بنجاح,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},الصف {0}: لا يمكن إنشاء إدخال دواء للمرضى الداخليين مقابل طلب دواء للمرضى الداخليين تم إلغاؤه {1},
+Row {0}: This Medication Order is already marked as completed,الصف {0}: تم بالفعل وضع علامة على طلب الدواء هذا على أنه مكتمل,
+Quantity not available for {0} in warehouse {1},الكمية غير متوفرة لـ {0} في المستودع {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,يرجى تمكين السماح بالمخزون السلبي في إعدادات المخزون أو إنشاء إدخال المخزون للمتابعة.,
+No Inpatient Record found against patient {0},لم يتم العثور على سجل للمرضى الداخليين للمريض {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,يوجد بالفعل طلب دواء للمرضى الداخليين {0} ضد مقابلة المريض {1}.,
+Allow In Returns,السماح في المرتجعات,
+Hide Unavailable Items,إخفاء العناصر غير المتوفرة,
+Apply Discount on Discounted Rate,تطبيق الخصم على السعر المخفض,
+Therapy Plan Template,نموذج خطة العلاج,
+Fetching Template Details,إحضار تفاصيل النموذج,
+Linked Item Details,تفاصيل العنصر المرتبط,
+Therapy Types,أنواع العلاج,
+Therapy Plan Template Detail,تفاصيل نموذج خطة العلاج,
+Non Conformance,غير مطابقة,
+Process Owner,صاحب العملية,
+Corrective Action,اجراء تصحيحي,
+Preventive Action,إجراءات وقائية,
+Problem,مشكلة,
+Responsible,مسؤول,
+Completion By,اكتمال بواسطة,
+Process Owner Full Name,الاسم الكامل لصاحب العملية,
+Right Index,الفهرس الأيمن,
+Left Index,الفهرس الأيسر,
+Sub Procedure,الإجراء الفرعي,
+Passed,تم الاجتياز بنجاح,
+Print Receipt,اطبع الايصال,
+Edit Receipt,تحرير الإيصال,
+Focus on search input,ركز على إدخال البحث,
+Focus on Item Group filter,التركيز على عامل تصفية مجموعة العناصر,
+Checkout Order / Submit Order / New Order,طلب الخروج / إرسال الطلب / طلب جديد,
+Add Order Discount,أضف خصم الطلب,
+Item Code: {0} is not available under warehouse {1}.,رمز العنصر: {0} غير متوفر ضمن المستودع {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,الأرقام التسلسلية غير متاحة للعنصر {0} تحت المستودع {1}. يرجى محاولة تغيير المستودع.,
+Fetched only {0} available serial numbers.,تم جلب {0} من الأرقام التسلسلية المتوفرة فقط.,
+Switch Between Payment Modes,التبديل بين طرق الدفع,
+Enter {0} amount.,أدخل مبلغ {0}.,
+You don't have enough points to redeem.,ليس لديك ما يكفي من النقاط لاستردادها.,
+You can redeem upto {0}.,يمكنك استرداد ما يصل إلى {0}.,
+Enter amount to be redeemed.,أدخل المبلغ المراد استرداده.,
+You cannot redeem more than {0}.,لا يمكنك استرداد أكثر من {0}.,
+Open Form View,افتح طريقة عرض النموذج,
+POS invoice {0} created succesfully,تم إنشاء فاتورة نقاط البيع {0} بنجاح,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,كمية المخزون غير كافية لرمز الصنف: {0} تحت المستودع {1}. الكمية المتوفرة {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,الرقم التسلسلي: تم بالفعل معاملة {0} في فاتورة نقطة بيع أخرى.,
+Balance Serial No,الرقم التسلسلي للميزان,
+Warehouse: {0} does not belong to {1},المستودع: {0} لا ينتمي إلى {1},
+Please select batches for batched item {0},الرجاء تحديد دفعات للصنف المجمّع {0},
+Please select quantity on row {0},الرجاء تحديد الكمية في الصف {0},
+Please enter serial numbers for serialized item {0},الرجاء إدخال الأرقام التسلسلية للعنصر المسلسل {0},
+Batch {0} already selected.,الدفعة {0} محددة بالفعل.,
+Please select a warehouse to get available quantities,الرجاء تحديد مستودع للحصول على الكميات المتاحة,
+"For transfer from source, selected quantity cannot be greater than available quantity",للتحويل من المصدر ، لا يمكن أن تكون الكمية المحددة أكبر من الكمية المتاحة,
+Cannot find Item with this Barcode,لا يمكن العثور على عنصر بهذا الرمز الشريطي,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} إلزامي. ربما لم يتم إنشاء سجل صرف العملات من {1} إلى {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,قام {} بتقديم أصول مرتبطة به. تحتاج إلى إلغاء الأصول لإنشاء عائد شراء.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,لا يمكن إلغاء هذا المستند لأنه مرتبط بالأصل المقدم {0}. من فضلك قم بإلغائها للمتابعة.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,الصف # {}: الرقم التسلسلي {} تم بالفعل التعامل معه في فاتورة نقطة بيع أخرى. الرجاء تحديد رقم تسلسلي صالح.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,الصف # {}: تم بالفعل التعامل مع الأرقام التسلسلية. {} في فاتورة نقطة بيع أخرى. الرجاء تحديد رقم تسلسلي صالح.,
+Item Unavailable,العنصر غير متوفر,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},الصف # {}: لا يمكن إرجاع الرقم التسلسلي {} لأنه لم يتم التعامل معه في الفاتورة الأصلية {},
+Please set default Cash or Bank account in Mode of Payment {},الرجاء تعيين حساب نقدي أو مصرفي افتراضي في طريقة الدفع {},
+Please set default Cash or Bank account in Mode of Payments {},الرجاء تعيين حساب نقدي أو مصرفي افتراضي في طريقة الدفع {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,يرجى التأكد من أن حساب {} هو حساب الميزانية العمومية. يمكنك تغيير الحساب الرئيسي إلى حساب الميزانية العمومية أو تحديد حساب مختلف.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,الرجاء التأكد من أن حساب {} حساب قابل للدفع. قم بتغيير نوع الحساب إلى "مستحق الدفع" أو حدد حسابًا مختلفًا.,
+Row {}: Expense Head changed to {} ,الصف {}: تم تغيير رأس المصاريف إلى {},
+because account {} is not linked to warehouse {} ,لأن الحساب {} غير مرتبط بالمستودع {},
+or it is not the default inventory account,أو أنه ليس حساب المخزون الافتراضي,
+Expense Head Changed,تغيير رأس المصاريف,
+because expense is booked against this account in Purchase Receipt {},لأنه تم حجز المصروفات مقابل هذا الحساب في إيصال الشراء {},
+as no Purchase Receipt is created against Item {}. ,حيث لم يتم إنشاء إيصال شراء مقابل العنصر {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,يتم إجراء ذلك للتعامل مع محاسبة الحالات التي يتم فيها إنشاء إيصال الشراء بعد فاتورة الشراء,
+Purchase Order Required for item {},طلب الشراء مطلوب للعنصر {},
+To submit the invoice without purchase order please set {} ,لإرسال الفاتورة بدون أمر شراء ، يرجى تعيين {},
+as {} in {},كـ {} في {},
+Mandatory Purchase Order,أمر شراء إلزامي,
+Purchase Receipt Required for item {},إيصال الشراء مطلوب للعنصر {},
+To submit the invoice without purchase receipt please set {} ,لإرسال الفاتورة بدون إيصال شراء ، يرجى تعيين {},
+Mandatory Purchase Receipt,إيصال الشراء الإلزامي,
+POS Profile {} does not belongs to company {},الملف الشخصي لنقاط البيع {} لا ينتمي إلى الشركة {},
+User {} is disabled. Please select valid user/cashier,المستخدم {} معطل. الرجاء تحديد مستخدم / أمين صندوق صالح,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,الصف رقم {}: الفاتورة الأصلية {} فاتورة الإرجاع {} هي {}.,
+Original invoice should be consolidated before or along with the return invoice.,يجب دمج الفاتورة الأصلية قبل أو مع فاتورة الإرجاع.,
+You can add original invoice {} manually to proceed.,يمكنك إضافة الفاتورة الأصلية {} يدويًا للمتابعة.,
+Please ensure {} account is a Balance Sheet account. ,يرجى التأكد من أن حساب {} هو حساب الميزانية العمومية.,
+You can change the parent account to a Balance Sheet account or select a different account.,يمكنك تغيير الحساب الرئيسي إلى حساب الميزانية العمومية أو تحديد حساب مختلف.,
+Please ensure {} account is a Receivable account. ,يرجى التأكد من أن حساب {} هو حساب مدينة.,
+Change the account type to Receivable or select a different account.,قم بتغيير نوع الحساب إلى "ذمم مدينة" أو حدد حسابًا مختلفًا.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},لا يمكن إلغاء {} نظرًا لاسترداد نقاط الولاء المكتسبة. قم أولاً بإلغاء {} لا {},
+already exists,موجود أصلا,
+POS Closing Entry {} against {} between selected period,دخول إغلاق نقطة البيع {} مقابل {} بين الفترة المحددة,
+POS Invoice is {},فاتورة نقاط البيع {},
+POS Profile doesn't matches {},الملف الشخصي لنقطة البيع لا يتطابق مع {},
+POS Invoice is not {},فاتورة نقاط البيع ليست {},
+POS Invoice isn't created by user {},لم ينشئ المستخدم فاتورة نقاط البيع {},
+Row #{}: {},رقم الصف {}: {},
+Invalid POS Invoices,فواتير نقاط البيع غير صالحة,
+Please add the account to root level Company - {},الرجاء إضافة الحساب إلى شركة على مستوى الجذر - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",أثناء إنشاء حساب Child Company {0} ، لم يتم العثور على الحساب الرئيسي {1}. الرجاء إنشاء الحساب الرئيسي في شهادة توثيق البرامج المقابلة,
+Account Not Found,الحساب غير موجود,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",أثناء إنشاء حساب الشركة الفرعية {0} ، تم العثور على الحساب الرئيسي {1} كحساب دفتر أستاذ.,
+Please convert the parent account in corresponding child company to a group account.,الرجاء تحويل الحساب الرئيسي في الشركة الفرعية المقابلة إلى حساب مجموعة.,
+Invalid Parent Account,حساب الوالد غير صالح,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",يُسمح بإعادة تسميته فقط عبر الشركة الأم {0} ، لتجنب عدم التطابق.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",إذا قمت {0} {1} بكميات العنصر {2} ، فسيتم تطبيق المخطط {3} على العنصر.,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",إذا كنت {0} {1} تستحق العنصر {2} ، فسيتم تطبيق النظام {3} على العنصر.,
+"As the field {0} is enabled, the field {1} is mandatory.",نظرًا لتمكين الحقل {0} ، يكون الحقل {1} إلزاميًا.,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",أثناء تمكين الحقل {0} ، يجب أن تكون قيمة الحقل {1} أكثر من 1.,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},لا يمكن تسليم الرقم التسلسلي {0} للصنف {1} لأنه محجوز لملء طلب المبيعات {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",طلب المبيعات {0} لديه حجز للعنصر {1} ، يمكنك فقط تسليم {1} محجوز مقابل {0}.,
+{0} Serial No {1} cannot be delivered,لا يمكن تسليم {0} الرقم التسلسلي {1},
+Row {0}: Subcontracted Item is mandatory for the raw material {1},الصف {0}: العنصر المتعاقد عليه من الباطن إلزامي للمادة الخام {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",نظرًا لوجود مواد خام كافية ، فإن طلب المواد ليس مطلوبًا للمستودع {0}.,
+" If you still want to proceed, please enable {0}.",إذا كنت لا تزال تريد المتابعة ، فيرجى تمكين {0}.,
+The item referenced by {0} - {1} is already invoiced,العنصر المشار إليه بواسطة {0} - {1} تم تحرير فاتورة به بالفعل,
+Therapy Session overlaps with {0},تتداخل جلسة العلاج مع {0},
+Therapy Sessions Overlapping,جلسات العلاج متداخلة,
+Therapy Plans,خطط العلاج,
+"Item Code, warehouse, quantity are required on row {0}",مطلوب رمز الصنف والمستودع والكمية في الصف {0},
+Get Items from Material Requests against this Supplier,الحصول على عناصر من طلبات المواد ضد هذا المورد,
+Enable European Access,تمكين الوصول الأوروبي,
+Creating Purchase Order ...,إنشاء أمر شراء ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",حدد موردًا من الموردين الافتراضيين للعناصر أدناه. عند التحديد ، سيتم إجراء طلب الشراء مقابل العناصر التي تنتمي إلى المورد المحدد فقط.,
+Row #{}: You must select {} serial numbers for item {}.,الصف # {}: يجب تحديد {} الأرقام التسلسلية للعنصر {}.,
diff --git a/erpnext/translations/bg.csv b/erpnext/translations/bg.csv
index c02c565..15278a6 100644
--- a/erpnext/translations/bg.csv
+++ b/erpnext/translations/bg.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Актуалния вид данък не може да бъде включен в цената на артикула от ред {0},
Add,Добави,
Add / Edit Prices,Добавяне / Редактиране на цените,
-Add All Suppliers,Добавете всички доставчици,
Add Comment,Добави коментар,
Add Customers,Добавете клиенти,
Add Employees,Добави Служители,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Не може да се приспадне при категория е за "оценка" или "Vaulation и Total",
"Cannot delete Serial No {0}, as it is used in stock transactions","Не може да се изтрие Пореден № {0}, тъй като се използва в транзакции с материали",
Cannot enroll more than {0} students for this student group.,Не може да се запишат повече от {0} студенти за този студентска група.,
-Cannot find Item with this barcode,Не може да се намери елемент с този баркод,
Cannot find active Leave Period,Не може да се намери активен период на отпуск,
Cannot produce more Item {0} than Sales Order quantity {1},Не може да се произвежда повече позиция {0} от количеството в поръчка за продажба {1},
Cannot promote Employee with status Left,Не мога да популяризирам служител със състояние вляво,
Cannot refer row number greater than or equal to current row number for this Charge type,Не може да се отнесе поредни номера по-голям или равен на текущия брой ред за този тип Charge,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Не можете да изберете тип заряд като "На предишния ред Сума" или "На предишния ред Total" за първи ред,
-Cannot set a received RFQ to No Quote,Не може да се зададе получена RFQ в Без котировка,
Cannot set as Lost as Sales Order is made.,Не може да се определи като загубена тъй като поръчка за продажба е направена.,
Cannot set authorization on basis of Discount for {0},Не можете да зададете разрешение въз основа на Отстъпка за {0},
Cannot set multiple Item Defaults for a company.,Не може да се задават няколко елемента по подразбиране за компания.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Такси се обновяват на изкупните Квитанция за всяка стока,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Таксите ще бъдат разпределени пропорционално на базата на т Количество или количество, според вашия избор",
-Chart Of Accounts,Сметкоплан,
Chart of Cost Centers,Списък на Разходни центрове,
Check all,Избери всичко,
Checkout,Поръчка,
@@ -581,7 +577,6 @@
Compensatory Off,Компенсаторни Off,
Compensatory leave request days not in valid holidays,Компенсаторните отпуски не важат за валидни празници,
Complaint,оплакване,
-Completed Qty can not be greater than 'Qty to Manufacture',"Изпълнено Количество не може да бъде по-голямо от ""Количество за производство""",
Completion Date,дата на завършване,
Computer,компютър,
Condition,Състояние,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Създаване и управление на дневни, седмични и месечни имейл бюлетини.",
Create customer quotes,Създаване на оферти на клиенти,
Create rules to restrict transactions based on values.,"Създаване на правила за ограничаване на транзакции, основани на стойност.",
-Created By,Създаден от,
Created {0} scorecards for {1} between: ,Създадохте {0} scorecards за {1} между:,
Creating Company and Importing Chart of Accounts,Създаване на компания и импортиране на сметкоплан,
Creating Fees,Създаване на такси,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Прехвърлянето на служители не може да бъде подадено преди датата на прехвърлянето,
Employee cannot report to himself.,Служител не може да докладва пред самия себе си.,
Employee relieved on {0} must be set as 'Left',Служител облекчение на {0} трябва да се зададе като "Ляв",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Състоянието на служителя не може да бъде зададено на „Наляво“, тъй като в момента следните служители докладват на този служител:",
Employee {0} already submited an apllication {1} for the payroll period {2},Служител {0} вече подаде приложение {1} за периода на заплащане {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Служител {0} вече кандидатства за {1} между {2} и {3}:,
Employee {0} has no maximum benefit amount,Служител {0} няма максимална сума на доходите,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,За ред {0}: Въведете планираните количества,
"For {0}, only credit accounts can be linked against another debit entry","За {0}, само кредитни сметки могат да бъдат свързани с друг запис дебитна",
"For {0}, only debit accounts can be linked against another credit entry","За {0}, само дебитни сметки могат да бъдат свързани с друга кредитна влизане",
-Form View,Изглед на формата,
Forum Activity,Форумна активност,
Free item code is not selected,Безплатният код на артикула не е избран,
Freight and Forwarding Charges,Товарни и спедиция Такси,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Отпуск не могат да бъдат разпределени преди {0}, като баланс отпуск вече е ръчен изпраща в записа на бъдещото разпределение отпуск {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Остави, не може да се прилага / отмени преди {0}, като баланс отпуск вече е ръчен изпраща в записа на бъдещото разпределение отпуск {1}",
Leave of type {0} cannot be longer than {1},Разрешение за типа {0} не може да бъде по-дълъг от {1},
-Leave the field empty to make purchase orders for all suppliers,"Оставете полето празно, за да направите поръчки за покупка за всички доставчици",
Leaves,Листа,
Leaves Allocated Successfully for {0},Листата Разпределен успешно в продължение на {0},
Leaves has been granted sucessfully,Листата е предоставена успешно,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Не артикули с Бил на материали за производство на,
No Items with Bill of Materials.,Няма артикули с разчет на материали.,
No Permission,Няма разрешение,
-No Quote,Без цитат,
No Remarks,Няма забележки,
No Result to submit,Няма отговор за изпращане,
No Salary Structure assigned for Employee {0} on given date {1},"Няма структура на заплатата, определена за служител {0} на дадена дата {1}",
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Припокриване условия намерени между:,
Owner,Собственик,
PAN,PAN,
-PO already created for all sales order items,PO вече е създадена за всички елементи от поръчките за продажба,
POS,POS,
POS Profile,POS профил,
POS Profile is required to use Point-of-Sale,Профилът на POS е необходим за използване на Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Моля изберете вид на разхода първо,
Please select Company,Моля изберете фирма,
Please select Company and Designation,"Моля, изберете Company and Designation",
-Please select Company and Party Type first,Моля изберете Company и Party Type първи,
Please select Company and Posting Date to getting entries,"Моля, изберете Фирма и дата на публикуване, за да получавате записи",
Please select Company first,"Моля, изберете първо фирма",
Please select Completion Date for Completed Asset Maintenance Log,"Моля, изберете Дата на завършване на регистрационния дневник за завършено състояние на активите",
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Row {0}: мерна единица реализациите Factor е задължително,
Row {0}: select the workstation against the operation {1},Ред {0}: изберете работната станция срещу операцията {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,"Ред {0}: {1} Серийни номера, изисквани за елемент {2}. Предоставихте {3}.",
-Row {0}: {1} is required to create the Opening {2} Invoices,Ред {0}: {1} е необходим за създаване на {2} Фактури за отваряне,
Row {0}: {1} must be greater than 0,Ред {0}: {1} трябва да е по-голям от 0,
Row {0}: {1} {2} does not match with {3},Ред {0}: {1} {2} не съвпада с {3},
Row {0}:Start Date must be before End Date,Row {0}: Началната дата трябва да е преди крайната дата,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Изпратете имейл за преглед на одобрението,
Send Now,Изпрати сега,
Send SMS,Изпратете SMS,
-Send Supplier Emails,Изпрати Доставчик имейли,
Send mass SMS to your contacts,Изпратете маса SMS към вашите контакти,
Sensitivity,чувствителност,
Sent,Изпратено,
-Serial #,Serial #,
Serial No and Batch,Сериен № и Партида,
Serial No is mandatory for Item {0},Сериен № е задължително за позиция {0},
Serial No {0} does not belong to Batch {1},Сериен номер {0} не принадлежи на партида {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Името на Вашата фирма, за която искате да създадете тази система.",
The number of shares and the share numbers are inconsistent,Броят на акциите и номерата на акциите са неконсистентни,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Профилът на платежния шлюз в плана {0} е различен от профила на платежния шлюз в това искане за плащане,
-The request for quotation can be accessed by clicking on the following link,Искането за котировки могат да бъдат достъпни чрез щракване върху следния линк,
The selected BOMs are not for the same item,Избраните списъците с материали не са за една и съща позиция,
The selected item cannot have Batch,Избраният елемент не може да има партида,
The seller and the buyer cannot be the same,Продавачът и купувачът не могат да бъдат същите,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Общият размер на гъвкавия компонент на обезщетението {0} не трябва да бъде по-малък от максималните ползи {1},
Total hours: {0},Общо часове: {0},
Total leaves allocated is mandatory for Leave Type {0},Общото разпределение на листа е задължително за тип "Отпуск" {0},
-Total weightage assigned should be 100%. It is {0},Общо weightage определен да бъде 100%. Това е {0},
Total working hours should not be greater than max working hours {0},Общо работно време не трябва да са по-големи от работното време макс {0},
Total {0} ({1}),Общо {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Общо {0} за всички позиции е равна на нула, може да е необходимо да се промени "Разпределете такси на базата на"",
@@ -3316,7 +3299,6 @@
What do you need help with?,За какво ти е необходима помощ?,
What does it do?,Какво прави?,
Where manufacturing operations are carried.,Когато се извършват производствени операции.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Докато създавате акаунт за дъщерна компания {0}, родителски акаунт {1} не е намерен. Моля, създайте родителския акаунт в съответния COA",
White,бял,
Wire Transfer,Банков превод,
WooCommerce Products,Продукти на WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} вариантите са създадени.,
{0} {1} created,{0} {1} създаден,
{0} {1} does not exist,{0} {1} не съществува,
-{0} {1} does not exist.,{0} {1} не съществува.,
{0} {1} has been modified. Please refresh.,"{0} {1} е променен. Моля, опреснете.",
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} не е изпратена, така че действието не може да бъде завършено",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} е свързана с {2}, но профилът на компания е {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} не съществува,
{0}: {1} not found in Invoice Details table,{0}: {1} не е намерен в Таблицата с Датайлите на Фактури,
{} of {},{} на {},
+Assigned To,Възложените,
Chat,Чат,
Completed By,Завършено от,
Conditions,условия,
@@ -3506,7 +3488,9 @@
Merge with existing,Обединяване със съществуващото,
Office,Офис,
Orientation,ориентация,
+Parent,Родител,
Passive,Пасивен,
+Payment Failed,Неуспешно плащане,
Percent,Процент,
Permanent,постоянен,
Personal,Персонален,
@@ -3544,7 +3528,6 @@
Company field is required,Полето на фирмата е задължително,
Creating Dimensions...,Създаване на размери ...,
Duplicate entry against the item code {0} and manufacturer {1},Дублиран запис срещу кода на артикула {0} и производителя {1},
-Import Chart Of Accounts from CSV / Excel files,Импортиране на сметкоплан от CSV / Excel файлове,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Невалиден GSTIN! Въведеният от вас вход не съвпада с GSTIN формата за притежатели на UIN или нерезидентни доставчици на услуги OIDAR,
Invoice Grand Total,Фактура Голяма Обща,
Last carbon check date cannot be a future date,Последната дата за проверка на въглерода не може да бъде бъдеща дата,
@@ -3556,6 +3539,7 @@
Show {0},Показване на {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Специални символи, с изключение на "-", "#", ".", "/", "{" И "}" не са позволени в именуването на серии",
Target Details,Детайли за целта,
+{0} already has a Parent Procedure {1}.,{0} вече има родителска процедура {1}.,
API,API,
Annual,Годишен,
Approved,Одобрен,
@@ -3572,6 +3556,8 @@
No data to export,Няма данни за експорт,
Portrait,Портрет,
Print Heading,Print Heading,
+Scheduler Inactive,Графикът е неактивен,
+Scheduler is inactive. Cannot import data.,Графикът е неактивен. Данните не могат да се импортират.,
Show Document,Показване на документ,
Show Traceback,Показване на Traceback,
Video,Видео,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Създаване на проверка на качеството на артикул {0},
Creating Accounts...,Създаване на акаунти ...,
Creating bank entries...,Създаване на банкови записи ...,
-Creating {0},Създаване на {0},
Credit limit is already defined for the Company {0},Кредитният лимит вече е определен за компанията {0},
Ctrl + Enter to submit,Ctrl + Enter за изпращане,
Ctrl+Enter to submit,Ctrl + Enter за изпращане,
@@ -3921,7 +3906,6 @@
Plaid public token error,Грешка в обществен маркер,
Plaid transactions sync error,Грешка при синхронизиране на транзакции,
Please check the error log for details about the import errors,"Моля, проверете журнала за грешки за подробности относно грешките при импортиране",
-Please click on the following link to set your new password,"Моля, кликнете върху следния линк, за да зададете нова парола",
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,"Моля, създайте <b>настройките</b> на <b>DATEV</b> за компания <b>{}</b> .",
Please create adjustment Journal Entry for amount {0} ,"Моля, създайте корекция на вписването в журнала за сума {0}",
Please do not create more than 500 items at a time,"Моля, не създавайте повече от 500 артикула наведнъж",
@@ -3997,6 +3981,7 @@
Release date must be in the future,Дата на издаване трябва да бъде в бъдеще,
Relieving Date must be greater than or equal to Date of Joining,Дата на освобождаване трябва да бъде по-голяма или равна на датата на присъединяване,
Rename,Преименувай,
+Rename Not Allowed,Преименуването не е позволено,
Repayment Method is mandatory for term loans,Методът на погасяване е задължителен за срочните заеми,
Repayment Start Date is mandatory for term loans,Началната дата на погасяване е задължителна за срочните заеми,
Report Item,Елемент на отчета,
@@ -4043,7 +4028,6 @@
Select All,Избери всички,
Select Difference Account,Изберете Различен акаунт,
Select a Default Priority.,Изберете приоритет по подразбиране.,
-Select a Supplier from the Default Supplier List of the items below.,Изберете доставчик от списъка с доставчици по подразбиране на артикулите по-долу.,
Select a company,Изберете фирма,
Select finance book for the item {0} at row {1},Изберете книга за финансиране за елемента {0} на ред {1},
Select only one Priority as Default.,Изберете само един приоритет по подразбиране.,
@@ -4247,7 +4231,6 @@
Actual ,действителен,
Add to cart,Добави в кошницата,
Budget,бюджет,
-Chart Of Accounts Importer,Вносител на сметкоплан,
Chart of Accounts,График на сметките,
Customer database.,База данни на клиентите.,
Days Since Last order,Дни след последната поръчка,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Крайна дата не може да бъде по-малка от началната дата,
For Default Supplier (Optional),За доставчик по подразбиране (по избор),
From date cannot be greater than To date,От дата не може да бъде по-голямо от до дата,
-Get items from,Вземете елементи от,
Group by,Групирай по,
In stock,В наличност,
Item name,Име на артикул,
@@ -4532,32 +4514,22 @@
Accounts Settings,Настройки на Сметки,
Settings for Accounts,Настройки за сметки,
Make Accounting Entry For Every Stock Movement,Направи счетоводен запис за всеки склад Movement,
-"If enabled, the system will post accounting entries for inventory automatically.","Ако е активирана, системата ще публикуваме счетоводни записвания за инвентара автоматично.",
-Accounts Frozen Upto,Замразени Сметки до,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Счетоводен запис, замразени до тази дата, никой не може да направи / промени записите с изключение на ролята посочена по-долу",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Роля позволено да определят замразени сметки & Редактиране на замразени влизания,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Потребителите с тази роля е разрешено да задават замразени сметки и да се създаде / модифицира счетоводни записи срещу замразените сметки,
Determine Address Tax Category From,Определете категорията на адресния данък от,
-Address used to determine Tax Category in transactions.,"Адрес, използван за определяне на данъчна категория при транзакции.",
Over Billing Allowance (%),Надбавка за таксуване (%),
-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 for $110.,"Процент, който ви позволява да таксувате повече спрямо поръчаната сума. Например: Ако стойността на поръчката е 100 долара за артикул и толерансът е зададен като 10%, тогава можете да таксувате за 110 долара.",
Credit Controller,Кредит контрольор,
-Role that is allowed to submit transactions that exceed credit limits set.,"Роля, която е оставена да се представят сделки, които надвишават кредитни лимити, определени.",
Check Supplier Invoice Number Uniqueness,Провери за уникалност на фактура на доставчик,
Make Payment via Journal Entry,Направи Плащане чрез вестник Влизане,
Unlink Payment on Cancellation of Invoice,Прекратяване на връзката с плащане при анулиране на фактура,
-Unlink Advance Payment on Cancelation of Order,Прекратяване на авансовото плащане при анулиране на поръчката,
Book Asset Depreciation Entry Automatically,Автоматично отписване на амортизацията на активи,
Automatically Add Taxes and Charges from Item Tax Template,Автоматично добавяне на данъци и такси от шаблона за данък върху стоки,
Automatically Fetch Payment Terms,Автоматично извличане на условията за плащане,
-Show Inclusive Tax In Print,Показване на включения данък в печат,
Show Payment Schedule in Print,Показване на графика на плащанията в печат,
Currency Exchange Settings,Настройки за обмяна на валута,
Allow Stale Exchange Rates,Разрешаване на стационарни обменни курсове,
Stale Days,Старши дни,
Report Settings,Настройки на отчетите,
Use Custom Cash Flow Format,Използвайте персонализиран формат на паричен поток,
-Only select if you have setup Cash Flow Mapper documents,Изберете само ако имате настройки за документиране на паричните потоци,
Allowed To Transact With,Позволени да извършват транзакции с,
SWIFT number,SWIFT номер,
Branch Code,Код на клона,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Customer Group,
POS Field,ПОС поле,
POS Item Group,POS Позиция Group,
-[Select],[Избор],
Company Address,Адрес на компанията,
Update Stock,Актуализация Наличности,
Ignore Pricing Rule,Игнориране на правилата за ценообразуване,
@@ -5495,8 +5466,6 @@
Supplier Naming By,"Доставчик наименуването им,",
Default Supplier Group,Група доставчици по подразбиране,
Default Buying Price List,Ценови лист за закупуване по подразбиране,
-Maintain same rate throughout purchase cycle,Поддържане на същия процент в цялия цикъл на покупка,
-Allow Item to be added multiple times in a transaction,Оставя т да бъдат добавени няколко пъти в една сделка,
Backflush Raw Materials of Subcontract Based On,Възстановяване на суровини от договори за подизпълнение,
Material Transferred for Subcontract,Прехвърлен материал за подизпълнение,
Over Transfer Allowance (%),Помощ за прехвърляне (%),
@@ -5540,7 +5509,6 @@
Current Stock,Наличност,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,За отделен доставчик,
-Supplier Detail,Доставчик - детайли,
Link to Material Requests,Връзка към заявки за материали,
Message for Supplier,Съобщение за доставчика,
Request for Quotation Item,Запитване за оферта - позиция,
@@ -6481,7 +6449,6 @@
Appraisal Template,Оценка Template,
For Employee Name,За Име на служител,
Goals,Цели,
-Calculate Total Score,Изчисли Общ резултат,
Total Score (Out of 5),Общ резултат (от 5),
"Any other remarks, noteworthy effort that should go in the records.","Всякакви други забележки, отбелязване на усилието, които трябва да отиде в регистрите.",
Appraisal Goal,Оценка Goal,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Причина за напускане,
Leave Encashed?,Отсъствието е платено?,
Encashment Date,Инкасо Дата,
-Exit Interview Details,Exit Интервю - Детайли,
-Held On,Проведена На,
-Reason for Resignation,Причина за Оставка,
-Better Prospects,По-добри перспективи,
-Health Concerns,Здравни проблеми,
New Workplace,Ново работно място,
HR-EAD-.YYYY.-,HR-ЕАД-.YYYY.-,
Returned Amount,Върната сума,
@@ -6740,10 +6702,7 @@
Employee Settings,Настройки на служители,
Retirement Age,пенсионна възраст,
Enter retirement age in years,Въведете пенсионна възраст в години,
-Employee Records to be created by,Архивите на служителите да бъдат създадени от,
-Employee record is created using selected field. ,Запис на служителите е създаден с помощта на избран област.,
Stop Birthday Reminders,Stop напомняне за рождени дни,
-Don't send Employee Birthday Reminders,Не изпращайте на служителите напомняне за рождени дни,
Expense Approver Mandatory In Expense Claim,Задължителният разпоредител с разходи в декларацията за разходи,
Payroll Settings,Настройки ТРЗ,
Leave,Оставете,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Оставете призванието задължително в отпуск,
Show Leaves Of All Department Members In Calendar,Показване на листата на всички членове на катедрата в календара,
Auto Leave Encashment,Автоматично оставяне Encashment,
-Restrict Backdated Leave Application,Ограничете приложението за обратно изтегляне,
Hiring Settings,Настройки за наемане,
Check Vacancies On Job Offer Creation,Проверете свободни работни места при създаване на оферта за работа,
Identification Document Type,Идентификационен документ тип,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Настройки производство,
Raw Materials Consumption,Консумация на суровини,
Allow Multiple Material Consumption,Позволявайте многократна консумация на материали,
-Allow multiple Material Consumption against a Work Order,Позволете многократна консумация на материали срещу работна поръчка,
Backflush Raw Materials Based On,Изписване на суровини въз основа на,
Material Transferred for Manufacture,Материалът е прехвърлен за Производство,
Capacity Planning,Планиране на капацитета,
Disable Capacity Planning,Деактивиране на планирането на капацитета,
Allow Overtime,Разрешаване на Извънредно раб.време,
-Plan time logs outside Workstation Working Hours.,Планирайте времето трупи извън Workstation работно време.,
Allow Production on Holidays,Разрешаване на производство на празници,
Capacity Planning For (Days),Планиране на капацитет за (дни),
-Try planning operations for X days in advance.,Опитайте планира операции за Х дни предварително.,
-Time Between Operations (in mins),Време между операциите (в минути),
-Default 10 mins,По подразбиране 10 минути,
Default Warehouses for Production,Складове по подразбиране за производство,
Default Work In Progress Warehouse,Склад за незав.производство по подразбиране,
Default Finished Goods Warehouse,По подразбиране - Склад за готова продукция,
Default Scrap Warehouse,Склад за скрап по подразбиране,
-Over Production for Sales and Work Order,Над производство за продажба и поръчка за работа,
Overproduction Percentage For Sales Order,Процент на свръхпроизводство за поръчка за продажба,
Overproduction Percentage For Work Order,Процент на свръхпроизводство за работна поръчка,
Other Settings,Други настройки,
Update BOM Cost Automatically,Актуализиране на цената на BOM автоматично,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Актуализиране на BOM струва автоматично чрез Scheduler, въз основа на последната скорост на оценка / ценоразпис / последната сума на покупката на суровини.",
Material Request Plan Item,Елемент от плана за материали,
Material Request Type,Заявка за материал - тип,
Material Issue,Изписване на материал,
@@ -7603,10 +7554,6 @@
Quality Goal,Цел за качество,
Monitoring Frequency,Мониторинг на честотата,
Weekday,делничен,
-January-April-July-October,За периода януари-април до юли до октомври,
-Revision and Revised On,Ревизия и ревизия на,
-Revision,ревизия,
-Revised On,Ревизиран на,
Objectives,Цели,
Quality Goal Objective,Цел за качество,
Objective,Обективен,
@@ -7619,7 +7566,6 @@
Processes,процеси,
Quality Procedure Process,Процес на качествена процедура,
Process Description,Описание на процеса,
-Child Procedure,Детска процедура,
Link existing Quality Procedure.,Свържете съществуващата процедура за качество.,
Additional Information,Допълнителна информация,
Quality Review Objective,Цел за преглед на качеството,
@@ -7787,15 +7733,9 @@
Default Customer Group,Клиентска група по подразбиране,
Default Territory,Територия по подразбиране,
Close Opportunity After Days,Затвори възможността след брой дни,
-Auto close Opportunity after 15 days,Автоматично затваряне на възможността в 15-дневен срок,
Default Quotation Validity Days,Начални дни на валидност на котировката,
Sales Update Frequency,Честота на обновяване на продажбите,
-How often should project and company be updated based on Sales Transactions.,Колко често трябва да се актуализира проектът и фирмата въз основа на продажбите.,
Each Transaction,Всяка транзакция,
-Allow user to edit Price List Rate in transactions,Позволи на потребителя да редактира цените в Ценоразпис от транзакциите,
-Allow multiple Sales Orders against a Customer's Purchase Order,Разрешаване на множество Поръчки за продажби срещу поръчка на клиента,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Валидиране на продажна цена за позиция срещу процент за закупуване или цена по оценка,
-Hide Customer's Tax Id from Sales Transactions,Скриване на данъчния идентификационен номер на клиента от сделки за продажба,
SMS Center,SMS Center,
Send To,Изпрати на,
All Contact,Всички контакти,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Използвани производители в артикули,
Limited to 12 characters,Ограничено до 12 символа,
MAT-MR-.YYYY.-,МАТ-MR-.YYYY.-,
-Set Warehouse,Комплект Склад,
-Sets 'For Warehouse' in each row of the Items table.,Задава „За склад“ във всеки ред от таблицата „Предмети“.,
-Requested For,Поискана за,
Partially Ordered,Частично подредени,
Transferred,Прехвърлен,
% Ordered,% Поръчани,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Мерна единица за стоки по подразбиране,
Sample Retention Warehouse,Склад за съхраняване на проби,
Default Valuation Method,Метод на оценка по подразбиране,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Процент ви е позволено да получи или достави повече от поръчаното количество. Например: Ако сте поръчали 100 единици. и си Allowance е 10% след което се оставя да се получи 110 единици.,
-Action if Quality inspection is not submitted,"Действие, ако не бъде представена проверка за качество",
Show Barcode Field,Покажи поле за баркод,
Convert Item Description to Clean HTML,Конвертиране на елемента Описание за почистване на HTML,
-Auto insert Price List rate if missing,"Auto вложка Ценоразпис ставка, ако липсва",
Allow Negative Stock,Разрешаване на отрицателна наличност,
Automatically Set Serial Nos based on FIFO,Автоматично Определете серийни номера на базата на FIFO,
-Set Qty in Transactions based on Serial No Input,Задайте количество в транзакции въз основа на сериен № вход,
Auto Material Request,Auto Материал Искане,
-Raise Material Request when stock reaches re-order level,Повдигнете Материал Заявка когато фондова достигне ниво повторна поръчка,
-Notify by Email on creation of automatic Material Request,Изпращайте по имейл за създаване на автоматично искане за материали,
Inter Warehouse Transfer Settings,Настройки за прехвърляне на Inter Warehouse,
-Allow Material Transfer From Delivery Note and Sales Invoice,Разрешаване на прехвърляне на материали от бележка за доставка и фактура за продажба,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Разрешаване на трансфер на материали от разписка за покупка и фактура за покупка,
Freeze Stock Entries,Фиксиране на вписване в запасите,
Stock Frozen Upto,Фондова Frozen Upto,
-Freeze Stocks Older Than [Days],Freeze Запаси по-стари от [Days],
-Role Allowed to edit frozen stock,Роля за редактиране замразена,
Batch Identification,Идентификация на партидата,
Use Naming Series,Използвайте серията за наименуване,
Naming Series Prefix,Наименуване на серийния префикс,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Покупка Квитанция Trends,
Purchase Register,Покупка Регистрация,
Quotation Trends,Оферта Тенденции,
-Quoted Item Comparison,Сравнение на редове от оферти,
Received Items To Be Billed,"Приети артикули, които да се фактирират",
Qty to Order,Количество към поръчка,
Requested Items To Be Transferred,Желани артикули да бъдат прехвърлени,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Изберете склад за заявки за материали,
Transfer Materials For Warehouse {0},Прехвърляне на материали за склад {0},
Production Plan Material Request Warehouse,Склад за искане на материал за производствен план,
-Set From Warehouse,Комплект от склад,
-Source Warehouse (Material Transfer),Склад на източника (прехвърляне на материали),
Sets 'Source Warehouse' in each row of the items table.,Задава „Склад на източника“ във всеки ред от таблицата с артикули.,
Sets 'Target Warehouse' in each row of the items table.,Задава „Target Warehouse“ във всеки ред от таблицата с елементи.,
Show Cancelled Entries,Показване на отменени записи,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Услугата получена, но не е таксувана",
Deferred Accounting Settings,Настройки за отложено счетоводство,
Book Deferred Entries Based On,Резервирайте отложените записи въз основа на,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ако е избрано „Месеци“, тогава фиксираната сума ще бъде осчетоводена като отсрочени приходи или разходи за всеки месец, независимо от броя на дните в месеца. Ще бъде пропорционално, ако отложените приходи или разходи не бъдат записани за цял месец.",
Days,Дни,
Months,Месеци,
Book Deferred Entries Via Journal Entry,Резервирайте отложените записи чрез запис в дневника,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Ако това не е отметнато, ще бъдат създадени директни записи за GL, за да се резервират отсрочени приходи / разходи",
Submit Journal Entries,Изпращане на записи в дневника,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Ако това не е отметнато, записите в дневника ще бъдат запазени в състояние на чернова и ще трябва да бъдат изпратени ръчно",
Enable Distributed Cost Center,Активиране на разпределен център за разходи,
@@ -8901,8 +8823,6 @@
Is Inter State,Е Inter State,
Purchase Details,Подробности за покупката,
Depreciation Posting Date,Дата на осчетоводяване на амортизация,
-Purchase Order Required for Purchase Invoice & Receipt Creation,"Поръчка за покупка, необходима за създаване на фактура за покупка и получаване",
-Purchase Receipt Required for Purchase Invoice Creation,"Разписка за покупка, необходима за създаване на фактура за покупка",
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",По подразбиране името на доставчика е зададено според въведеното име на доставчика. Ако искате доставчиците да бъдат посочени от,
choose the 'Naming Series' option.,изберете опцията „Naming Series“.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,"Конфигурирайте ценовата листа по подразбиране, когато създавате нова транзакция за покупка. Цените на артикулите ще бъдат извлечени от тази ценова листа.",
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Е компонент на данъка върху дохода,
Component properties and references ,Свойства на компонентите и препратки,
Additional Salary ,Допълнителна заплата,
-Condtion and formula,Състояние и формула,
Unmarked days,Немаркирани дни,
Absent Days,Отсъстващи дни,
Conditions and Formula variable and example,Условия и формула променлива и пример,
Feedback By,Обратна връзка от,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Производствена секция,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Поръчка за продажба е необходима за фактура за продажба и създаване на бележка за доставка,
-Delivery Note Required for Sales Invoice Creation,Необходима бележка за доставка за създаване на фактура за продажба,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",По подразбиране Името на клиента се задава според въведеното Пълно име. Ако искате клиентите да бъдат именувани от,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,"Конфигурирайте ценовата листа по подразбиране, когато създавате нова транзакция за продажби. Цените на артикулите ще бъдат извлечени от тази ценова листа.",
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ако тази опция е конфигурирана „Да“, ERPNext ще ви попречи да създадете фактура за продажба или бележка за доставка, без първо да създавате поръчка за продажба. Тази конфигурация може да бъде заменена за конкретен клиент, като активирате квадратчето „Разрешаване на създаването на фактура за продажба без поръчка за продажба“ в клиентския мастер.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} бе добавен успешно към всички избрани теми.,
Topics updated,Темите са актуализирани,
Academic Term and Program,Академичен срок и програма,
-Last Stock Transaction for item {0} was on {1}.,Последната транзакция на склад за артикул {0} беше на {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Транзакции със запаси за артикул {0} не могат да бъдат публикувани преди това време.,
Please remove this item and try to submit again or update the posting time.,"Моля, премахнете този елемент и опитайте да изпратите отново или актуализирайте времето за публикуване.",
Failed to Authenticate the API key.,Неуспешно удостоверяване на API ключа.,
Invalid Credentials,Невалидни идентификационни данни,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,"Моля, проверете идентификационния номер на клиента си и тайните стойности",
Bank transaction creation error,Грешка при създаване на банкова транзакция,
Unit of Measurement,Мерна единица,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Ред № {}: Процентът на продажба на артикул {} е по-нисък от своя {}. Курсът на продажба трябва да бъде поне {},
Fiscal Year {0} Does Not Exist,Фискална година {0} не съществува,
Row # {0}: Returned Item {1} does not exist in {2} {3},Ред № {0}: Върнат артикул {1} не съществува в {2} {3},
Valuation type charges can not be marked as Inclusive,Таксите от типа оценка не могат да бъдат маркирани като Включително,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Времето за реакция за {0} приоритет в ред {1} не може да бъде по-голямо от времето за резолюция.,
{0} is not enabled in {1},{0} не е активиран в {1},
Group by Material Request,Групиране по заявка за материал,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Ред {0}: За доставчика {0} е необходим имейл адрес за изпращане на имейл,
Email Sent to Supplier {0},Изпратено имейл до доставчика {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Достъпът до заявка за оферта от портала е деактивиран. За да разрешите достъп, разрешете го в настройките на портала.",
Supplier Quotation {0} Created,Оферта на доставчика {0} Създадена,
Valid till Date cannot be before Transaction Date,Валидно до Дата не може да бъде преди Датата на транзакцията,
+Unlink Advance Payment on Cancellation of Order,Прекратете връзката с авансово плащане при анулиране на поръчка,
+"Simple Python Expression, Example: territory != 'All Territories'","Прост израз на Python, Пример: территория! = 'Всички територии'",
+Sales Contributions and Incentives,Вноски и стимули за продажби,
+Sourced by Supplier,Източник от доставчика,
+Total weightage assigned should be 100%.<br>It is {0},Общото определено претегляне трябва да бъде 100%.<br> Това е {0},
+Account {0} exists in parent company {1}.,Профилът {0} съществува в компанията майка {1}.,
+"To overrule this, enable '{0}' in company {1}","За да отмените това, активирайте „{0}“ във фирма {1}",
+Invalid condition expression,Невалиден израз на условие,
+Please Select a Company First,"Моля, първо изберете компания",
+Please Select Both Company and Party Type First,"Моля, първо изберете както фирма, така и тип страна",
+Provide the invoice portion in percent,Предоставете частта от фактурата в проценти,
+Give number of days according to prior selection,Посочете броя дни според предварителния подбор,
+Email Details,Подробности за имейл,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Изберете поздрав за приемника. Например г-н, г-жа и т.н.",
+Preview Email,Визуализация на имейл,
+Please select a Supplier,"Моля, изберете доставчик",
+Supplier Lead Time (days),Време за доставка на доставчика (дни),
+"Home, Work, etc.","Дом, работа и др.",
+Exit Interview Held On,Интервюто за изход се проведе,
+Condition and formula,Състояние и формула,
+Sets 'Target Warehouse' in each row of the Items table.,Задава „Целеви склад“ във всеки ред от таблицата „Елементи“.,
+Sets 'Source Warehouse' in each row of the Items table.,Задава „Склад на източника“ във всеки ред от таблицата „Елементи“.,
+POS Register,POS регистър,
+"Can not filter based on POS Profile, if grouped by POS Profile","Не може да се филтрира въз основа на POS профил, ако е групиран по POS профил",
+"Can not filter based on Customer, if grouped by Customer","Не може да се филтрира въз основа на Клиент, ако е групиран от Клиент",
+"Can not filter based on Cashier, if grouped by Cashier","Не може да се филтрира въз основа на Каса, ако е групирана по Каса",
+Payment Method,Начин на плащане,
+"Can not filter based on Payment Method, if grouped by Payment Method","Не може да се филтрира въз основа на начин на плащане, ако е групиран по начин на плащане",
+Supplier Quotation Comparison,Сравнение на офертите на доставчика,
+Price per Unit (Stock UOM),Цена за единица (запас UOM),
+Group by Supplier,Групиране по доставчик,
+Group by Item,Групиране по артикул,
+Remember to set {field_label}. It is required by {regulation}.,Не забравяйте да зададете {field_label}. Изисква се от {регламент}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Датата на записване не може да бъде преди началната дата на учебната година {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Датата на записване не може да бъде след Крайната дата на академичния срок {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Дата на записване не може да бъде преди началната дата на академичния срок {0},
+Future Posting Not Allowed,Публикуването в бъдеще не е разрешено,
+"To enable Capital Work in Progress Accounting, ","За да активирате счетоводното отчитане на текущата работа,",
+you must select Capital Work in Progress Account in accounts table,трябва да изберете Сметка за текущ капитал в таблицата на сметките,
+You can also set default CWIP account in Company {},Можете също да зададете CWIP акаунт по подразбиране във Фирма {},
+The Request for Quotation can be accessed by clicking on the following button,"Заявката за оферта може да бъде достъпна, като кликнете върху следния бутон",
+Regards,за разбирането,
+Please click on the following button to set your new password,"Моля, кликнете върху следния бутон, за да зададете новата си парола",
+Update Password,Актуализиране на паролата,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Ред № {}: Процентът на продажба на артикул {} е по-нисък от своя {}. Продажбата {} трябва да бъде поне {},
+You can alternatively disable selling price validation in {} to bypass this validation.,"Можете алтернативно да деактивирате проверката на продажните цени в {}, за да заобиколите тази проверка.",
+Invalid Selling Price,Невалидна продажна цена,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,"Адресът трябва да бъде свързан с компания. Моля, добавете ред за компания в таблицата с връзки.",
+Company Not Linked,Фирма не е свързана,
+Import Chart of Accounts from CSV / Excel files,Импортиране на сметката от CSV / Excel файлове,
+Completed Qty cannot be greater than 'Qty to Manufacture',Попълненото количество не може да бъде по-голямо от „Количество за производство“,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Ред {0}: За доставчика {1} е необходим имейл адрес за изпращане на имейл,
+"If enabled, the system will post accounting entries for inventory automatically","Ако е активирана, системата автоматично ще публикува счетоводни записи за инвентара",
+Accounts Frozen Till Date,"Сметки, замразени до датата",
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Счетоводните записи са замразени до тази дата. Никой не може да създава или променя записи освен потребители с посочената по-долу роля,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Позволена роля за задаване на замразени акаунти и редактиране на замразени записи,
+Address used to determine Tax Category in transactions,"Адрес, използван за определяне на данъчната категория при транзакции",
+"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 ","Процентът, който имате право да таксувате повече срещу поръчаната сума. Например, ако стойността на поръчката е $ 100 за артикул и толерансът е зададен като 10%, тогава имате право да таксувате до $ 110",
+This role is allowed to submit transactions that exceed credit limits,"Тази роля има право да подава транзакции, които надвишават кредитните лимити",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ако е избрано „Месеци“, фиксирана сума ще бъде осчетоводена като отсрочени приходи или разходи за всеки месец, независимо от броя на дните в месеца. Той ще бъде пропорционален, ако отложените приходи или разходи не бъдат записани за цял месец",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Ако това не е отметнато, ще бъдат създадени директни записи в GL, за да се отчетат отсрочени приходи или разходи",
+Show Inclusive Tax in Print,Показване на включения данък в печат,
+Only select this if you have set up the Cash Flow Mapper documents,Изберете това само ако сте настроили документите за картографиране на парични потоци,
+Payment Channel,Канал за плащане,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Изисква ли се поръчка за покупка за създаване на фактура за покупка и получаване?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Изисква ли се разписка за покупка за създаване на фактура за покупка?,
+Maintain Same Rate Throughout the Purchase Cycle,Поддържайте една и съща ставка през целия цикъл на покупка,
+Allow Item To Be Added Multiple Times in a Transaction,Разрешаване на добавянето на елемент няколко пъти в транзакция,
+Suppliers,Доставчици,
+Send Emails to Suppliers,Изпращайте имейли до доставчиците,
+Select a Supplier,Изберете доставчик,
+Cannot mark attendance for future dates.,Не може да се отбележи присъствие за бъдещи дати.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Искате ли да актуализирате присъствието?<br> Присъства: {0}<br> Отсъства: {1},
+Mpesa Settings,Настройки на Mpesa,
+Initiator Name,Име на инициатора,
+Till Number,До номер,
+Sandbox,Пясъчник,
+ Online PassKey,Онлайн PassKey,
+Security Credential,Удостоверения за сигурност,
+Get Account Balance,Вземете салдо по акаунта,
+Please set the initiator name and the security credential,"Моля, задайте името на инициатора и идентификационните данни за защита",
+Inpatient Medication Entry,Вход за стационарни лекарства,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Код на артикула (наркотик),
+Medication Orders,Поръчки за лекарства,
+Get Pending Medication Orders,Вземете чакащи поръчки за лекарства,
+Inpatient Medication Orders,Заповеди за стационарни медикаменти,
+Medication Warehouse,Склад за лекарства,
+Warehouse from where medication stock should be consumed,"Склад, откъдето трябва да се консумира запас от лекарства",
+Fetching Pending Medication Orders,Извличане на чакащи поръчки за лекарства,
+Inpatient Medication Entry Detail,Подробности за стационарното лекарство,
+Medication Details,Подробности за лекарствата,
+Drug Code,Код за наркотици,
+Drug Name,Име на лекарството,
+Against Inpatient Medication Order,Срещу заповед за стационарно лечение,
+Against Inpatient Medication Order Entry,Срещу влизане на заповед за стационарно лечение,
+Inpatient Medication Order,Заповед за стационарно лечение,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Общо поръчки,
+Completed Orders,Изпълнени поръчки,
+Add Medication Orders,Добавете поръчки за лекарства,
+Adding Order Entries,Добавяне на записи за поръчки,
+{0} medication orders completed,{0} поръчки за лекарства завършени,
+{0} medication order completed,{0} поръчка за лекарства завършена,
+Inpatient Medication Order Entry,Вписване на заповед за стационарно лечение,
+Is Order Completed,Изпълнена ли е поръчката,
+Employee Records to Be Created By,"Записи на служителите, които ще бъдат създадени от",
+Employee records are created using the selected field,Записите на служителите се създават с помощта на избраното поле,
+Don't send employee birthday reminders,Не изпращайте напомняния за рождения ден на служителите,
+Restrict Backdated Leave Applications,Ограничете приложенията за отпуск със задна дата,
+Sequence ID,Идент. № на последователността,
+Sequence Id,Идент. № на последователността,
+Allow multiple material consumptions against a Work Order,Позволете многократни консумации на материали срещу работна поръчка,
+Plan time logs outside Workstation working hours,Планирайте дневници за време извън работното време на работната станция,
+Plan operations X days in advance,Планирайте операциите X дни предварително,
+Time Between Operations (Mins),Време между операциите (минути),
+Default: 10 mins,По подразбиране: 10 минути,
+Overproduction for Sales and Work Order,Свръхпроизводство за продажби и работна поръчка,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Актуализирайте BOM разходите автоматично чрез планиращ механизъм, въз основа на най-новия процент на оценка / Ценова листа / Степен на последно закупуване на суровини",
+Purchase Order already created for all Sales Order items,Поръчка за покупка вече е създадена за всички елементи на Поръчка за продажба,
+Select Items,Изберете елементи,
+Against Default Supplier,Срещу доставчик по подразбиране,
+Auto close Opportunity after the no. of days mentioned above,"Автоматично затваряне Възможност след не. от дните, споменати по-горе",
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Изисква ли се поръчка за продажба за създаване на фактура за продажба и бележка за доставка?,
+Is Delivery Note Required for Sales Invoice Creation?,Необходима ли е бележка за доставка за създаване на фактура за продажба?,
+How often should Project and Company be updated based on Sales Transactions?,Колко често проектът и компанията трябва да се актуализират въз основа на транзакции за продажба?,
+Allow User to Edit Price List Rate in Transactions,Позволете на потребителя да редактира ценовата листа в транзакциите,
+Allow Item to Be Added Multiple Times in a Transaction,Разрешаване на добавянето на елемент няколко пъти в транзакция,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Разрешаване на множество поръчки за продажба срещу поръчка на клиента,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Проверете продажната цена за артикул спрямо процента на покупка или степента на оценка,
+Hide Customer's Tax ID from Sales Transactions,Скриване на данъчния номер на клиента от продажби,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Процентът, който имате право да получавате или доставяте повече спрямо поръчаното количество. Например, ако сте поръчали 100 единици и вашата надбавка е 10%, тогава имате право да получите 110 единици.",
+Action If Quality Inspection Is Not Submitted,"Действие, ако не е представена проверка на качеството",
+Auto Insert Price List Rate If Missing,"Автоматично въвеждане на ценоразпис, ако липсва",
+Automatically Set Serial Nos Based on FIFO,Автоматично задаване на серийни номера въз основа на FIFO,
+Set Qty in Transactions Based on Serial No Input,Задайте количество в транзакции въз основа на сериен вход,
+Raise Material Request When Stock Reaches Re-order Level,"Повишете заявката за материал, когато запасите достигнат ниво на повторна поръчка",
+Notify by Email on Creation of Automatic Material Request,Уведомете по имейл за създаването на автоматична заявка за материал,
+Allow Material Transfer from Delivery Note to Sales Invoice,Разрешаване на прехвърляне на материал от бележка за доставка до фактура за продажба,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Разрешаване на прехвърляне на материал от разписка за покупка към фактура за покупка,
+Freeze Stocks Older Than (Days),Замразете запасите по-стари от (дни),
+Role Allowed to Edit Frozen Stock,"Роля, разрешена за редактиране на замразени запаси",
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Неразпределената сума на запис за плащане {0} е по-голяма от неразпределената сума на банковата транзакция,
+Payment Received,Получено плащане,
+Attendance cannot be marked outside of Academic Year {0},Присъствието не може да бъде маркирано извън академичната година {0},
+Student is already enrolled via Course Enrollment {0},Студентът вече е записан чрез записване на курс {0},
+Attendance cannot be marked for future dates.,Присъствието не може да бъде маркирано за бъдещи дати.,
+Please add programs to enable admission application.,"Моля, добавете програми, за да разрешите кандидатстване.",
+The following employees are currently still reporting to {0}:,Понастоящем следните служители все още се отчитат пред {0}:,
+Please make sure the employees above report to another Active employee.,"Моля, уверете се, че служителите по-горе се отчитат пред друг активен служител.",
+Cannot Relieve Employee,Не може да облекчи служителя,
+Please enter {0},"Моля, въведете {0}",
+Please select another payment method. Mpesa does not support transactions in currency '{0}',"Моля, изберете друг начин на плащане. Mpesa не поддържа транзакции във валута „{0}“",
+Transaction Error,Грешка в транзакцията,
+Mpesa Express Transaction Error,Грешка при транзакцията на Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Открит е проблем с конфигурацията на Mpesa, проверете регистрационните файлове за грешки за повече подробности",
+Mpesa Express Error,Грешка в Mpesa Express,
+Account Balance Processing Error,Грешка при обработката на салдото по акаунта,
+Please check your configuration and try again,"Моля, проверете вашата конфигурация и опитайте отново",
+Mpesa Account Balance Processing Error,Грешка при обработката на салдото в Mpesa акаунт,
+Balance Details,Подробности за баланса,
+Current Balance,Текущ баланс,
+Available Balance,Наличен баланс,
+Reserved Balance,Запазен баланс,
+Uncleared Balance,Неизчистен баланс,
+Payment related to {0} is not completed,"Плащането, свързано с {0}, не е завършено",
+Row #{}: Item Code: {} is not available under warehouse {}.,Ред № {}: Код на артикула: {} не е наличен в склада {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Ред № {}: Количеството на склад не е достатъчно за Код на артикула: {} под склад {}. Налично количество {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,"Ред № {}: Моля, изберете сериен номер и партида срещу елемент: {} или го премахнете, за да завършите транзакцията.",
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"Ред № {}: Не е избран сериен номер за елемент: {}. Моля, изберете един или го премахнете, за да завършите транзакцията.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,"Ред № {}: Не е избрана партида срещу елемент: {}. Моля, изберете партида или я премахнете, за да завършите транзакцията.",
+Payment amount cannot be less than or equal to 0,Сумата на плащането не може да бъде по-малка или равна на 0,
+Please enter the phone number first,"Моля, въведете първо телефонния номер",
+Row #{}: {} {} does not exist.,Ред № {}: {} {} не съществува.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Ред № {0}: {1} е необходим за създаване на отварящите се {2} фактури,
+You had {} errors while creating opening invoices. Check {} for more details,Имахте {} грешки при създаването на фактури за отваряне. Проверете {} за повече подробности,
+Error Occured,Възникна грешка,
+Opening Invoice Creation In Progress,Отваряне на фактура в процес на създаване,
+Creating {} out of {} {},Създава се {} от {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Сериен номер: {0}) не може да бъде консумиран, тъй като е резервиран за пълно изпълнение на поръчка за продажба {1}.",
+Item {0} {1},Елемент {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Последната транзакция на склад за артикул {0} под склад {1} беше на {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Транзакции със запаси за артикул {0} под склад {1} не могат да бъдат публикувани преди това време.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Публикуването на бъдещи сделки с акции не е разрешено поради неизменяема книга,
+A BOM with name {0} already exists for item {1}.,Спецификация със име {0} вече съществува за елемент {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,"{0} {1} Преименувахте ли елемента? Моля, свържете се с администратор / техническа поддръжка",
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},На ред № {0}: идентификаторът на последователността {1} не може да бъде по-малък от идентификатора на последователността на предишния ред {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) трябва да е равно на {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, завършете операцията {1} преди операцията {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Не може да се гарантира доставка чрез сериен номер, тъй като елемент {0} е добавен със и без Осигурете доставка чрез сериен номер",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Елемент {0} няма сериен номер. Само сериализираните артикули могат да имат доставка въз основа на сериен номер,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Не е намерена активна спецификация за елемент {0}. Доставката по сериен номер не може да бъде осигурена,
+No pending medication orders found for selected criteria,Не са намерени чакащи поръчки за лекарства за избрани критерии,
+From Date cannot be after the current date.,От дата не може да бъде след текущата дата.,
+To Date cannot be after the current date.,До дата не може да бъде след текущата дата.,
+From Time cannot be after the current time.,От Time не може да бъде след текущото време.,
+To Time cannot be after the current time.,To Time не може да бъде след текущото време.,
+Stock Entry {0} created and ,Запис на запас {0} създаден и,
+Inpatient Medication Orders updated successfully,Поръчките за стационарни лекарства се актуализират успешно,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Ред {0}: Не може да се създаде запис за стационарно лекарство срещу отменена заповед за стационарно лечение {1},
+Row {0}: This Medication Order is already marked as completed,Ред {0}: Тази поръчка за лекарства вече е отбелязана като изпълнена,
+Quantity not available for {0} in warehouse {1},Количеството не е налично за {0} в склада {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"Моля, активирайте Разрешаване на отрицателни запаси в настройките на запасите или създайте запис на запаси, за да продължите.",
+No Inpatient Record found against patient {0},Не е открит стационарен запис срещу пациент {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Вече съществува заповед за стационарно лечение {0} срещу среща с пациент {1}.,
+Allow In Returns,Разрешаване на връщания,
+Hide Unavailable Items,Скриване на недостъпните елементи,
+Apply Discount on Discounted Rate,Приложете отстъпка при отстъпка,
+Therapy Plan Template,Шаблон за план за терапия,
+Fetching Template Details,Извличане на подробности за шаблона,
+Linked Item Details,Свързани подробности за артикула,
+Therapy Types,Видове терапия,
+Therapy Plan Template Detail,Подробности за шаблона на терапевтичния план,
+Non Conformance,Несъответствие,
+Process Owner,Собственик на процеса,
+Corrective Action,Коригиращи действия,
+Preventive Action,Превантивно действие,
+Problem,Проблем,
+Responsible,Отговорен,
+Completion By,Завършване от,
+Process Owner Full Name,Пълно име на собственика на процеса,
+Right Index,Индекс вдясно,
+Left Index,Ляв указател,
+Sub Procedure,Подпроцедура,
+Passed,Преминали,
+Print Receipt,Разписка за печат,
+Edit Receipt,Редактиране на разписка,
+Focus on search input,Фокусирайте се върху въвеждането при търсене,
+Focus on Item Group filter,Съсредоточете се върху филтъра за група артикули,
+Checkout Order / Submit Order / New Order,Поръчка за плащане / Изпращане на поръчка / Нова поръчка,
+Add Order Discount,Добавете отстъпка за поръчка,
+Item Code: {0} is not available under warehouse {1}.,Код на артикула: {0} не е наличен в склада {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,"Серийни номера не са налични за артикул {0} под склад {1}. Моля, опитайте да смените склада.",
+Fetched only {0} available serial numbers.,Извлечени са само {0} налични серийни номера.,
+Switch Between Payment Modes,Превключване между режимите на плащане,
+Enter {0} amount.,Въведете {0} сума.,
+You don't have enough points to redeem.,"Нямате достатъчно точки, за да осребрите.",
+You can redeem upto {0}.,Можете да осребрите до {0}.,
+Enter amount to be redeemed.,Въведете сума за осребряване.,
+You cannot redeem more than {0}.,Не можете да осребрите повече от {0}.,
+Open Form View,Отворете изгледа на формуляра,
+POS invoice {0} created succesfully,POS фактура {0} е създадена успешно,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Количеството на склад не е достатъчно за Код на артикула: {0} под склад {1}. Налично количество {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Сериен номер: {0} вече е транзактиран в друга POS фактура.,
+Balance Serial No,Сериен номер на баланса,
+Warehouse: {0} does not belong to {1},Склад: {0} не принадлежи на {1},
+Please select batches for batched item {0},"Моля, изберете партиди за групиран елемент {0}",
+Please select quantity on row {0},"Моля, изберете количество на ред {0}",
+Please enter serial numbers for serialized item {0},"Моля, въведете серийни номера за сериализиран елемент {0}",
+Batch {0} already selected.,Партида {0} вече е избрана.,
+Please select a warehouse to get available quantities,"Моля, изберете склад, за да получите налични количества",
+"For transfer from source, selected quantity cannot be greater than available quantity",За прехвърляне от източник избраното количество не може да бъде по-голямо от наличното количество,
+Cannot find Item with this Barcode,Не може да се намери елемент с този баркод,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} е задължително. Може би записът за обмяна на валута не е създаден за {1} до {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} изпрати активи, свързани с него. Трябва да анулирате активите, за да създадете възвръщаемост на покупката.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Не може да се анулира този документ, тъй като е свързан с изпратен актив {0}. Моля, отменете го, за да продължите.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,"Ред № {}: Сериен номер {} вече е транзактиран в друга POS фактура. Моля, изберете валиден сериен номер.",
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,"Ред № {}: Серийни номера. {} Вече е транзактиран в друга POS фактура. Моля, изберете валиден сериен номер.",
+Item Unavailable,Артикулът не е наличен,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Ред № {}: Пореден номер {} не може да бъде върнат, тъй като не е бил транзактиран в оригинална фактура {}",
+Please set default Cash or Bank account in Mode of Payment {},"Моля, задайте по подразбиране Парична или банкова сметка в режим на плащане {}",
+Please set default Cash or Bank account in Mode of Payments {},"Моля, задайте по подразбиране Парична или банкова сметка в режим на плащане {}",
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Моля, уверете се, че {} акаунтът е акаунт в баланса. Можете да промените родителския акаунт на акаунт в баланс или да изберете друг акаунт.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Моля, уверете се, че {} акаунтът е платежна сметка. Променете типа акаунт на Платимо или изберете друг акаунт.",
+Row {}: Expense Head changed to {} ,Ред {}: Разходната глава е променена на {},
+because account {} is not linked to warehouse {} ,защото акаунтът {} не е свързан със склад {},
+or it is not the default inventory account,или това не е основната сметка за инвентара,
+Expense Head Changed,Главата на разходите е променена,
+because expense is booked against this account in Purchase Receipt {},защото разходите се записват срещу този акаунт в разписка за покупка {},
+as no Purchase Receipt is created against Item {}. ,тъй като не се създава разписка за покупка срещу артикул {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Това се прави, за да се обработи счетоводното отчитане на случаи, когато разписка за покупка се създава след фактура за покупка",
+Purchase Order Required for item {},Поръчка за покупка се изисква за артикул {},
+To submit the invoice without purchase order please set {} ,"За да подадете фактура без поръчка за покупка, моля, задайте {}",
+as {} in {},като {} в {},
+Mandatory Purchase Order,Задължителна поръчка за покупка,
+Purchase Receipt Required for item {},Изисква се разписка за покупка за артикул {},
+To submit the invoice without purchase receipt please set {} ,"За да подадете фактурата без разписка за покупка, моля, задайте {}",
+Mandatory Purchase Receipt,Задължителна разписка за покупка,
+POS Profile {} does not belongs to company {},POS профил {} не принадлежи на компания {},
+User {} is disabled. Please select valid user/cashier,"Потребителят {} е деактивиран. Моля, изберете валиден потребител / касиер",
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Ред № {}: Оригинална фактура {} на фактура за връщане {} е {}.,
+Original invoice should be consolidated before or along with the return invoice.,Оригиналната фактура трябва да бъде консолидирана преди или заедно с фактурата за връщане.,
+You can add original invoice {} manually to proceed.,"Можете да добавите оригинална фактура {} ръчно, за да продължите.",
+Please ensure {} account is a Balance Sheet account. ,"Моля, уверете се, че {} акаунтът е акаунт в баланса.",
+You can change the parent account to a Balance Sheet account or select a different account.,Можете да промените родителския акаунт на акаунт в баланс или да изберете друг акаунт.,
+Please ensure {} account is a Receivable account. ,"Моля, уверете се, че {} акаунтът е сметка за вземания.",
+Change the account type to Receivable or select a different account.,Променете типа акаунт на Вземане или изберете друг акаунт.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"{} не може да бъде отменено, тъй като спечелените точки за лоялност са осребрени. Първо анулирайте {} Не {}",
+already exists,вече съществува,
+POS Closing Entry {} against {} between selected period,Затваряне на POS влизане {} срещу {} между избрания период,
+POS Invoice is {},POS фактурата е {},
+POS Profile doesn't matches {},POS профилът не съвпада с {},
+POS Invoice is not {},POS фактура не е {},
+POS Invoice isn't created by user {},POS фактура не е създадена от потребител {},
+Row #{}: {},Ред № {}: {},
+Invalid POS Invoices,Невалидни POS фактури,
+Please add the account to root level Company - {},"Моля, добавете акаунта към основна компания - {}",
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Докато създавате акаунт за Child Company {0}, родителският акаунт {1} не е намерен. Моля, създайте родителския акаунт в съответното COA",
+Account Not Found,Акаунтът не е намерен,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Докато създавахте акаунт за Child Company {0}, родителският акаунт {1} беше намерен като акаунт в дневник.",
+Please convert the parent account in corresponding child company to a group account.,"Моля, конвертирайте родителския акаунт в съответната дъщерна компания в групов акаунт.",
+Invalid Parent Account,Невалиден родителски акаунт,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Преименуването му е разрешено само чрез компанията майка {0}, за да се избегне несъответствие.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Ако {0} {1} количество от артикула {2}, схемата {3} ще бъде приложена върху артикула.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ако {0} {1} си заслужавате елемент {2}, схемата {3} ще бъде приложена върху елемента.",
+"As the field {0} is enabled, the field {1} is mandatory.","Тъй като полето {0} е активирано, полето {1} е задължително.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Тъй като полето {0} е активирано, стойността на полето {1} трябва да бъде повече от 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Не може да се достави сериен номер {0} на артикул {1}, тъй като е резервиран за пълна поръчка за продажба {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Поръчката за продажба {0} има резервация за артикула {1}, можете да доставите само резервирана {1} срещу {0}.",
+{0} Serial No {1} cannot be delivered,{0} Сериен номер {1} не може да бъде доставен,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Ред {0}: Подизпълнителят е задължителен за суровината {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Тъй като има достатъчно суровини, не е необходима заявка за материал за Склад {0}.",
+" If you still want to proceed, please enable {0}.","Ако все пак искате да продължите, моля, активирайте {0}.",
+The item referenced by {0} - {1} is already invoiced,"Позицията, посочена от {0} - {1}, вече е фактурирана",
+Therapy Session overlaps with {0},Терапевтичната сесия се припокрива с {0},
+Therapy Sessions Overlapping,Терапевтични сесии Припокриване,
+Therapy Plans,Планове за терапия,
+"Item Code, warehouse, quantity are required on row {0}","Код на артикул, склад, количество се изискват на ред {0}",
+Get Items from Material Requests against this Supplier,Вземете артикули от заявки за материали срещу този доставчик,
+Enable European Access,Активирайте европейския достъп,
+Creating Purchase Order ...,Създаване на поръчка ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Изберете доставчик от доставчиците по подразбиране на елементите по-долу. При избора ще бъде направена Поръчка за покупка срещу артикули, принадлежащи само на избрания Доставчик.",
+Row #{}: You must select {} serial numbers for item {}.,Ред № {}: Трябва да изберете {} серийни номера за артикул {}.,
diff --git a/erpnext/translations/bn.csv b/erpnext/translations/bn.csv
index 349df65..cf09716 100644
--- a/erpnext/translations/bn.csv
+++ b/erpnext/translations/bn.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},প্রকৃত টাইপ ট্যাক্স সারিতে আইটেম রেট অন্তর্ভুক্ত করা যাবে না {0},
Add,যোগ,
Add / Edit Prices,/ সম্পাদনা বর্ণনা করো,
-Add All Suppliers,সমস্ত সরবরাহকারী যোগ করুন,
Add Comment,মন্তব্য যোগ করুন,
Add Customers,গ্রাহকরা যোগ করুন,
Add Employees,এমপ্লয়িজ যোগ,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',কেটে যাবে না যখন আরো মূল্যনির্ধারণ 'বা' Vaulation এবং মোট 'জন্য নয়,
"Cannot delete Serial No {0}, as it is used in stock transactions","মুছে ফেলা যায় না সিরিয়াল কোন {0}, এটা শেয়ার লেনদেনের ক্ষেত্রে ব্যবহার করা হয় যেমন",
Cannot enroll more than {0} students for this student group.,{0} এই ছাত্র দলের জন্য ছাত্রদের তুলনায় আরো নথিভুক্ত করা যায় না.,
-Cannot find Item with this barcode,এই বারকোড সহ আইটেমটি খুঁজে পাওয়া যায় না,
Cannot find active Leave Period,সক্রিয় ছাড়ের সময়কাল খুঁজে পাওয়া যাবে না,
Cannot produce more Item {0} than Sales Order quantity {1},সেলস আদেশ পরিমাণ বেশী আইটেম {0} সৃষ্টি করতে পারে না {1},
Cannot promote Employee with status Left,কর্মচারী উন্নয়নে স্থিরতা বজায় রাখতে পারে না,
Cannot refer row number greater than or equal to current row number for this Charge type,এই চার্জ ধরণ জন্য বর্তমান সারির সংখ্যা এর চেয়ে বড় বা সমান সারির সংখ্যা পড়ুন করতে পারবেন না,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,প্রথম সারির 'পূর্ববর্তী সারি মোট' 'পূর্ববর্তী সারি পরিমাণ' হিসেবে অভিযোগ টাইপ নির্বাচন করা বা না করা,
-Cannot set a received RFQ to No Quote,কোন উদ্ধৃত কোন প্রাপ্ত RFQ সেট করতে পারবেন না,
Cannot set as Lost as Sales Order is made.,বিক্রয় আদেশ তৈরি করা হয় যেমন বিচ্ছিন্ন সেট করা যায় না.,
Cannot set authorization on basis of Discount for {0},জন্য ছাড়ের ভিত্তিতে অনুমোদন সেট করা যায় না {0},
Cannot set multiple Item Defaults for a company.,একটি কোম্পানির জন্য একাধিক আইটেম ডিফল্ট সেট করতে পারবেন না।,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,চার্জ প্রতিটি আইটেমের বিরুদ্ধে কেনার রসিদ মধ্যে আপডেট করা হয়,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","চার্জ আনুপাতিক আপনার নির্বাচন অনুযায়ী, আইটেম Qty বা পরিমাণ উপর ভিত্তি করে বিতরণ করা হবে",
-Chart Of Accounts,হিসাবরক্ষনের তালিকা,
Chart of Cost Centers,খরচ কেন্দ্র এর চার্ট,
Check all,সবগুলু যাচাই করুন,
Checkout,চেকআউট,
@@ -581,7 +577,6 @@
Compensatory Off,পূরক অফ,
Compensatory leave request days not in valid holidays,বাধ্যতামূলক ছুটি অনুরোধ দিন বৈধ ছুটির দিন না,
Complaint,অভিযোগ,
-Completed Qty can not be greater than 'Qty to Manufacture',চেয়ে 'স্টক প্রস্তুত করতে' সম্পন্ন Qty বৃহত্তর হতে পারে না,
Completion Date,সমাপ্তির তারিখ,
Computer,কম্পিউটার,
Condition,শর্ত,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","তৈরি করুন এবং দৈনিক, সাপ্তাহিক এবং মাসিক ইমেল digests পরিচালনা.",
Create customer quotes,গ্রাহকের কোট তৈরি করুন,
Create rules to restrict transactions based on values.,মান উপর ভিত্তি করে লেনদেনের সীমিত করার নিয়ম তৈরি করুন.,
-Created By,দ্বারা নির্মিত,
Created {0} scorecards for {1} between: ,{1} এর জন্য {1} স্কোরকার্ড তৈরি করেছেন:,
Creating Company and Importing Chart of Accounts,সংস্থা তৈরি করা এবং অ্যাকাউন্টগুলির আমদানি চার্ট,
Creating Fees,ফি তৈরি করা,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,স্থানান্তর তারিখ আগে কর্মচারী স্থানান্তর জমা দেওয়া যাবে না,
Employee cannot report to himself.,কর্মচারী নিজেকে প্রতিবেদন করতে পারবে না.,
Employee relieved on {0} must be set as 'Left',{0} নির্ধারণ করা আবশ্যক উপর অব্যাহতিপ্রাপ্ত কর্মচারী 'বাম' হিসাবে,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,নিম্নোক্ত কর্মীরা বর্তমানে এই কর্মচারীর প্রতিবেদন করছেন বলে কর্মচারীর অবস্থা 'বামে' সেট করা যাবে না:,
Employee {0} already submited an apllication {1} for the payroll period {2},কর্মচারী {0} ইতিমধ্যে payroll সময়ের {2} জন্য একটি anpllication {1} জমা দিয়েছে,
Employee {0} has already applied for {1} between {2} and {3} : ,কর্মচারী {0} ইতিমধ্যে {1} এবং {3} এর মধ্যে {1} জন্য প্রয়োগ করেছেন:,
Employee {0} has no maximum benefit amount,কর্মচারী {0} এর সর্বাধিক বেনিফিট পরিমাণ নেই,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,সারি {0} জন্য: পরিকল্পিত পরিমাণ লিখুন,
"For {0}, only credit accounts can be linked against another debit entry","{0}, শুধুমাত্র ক্রেডিট অ্যাকাউন্ট অন্য ডেবিট এন্ট্রি বিরুদ্ধে সংযুক্ত করা যাবে জন্য",
"For {0}, only debit accounts can be linked against another credit entry","{0}, শুধুমাত্র ডেবিট অ্যাকাউন্ট অন্য ক্রেডিট এন্ট্রি বিরুদ্ধে সংযুক্ত করা যাবে জন্য",
-Form View,ফর্ম দেখুন,
Forum Activity,ফোরাম কার্যক্রম,
Free item code is not selected,ফ্রি আইটেম কোড নির্বাচন করা হয়নি,
Freight and Forwarding Charges,মাল ও ফরোয়ার্ডিং চার্জ,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","আগে বরাদ্দ করা না যাবে ছেড়ে {0}, ছুটি ভারসাম্য ইতিমধ্যে হ্যান্ড ফরওয়ার্ড ভবিষ্যতে ছুটি বরাদ্দ রেকর্ড হয়েছে হিসাবে {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ছুটি ভারসাম্য ইতিমধ্যে হ্যান্ড ফরওয়ার্ড ভবিষ্যতে ছুটি বরাদ্দ রেকর্ড হয়েছে হিসাবে, আগে {0} বাতিল / প্রয়োগ করা যাবে না ছেড়ে {1}",
Leave of type {0} cannot be longer than {1},ধরনের ছুটি {0} চেয়ে বেশি হতে পারেনা {1},
-Leave the field empty to make purchase orders for all suppliers,সব সরবরাহকারীদের জন্য ক্রয় আদেশ করতে ফাঁকা ক্ষেত্র ত্যাগ করুন,
Leaves,পত্রাদি,
Leaves Allocated Successfully for {0},সাফল্যের বরাদ্দ পাতার {0},
Leaves has been granted sucessfully,পাতাগুলি সফলভাবে দেওয়া হয়েছে,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,সামগ্রী বিল দিয়ে কোন সামগ্রী উত্পাদনপ্রণালী,
No Items with Bill of Materials.,বিল আইটেমস সহ কোনও আইটেম নেই।,
No Permission,অনুমতি নেই,
-No Quote,কোন উদ্ধৃতি নেই,
No Remarks,কোন মন্তব্য,
No Result to submit,কোন ফলাফল জমা নেই,
No Salary Structure assigned for Employee {0} on given date {1},প্রদত্ত তারিখের {0} কর্মচারীর জন্য নির্ধারিত কোন বেতন কাঠামো {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,মধ্যে পাওয়া ওভারল্যাপিং শর্ত:,
Owner,মালিক,
PAN,প্যান,
-PO already created for all sales order items,PO ইতিমধ্যে সমস্ত বিক্রয় আদেশ আইটেম জন্য তৈরি,
POS,পিওএস,
POS Profile,পিওএস প্রোফাইল,
POS Profile is required to use Point-of-Sale,পয়েন্ট-অফ-সেল ব্যবহার করার জন্য পিওএস প্রোফাইল প্রয়োজন,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,প্রথম অভিযোগ টাইপ নির্বাচন করুন,
Please select Company,কোম্পানি নির্বাচন করুন,
Please select Company and Designation,দয়া করে কোম্পানি এবং মনোনীত নির্বাচন করুন,
-Please select Company and Party Type first,প্রথম কোম্পানি ও অনুষ্ঠান প্রকার নির্বাচন করুন,
Please select Company and Posting Date to getting entries,অনুগ্রহ করে এন্ট্রি পাওয়ার জন্য কোম্পানি এবং পোস্টিং তারিখ নির্বাচন করুন,
Please select Company first,প্রথম কোম্পানি নির্বাচন করুন,
Please select Completion Date for Completed Asset Maintenance Log,সম্পুর্ণ সম্পত্তির রক্ষণাবেক্ষণ লগের জন্য সমাপ্তির তারিখ নির্বাচন করুন,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,সারি {0}: UOM রূপান্তর ফ্যাক্টর বাধ্যতামূলক,
Row {0}: select the workstation against the operation {1},সারি {0}: অপারেশন {1} বিরুদ্ধে ওয়ার্কস্টেশন নির্বাচন করুন,
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,সারি {0}: {1} আইটেমের জন্য প্রয়োজনীয় সিরিয়াল নম্বর {2}। আপনি {3} প্রদান করেছেন।,
-Row {0}: {1} is required to create the Opening {2} Invoices,সারি {0}: {1} ওপেনিং {2} চালান তৈরি করতে হবে,
Row {0}: {1} must be greater than 0,সারি {0}: {1} 0 এর থেকে বড় হতে হবে,
Row {0}: {1} {2} does not match with {3},সারি {0}: {1} {2} সঙ্গে মেলে না {3},
Row {0}:Start Date must be before End Date,সারি {0}: আরম্ভের তারিখ শেষ তারিখের আগে হওয়া আবশ্যক,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,গ্রান্ট রিভিউ ইমেল পাঠান,
Send Now,এখন পাঠান,
Send SMS,এসএমএস পাঠান,
-Send Supplier Emails,সরবরাহকারী ইমেইল পাঠান,
Send mass SMS to your contacts,ভর এসএমএস আপনার পরিচিতি পাঠান,
Sensitivity,সংবেদনশীলতা,
Sent,প্রেরিত,
-Serial #,সিরিয়াল #,
Serial No and Batch,ক্রমিক নং এবং ব্যাচ,
Serial No is mandatory for Item {0},সিরিয়াল কোন আইটেম জন্য বাধ্যতামূলক {0},
Serial No {0} does not belong to Batch {1},সিরিয়াল না {0} ব্যাচের অন্তর্গত নয় {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"আপনার কোম্পানির নাম, যার জন্য আপনি এই সিস্টেম সেট আপ করা হয়.",
The number of shares and the share numbers are inconsistent,শেয়ার সংখ্যা এবং শেয়ার নম্বর অসম্পূর্ণ,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,এই পেমেন্ট অনুরোধে পেমেন্ট গেটওয়ে অ্যাকাউন্ট থেকে প্ল্যান {0} পেমেন্ট গেটওয়ে অ্যাকাউন্টটি ভিন্ন,
-The request for quotation can be accessed by clicking on the following link,উদ্ধৃতি জন্য অনুরোধ নিম্নলিখিত লিঙ্কে ক্লিক করে প্রবেশ করা যেতে পারে,
The selected BOMs are not for the same item,নির্বাচিত BOMs একই আইটেমের জন্য নয়,
The selected item cannot have Batch,নির্বাচিত আইটেমের ব্যাচ থাকতে পারে না,
The seller and the buyer cannot be the same,বিক্রেতা এবং ক্রেতা একই হতে পারে না,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},মোট নমনীয় সুবিধা উপাদান পরিমাণ {0} সর্বোচ্চ সুবিধাগুলির চেয়ে কম হওয়া উচিত নয় {1},
Total hours: {0},মোট ঘন্টা: {0},
Total leaves allocated is mandatory for Leave Type {0},বন্টন প্রকারের {0} জন্য বরাদ্দকৃত মোট পাতার বাধ্যতামূলক,
-Total weightage assigned should be 100%. It is {0},100% হওয়া উচিত নির্ধারিত মোট গুরুত্ব. এটা হল {0},
Total working hours should not be greater than max working hours {0},মোট কাজ ঘন্টা সর্বোচ্চ কর্মঘন্টা চেয়ে বেশী করা উচিত হবে না {0},
Total {0} ({1}),মোট {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","মোট {0} সব আইটেম জন্য শূন্য, আপনি 'উপর ভিত্তি করে চার্জ বিতরণ' পরিবর্তন করা উচিত হতে পারে",
@@ -3316,7 +3299,6 @@
What do you need help with?,আপনি সাহায্য প্রয়োজন কি?,
What does it do?,এটার কাজ কি?,
Where manufacturing operations are carried.,উত্পাদন অপারেশন কোথায় সম্পন্ন হয়.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","চাইল্ড কোম্পানির জন্য অ্যাকাউন্ট তৈরি করার সময় {0}, প্যারেন্ট অ্যাকাউন্ট {1} পাওয়া যায় নি। অনুগ্রহ করে সংশ্লিষ্ট সিওএতে প্যারেন্ট অ্যাকাউন্টটি তৈরি করুন",
White,সাদা,
Wire Transfer,ওয়্যার ট্রান্সফার,
WooCommerce Products,WooCommerce পণ্য,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} বৈকল্পিক তৈরি করা হয়েছে।,
{0} {1} created,{0} {1} সৃষ্টি,
{0} {1} does not exist,{0} {1} অস্তিত্ব নেই,
-{0} {1} does not exist.,{0} {1} বিদ্যমান নেই,
{0} {1} has been modified. Please refresh.,{0} {1} নথীটি পরিবর্তিত হয়েছে. রিফ্রেশ করুন.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} জমা দেওয়া হয়েছে করেননি তাই কর্ম সম্পন্ন করা যাবে না,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} {2} সাথে যুক্ত, কিন্তু পার্টি অ্যাকাউন্ট {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} বিদ্যমান নয়,
{0}: {1} not found in Invoice Details table,{0}: {1} চালান বিবরণ টেবিল মধ্যে পাওয়া যায়নি,
{} of {},{} এর {},
+Assigned To,নিযুক্ত করা,
Chat,চ্যাট,
Completed By,দ্বারা সম্পন্ন,
Conditions,পরিবেশ,
@@ -3506,7 +3488,9 @@
Merge with existing,বিদ্যমান সাথে একত্রীকরণ,
Office,অফিস,
Orientation,ঝোঁক,
+Parent,মাতা,
Passive,নিষ্ক্রিয়,
+Payment Failed,পেমেন্ট ব্যর্থ হয়েছে,
Percent,শতাংশ,
Permanent,স্থায়ী,
Personal,ব্যক্তিগত,
@@ -3544,7 +3528,6 @@
Company field is required,কোম্পানির ক্ষেত্র প্রয়োজন,
Creating Dimensions...,মাত্রা তৈরি করা হচ্ছে ...,
Duplicate entry against the item code {0} and manufacturer {1},আইটেম কোড {0} এবং প্রস্তুতকারকের {1 against এর বিপরীতে সদৃশ প্রবেশ,
-Import Chart Of Accounts from CSV / Excel files,সিএসভি / এক্সেল ফাইলগুলি থেকে অ্যাকাউন্টগুলির চার্ট আমদানি করুন,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,অবৈধ জিএসটিআইএন! আপনি যে ইনপুটটি প্রবেশ করেছেন তা ইউআইএন হোল্ডার বা অনাবাসিক OIDAR পরিষেবা সরবরাহকারীদের জন্য জিএসটিআইএন ফর্ম্যাটের সাথে মেলে না,
Invoice Grand Total,চালান গ্র্যান্ড টোটাল,
Last carbon check date cannot be a future date,শেষ কার্বন চেকের তারিখ কোনও ভবিষ্যতের তারিখ হতে পারে না,
@@ -3556,6 +3539,7 @@
Show {0},{0} দেখান,
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","নামকরণ সিরিজে "-", "#", "।", "/", "{" এবং "}" ব্যতীত বিশেষ অক্ষর অনুমোদিত নয়",
Target Details,টার্গেটের বিশদ,
+{0} already has a Parent Procedure {1}.,{0} ইতিমধ্যে একটি মূল পদ্ধতি আছে {1}।,
API,এপিআই,
Annual,বার্ষিক,
Approved,অনুমোদিত,
@@ -3572,6 +3556,8 @@
No data to export,রফতানির জন্য কোনও ডেটা নেই,
Portrait,প্রতিকৃতি,
Print Heading,প্রিন্ট শীর্ষক,
+Scheduler Inactive,সময়সূচী নিষ্ক্রিয়,
+Scheduler is inactive. Cannot import data.,সময়সূচী নিষ্ক্রিয়। ডেটা আমদানি করা যায় না।,
Show Document,দস্তাবেজ দেখান,
Show Traceback,ট্রেসব্যাক প্রদর্শন করুন,
Video,ভিডিও,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},আইটেমের জন্য গুণগত পরিদর্শন তৈরি করুন {0},
Creating Accounts...,অ্যাকাউন্ট তৈরি করা হচ্ছে ...,
Creating bank entries...,ব্যাঙ্ক এন্ট্রি তৈরি করা হচ্ছে ...,
-Creating {0},{0} তৈরি করা হচ্ছে,
Credit limit is already defined for the Company {0},ক্রেডিট সীমা ইতিমধ্যে সংস্থার জন্য নির্ধারিত হয়েছে {0},
Ctrl + Enter to submit,জমা দিতে Ctrl + Enter,
Ctrl+Enter to submit,জমা দিতে Ctrl + লিখুন,
@@ -3921,7 +3906,6 @@
Plaid public token error,প্লেড পাবলিক টোকেন ত্রুটি,
Plaid transactions sync error,প্লেড লেনদেনের সিঙ্ক ত্রুটি,
Please check the error log for details about the import errors,আমদানি ত্রুটি সম্পর্কে বিশদ জন্য ত্রুটি লগ চেক করুন,
-Please click on the following link to set your new password,আপনার নতুন পাসওয়ার্ড সেট করতে নিচের লিঙ্কে ক্লিক করুন,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,দয়া করে কোম্পানির জন্য <b>DATEV সেটিংস</b> তৈরি করুন <b>}}</b>,
Please create adjustment Journal Entry for amount {0} ,দয়া করে} 0 amount পরিমাণের জন্য সামঞ্জস্য জার্নাল এন্ট্রি তৈরি করুন,
Please do not create more than 500 items at a time,দয়া করে একবারে 500 টিরও বেশি আইটেম তৈরি করবেন না,
@@ -3997,6 +3981,7 @@
Release date must be in the future,প্রকাশের তারিখ অবশ্যই ভবিষ্যতে হবে,
Relieving Date must be greater than or equal to Date of Joining,মুক্তির তারিখ অবশ্যই যোগদানের তারিখের চেয়ে বড় বা সমান হতে হবে,
Rename,পুনঃনামকরণ,
+Rename Not Allowed,পুনঃনামকরণ অনুমোদিত নয়,
Repayment Method is mandatory for term loans,মেয়াদী loansণের জন্য পরিশোধের পদ্ধতি বাধ্যতামূলক,
Repayment Start Date is mandatory for term loans,মেয়াদী loansণের জন্য পরিশোধ পরিশোধের তারিখ বাধ্যতামূলক,
Report Item,আইটেম প্রতিবেদন করুন,
@@ -4043,7 +4028,6 @@
Select All,সবগুলো নির্বাচন করা,
Select Difference Account,ডিফারেন্স অ্যাকাউন্ট নির্বাচন করুন,
Select a Default Priority.,একটি ডিফল্ট অগ্রাধিকার নির্বাচন করুন।,
-Select a Supplier from the Default Supplier List of the items below.,নীচের আইটেমগুলির ডিফল্ট সরবরাহকারী তালিকা থেকে একটি সরবরাহকারী নির্বাচন করুন।,
Select a company,একটি সংস্থা নির্বাচন করুন,
Select finance book for the item {0} at row {1},সারি for 1} আইটেমের জন্য book 0 finance জন্য অর্থ বই নির্বাচন করুন,
Select only one Priority as Default.,ডিফল্ট হিসাবে কেবলমাত্র একটি অগ্রাধিকার নির্বাচন করুন।,
@@ -4247,7 +4231,6 @@
Actual ,আসল,
Add to cart,কার্ট যোগ করুন,
Budget,বাজেট,
-Chart Of Accounts Importer,অ্যাকাউন্ট আমদানিকারক চার্ট,
Chart of Accounts,হিসাবরক্ষনের তালিকা,
Customer database.,গ্রাহক ডাটাবেস।,
Days Since Last order,শেষ আদেশের দিনগুলি,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,শেষ তারিখ শুরু তারিখ থেকে কম হতে পারে না,
For Default Supplier (Optional),ডিফল্ট সরবরাহকারীর জন্য (ঐচ্ছিক),
From date cannot be greater than To date,তারিখ থেকে তারিখের চেয়ে বেশি হতে পারে না,
-Get items from,থেকে আইটেম পান,
Group by,গ্রুপ দ্বারা,
In stock,স্টক ইন,
Item name,আইটেম নাম,
@@ -4532,32 +4514,22 @@
Accounts Settings,সেটিংস অ্যাকাউন্ট,
Settings for Accounts,অ্যাকাউন্ট এর জন্য সেটিং,
Make Accounting Entry For Every Stock Movement,প্রতি স্টক আন্দোলনের জন্য অ্যাকাউন্টিং এন্ট্রি করতে,
-"If enabled, the system will post accounting entries for inventory automatically.","সক্রিয় করা হলে, সিস্টেম স্বয়ংক্রিয়ভাবে পরিসংখ্যা জন্য অ্যাকাউন্টিং এন্ট্রি পোস্ট করতে হবে.",
-Accounts Frozen Upto,হিমায়িত পর্যন্ত অ্যাকাউন্ট,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","এই ডেট নিথর অ্যাকাউন্টিং এন্ট্রি, কেউ / না নিম্নোল্লিখিত শর্ত ভূমিকা ছাড়া এন্ট্রি পরিবর্তন করতে পারেন.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,ভূমিকা হিমায়িত একাউন্টস ও সম্পাদনা হিমায়িত সাজপোশাকটি সেট করার মঞ্জুরি,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,এই ব্যবহারকারীরা হিমায়িত অ্যাকাউন্ট বিরুদ্ধে হিসাব থেকে হিমায়িত অ্যাকাউন্ট সেট এবং তৈরি / পরিবর্তন করার অনুমতি দেওয়া হয়,
Determine Address Tax Category From,এড্রেস ট্যাক্স বিভাগ থেকে নির্ধারণ করুন,
-Address used to determine Tax Category in transactions.,লেনদেনে ট্যাক্স বিভাগ নির্ধারণ করতে ব্যবহৃত ঠিকানা Address,
Over Billing Allowance (%),ওভার বিলিং ভাতা (%),
-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 for $110.,অর্ডারের পরিমাণের তুলনায় আপনাকে আরও বেশি বিল দেওয়ার অনুমতি দেওয়া হচ্ছে শতাংশ। উদাহরণস্বরূপ: যদি কোনও আইটেমের জন্য অর্ডার মান $ 100 এবং সহনশীলতা 10% হিসাবে সেট করা থাকে তবে আপনাকে 110 ডলারে বিল দেওয়ার অনুমতি দেওয়া হবে।,
Credit Controller,ক্রেডিট কন্ট্রোলার,
-Role that is allowed to submit transactions that exceed credit limits set.,সেট ক্রেডিট সীমা অতিক্রম লেনদেন জমা করার অনুমতি দেওয়া হয় যে ভূমিকা.,
Check Supplier Invoice Number Uniqueness,চেক সরবরাহকারী চালান নম্বর স্বতন্ত্রতা,
Make Payment via Journal Entry,জার্নাল এন্ট্রি মাধ্যমে টাকা প্রাপ্তির,
Unlink Payment on Cancellation of Invoice,চালান বাতিলের পেমেন্ট লিঙ্কমুক্ত,
-Unlink Advance Payment on Cancelation of Order,অর্ডার বাতিলকরণে অগ্রিম প্রদানের লিঙ্কমুক্ত করুন,
Book Asset Depreciation Entry Automatically,বইয়ের অ্যাসেট অবচয় এণ্ট্রি স্বয়ংক্রিয়ভাবে,
Automatically Add Taxes and Charges from Item Tax Template,আইটেম ট্যাক্স টেম্পলেট থেকে স্বয়ংক্রিয়ভাবে কর এবং চার্জ যুক্ত করুন,
Automatically Fetch Payment Terms,স্বয়ংক্রিয়ভাবে প্রদানের শর্তাদি আনুন,
-Show Inclusive Tax In Print,প্রিন্ট ইন ইনজেকশন ট্যাক্স দেখান,
Show Payment Schedule in Print,প্রিন্ট ইন পেমেন্ট শেল্ড দেখান,
Currency Exchange Settings,মুদ্রা বিনিময় সেটিংস,
Allow Stale Exchange Rates,স্টেলা এক্সচেঞ্জের হার মঞ্জুর করুন,
Stale Days,স্টাইল দিন,
Report Settings,রিপোর্ট সেটিংস,
Use Custom Cash Flow Format,কাস্টম ক্যাশ ফ্লো বিন্যাস ব্যবহার করুন,
-Only select if you have setup Cash Flow Mapper documents,যদি আপনি সেটআপ ক্যাশ ফ্লো ম্যাপার ডকুমেন্টগুলি নির্বাচন করেন তবে কেবল নির্বাচন করুন,
Allowed To Transact With,সঙ্গে লেনদেন অনুমোদিত,
SWIFT number,দ্রুতগতি সংখ্যা,
Branch Code,শাখা কোড,
@@ -4940,7 +4912,6 @@
POS Customer Group,পিওএস গ্রাহক গ্রুপ,
POS Field,পস ফিল্ড,
POS Item Group,পিওএস আইটেম গ্রুপ,
-[Select],[নির্বাচন],
Company Address,প্রতিস্থান এর ঠিকানা,
Update Stock,আপডেট শেয়ার,
Ignore Pricing Rule,প্রাইসিং বিধি উপেক্ষা,
@@ -5495,8 +5466,6 @@
Supplier Naming By,দ্বারা সরবরাহকারী নেমিং,
Default Supplier Group,ডিফল্ট সরবরাহকারী গ্রুপ,
Default Buying Price List,ডিফল্ট ক্রয় মূল্য তালিকা,
-Maintain same rate throughout purchase cycle,কেনার চক্র সারা একই হার বজায় রাখা,
-Allow Item to be added multiple times in a transaction,আইটেম একটি লেনদেনের মধ্যে একাধিক বার যুক্ত করা সম্ভব,
Backflush Raw Materials of Subcontract Based On,উপর ভিত্তি করে Subcontract এর কাঁচামাল Backflush,
Material Transferred for Subcontract,উপসম্পাদকীয় জন্য উপাদান হস্তান্তর,
Over Transfer Allowance (%),ওভার ট্রান্সফার ভাতা (%),
@@ -5540,7 +5509,6 @@
Current Stock,বর্তমান তহবিল,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,পৃথক সরবরাহকারী জন্য,
-Supplier Detail,সরবরাহকারী বিস্তারিত,
Link to Material Requests,উপাদান অনুরোধ লিঙ্ক,
Message for Supplier,সরবরাহকারী জন্য বার্তা,
Request for Quotation Item,উদ্ধৃতি আইটেম জন্য অনুরোধ,
@@ -6481,7 +6449,6 @@
Appraisal Template,মূল্যায়ন টেমপ্লেট,
For Employee Name,কর্মচারীর নাম জন্য,
Goals,গোল,
-Calculate Total Score,মোট স্কোর গণনা করা,
Total Score (Out of 5),(5 এর মধ্যে) মোট স্কোর,
"Any other remarks, noteworthy effort that should go in the records.","অন্য কোন মন্তব্য, রেকর্ড মধ্যে যেতে হবে যে উল্লেখযোগ্য প্রচেষ্টা.",
Appraisal Goal,মূল্যায়ন গোল,
@@ -6599,11 +6566,6 @@
Reason for Leaving,ত্যাগ করার জন্য কারণ,
Leave Encashed?,Encashed ত্যাগ করবেন?,
Encashment Date,নগদীকরণ তারিখ,
-Exit Interview Details,প্রস্থান ইন্টারভিউ এর বর্ণনা,
-Held On,অনুষ্ঠিত,
-Reason for Resignation,পদত্যাগ করার কারণ,
-Better Prospects,ভাল সম্ভাবনা,
-Health Concerns,স্বাস্থ সচেতন,
New Workplace,নতুন কর্মক্ষেত্রে,
HR-EAD-.YYYY.-,এইচআর-EAD-.YYYY.-,
Returned Amount,ফেরত পরিমাণ,
@@ -6740,10 +6702,7 @@
Employee Settings,কর্মচারী সেটিংস,
Retirement Age,কর্ম - ত্যাগ বয়ম,
Enter retirement age in years,বছরে অবসরের বয়স লিখুন,
-Employee Records to be created by,কর্মচারী রেকর্ড করে তৈরি করা,
-Employee record is created using selected field. ,কর্মচারী রেকর্ড নির্বাচিত ক্ষেত্র ব্যবহার করে নির্মিত হয়.,
Stop Birthday Reminders,বন্ধ করুন জন্মদিনের রিমাইন্ডার,
-Don't send Employee Birthday Reminders,কর্মচারী জন্মদিনের রিমাইন্ডার পাঠাবেন না,
Expense Approver Mandatory In Expense Claim,ব্যয় দাবি মধ্যে ব্যয়বহুল ব্যয়বহুল,
Payroll Settings,বেতনের সেটিংস,
Leave,ছেড়ে দিন,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,আবেদন ত্যাগ করুন,
Show Leaves Of All Department Members In Calendar,ক্যালেন্ডারে সকল বিভাগের সদস্যদের তালিকা দেখান,
Auto Leave Encashment,অটো ছেড়ে দিন এনক্যাশমেন্ট,
-Restrict Backdated Leave Application,ব্যাকটেড ছুটির আবেদন সীমাবদ্ধ করুন,
Hiring Settings,নিয়োগের সেটিংস,
Check Vacancies On Job Offer Creation,কাজের অফার তৈরিতে শূন্যপদগুলি পরীক্ষা করুন,
Identification Document Type,সনাক্তকরণ নথি প্রকার,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,উৎপাদন সেটিংস,
Raw Materials Consumption,কাঁচামাল ব্যবহার,
Allow Multiple Material Consumption,একাধিক উপাদান ব্যবহার অনুমোদন,
-Allow multiple Material Consumption against a Work Order,একটি ওয়ার্ক অর্ডার বিরুদ্ধে একাধিক উপাদান ব্যবহার অনুমোদন,
Backflush Raw Materials Based On,Backflush কাঁচামালের ভিত্তিতে,
Material Transferred for Manufacture,উপাদান প্রস্তুত জন্য বদলিকৃত,
Capacity Planning,ক্ষমতা পরিকল্পনা,
Disable Capacity Planning,সক্ষমতা পরিকল্পনা অক্ষম করুন,
Allow Overtime,ওভারটাইম মঞ্জুরি,
-Plan time logs outside Workstation Working Hours.,ওয়ার্কস্টেশন ওয়ার্কিং সময়ের বাইরে সময় লগ পরিকল্পনা করুন.,
Allow Production on Holidays,ছুটির উৎপাদন মঞ্জুরি,
Capacity Planning For (Days),(দিন) জন্য ক্ষমতা পরিকল্পনা,
-Try planning operations for X days in advance.,অগ্রিম এক্স দিনের জন্য অপারেশন পরিকল্পনা চেষ্টা করুন.,
-Time Between Operations (in mins),(মিনিট) অপারেশনস মধ্যে সময়,
-Default 10 mins,10 মিনিট ডিফল্ট,
Default Warehouses for Production,উত্পাদনের জন্য ডিফল্ট গুদাম,
Default Work In Progress Warehouse,প্রগতি গুদাম ডিফল্ট কাজ,
Default Finished Goods Warehouse,ডিফল্ট তৈরি পণ্য গুদাম,
Default Scrap Warehouse,ডিফল্ট স্ক্র্যাপ গুদাম,
-Over Production for Sales and Work Order,বিক্রয় ও কাজের আদেশের জন্য ওভার প্রোডাকশন,
Overproduction Percentage For Sales Order,বিক্রয় আদেশের জন্য প্রযোজক শতাংশ,
Overproduction Percentage For Work Order,কাজের আদেশের জন্য প্রযোজক শতাংশ,
Other Settings,অন্যান্য সেটিংস্,
Update BOM Cost Automatically,স্বয়ংক্রিয়ভাবে BOM খরচ আপডেট করুন,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",সর্বশেষ মূল্যনির্ধারণ হার / মূল্য তালিকা হার / কাঁচামালের সর্বশেষ ক্রয়ের হারের ভিত্তিতে স্বয়ংক্রিয়ভাবে নির্ধারিত BOM- এর মূল্য নির্ধারনের মাধ্যমে।,
Material Request Plan Item,উপাদান অনুরোধের পরিকল্পনা আইটেম,
Material Request Type,উপাদান অনুরোধ টাইপ,
Material Issue,উপাদান ইস্যু,
@@ -7603,10 +7554,6 @@
Quality Goal,মান লক্ষ্য,
Monitoring Frequency,নিরীক্ষণ ফ্রিকোয়েন্সি,
Weekday,রবিবার বাদে সপ্তাহের যে-কোন দিন,
-January-April-July-October,জানুয়ারি-এপ্রিল-জুলাই-অক্টোবর,
-Revision and Revised On,রিভিশন এবং সংশোধিত চালু,
-Revision,সংস্করণ,
-Revised On,সংশোধিত অন,
Objectives,উদ্দেশ্য,
Quality Goal Objective,গুণগত লক্ষ্য লক্ষ্য,
Objective,উদ্দেশ্য,
@@ -7619,7 +7566,6 @@
Processes,প্রসেস,
Quality Procedure Process,গুণমান প্রক্রিয়া প্রক্রিয়া,
Process Description,প্রক্রিয়া বর্ণনা,
-Child Procedure,শিশু প্রক্রিয়া,
Link existing Quality Procedure.,বিদ্যমান গুণমানের পদ্ধতিটি লিঙ্ক করুন।,
Additional Information,অতিরিক্ত তথ্য,
Quality Review Objective,গুণ পর্যালোচনা উদ্দেশ্য,
@@ -7787,15 +7733,9 @@
Default Customer Group,ডিফল্ট গ্রাহক গ্রুপ,
Default Territory,ডিফল্ট টেরিটরি,
Close Opportunity After Days,বন্ধ সুযোগ দিন পরে,
-Auto close Opportunity after 15 days,15 দিন পর অটো বন্ধ সুযোগ,
Default Quotation Validity Days,ডিফল্ট কোটেশন বৈধতা দিন,
Sales Update Frequency,বিক্রয় আপডেট ফ্রিকোয়েন্সি,
-How often should project and company be updated based on Sales Transactions.,সেলস লেনদেনের উপর ভিত্তি করে কতগুলি প্রকল্প এবং কোম্পানিকে আপডেট করা উচিত।,
Each Transaction,প্রতিটি লেনদেন,
-Allow user to edit Price List Rate in transactions,ব্যবহারকারী লেনদেনের মূল্য তালিকা হার সম্পাদন করার অনুমতি প্রদান,
-Allow multiple Sales Orders against a Customer's Purchase Order,একটি গ্রাহকের ক্রয় আদেশের বিরুদ্ধে একাধিক বিক্রয় আদেশ মঞ্জুরি,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,যাচাই করে নিন বিক্রয় মূল্য ক্রয় হার বা মূল্যনির্ধারণ হার বিরুদ্ধে আইটেম জন্য,
-Hide Customer's Tax Id from Sales Transactions,সেলস লেনদেন থেকে গ্রাহকের ট্যাক্স আইডি লুকান,
SMS Center,এসএমএস কেন্দ্র,
Send To,পাঠানো,
All Contact,সমস্ত যোগাযোগ,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,চলছে ব্যবহৃত উৎপাদনকারী,
Limited to 12 characters,12 অক্ষরের মধ্যে সীমাবদ্ধ,
MAT-MR-.YYYY.-,Mat-এম আর-.YYYY.-,
-Set Warehouse,গুদাম সেট করুন,
-Sets 'For Warehouse' in each row of the Items table.,আইটেম টেবিলের প্রতিটি সারিতে 'গুদামের জন্য' সেট করুন।,
-Requested For,জন্য অনুরোধ করা,
Partially Ordered,আংশিক অর্ডার করা,
Transferred,স্থানান্তরিত,
% Ordered,% আদেশ,
@@ -8407,24 +8344,14 @@
Default Stock UOM,ডিফল্ট শেয়ার UOM,
Sample Retention Warehouse,নমুনা ধারণ গুদাম,
Default Valuation Method,ডিফল্ট মূল্যনির্ধারণ পদ্ধতি,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,শতকরা আপনি পাবেন বা আদেশ পরিমাণ বিরুদ্ধে আরো বিলি করার অনুমতি দেওয়া হয়. উদাহরণস্বরূপ: আপনি 100 ইউনিট আদেশ আছে. এবং আপনার ভাতা তারপর আপনি 110 ইউনিট গ্রহণ করার অনুমতি দেওয়া হয় 10% হয়.,
-Action if Quality inspection is not submitted,মান পরিদর্শন জমা না দেওয়া হলে পদক্ষেপ,
Show Barcode Field,দেখান বারকোড ফিল্ড,
Convert Item Description to Clean HTML,পরিষ্কার এইচটিএমএল আইটেম বর্ণনা রূপান্তর,
-Auto insert Price List rate if missing,অটো সন্নিবেশ মূল্য তালিকা হার অনুপস্থিত যদি,
Allow Negative Stock,নেতিবাচক শেয়ার মঞ্জুরি,
Automatically Set Serial Nos based on FIFO,স্বয়ংক্রিয়ভাবে FIFO উপর ভিত্তি করে আমরা সিরিয়াল সেট,
-Set Qty in Transactions based on Serial No Input,সিরিয়াল কোন ইনপুটের উপর ভিত্তি করে লেনদেনের পরিমাণ নির্ধারণ করুন,
Auto Material Request,অটো উপাদানের জন্য অনুরোধ,
-Raise Material Request when stock reaches re-order level,শেয়ার পুনরায় আদেশ পর্যায়ে পৌঁছে যখন উপাদান অনুরোধ বাড়াতে,
-Notify by Email on creation of automatic Material Request,স্বয়ংক্রিয় উপাদান অনুরোধ নির্মাণের ইমেইল দ্বারা সূচিত,
Inter Warehouse Transfer Settings,আন্তঃ গুদাম স্থানান্তর সেটিংস,
-Allow Material Transfer From Delivery Note and Sales Invoice,বিতরণ নোট এবং বিক্রয় চালান থেকে উপাদান স্থানান্তরের অনুমতি দিন,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,ক্রয় রশিদ এবং ক্রয় চালান থেকে উপাদান স্থানান্তরকে অনুমতি দিন,
Freeze Stock Entries,ফ্রিজ শেয়ার সাজপোশাকটি,
Stock Frozen Upto,শেয়ার হিমায়িত পর্যন্ত,
-Freeze Stocks Older Than [Days],ফ্রিজ স্টক চেয়ে পুরোনো [দিন],
-Role Allowed to edit frozen stock,ভূমিকা হিমায়িত শেয়ার সম্পাদনা করতে পারবেন,
Batch Identification,ব্যাচ সনাক্তকরণ,
Use Naming Series,নামকরণ সিরিজ ব্যবহার করুন,
Naming Series Prefix,নামকরণ সিরিজ উপসর্গ,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,কেনার রসিদ প্রবণতা,
Purchase Register,ক্রয় নিবন্ধন,
Quotation Trends,উদ্ধৃতি প্রবণতা,
-Quoted Item Comparison,উদ্ধৃত আইটেম তুলনা,
Received Items To Be Billed,গৃহীত চলছে বিল তৈরি করা,
Qty to Order,অর্ডার Qty,
Requested Items To Be Transferred,অনুরোধ করা চলছে স্থানান্তর করা,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,উপাদান অনুরোধের জন্য গুদাম নির্বাচন করুন,
Transfer Materials For Warehouse {0},গুদাম {0 For জন্য উপাদান স্থানান্তর,
Production Plan Material Request Warehouse,উত্পাদন পরিকল্পনার সামগ্রী অনুরোধ গুদাম,
-Set From Warehouse,গুদাম থেকে সেট করুন,
-Source Warehouse (Material Transfer),উত্স গুদাম (উপাদান স্থানান্তর),
Sets 'Source Warehouse' in each row of the items table.,আইটেম টেবিলের প্রতিটি সারিতে 'উত্স গুদাম' সেট করুন।,
Sets 'Target Warehouse' in each row of the items table.,আইটেম সারণির প্রতিটি সারিতে 'টার্গেট ওয়েয়ারহাউস' সেট করুন।,
Show Cancelled Entries,বাতিল এন্ট্রিগুলি দেখান,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,পরিষেবা প্রাপ্ত হয়েছে তবে বিল দেওয়া হয়নি,
Deferred Accounting Settings,স্থগিত অ্যাকাউন্টিং সেটিংস,
Book Deferred Entries Based On,বুক ডিফার্ড এন্ট্রি উপর ভিত্তি করে,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",যদি "মাসস" বাছাই করা হয় তবে নির্দিষ্ট মাসে এক মাসের দিন নির্বিশেষে প্রতিটি মাসের জন্য পিছিয়ে যাওয়া আয় বা ব্যয় হিসাবে বুক করা হবে। স্থগিত রাজস্ব বা ব্যয় পুরো এক মাসের জন্য বুকিং না দেওয়া থাকলে তা প্রমাণিত হবে।,
Days,দিনগুলি,
Months,মাস,
Book Deferred Entries Via Journal Entry,জার্নাল এন্ট্রি মাধ্যমে বুক ডিফার্ড এন্ট্রি,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,এটি যদি চেক না করা হয় তবে সরাসরি জিএল এন্ট্রিগুলি ডিফার্ড রাজস্ব / ব্যয় বুকিংয়ের জন্য তৈরি করা হবে,
Submit Journal Entries,জার্নাল এন্ট্রি জমা দিন,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,এটি যদি চেক না করা হয় তবে জার্নাল এন্ট্রিগুলি একটি খসড়া অবস্থায় সংরক্ষণ করা হবে এবং ম্যানুয়ালি জমা দিতে হবে,
Enable Distributed Cost Center,বিতরণ ব্যয় কেন্দ্র সক্ষম করুন,
@@ -8901,8 +8823,6 @@
Is Inter State,ইন্টার স্টেট,
Purchase Details,ক্রয়ের বিশদ,
Depreciation Posting Date,অবচয় পোস্টের তারিখ,
-Purchase Order Required for Purchase Invoice & Receipt Creation,ক্রয় চালান এবং প্রাপ্তি তৈরির জন্য ক্রয়ের অর্ডার প্রয়োজনীয়,
-Purchase Receipt Required for Purchase Invoice Creation,ইনভয়েস তৈরির জন্য ক্রয়ের রশিদ প্রয়োজনীয়,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","ডিফল্টরূপে, সরবরাহকারী নাম প্রবেশ করানো সরবরাহকারীর নাম অনুসারে সেট করা হয়। আপনি যদি সরবরাহকারীদের দ্বারা একটি দ্বারা নামকরণ করতে চান",
choose the 'Naming Series' option.,'নামকরণ সিরিজ' বিকল্পটি চয়ন করুন।,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,নতুন ক্রয় লেনদেন তৈরি করার সময় ডিফল্ট মূল্য তালিকাকে কনফিগার করুন। এই মূল্য তালিকা থেকে আইটেমের দামগুলি আনা হবে।,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,আয়কর অংশ,
Component properties and references ,উপাদান বৈশিষ্ট্য এবং রেফারেন্স,
Additional Salary ,অতিরিক্ত বেতন,
-Condtion and formula,শর্ত এবং সূত্র,
Unmarked days,চিহ্নহীন দিনগুলি,
Absent Days,অনুপস্থিত দিন,
Conditions and Formula variable and example,শর্ত এবং সূত্র পরিবর্তনশীল এবং উদাহরণ,
Feedback By,প্রতিক্রিয়া দ্বারা,
-MTNG-.YYYY.-.MM.-.DD.-,এমটিএনজি -হায়িওয়াই .- এমএম .-। ডিডি.-,
Manufacturing Section,উত্পাদন বিভাগ,
-Sales Order Required for Sales Invoice & Delivery Note Creation,বিক্রয় চালান এবং বিতরণ নোট তৈরির জন্য প্রয়োজনীয় বিক্রয় অর্ডার,
-Delivery Note Required for Sales Invoice Creation,বিক্রয় চালান তৈরির জন্য বিতরণ নোট প্রয়োজনীয় Requ,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","ডিফল্টরূপে, গ্রাহকের নাম প্রবেশ সম্পূর্ণ নাম অনুসারে সেট করা হয়। আপনি যদি চান গ্রাহকদের একটি দ্বারা নামকরণ করা",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,নতুন বিক্রয় লেনদেন তৈরি করার সময় ডিফল্ট মূল্য তালিকাকে কনফিগার করুন। এই মূল্য তালিকা থেকে আইটেমের দামগুলি আনা হবে।,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",যদি এই বিকল্পটি 'হ্যাঁ' কনফিগার করা থাকে তবে ERPNext আপনাকে প্রথমে বিক্রয় আদেশ তৈরি না করে বিক্রয় চালান বা বিতরণ নোট তৈরি করা থেকে বিরত রাখবে। এই কনফিগারেশনটি কোনও নির্দিষ্ট গ্রাহকের জন্য 'বিক্রয় অর্ডার ব্যতীত বিক্রয় চালানের ক্রয়কে অনুমতি দিন' চেকবক্সটি সক্ষম করে ওভাররাইড করা যেতে পারে।,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,Selected 0} {1 successfully সফলভাবে নির্বাচিত সমস্ত বিষয়ের সাথে যুক্ত করা হয়েছে।,
Topics updated,বিষয় আপডেট হয়েছে,
Academic Term and Program,একাডেমিক টার্ম এবং প্রোগ্রাম,
-Last Stock Transaction for item {0} was on {1}.,আইটেম Last 0} এর জন্য সর্বশেষ স্টক লেনদেন {1} এ ছিল},
-Stock Transactions for Item {0} cannot be posted before this time.,আইটেম for 0 for এর জন্য স্টক লেনদেন এই সময়ের আগে পোস্ট করা যাবে না।,
Please remove this item and try to submit again or update the posting time.,দয়া করে এই আইটেমটি সরান এবং আবার জমা দেওয়ার চেষ্টা করুন বা পোস্টিং সময় আপডেট করুন।,
Failed to Authenticate the API key.,API কীটি প্রমাণীকরণে ব্যর্থ।,
Invalid Credentials,অবৈধ প্রশংসাপত্র,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,আপনার প্লাইড ক্লায়েন্ট আইডি এবং গোপন মান পরীক্ষা করুন,
Bank transaction creation error,ব্যাংক লেনদেন তৈরির ত্রুটি,
Unit of Measurement,পরিমাপের ইউনিট,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},সারি # {}: আইটেম for for এর বিক্রয়ের হার তার {} এর চেয়ে কম} বিক্রয় হার কমপক্ষে হওয়া উচিত {},
Fiscal Year {0} Does Not Exist,আর্থিক বছর {0} বিদ্যমান নেই,
Row # {0}: Returned Item {1} does not exist in {2} {3},সারি # {0}: ফিরে আসা আইটেম {1 {{2} {3 in তে বিদ্যমান নেই,
Valuation type charges can not be marked as Inclusive,মূল্য মূল্য ধরণের চার্জগুলি সমেত হিসাবে চিহ্নিত করা যায় না,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,সারিতে} 1} অগ্রাধিকারের জন্য প্রতিক্রিয়া সময়টি olution 1} রেজোলিউশন সময়ের চেয়ে বেশি হতে পারে না।,
{0} is not enabled in {1},{0} {1} এ সক্ষম নয়,
Group by Material Request,উপাদান অনুরোধ দ্বারা গ্রুপ,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",সারি {0}: সরবরাহকারী {0} এর জন্য ইমেল প্রেরণের জন্য ইমেল ঠিকানা প্রয়োজন,
Email Sent to Supplier {0},সরবরাহকারীকে ইমেল প্রেরণ করা হয়েছে {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","পোর্টাল থেকে উদ্ধৃতি জন্য অনুরোধ অ্যাক্সেস অক্ষম করা হয়েছে। অ্যাক্সেসের অনুমতি দেওয়ার জন্য, এটি পোর্টাল সেটিংসে সক্ষম করুন।",
Supplier Quotation {0} Created,সরবরাহকারী কোটেশন {0} তৈরি হয়েছে,
Valid till Date cannot be before Transaction Date,তারিখ অবধি বৈধ লেনদেনের তারিখের আগে হতে পারে না,
+Unlink Advance Payment on Cancellation of Order,অর্ডার বাতিলকরণে অগ্রিম প্রদানের লিঙ্কমুক্ত করুন,
+"Simple Python Expression, Example: territory != 'All Territories'","সাধারণ পাইথন এক্সপ্রেশন, উদাহরণ: অঞ্চল! = 'সমস্ত অঞ্চল'",
+Sales Contributions and Incentives,বিক্রয় অবদান এবং উত্সাহ,
+Sourced by Supplier,সরবরাহকারী দ্বারা উত্সাহিত,
+Total weightage assigned should be 100%.<br>It is {0},বরাদ্দকৃত মোট ওজন 100% হওয়া উচিত।<br> এটি {0},
+Account {0} exists in parent company {1}.,অ্যাকাউন্ট {0 parent মূল কোম্পানিতে} 1} বিদ্যমান},
+"To overrule this, enable '{0}' in company {1}","এটি উপেক্ষা করার জন্য, কোম্পানির '1}' {0} 'সক্ষম করুন",
+Invalid condition expression,অবৈধ শর্তের অভিব্যক্তি,
+Please Select a Company First,দয়া করে প্রথমে একটি সংস্থা নির্বাচন করুন,
+Please Select Both Company and Party Type First,দয়া করে প্রথম সংস্থা এবং পার্টি উভয়ই নির্বাচন করুন,
+Provide the invoice portion in percent,চালানের অংশ শতাংশে সরবরাহ করুন,
+Give number of days according to prior selection,পূর্ববর্তী নির্বাচন অনুযায়ী দিন সংখ্যা দিন,
+Email Details,ইমেল বিশদ,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","গ্রহীতার জন্য একটি শুভেচ্ছা নির্বাচন করুন। যেমন মিঃ, মিসেস, ইত্যাদি",
+Preview Email,পূর্বরূপ ইমেল,
+Please select a Supplier,একটি সরবরাহকারী নির্বাচন করুন,
+Supplier Lead Time (days),সরবরাহকারী সীসা সময় (দিন),
+"Home, Work, etc.","বাড়ি, কাজ ইত্যাদি",
+Exit Interview Held On,সাক্ষাত্কারটি প্রস্থান করুন,
+Condition and formula,শর্ত এবং সূত্র,
+Sets 'Target Warehouse' in each row of the Items table.,আইটেম টেবিলের প্রতিটি সারিতে 'টার্গেট ওয়েয়ারহাউস' সেট করুন।,
+Sets 'Source Warehouse' in each row of the Items table.,আইটেম টেবিলের প্রতিটি সারিতে 'উত্স গুদাম' সেট করুন।,
+POS Register,পস রেজিস্টার,
+"Can not filter based on POS Profile, if grouped by POS Profile","POS প্রোফাইলের ভিত্তিতে ফিল্টার করা যায় না, যদি পস প্রোফাইল দ্বারা গোষ্ঠীভূত হয়",
+"Can not filter based on Customer, if grouped by Customer",গ্রাহক দ্বারা গ্রুপ করা থাকলে গ্রাহকের উপর ভিত্তি করে ফিল্টার করতে পারবেন না,
+"Can not filter based on Cashier, if grouped by Cashier","ক্যাশিয়ারের ভিত্তিতে, ক্যাশিয়ারের ভিত্তিতে ফিল্টার করা যায় না",
+Payment Method,মূল্যপরিশোধ পদ্ধতি,
+"Can not filter based on Payment Method, if grouped by Payment Method",অর্থ প্রদানের পদ্ধতি অনুসারে অর্থ প্রদানের পদ্ধতির ভিত্তিতে ফিল্টার করতে পারবেন না,
+Supplier Quotation Comparison,সরবরাহকারী কোটেশন তুলনা,
+Price per Unit (Stock UOM),ইউনিট প্রতি মূল্য (স্টক ইউওএম),
+Group by Supplier,সরবরাহকারী দ্বারা গ্রুপ,
+Group by Item,আইটেম দ্বারা গ্রুপ,
+Remember to set {field_label}. It is required by {regulation}.,{ক্ষেত্র_লাবেল set সেট করতে মনে রাখবেন} এটি {নিয়ন্ত্রণ by দ্বারা প্রয়োজনীয়},
+Enrollment Date cannot be before the Start Date of the Academic Year {0},তালিকাভুক্তির তারিখ একাডেমিক বছরের শুরুর তারিখের আগে হতে পারে না {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},তালিকাভুক্তির তারিখ একাডেমিক মেয়াদ শেষের তারিখের পরে হতে পারে না {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},তালিকাভুক্তির তারিখ একাডেমিক টার্মের শুরুর তারিখের আগে হতে পারে না {0},
+Future Posting Not Allowed,ভবিষ্যতের পোস্টিং অনুমোদিত নয়,
+"To enable Capital Work in Progress Accounting, ","অগ্রগতি অ্যাকাউন্টিংয়ে মূলধন কাজ সক্ষম করতে,",
+you must select Capital Work in Progress Account in accounts table,আপনার অবশ্যই অ্যাকাউন্টের সারণীতে প্রগতি অ্যাকাউন্টে মূলধন কাজ নির্বাচন করতে হবে,
+You can also set default CWIP account in Company {},আপনি সংস্থা default default এ ডিফল্ট সিডব্লিউআইপি অ্যাকাউন্টও সেট করতে পারেন,
+The Request for Quotation can be accessed by clicking on the following button,অনুরোধের জন্য নিচের বোতামটি ক্লিক করে প্রবেশ করা যাবে,
+Regards,শ্রদ্ধা,
+Please click on the following button to set your new password,আপনার নতুন পাসওয়ার্ড সেট করতে দয়া করে নীচের বোতামটিতে ক্লিক করুন,
+Update Password,পাসওয়ার্ড আপডেট করুন,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},সারি # {}: আইটেম for for এর বিক্রয়ের হার তার {{এর চেয়ে কম} {Lling বিক্রয় কমপক্ষে হওয়া উচিত {},
+You can alternatively disable selling price validation in {} to bypass this validation.,আপনি এই বৈধতাটিকে বাইপাস করতে বিকল্প মূল্য valid in এ বিক্রয় বৈধতা অক্ষম করতে পারেন।,
+Invalid Selling Price,অবৈধ বিক্রয় মূল্য,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,ঠিকানা কোনও সংস্থার সাথে সংযুক্ত করা দরকার। লিংক সারণীতে সংস্থার জন্য একটি সারি যুক্ত করুন।,
+Company Not Linked,সংযুক্ত নয় সংস্থা,
+Import Chart of Accounts from CSV / Excel files,সিএসভি / এক্সেল ফাইলগুলি থেকে অ্যাকাউন্টগুলির চার্ট আমদানি করুন,
+Completed Qty cannot be greater than 'Qty to Manufacture',সম্পূর্ণ পরিমাণটি 'কোটির থেকে উত্পাদন' এর চেয়ে বড় হতে পারে না,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",সারি {0}: সরবরাহকারী {1} এর জন্য ইমেল প্রেরণের জন্য ইমেল ঠিকানা প্রয়োজন,
+"If enabled, the system will post accounting entries for inventory automatically","সক্ষম করা থাকলে, সিস্টেম স্বয়ংক্রিয়ভাবে ইনভেন্টরির জন্য অ্যাকাউন্টিং এন্ট্রি পোস্ট করবে",
+Accounts Frozen Till Date,অ্যাকাউন্টগুলি হিমশীতল তারিখ পর্যন্ত,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,অ্যাকাউন্টিং এন্ট্রি এই তারিখ পর্যন্ত হিমশীতল। নীচে উল্লিখিত ভূমিকাযুক্ত ব্যবহারকারী ব্যতীত কেউ এন্ট্রি তৈরি বা সংশোধন করতে পারবেন না,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,হিমায়িত অ্যাকাউন্টগুলি সেট করতে এবং হিমায়িত এন্ট্রি সম্পাদনা করার জন্য ভূমিকা অনুমোদিত,
+Address used to determine Tax Category in transactions,লেনদেনে ট্যাক্স বিভাগ নির্ধারণ করতে ব্যবহৃত ঠিকানা Address,
+"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 ","অর্ডারের পরিমাণের তুলনায় আপনাকে যে পরিমাণ শতাংশ বেশি বিল দেওয়ার অনুমতি দেওয়া হচ্ছে। উদাহরণস্বরূপ, যদি কোনও আইটেমের জন্য অর্ডার মান $ 100 এবং সহনশীলতা 10% হিসাবে সেট করা থাকে তবে আপনাকে 110 ডলার পর্যন্ত বিল দেওয়ার অনুমতি দেওয়া হবে",
+This role is allowed to submit transactions that exceed credit limits,এই ভূমিকাটি transactionsণের সীমা অতিক্রম করে এমন লেনদেন জমা দেওয়ার অনুমতিপ্রাপ্ত,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",যদি "মাস" নির্বাচিত হয় তবে এক মাসের কতগুলি দিন নির্বিশেষে প্রতিটি মাসের জন্য একটি নির্দিষ্ট পরিমাণ স্থগিত রাজস্ব বা ব্যয় হিসাবে বুক করা হবে। স্থগিত রাজস্ব বা ব্যয় পুরো এক মাসের জন্য বুকিং না দেওয়া থাকলে এটি প্রমাণিত হবে,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",এটি যদি চেক না করা থাকে তবে মুলতুবি রাজস্ব বা ব্যয় বুক করার জন্য সরাসরি জিএল এন্ট্রি তৈরি করা হবে,
+Show Inclusive Tax in Print,প্রিন্টে অন্তর্ভুক্ত কর প্রদর্শন করুন,
+Only select this if you have set up the Cash Flow Mapper documents,আপনি যদি নগদ ফ্লো ম্যাপার নথিগুলি সেট আপ করেন তবেই এটি নির্বাচন করুন,
+Payment Channel,পেমেন্ট চ্যানেল,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,ক্রয় চালান এবং প্রাপ্তি তৈরির জন্য কি ক্রয়ের অর্ডার প্রয়োজনীয়?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,ক্রয় চালান তৈরির জন্য কি ক্রয়ের রশিদ প্রয়োজন?,
+Maintain Same Rate Throughout the Purchase Cycle,ক্রয় চক্র জুড়ে একই হার বজায় রাখুন,
+Allow Item To Be Added Multiple Times in a Transaction,কোনও লেনদেনে আইটেমটি একাধিকবার যুক্ত হওয়ার অনুমতি দিন,
+Suppliers,সরবরাহকারীদের,
+Send Emails to Suppliers,সরবরাহকারীদের ইমেল প্রেরণ করুন,
+Select a Supplier,সরবরাহকারী নির্বাচন করুন,
+Cannot mark attendance for future dates.,ভবিষ্যতের তারিখগুলির জন্য উপস্থিতি চিহ্নিত করতে পারে না।,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},আপনি কি উপস্থিতি আপডেট করতে চান?<br> বর্তমান: {0}<br> অনুপস্থিত: {1},
+Mpesa Settings,ম্যাপিসা সেটিংস,
+Initiator Name,শুরুর নাম,
+Till Number,সংখ্যা পর্যন্ত,
+Sandbox,স্যান্ডবক্স,
+ Online PassKey,অনলাইন পাসকি,
+Security Credential,সুরক্ষা শংসাপত্র,
+Get Account Balance,অ্যাকাউন্ট ব্যালেন্স পান,
+Please set the initiator name and the security credential,দয়া করে প্রারম্ভিকের নাম এবং সুরক্ষা শংসাপত্র সেট করুন,
+Inpatient Medication Entry,ইনপ্যাশেন্ট মেডিকেশন এন্ট্রি,
+HLC-IME-.YYYY.-,এইচএলসি-আইএমই -YYYY.-,
+Item Code (Drug),আইটেম কোড (ড্রাগ),
+Medication Orders,ওষুধের আদেশ,
+Get Pending Medication Orders,মুলতুবি ওষুধের আদেশ পান,
+Inpatient Medication Orders,রোগী ওষুধের আদেশ,
+Medication Warehouse,Icationষধ গুদাম,
+Warehouse from where medication stock should be consumed,গুদাম যেখান থেকে ওষুধের স্টক খাওয়া উচিত,
+Fetching Pending Medication Orders,মুলতুবি ওষুধের আদেশগুলি আনা হচ্ছে,
+Inpatient Medication Entry Detail,ইনপ্যাশেন্ট ওষুধ এন্ট্রি বিশদ,
+Medication Details,ওষুধের বিশদ,
+Drug Code,ড্রাগ কোড,
+Drug Name,ড্রাগ নাম,
+Against Inpatient Medication Order,ইনপ্যাশেন্ট ওষুধের আদেশের বিরুদ্ধে,
+Against Inpatient Medication Order Entry,ইনপ্যাশেন্ট ওষুধের আদেশ প্রবেশের বিরুদ্ধে,
+Inpatient Medication Order,ইনপ্যাশেন্ট মেডিকেশন অর্ডার,
+HLC-IMO-.YYYY.-,এইচএলসি-আইএমও-.YYYY.-,
+Total Orders,মোট আদেশ,
+Completed Orders,সম্পূর্ণ আদেশ,
+Add Medication Orders,ওষুধের আদেশ যুক্ত করুন,
+Adding Order Entries,অর্ডার এন্ট্রি যুক্ত করা হচ্ছে,
+{0} medication orders completed,{0} ওষুধের অর্ডার সম্পূর্ণ হয়েছে,
+{0} medication order completed,{0} ওষুধের অর্ডার সম্পূর্ণ হয়েছে,
+Inpatient Medication Order Entry,ইনপ্যাশেন্ট মেডিকেশন অর্ডার এন্ট্রি,
+Is Order Completed,অর্ডার সম্পূর্ণ হয়েছে,
+Employee Records to Be Created By,দ্বারা তৈরি করা হবে কর্মচারী রেকর্ডস,
+Employee records are created using the selected field,কর্মচারী রেকর্ডগুলি নির্বাচিত ক্ষেত্রটি ব্যবহার করে তৈরি করা হয়,
+Don't send employee birthday reminders,কর্মচারীর জন্মদিনের অনুস্মারকগুলি প্রেরণ করবেন না,
+Restrict Backdated Leave Applications,ব্যাকটেড ছুটি অ্যাপ্লিকেশনগুলি সীমাবদ্ধ করুন,
+Sequence ID,সিকোয়েন্স আইডি,
+Sequence Id,সিকোয়েন্স আইডি,
+Allow multiple material consumptions against a Work Order,ওয়ার্ক অর্ডারের বিপরীতে একাধিক উপাদানের কনসপোশনগুলিকে মঞ্জুরি দিন,
+Plan time logs outside Workstation working hours,ওয়ার্কস্টেশন কাজের সময় বাইরে লগ পরিকল্পনা করুন,
+Plan operations X days in advance,এক্স ক্রিয়াকলাপের এক্স দিন আগেই,
+Time Between Operations (Mins),অপারেশনগুলির মধ্যে সময় (মিনিট),
+Default: 10 mins,ডিফল্ট: 10 মিনিট,
+Overproduction for Sales and Work Order,বিক্রয় ও কাজের আদেশের জন্য অতিরিক্ত উত্পাদন,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",সর্বশেষ মূল্যমানের হার / মূল্য তালিকার হার / কাঁচামালের সর্বশেষ ক্রয়ের হারের উপর ভিত্তি করে শিডিউলের মাধ্যমে বিওএমের দাম স্বয়ংক্রিয়ভাবে আপডেট করুন,
+Purchase Order already created for all Sales Order items,ক্রয়ের আদেশ ইতিমধ্যে সমস্ত বিক্রয় আদেশ আইটেমগুলির জন্য তৈরি করা হয়েছে,
+Select Items,আইটেম নির্বাচন করুন,
+Against Default Supplier,ডিফল্ট সরবরাহকারী বিরুদ্ধে,
+Auto close Opportunity after the no. of days mentioned above,নোটের পরে অটো বন্ধ করার সুযোগ। উপরে উল্লিখিত দিনের,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,বিক্রয় চালান এবং বিতরণ নোট তৈরির জন্য কি বিক্রয় আদেশের প্রয়োজনীয়?,
+Is Delivery Note Required for Sales Invoice Creation?,ডেলিভারি নোটটি কি বিক্রয় চালান তৈরির জন্য প্রয়োজনীয়?,
+How often should Project and Company be updated based on Sales Transactions?,বিক্রয় লেনদেনের উপর ভিত্তি করে কতবার প্রকল্প এবং সংস্থাকে আপডেট করা উচিত?,
+Allow User to Edit Price List Rate in Transactions,লেনদেনগুলিতে ব্যবহারকারীকে মূল্য তালিকার হার সম্পাদনা করার অনুমতি দিন,
+Allow Item to Be Added Multiple Times in a Transaction,কোনও লেনদেনে আইটেমটিকে একাধিকবার যুক্ত হওয়ার অনুমতি দিন,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,গ্রাহকের ক্রয়ের আদেশের বিরুদ্ধে একাধিক বিক্রয় অর্ডার মঞ্জুরি দিন,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,ক্রয় হার বা মূল্য হারের বিপরীতে আইটেমের জন্য বিক্রয় মূল্য বৈধ করুন,
+Hide Customer's Tax ID from Sales Transactions,বিক্রয় লেনদেন থেকে গ্রাহকের করের আইডি লুকান,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","অর্ডারের পরিমাণের তুলনায় আপনাকে যে পরিমাণ শতাংশ পাওয়ার বা আরও সরবরাহ করার অনুমতি দেওয়া হয়। উদাহরণস্বরূপ, আপনি যদি 100 ইউনিট অর্ডার করে থাকেন এবং আপনার ভাতা 10% হয় তবে আপনাকে 110 টি ইউনিট পাওয়ার অনুমতি দেওয়া হবে।",
+Action If Quality Inspection Is Not Submitted,মান পরিদর্শন জমা না দেওয়া হলে অ্যাকশন,
+Auto Insert Price List Rate If Missing,অনুপস্থিত থাকলে অটো সন্নিবেশ মূল্য তালিকার হার,
+Automatically Set Serial Nos Based on FIFO,ফিফোর উপর ভিত্তি করে স্বয়ংক্রিয়ভাবে সিরিয়াল নম্বর সেট করুন,
+Set Qty in Transactions Based on Serial No Input,সিরিয়াল কোনও ইনপুট ভিত্তিক লেনদেনের পরিমাণ নির্ধারণ করুন,
+Raise Material Request When Stock Reaches Re-order Level,স্টক পুনঃ-অর্ডার স্তরে পৌঁছালে উপাদানের অনুরোধ উত্থাপন করুন,
+Notify by Email on Creation of Automatic Material Request,স্বয়ংক্রিয় পদার্থের অনুরোধ তৈরির বিষয়ে ইমেল দ্বারা অবহিত করুন,
+Allow Material Transfer from Delivery Note to Sales Invoice,বিতরণ নোট থেকে বিক্রয় ইনভয়েসে উপাদান স্থানান্তরের অনুমতি দিন,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,ক্রয় রশিদ থেকে ক্রয় চালানের কাছে পদার্থ স্থানান্তরকে অনুমতি দিন,
+Freeze Stocks Older Than (Days),পুরানো স্টকগুলি (দিনগুলি) থেকে পুরানো,
+Role Allowed to Edit Frozen Stock,ফ্রোজেন স্টক সম্পাদনা করার জন্য ভূমিকা অনুমোদিত,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,পেমেন্ট এন্ট্রি un 0 The এর অবিকৃত পরিমাণটি ব্যাংকের লেনদেনের অযাচিত পরিমাণের চেয়ে বেশি,
+Payment Received,পেমেন্ট পেয়েছি,
+Attendance cannot be marked outside of Academic Year {0},উপস্থিতি একাডেমিক বছর marked 0 outside এর বাইরে চিহ্নিত করা যায় না,
+Student is already enrolled via Course Enrollment {0},শিক্ষার্থী ইতিমধ্যে কোর্স তালিকাভুক্তি {0 via এর মাধ্যমে তালিকাভুক্ত হয়েছে,
+Attendance cannot be marked for future dates.,উপস্থিতি ভবিষ্যতের তারিখগুলির জন্য চিহ্নিত করা যায় না।,
+Please add programs to enable admission application.,ভর্তির আবেদন সক্ষম করতে প্রোগ্রাম যুক্ত করুন।,
+The following employees are currently still reporting to {0}:,নিম্নলিখিত কর্মচারী বর্তমানে {0} প্রতিবেদন করছেন:,
+Please make sure the employees above report to another Active employee.,উপরের কর্মীরা অন্য সক্রিয় কর্মচারীকে রিপোর্ট করেছেন তা নিশ্চিত করুন।,
+Cannot Relieve Employee,কর্মচারীকে মুক্তি দিতে পারে না,
+Please enter {0},দয়া করে {0 enter লিখুন,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',দয়া করে অন্য অর্থ প্রদানের পদ্ধতিটি নির্বাচন করুন। এমপিসা মুদ্রা '{0}' এর লেনদেনকে সমর্থন করে না,
+Transaction Error,লেনদেনের ত্রুটি,
+Mpesa Express Transaction Error,ম্যাপ্সা এক্সপ্রেস লেনদেন ত্রুটি,
+"Issue detected with Mpesa configuration, check the error logs for more details","এমপেসা কনফিগারেশন সহ সমস্যা সনাক্ত হয়েছে, আরও তথ্যের জন্য ত্রুটিযুক্ত লগগুলি পরীক্ষা করুন",
+Mpesa Express Error,ম্যাপিসা এক্সপ্রেস ত্রুটি,
+Account Balance Processing Error,অ্যাকাউন্ট ব্যালেন্স প্রক্রিয়াকরণ ত্রুটি,
+Please check your configuration and try again,আপনার কনফিগারেশন পরীক্ষা করে দেখুন এবং আবার চেষ্টা করুন,
+Mpesa Account Balance Processing Error,মাইপা অ্যাকাউন্টে ব্যালেন্স প্রক্রিয়াকরণ ত্রুটি,
+Balance Details,ব্যালেন্স বিশদ,
+Current Balance,বর্তমান হিসাব,
+Available Balance,পর্যাপ্ত টাকা,
+Reserved Balance,সংরক্ষিত ভারসাম্য,
+Uncleared Balance,অপরিচ্ছন্ন ব্যালেন্স,
+Payment related to {0} is not completed,{0} সম্পর্কিত অর্থ প্রদান সম্পূর্ণ হয়নি,
+Row #{}: Item Code: {} is not available under warehouse {}.,সারি # {}: আইটেম কোড: {w গুদাম under} এর অধীন উপলব্ধ},
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,সারি # {}: স্টক পরিমাণ আইটেম কোডের জন্য পর্যাপ্ত নয়: are w গুদাম}} এর অধীনে} উপলব্ধ পরিমাণ {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,সারি # {}: দয়া করে একটি সিরিয়াল নং এবং আইটেমের বিরুদ্ধে ব্যাচ নির্বাচন করুন::} বা লেনদেন সম্পূর্ণ করতে এটি সরান।,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,সারি # {}: আইটেমের বিরুদ্ধে কোনও ক্রমিক সংখ্যা নির্বাচন করা হয়নি:}}। লেনদেন সম্পূর্ণ করতে দয়া করে একটি নির্বাচন করুন বা এটি সরান।,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,সারি # {}: আইটেমের বিরুদ্ধে কোনও ব্যাচ নির্বাচন করা হয়নি:}}। লেনদেন সম্পূর্ণ করতে দয়া করে একটি ব্যাচ নির্বাচন করুন বা এটি সরান।,
+Payment amount cannot be less than or equal to 0,প্রদানের পরিমাণ 0 এর চেয়ে কম বা সমান হতে পারে না,
+Please enter the phone number first,প্রথমে ফোন নম্বরটি প্রবেশ করান,
+Row #{}: {} {} does not exist.,সারি # {}: {} {} বিদ্যমান নেই।,
+Row #{0}: {1} is required to create the Opening {2} Invoices,সারি # {0}: উদ্বোধনী} 2} চালানগুলি তৈরি করতে {1 required প্রয়োজন,
+You had {} errors while creating opening invoices. Check {} for more details,খোলার চালান তৈরি করার সময় আপনার}} ত্রুটি হয়েছিল। আরও তথ্যের জন্য Check Check পরীক্ষা করুন,
+Error Occured,ত্রুটি ঘটেছে,
+Opening Invoice Creation In Progress,চালানের চালনা প্রগতিতে চলছে,
+Creating {} out of {} {},{} {Of এর বাইরে Creat} তৈরি করা হচ্ছে,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(ক্রমিক নং: {0}) সেবন পুরোপুরি বিক্রয় আদেশ {1 to এ সংরক্ষিত থাকায় সেবন করা যায় না},
+Item {0} {1},আইটেম {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,গুদাম {1} এর অধীনে আইটেম {0} এর জন্য সর্বশেষ স্টক লেনদেন {2 on এ ছিল},
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,গুদাম {1} এর অধীনে আইটেম {0। এর জন্য স্টক লেনদেন এই সময়ের আগে পোস্ট করা যাবে না।,
+Posting future stock transactions are not allowed due to Immutable Ledger,অপরিবর্তনীয় লেজারের কারণে ভবিষ্যতে স্টক লেনদেনের অনুমতি দেওয়া হয় না,
+A BOM with name {0} already exists for item {1}.,আইটেম {1} এর জন্য B 0 name নামের একটি বিওএম ইতিমধ্যে বিদ্যমান},
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1 you আপনি কি আইটেমটির নাম পরিবর্তন করেছেন? প্রশাসক / প্রযুক্তি সহায়তার সাথে যোগাযোগ করুন,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},সারিতে # {0}: সিকোয়েন্স আইডি {1 previous পূর্ববর্তী সারির সিকোয়েন্স আইডি {2 than এর চেয়ে কম হতে পারে না,
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) অবশ্যই {2} ({3}) এর সমান হতে হবে,
+"{0}, complete the operation {1} before the operation {2}.","{0}, অপারেশন} 2} এর আগে অপারেশনটি complete 1 {সম্পূর্ণ করুন}",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,সিরিয়াল নং দ্বারা সরবরাহ নিশ্চিত করা যায় না যেমন আইটেম {0 Ser ক্রমিক নং দ্বারা সরবরাহ নিশ্চিতকরণ ছাড়া এবং যোগ করা হয়,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,আইটেম {0 no এর কোনও ক্রমিক নং নেই কেবল সিরিলাইজ করা আইটেমগুলির ক্রমিক নংয়ের ভিত্তিতে ডেলিভারি থাকতে পারে,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,আইটেম {0} এর জন্য কোনও সক্রিয় বিওএম পাওয়া যায় নি} ক্রমিক নং দ্বারা সরবরাহ নিশ্চিত করা যায় না,
+No pending medication orders found for selected criteria,নির্বাচিত মানদণ্ডের জন্য কোনও মুলতুবি medicationষধের অর্ডার পাওয়া যায় নি,
+From Date cannot be after the current date.,তারিখ থেকে বর্তমান তারিখের পরে হতে পারে না।,
+To Date cannot be after the current date.,তারিখের তারিখ বর্তমান তারিখের পরে হতে পারে না।,
+From Time cannot be after the current time.,সময় থেকে বর্তমান সময়ের পরে আর হতে পারে না।,
+To Time cannot be after the current time.,টু টাইম বর্তমান সময়ের পরে হতে পারে না।,
+Stock Entry {0} created and ,স্টক এন্ট্রি {0} তৈরি এবং,
+Inpatient Medication Orders updated successfully,ইনপ্যাশেন্ট মেডিকেশন অর্ডারগুলি সফলভাবে আপডেট হয়েছে updated,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},সারি {0}: বাতিল রোগীদের Medষধ আদেশের বিরুদ্ধে ইনপিশেন্ট entষধ প্রবেশ তৈরি করতে পারে না {1},
+Row {0}: This Medication Order is already marked as completed,সারি {0}: এই icationষধ আদেশটি ইতিমধ্যে সম্পূর্ণ হিসাবে চিহ্নিত হয়েছে,
+Quantity not available for {0} in warehouse {1},গুদামে {0} এর জন্য পরিমাণ পাওয়া যায় না {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,স্টক সেটিংসে নেতিবাচক স্টককে মঞ্জুরি দিন বা এগিয়ে যাওয়ার জন্য স্টক এন্ট্রি তৈরি করুন।,
+No Inpatient Record found against patient {0},রোগীর বিরুদ্ধে কোনও ইনপিশেন্ট রেকর্ড পাওয়া যায় নি {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,রোগী এনকাউন্টার} 1} এর বিপরীতে একটি ইনপিশেন্ট icationষধ আদেশ {0} ইতিমধ্যে বিদ্যমান।,
+Allow In Returns,রিটার্নগুলিতে অনুমতি দিন,
+Hide Unavailable Items,উপলভ্য আইটেমগুলি লুকান,
+Apply Discount on Discounted Rate,ছাড়ের হারে ছাড় প্রয়োগ করুন,
+Therapy Plan Template,থেরাপি পরিকল্পনা টেম্পলেট,
+Fetching Template Details,টেমপ্লেটের বিশদ সংগ্রহ করা হচ্ছে,
+Linked Item Details,লিঙ্কযুক্ত আইটেমের বিশদ,
+Therapy Types,থেরাপির প্রকারগুলি,
+Therapy Plan Template Detail,থেরাপি পরিকল্পনা টেম্পলেট বিস্তারিত,
+Non Conformance,নন কনফারেন্স,
+Process Owner,প্রক্রিয়া মালিক,
+Corrective Action,সংশোধনমূলক কাজ,
+Preventive Action,প্রতিরোধী ব্যবস্থা,
+Problem,সমস্যা,
+Responsible,দায়বদ্ধ,
+Completion By,সমাপ্তি দ্বারা,
+Process Owner Full Name,প্রক্রিয়া মালিকের পুরো নাম,
+Right Index,রাইট ইনডেক্স,
+Left Index,বাম সূচক,
+Sub Procedure,উপ পদ্ধতি,
+Passed,পাস করেছেন,
+Print Receipt,রশিদ প্রিন্ট করুন,
+Edit Receipt,প্রাপ্তি সম্পাদনা করুন,
+Focus on search input,অনুসন্ধান ইনপুট উপর ফোকাস,
+Focus on Item Group filter,আইটেম গ্রুপ ফিল্টার উপর ফোকাস,
+Checkout Order / Submit Order / New Order,চেকআউট অর্ডার / অর্ডার জমা / নতুন আদেশ,
+Add Order Discount,অর্ডার ছাড় ছাড়ুন,
+Item Code: {0} is not available under warehouse {1}.,আইটেম কোড: {0 w গুদাম {1} এর অধীন উপলব্ধ নয়},
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,গুদাম {1} এর অধীনে আইটেম {0} এর জন্য ক্রমিক সংখ্যা অনুপলব্ধ} গুদাম পরিবর্তন করার চেষ্টা করুন।,
+Fetched only {0} available serial numbers.,কেবল পাওয়া যায় serial 0 serial ক্রমিক সংখ্যা।,
+Switch Between Payment Modes,পেমেন্ট মোডগুলির মধ্যে স্যুইচ করুন,
+Enter {0} amount.,{0} পরিমাণ লিখুন।,
+You don't have enough points to redeem.,খালাস দেওয়ার মতো পর্যাপ্ত পয়েন্ট আপনার কাছে নেই।,
+You can redeem upto {0}.,আপনি {0 to অবধি রিডিম করতে পারেন},
+Enter amount to be redeemed.,খালাস পাওয়ার পরিমাণ প্রবেশ করান।,
+You cannot redeem more than {0}.,আপনি {0 than এর বেশি খালাস করতে পারবেন না},
+Open Form View,ফর্ম ভিউ খুলুন,
+POS invoice {0} created succesfully,পস চালান {0 suc সফলভাবে তৈরি করা হয়েছে,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,আইটেম কোডের জন্য স্টকের পরিমাণ পর্যাপ্ত নয়: {0 w গুদাম {1} এর অধীনে} উপলব্ধ পরিমাণ {2}।,
+Serial No: {0} has already been transacted into another POS Invoice.,ক্রমিক নং: {0 already ইতিমধ্যে অন্য একটি পস ইনভয়েসে লেনদেন হয়েছে।,
+Balance Serial No,ব্যালেন্স সিরিয়াল নং,
+Warehouse: {0} does not belong to {1},গুদাম: {0} {1} এর সাথে সম্পর্কিত নয়,
+Please select batches for batched item {0},ব্যাচযুক্ত আইটেমের জন্য ব্যাচগুলি নির্বাচন করুন {0},
+Please select quantity on row {0},দয়া করে সারিতে পরিমাণ নির্বাচন করুন quantity 0},
+Please enter serial numbers for serialized item {0},ক্রমিক আইটেম for 0 for জন্য ক্রমিক নম্বর লিখুন,
+Batch {0} already selected.,ব্যাচ {0} ইতিমধ্যে নির্বাচিত।,
+Please select a warehouse to get available quantities,উপলব্ধ পরিমাণে পেতে একটি গুদাম নির্বাচন করুন,
+"For transfer from source, selected quantity cannot be greater than available quantity","উত্স থেকে স্থানান্তর করার জন্য, নির্বাচিত পরিমাণ উপলব্ধ পরিমাণের চেয়ে বড় হতে পারে না",
+Cannot find Item with this Barcode,এই বারকোড সহ আইটেমটি খুঁজে পাওয়া যায় না,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} বাধ্যতামূলক। হতে পারে মুদ্রা বিনিময় রেকর্ডটি {1} থেকে {2} এর জন্য তৈরি করা হয়নি,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{it এর সাথে সংযুক্ত সম্পদ জমা দিয়েছে। ক্রয় রিটার্ন তৈরি করতে আপনার সম্পত্তিগুলি বাতিল করতে হবে।,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,জমা দেওয়া সম্পদ {0} এর সাথে সংযুক্ত থাকায় এই দস্তাবেজটি বাতিল করতে পারবেন না} চালিয়ে যেতে দয়া করে এটি বাতিল করুন।,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,সারি # {}: সিরিয়াল নং {already ইতিমধ্যে অন্য একটি পস ইনভয়েসে লেনদেন হয়েছে। দয়া করে বৈধ সিরিয়াল নম্বর নির্বাচন করুন।,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,সারি # {}: সিরিয়াল নম্বর {already ইতিমধ্যে অন্য একটি পস ইনভয়েসে লেনদেন হয়েছে। দয়া করে বৈধ সিরিয়াল নম্বর নির্বাচন করুন।,
+Item Unavailable,আইটেম অনুপলব্ধ,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},সারি # {}: সিরিয়াল নং {returned আসল চালানে লেনদেন না হওয়ায় এটি ফেরানো যাবে না {},
+Please set default Cash or Bank account in Mode of Payment {},দয়া করে প্রদানের পদ্ধতিতে ডিফল্ট নগদ বা ব্যাংক অ্যাকাউন্ট সেট করুন {,
+Please set default Cash or Bank account in Mode of Payments {},অর্থপ্রদানের মোডে দয়া করে ডিফল্ট নগদ বা ব্যাংক অ্যাকাউন্ট সেট করুন {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,দয়া করে নিশ্চিত করুন যে}} অ্যাকাউন্টটি ব্যালেন্স শীট অ্যাকাউন্ট। আপনি প্যারেন্ট অ্যাকাউন্টটি ব্যালেন্স শীট অ্যাকাউন্টে পরিবর্তন করতে পারেন বা একটি আলাদা অ্যাকাউন্ট নির্বাচন করতে পারেন।,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,দয়া করে নিশ্চিত করুন যে {} অ্যাকাউন্টটি একটি প্রদেয় অ্যাকাউন্ট। অ্যাকাউন্টের ধরণটি প্রদানযোগ্য হিসাবে পরিবর্তন করুন বা একটি আলাদা অ্যাকাউন্ট নির্বাচন করুন।,
+Row {}: Expense Head changed to {} ,সারি {}: ব্যয় হেড পরিবর্তন করে {to,
+because account {} is not linked to warehouse {} ,কারণ অ্যাকাউন্ট {} গুদামের সাথে যুক্ত নয় {linked,
+or it is not the default inventory account,বা এটি ডিফল্ট ইনভেন্টরি অ্যাকাউন্ট নয়,
+Expense Head Changed,ব্যয় মাথা পরিবর্তন হয়েছে,
+because expense is booked against this account in Purchase Receipt {},কেননা ব্যয় ক্রয় রশিদে এই অ্যাকাউন্টের বিরুদ্ধে বুকিং করা হয়েছে is},
+as no Purchase Receipt is created against Item {}. ,আইটেম against against এর বিপরীতে কোনও ক্রয়ের রশিদ তৈরি হয় না},
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,ক্রয়ের চালানের পরে যখন ক্রয় রশিদ তৈরি হয় তখন অ্যাকাউন্টগুলির জন্য অ্যাকাউন্টিং পরিচালনা করতে এটি করা হয়,
+Purchase Order Required for item {},আইটেমের জন্য ক্রয়ের অর্ডার প্রয়োজনীয় {},
+To submit the invoice without purchase order please set {} ,ক্রয়ের আদেশ ছাড়াই চালান জমা দিতে দয়া করে set set সেট করুন,
+as {} in {},{} হিসাবে {,
+Mandatory Purchase Order,বাধ্যতামূলক ক্রয়ের আদেশ,
+Purchase Receipt Required for item {},আইটেমের জন্য প্রয়োজনীয় ক্রয়ের রশিদ}},
+To submit the invoice without purchase receipt please set {} ,ক্রয় প্রাপ্তি ছাড়াই চালান জমা দিতে দয়া করে {set সেট করুন,
+Mandatory Purchase Receipt,বাধ্যতামূলক ক্রয়ের রশিদ,
+POS Profile {} does not belongs to company {},পস প্রোফাইল {} সংস্থার নয় {company,
+User {} is disabled. Please select valid user/cashier,ব্যবহারকারী {disabled অক্ষম। বৈধ ব্যবহারকারী / ক্যাশিয়ার নির্বাচন করুন,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,সারি # {}: রিটার্ন চালানের মূল চালান {} {}}}},
+Original invoice should be consolidated before or along with the return invoice.,আসল চালানটি রিটার্ন চালানের আগে বা তার সাথে একীভূত করা উচিত।,
+You can add original invoice {} manually to proceed.,আপনি এগিয়ে চলার জন্য ম্যানুয়ালি মূল চালান can {যুক্ত করতে পারেন।,
+Please ensure {} account is a Balance Sheet account. ,দয়া করে নিশ্চিত করুন যে}} অ্যাকাউন্টটি ব্যালেন্স শীট অ্যাকাউন্ট।,
+You can change the parent account to a Balance Sheet account or select a different account.,আপনি প্যারেন্ট অ্যাকাউন্টটি ব্যালেন্স শীট অ্যাকাউন্টে পরিবর্তন করতে পারেন বা একটি আলাদা অ্যাকাউন্ট নির্বাচন করতে পারেন।,
+Please ensure {} account is a Receivable account. ,দয়া করে নিশ্চিত করুন যে {} অ্যাকাউন্টটি একটি গ্রহণযোগ্য অ্যাকাউন্ট।,
+Change the account type to Receivable or select a different account.,প্রাপ্তির জন্য অ্যাকাউন্টের ধরণটি পরিবর্তন করুন বা একটি আলাদা অ্যাকাউন্ট নির্বাচন করুন।,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},অর্জিত আনুগত্য পয়েন্টগুলি খালাস করার পরে L canceled বাতিল করা যাবে না। প্রথমে {} না {cancel বাতিল করুন,
+already exists,আগে থেকেই আছে,
+POS Closing Entry {} against {} between selected period,নির্বাচিত সময়ের মধ্যে POS সমাপ্তি এন্ট্রি}} এর বিপরীতে।।,
+POS Invoice is {},পস চালান {},
+POS Profile doesn't matches {},পোস প্রোফাইল {matches এর সাথে মেলে না,
+POS Invoice is not {},পস চালান {is নয়,
+POS Invoice isn't created by user {},পস চালান ব্যবহারকারী user by দ্বারা তৈরি করা হয়নি,
+Row #{}: {},সারি # {}: {},
+Invalid POS Invoices,অবৈধ পস চালানগুলি,
+Please add the account to root level Company - {},অ্যাকাউন্টটি মূল স্তরের সংস্থায় যুক্ত করুন - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","চাইল্ড কোম্পানির জন্য অ্যাকাউন্ট তৈরি করার সময় {0।, প্যারেন্ট অ্যাকাউন্ট {1} পাওয়া যায় নি। অনুগ্রহ করে সংশ্লিষ্ট সিওএতে প্যারেন্ট অ্যাকাউন্টটি তৈরি করুন",
+Account Not Found,অ্যাকাউন্ট পাওয়া যায় না,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","চাইল্ড কোম্পানির জন্য অ্যাকাউন্ট তৈরি করার সময় {0}, পিতৃ অ্যাকাউন্ট {1 a একটি খাত্তরের অ্যাকাউন্ট হিসাবে পাওয়া গেছে।",
+Please convert the parent account in corresponding child company to a group account.,অনুগ্রহ করে সংশ্লিষ্ট শিশু সংস্থায় পিতৃ অ্যাকাউন্টটি একটি গোষ্ঠী অ্যাকাউন্টে রূপান্তর করুন।,
+Invalid Parent Account,অবৈধ প্যারেন্ট অ্যাকাউন্ট,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",অমিলটি এড়ানোর জন্য এটির পুনঃনামকরণ কেবলমাত্র মূল সংস্থা {0} এর মাধ্যমে অনুমোদিত।,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",আপনি যদি আইটেমের পরিমাণ {0} {1} {2} করেন তবে স্কিম {3 the আইটেমটিতে প্রয়োগ করা হবে।,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",আপনি যদি {0} {1} মূল্যবান আইটেম {2} করেন তবে স্কিমে {3 the আইটেমটিতে প্রয়োগ করা হবে।,
+"As the field {0} is enabled, the field {1} is mandatory.",ক্ষেত্রটি {0} সক্ষম করা হওয়ায় ক্ষেত্র {1} বাধ্যতামূলক।,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",ক্ষেত্রের {0} সক্ষম করা হওয়ায় ক্ষেত্রের মান {1} 1 এর বেশি হওয়া উচিত।,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},আইটেম Ser 1} এর ক্রমিক নং {0 deliver সরবরাহ করতে পারে না কেননা এটি বিক্রয় পূর্ণ অর্ডার অর্ডার {2 to,
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","বিক্রয় অর্ডার {0} এর আইটেমটির জন্য সংরক্ষণ রয়েছে {1}, আপনি কেবল reserved 0} এর বিপরীতে সংরক্ষিত {1 deliver সরবরাহ করতে পারেন}",
+{0} Serial No {1} cannot be delivered,{0} ক্রমিক নং {1} সরবরাহ করা যায় না,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},সারি {0}: সাবকন্ট্রাক্ট আইটেমটি কাঁচামালের জন্য বাধ্যতামূলক for 1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","যেহেতু পর্যাপ্ত কাঁচামাল রয়েছে, গুদাম {0} এর জন্য সামগ্রীর অনুরোধের প্রয়োজন নেই}",
+" If you still want to proceed, please enable {0}.",আপনি যদি এখনও এগিয়ে যেতে চান তবে দয়া করে {0 enable সক্ষম করুন},
+The item referenced by {0} - {1} is already invoiced,{0} - {1} দ্বারা রেফারেন্স করা আইটেমটি ইতিমধ্যে চালিত,
+Therapy Session overlaps with {0},থেরাপি সেশন {0 with দিয়ে ওভারল্যাপ করে,
+Therapy Sessions Overlapping,থেরাপি সেশনস ওভারল্যাপিং,
+Therapy Plans,থেরাপি পরিকল্পনা,
+"Item Code, warehouse, quantity are required on row {0}","আইটেম কোড, গুদাম, পরিমাণ সারিতে প্রয়োজন {0}",
+Get Items from Material Requests against this Supplier,এই সরবরাহকারীর বিরুদ্ধে উপাদান অনুরোধগুলি থেকে আইটেমগুলি পান,
+Enable European Access,ইউরোপীয় অ্যাক্সেস সক্ষম করুন,
+Creating Purchase Order ...,ক্রয় ক্রম তৈরি করা হচ্ছে ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","নীচের আইটেমগুলির ডিফল্ট সরবরাহকারী থেকে কোনও সরবরাহকারী নির্বাচন করুন। নির্বাচনের সময়, কেবলমাত্র নির্বাচিত সরবরাহকারীর অন্তর্ভুক্ত আইটেমগুলির বিরুদ্ধে ক্রয় আদেশ দেওয়া হবে।",
+Row #{}: You must select {} serial numbers for item {}.,সারি # {}: আইটেমের জন্য আপনাকে অবশ্যই}} ক্রমিক সংখ্যা নির্বাচন করতে হবে {}।,
diff --git a/erpnext/translations/bs.csv b/erpnext/translations/bs.csv
index 7fee0ab..6ef445a 100644
--- a/erpnext/translations/bs.csv
+++ b/erpnext/translations/bs.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Stvarni tip porez ne može biti uključen u stopu stavka u nizu {0},
Add,Dodaj,
Add / Edit Prices,Dodaj / uredi cijene,
-Add All Suppliers,Dodajte sve dobavljače,
Add Comment,Dodaj komentar,
Add Customers,Dodaj Kupci,
Add Employees,Dodaj zaposlenog,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Ne mogu odbiti kada kategorija je za 'Vrednovanje' ili 'Vaulation i Total',
"Cannot delete Serial No {0}, as it is used in stock transactions","Ne možete izbrisati serijski broj {0}, koji se koristi u prodaji transakcije",
Cannot enroll more than {0} students for this student group.,Ne može upisati više od {0} studenata za ovu grupa studenata.,
-Cannot find Item with this barcode,Stavka sa ovim barkodom nije pronađena,
Cannot find active Leave Period,Ne mogu pronaći aktivni period otpusta,
Cannot produce more Item {0} than Sales Order quantity {1},Ne može proizvesti više predmeta {0} od prodajnog naloga količina {1},
Cannot promote Employee with status Left,Ne može promovirati zaposlenika sa statusom levo,
Cannot refer row number greater than or equal to current row number for this Charge type,Ne mogu se odnositi broj retka veći ili jednak trenutnom broju red za ovu vrstu Charge,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"Ne možete odabrati vrstu naboja kao ' na prethodnim Row Iznos ""ili"" u odnosu na prethodnu Row Ukupno ""za prvi red",
-Cannot set a received RFQ to No Quote,Ne možete postaviti primljeni RFQ na No Quote,
Cannot set as Lost as Sales Order is made.,Ne mogu se postaviti kao izgubljen kao prodajnog naloga je napravio .,
Cannot set authorization on basis of Discount for {0},Ne mogu postaviti odobrenje na temelju popusta za {0},
Cannot set multiple Item Defaults for a company.,Ne može se podesiti više postavki postavki za preduzeće.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Naknade se ažuriraju u Kupovina Prijem protiv svaku stavku,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Naknade će se distribuirati proporcionalno na osnovu stavka količina ili iznos, po svom izboru",
-Chart Of Accounts,Šifarnik konta,
Chart of Cost Centers,Grafikon troškovnih centara,
Check all,Provjerite sve,
Checkout,Provjeri,
@@ -581,7 +577,6 @@
Compensatory Off,kompenzacijski Off,
Compensatory leave request days not in valid holidays,Dane zahtjeva za kompenzacijski odmor ne važe u valjanim praznicima,
Complaint,Žalba,
-Completed Qty can not be greater than 'Qty to Manufacture',Završene Qty ne može biti veća od 'Količina za proizvodnju',
Completion Date,Završetak Datum,
Computer,Računar,
Condition,Stanje,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Stvaranje i upravljanje dnevne , tjedne i mjesečne e razgradnju .",
Create customer quotes,Napravi citati kupac,
Create rules to restrict transactions based on values.,Stvaranje pravila za ograničavanje prometa na temelju vrijednosti .,
-Created By,Kreirao,
Created {0} scorecards for {1} between: ,Napravljene {0} pokazivačke karte za {1} između:,
Creating Company and Importing Chart of Accounts,Stvaranje preduzeća i uvoz računa,
Creating Fees,Kreiranje naknada,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Transfer radnika ne može se podneti pre datuma prenosa,
Employee cannot report to himself.,Zaposleni ne može prijaviti samog sebe.,
Employee relieved on {0} must be set as 'Left',Zaposlenik razriješen na {0} mora biti postavljen kao 'lijevo ',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Status zaposlenog ne može se postaviti na „Levo“, jer sledeći zaposlenici trenutno prijavljuju ovog zaposlenika:",
Employee {0} already submited an apllication {1} for the payroll period {2},Zaposleni {0} već je podneo primenu {1} za period platnog spiska {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Zaposleni {0} već je prijavio za {1} između {2} i {3}:,
Employee {0} has no maximum benefit amount,Zaposleni {0} nema maksimalni iznos naknade,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Za red {0}: Unesite planirani broj,
"For {0}, only credit accounts can be linked against another debit entry","Za {0}, samo kredit računa može biti povezan protiv drugog ulaska debit",
"For {0}, only debit accounts can be linked against another credit entry","Za {0}, samo debitne račune mogu povezati protiv druge kreditne unos",
-Form View,Form View,
Forum Activity,Aktivnost foruma,
Free item code is not selected,Besplatni kod artikla nije odabran,
Freight and Forwarding Charges,Teretni i Forwarding Optužbe,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Ostavite se ne može dodijeliti prije {0}, kao odsustvo ravnoteža je već carry-proslijeđen u budućnosti rekord raspodjeli odsustvo {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Ostavite ne može se primijeniti / otkazan prije nego {0}, kao odsustvo ravnoteža je već carry-proslijeđen u budućnosti rekord raspodjeli odsustvo {1}",
Leave of type {0} cannot be longer than {1},Ostavite tipa {0} ne može biti duži od {1},
-Leave the field empty to make purchase orders for all suppliers,Ostavite polje prazno da biste naručili naloge za sve dobavljače,
Leaves,Lišće,
Leaves Allocated Successfully for {0},Lišće Dodijeljeni uspješno za {0},
Leaves has been granted sucessfully,Lišće je uspešno izdato,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Nema artikala sa Bill materijala za proizvodnju,
No Items with Bill of Materials.,Nema predmeta s računom materijala.,
No Permission,Bez dozvole,
-No Quote,Nema citata,
No Remarks,No Napomene,
No Result to submit,Nije rezultat koji se šalje,
No Salary Structure assigned for Employee {0} on given date {1},Struktura zarada nije dodeljena zaposlenom {0} na datom datumu {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Preklapanje uvjeti nalaze između :,
Owner,vlasnik,
PAN,PAN,
-PO already created for all sales order items,PO je već kreiran za sve stavke porudžbine,
POS,POS,
POS Profile,POS profil,
POS Profile is required to use Point-of-Sale,POS profil je potreban za korištenje Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Odaberite Naknada za prvi,
Please select Company,Molimo odaberite Company,
Please select Company and Designation,Izaberite kompaniju i oznaku,
-Please select Company and Party Type first,Molimo najprije odaberite Društva i Party Tip,
Please select Company and Posting Date to getting entries,Molimo da odaberete Kompaniju i Datum objavljivanja da biste dobili unose,
Please select Company first,Molimo najprije odaberite Company,
Please select Completion Date for Completed Asset Maintenance Log,Molimo izaberite Datum završetka za popunjeni dnevnik održavanja sredstava,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Red {0}: UOM Faktor konverzije je obavezno,
Row {0}: select the workstation against the operation {1},Red {0}: izaberite radnu stanicu protiv operacije {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Red {0}: {1} Serijski brojevi potrebni za stavku {2}. Proveli ste {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Red {0}: {1} je potreban za kreiranje Opening {2} faktura,
Row {0}: {1} must be greater than 0,Red {0}: {1} mora biti veći od 0,
Row {0}: {1} {2} does not match with {3},Row {0}: {1} {2} ne odgovara {3},
Row {0}:Start Date must be before End Date,Red {0} : Datum početka mora biti prije datuma završetka,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Pošaljite e-poruku za Grant Review,
Send Now,Pošalji odmah,
Send SMS,Pošalji SMS,
-Send Supplier Emails,Pošalji dobavljač Email,
Send mass SMS to your contacts,Pošalji masovne SMS poruke svojim kontaktima,
Sensitivity,Osjetljivost,
Sent,Poslano,
-Serial #,Serial #,
Serial No and Batch,Serijski broj i Batch,
Serial No is mandatory for Item {0},Serijski Nema je obvezna za točke {0},
Serial No {0} does not belong to Batch {1},Serijski broj {0} ne pripada Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Ime vaše tvrtke za koje ste postavljanje ovog sustava .,
The number of shares and the share numbers are inconsistent,Broj akcija i brojevi učešća su nedosljedni,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Račun plaćačkog plaćanja u planu {0} razlikuje se od naloga za plaćanje u ovom zahtjevu za plaćanje,
-The request for quotation can be accessed by clicking on the following link,Zahtjev za ponudu se može pristupiti klikom na sljedeći link,
The selected BOMs are not for the same item,Izabrani sastavnica nisu za isti predmet,
The selected item cannot have Batch,Izabrana stavka ne može imati Batch,
The seller and the buyer cannot be the same,Prodavac i kupac ne mogu biti isti,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Ukupni iznos komponente fleksibilne naknade {0} ne smije biti manji od maksimuma {1},
Total hours: {0},Ukupan broj sati: {0},
Total leaves allocated is mandatory for Leave Type {0},Ukupna izdvojena listića su obavezna za Tip Leave {0},
-Total weightage assigned should be 100%. It is {0},Ukupno bi trebalo biti dodijeljena weightage 100 % . To je {0},
Total working hours should not be greater than max working hours {0},Ukupno radnog vremena ne smije biti veća od max radnog vremena {0},
Total {0} ({1}),Ukupno {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Ukupno {0} za sve stavke je nula, možda biste trebali promijeniti 'Rasporedite Optužbe na osnovu'",
@@ -3316,7 +3299,6 @@
What do you need help with?,Šta ti je potrebna pomoć?,
What does it do?,Što učiniti ?,
Where manufacturing operations are carried.,Gdje se obavljaju proizvodne operacije.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Dok ste kreirali račun za nadređeno preduzeće {0}, roditeljski račun {1} nije pronađen. Napravite roditeljski račun u odgovarajućem COA",
White,Bijel,
Wire Transfer,Wire Transfer,
WooCommerce Products,WooCommerce Proizvodi,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} kreirane varijante.,
{0} {1} created,{0} {1} stvorio,
{0} {1} does not exist,{0} {1} ne postoji,
-{0} {1} does not exist.,{0} {1} ne postoji.,
{0} {1} has been modified. Please refresh.,{0} {1} je izmijenjen . Osvježite stranicu.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} nije dostavljen tako akciju nije moguće dovršiti,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} je povezan sa {2}, ali Party Party je {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} ne postoji,
{0}: {1} not found in Invoice Details table,{0}: {1} nije pronađen u tabeli details na fakturi,
{} of {},{} od {},
+Assigned To,Dodijeljeno,
Chat,Chat,
Completed By,Završio,
Conditions,Uslovi,
@@ -3506,7 +3488,9 @@
Merge with existing,Merge sa postojećim,
Office,Ured,
Orientation,orijentacija,
+Parent,Roditelj,
Passive,Pasiva,
+Payment Failed,plaćanje nije uspjelo,
Percent,Postotak,
Permanent,trajan,
Personal,Osobno,
@@ -3544,7 +3528,6 @@
Company field is required,Polje kompanije je obavezno,
Creating Dimensions...,Stvaranje dimenzija ...,
Duplicate entry against the item code {0} and manufacturer {1},Duplikat unosa sa šifrom artikla {0} i proizvođačem {1},
-Import Chart Of Accounts from CSV / Excel files,Uvoz računa sa CSV / Excel datoteka,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Nevažeći GSTIN! Uneseni unos ne odgovara formatu GSTIN za vlasnike UIN-a ili nerezidentne dobavljače usluga OIDAR,
Invoice Grand Total,Faktura Grand Total,
Last carbon check date cannot be a future date,Posljednji datum provjere ugljika ne može biti budući datum,
@@ -3556,6 +3539,7 @@
Show {0},Prikaži {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Posebni znakovi osim "-", "#", ".", "/", "{" I "}" nisu dozvoljeni u imenovanju serija",
Target Details,Detalji cilja,
+{0} already has a Parent Procedure {1}.,{0} već ima roditeljsku proceduru {1}.,
API,API,
Annual,godišnji,
Approved,Odobreno,
@@ -3572,6 +3556,8 @@
No data to export,Nema podataka za izvoz,
Portrait,Portret,
Print Heading,Ispis Naslov,
+Scheduler Inactive,Planer neaktivan,
+Scheduler is inactive. Cannot import data.,Planer je neaktivan. Nije moguće uvesti podatke.,
Show Document,Prikaži dokument,
Show Traceback,Prikaži Traceback,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Napravite inspekciju kvaliteta za predmet {0},
Creating Accounts...,Stvaranje računa ...,
Creating bank entries...,Stvaranje bankovnih unosa ...,
-Creating {0},Kreiranje {0},
Credit limit is already defined for the Company {0},Kreditni limit je već definisan za Kompaniju {0},
Ctrl + Enter to submit,Ctrl + Enter da biste poslali,
Ctrl+Enter to submit,Ctrl + Enter za slanje,
@@ -3921,7 +3906,6 @@
Plaid public token error,Greška u javnom tokenu,
Plaid transactions sync error,Greška sinhronizacije transakcija u plaidu,
Please check the error log for details about the import errors,Molimo provjerite dnevnik grešaka za detalje o uvoznim greškama,
-Please click on the following link to set your new password,Molimo kliknite na sljedeći link i postaviti novu lozinku,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Molimo kreirajte <b>DATEV postavke</b> za kompaniju <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Molimo izradite podešavanje unosa u časopisu za iznos {0},
Please do not create more than 500 items at a time,Molimo ne stvarajte više od 500 predmeta odjednom,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Datum izlaska mora biti u budućnosti,
Relieving Date must be greater than or equal to Date of Joining,Datum oslobađanja mora biti veći ili jednak datumu pridruživanja,
Rename,preimenovati,
+Rename Not Allowed,Preimenovanje nije dozvoljeno,
Repayment Method is mandatory for term loans,Način otplate je obavezan za oročene kredite,
Repayment Start Date is mandatory for term loans,Datum početka otplate je obavezan za oročene kredite,
Report Item,Izvještaj,
@@ -4043,7 +4028,6 @@
Select All,Odaberite sve,
Select Difference Account,Odaberite račun razlike,
Select a Default Priority.,Odaberite zadani prioritet.,
-Select a Supplier from the Default Supplier List of the items below.,Izaberite dobavljača sa zadanog popisa dobavljača donjih stavki.,
Select a company,Odaberite kompaniju,
Select finance book for the item {0} at row {1},Odaberite knjigu finansiranja za stavku {0} u retku {1},
Select only one Priority as Default.,Odaberite samo jedan prioritet kao podrazumevani.,
@@ -4247,7 +4231,6 @@
Actual ,Stvaran,
Add to cart,Dodaj u košaricu,
Budget,Budžet,
-Chart Of Accounts Importer,Uvoznik kontnog plana,
Chart of Accounts,Chart of Accounts,
Customer database.,Baza podataka klijenata.,
Days Since Last order,Dana od posljednje narudžbe,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Datum završetka ne može biti manja od početnog datuma,
For Default Supplier (Optional),Za podrazumevani dobavljač,
From date cannot be greater than To date,Od datuma ne može biti veća od To Date,
-Get items from,Get stavke iz,
Group by,Group By,
In stock,Na zalihama,
Item name,Naziv artikla,
@@ -4532,32 +4514,22 @@
Accounts Settings,Podešavanja konta,
Settings for Accounts,Postavke za račune,
Make Accounting Entry For Every Stock Movement,Provjerite knjiženje za svaki burzi pokreta,
-"If enabled, the system will post accounting entries for inventory automatically.","Ako je omogućeno, sustav će objaviti računovodstvene stavke za popis automatski.",
-Accounts Frozen Upto,Računi Frozen Upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Knjiženje zamrznuta do tog datuma, nitko ne može učiniti / mijenjati ulazak, osim uloge naveden u nastavku.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Uloga Dozvoljena Set Frozen Accounts & Frozen Edit unosi,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Korisnici s ovom ulogom smiju postaviti zamrznute račune i izradu / izmjenu računovodstvenih unosa protiv zamrznutih računa,
Determine Address Tax Category From,Odredite kategoriju adrese poreza od,
-Address used to determine Tax Category in transactions.,Adresa koja se koristi za određivanje porezne kategorije u transakcijama.,
Over Billing Allowance (%),Dodatak za naplatu (%),
-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 for $110.,"Postotak koji vam dozvoljava da naplatite više u odnosu na naručeni iznos. Na primjer: Ako je vrijednost narudžbe za artikl 100 USD, a tolerancija postavljena na 10%, tada vam je omogućeno da naplatite 110 USD.",
Credit Controller,Kreditne kontroler,
-Role that is allowed to submit transactions that exceed credit limits set.,Uloga koja je dopušteno podnijeti transakcije koje premašuju kreditnih ograničenja postavljena.,
Check Supplier Invoice Number Uniqueness,Check Dobavljač Faktura Broj Jedinstvenost,
Make Payment via Journal Entry,Izvršiti uplatu preko Journal Entry,
Unlink Payment on Cancellation of Invoice,Odvajanje Plaćanje o otkazivanju fakture,
-Unlink Advance Payment on Cancelation of Order,Prekidajte avansno plaćanje otkaza narudžbe,
Book Asset Depreciation Entry Automatically,Knjiga imovine Amortizacija Entry Automatski,
Automatically Add Taxes and Charges from Item Tax Template,Automatski dodajte poreze i pristojbe sa predloška poreza na stavke,
Automatically Fetch Payment Terms,Automatski preuzmi Uvjete plaćanja,
-Show Inclusive Tax In Print,Prikaži inkluzivni porez u štampi,
Show Payment Schedule in Print,Prikaži raspored plaćanja u štampanju,
Currency Exchange Settings,Postavke razmjene valuta,
Allow Stale Exchange Rates,Dozvolite stare kurseve,
Stale Days,Zastareli dani,
Report Settings,Postavke izveštaja,
Use Custom Cash Flow Format,Koristite Custom Flow Flow Format,
-Only select if you have setup Cash Flow Mapper documents,Samo izaberite ako imate postavke Map Flower Documents,
Allowed To Transact With,Dozvoljeno za transakciju,
SWIFT number,SWIFT broj,
Branch Code,Branch Code,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS kupaca Grupa,
POS Field,POS polje,
POS Item Group,POS Stavka Group,
-[Select],[ izaberite ],
Company Address,Company Adresa,
Update Stock,Ažurirajte Stock,
Ignore Pricing Rule,Ignorirajte Cijene pravilo,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Dobavljač nazivanje,
Default Supplier Group,Podrazumevana grupa dobavljača,
Default Buying Price List,Zadani cjenik kupnje,
-Maintain same rate throughout purchase cycle,Održavanje istu stopu tijekom kupnje ciklusa,
-Allow Item to be added multiple times in a transaction,Dozvolite Stavka treba dodati više puta u transakciji,
Backflush Raw Materials of Subcontract Based On,Backflush sirovine od podizvođača na bazi,
Material Transferred for Subcontract,Preneseni materijal za podugovaranje,
Over Transfer Allowance (%),Dodatak za prebacivanje (%),
@@ -5540,7 +5509,6 @@
Current Stock,Trenutni Stock,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Za pojedinačne dobavljač,
-Supplier Detail,dobavljač Detail,
Link to Material Requests,Link do zahtjeva za materijalom,
Message for Supplier,Poruka za dobavljača,
Request for Quotation Item,Zahtjev za ponudu artikla,
@@ -6481,7 +6449,6 @@
Appraisal Template,Procjena Predložak,
For Employee Name,Za ime zaposlenika,
Goals,Golovi,
-Calculate Total Score,Izračunaj ukupan rezultat,
Total Score (Out of 5),Ukupna ocjena (od 5),
"Any other remarks, noteworthy effort that should go in the records.","Bilo koji drugi primjedbe, napomenuti napor koji treba da ide u evidenciji.",
Appraisal Goal,Procjena gol,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Razlog za odlazak,
Leave Encashed?,Ostavite Encashed?,
Encashment Date,Encashment Datum,
-Exit Interview Details,Izlaz Intervju Detalji,
-Held On,Održanoj,
-Reason for Resignation,Razlog za ostavku,
-Better Prospects,Bolji izgledi,
-Health Concerns,Zdravlje Zabrinutost,
New Workplace,Novi radnom mjestu,
HR-EAD-.YYYY.-,HR-EAD-YYYY.-,
Returned Amount,Iznos vraćenog iznosa,
@@ -6740,10 +6702,7 @@
Employee Settings,Postavke zaposlenih,
Retirement Age,Retirement Godine,
Enter retirement age in years,Unesite dob za odlazak u penziju u godinama,
-Employee Records to be created by,Zaposlenik Records bi se stvorili,
-Employee record is created using selected field. ,Zapis o radniku je kreiran odabirom polja .,
Stop Birthday Reminders,Zaustavi Rođendan Podsjetnici,
-Don't send Employee Birthday Reminders,Ne šaljite podsjetnik za rođendan zaposlenika,
Expense Approver Mandatory In Expense Claim,Troškovi odobrenja obavezni u potraživanju troškova,
Payroll Settings,Postavke plaće,
Leave,Odlazi,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Ostavite odobrenje u obaveznoj aplikaciji,
Show Leaves Of All Department Members In Calendar,Pokažite liste svih članova departmana u kalendaru,
Auto Leave Encashment,Auto Leave Encashment,
-Restrict Backdated Leave Application,Ograničite unaprijed ostavljenu aplikaciju,
Hiring Settings,Postavke zapošljavanja,
Check Vacancies On Job Offer Creation,Proverite slobodna radna mesta na izradi ponude posla,
Identification Document Type,Identifikacioni tip dokumenta,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Proizvodnja Settings,
Raw Materials Consumption,Potrošnja sirovina,
Allow Multiple Material Consumption,Dozvolite višestruku potrošnju materijala,
-Allow multiple Material Consumption against a Work Order,Dozvoli višestruku potrošnju materijala protiv radnog naloga,
Backflush Raw Materials Based On,Backflush sirovine na osnovu,
Material Transferred for Manufacture,Materijal za Preneseni Proizvodnja,
Capacity Planning,Planiranje kapaciteta,
Disable Capacity Planning,Onemogući planiranje kapaciteta,
Allow Overtime,Omogućiti Prekovremeni rad,
-Plan time logs outside Workstation Working Hours.,Planirajte vrijeme za rezanje izvan Workstation Radno vrijeme.,
Allow Production on Holidays,Dopustite Production o praznicima,
Capacity Planning For (Days),Kapacitet planiranje (Dana),
-Try planning operations for X days in advance.,Pokušajte planiraju operacije za X dana unaprijed.,
-Time Between Operations (in mins),Vrijeme između operacije (u min),
-Default 10 mins,Uobičajeno 10 min,
Default Warehouses for Production,Zadane Skladišta za proizvodnju,
Default Work In Progress Warehouse,Uobičajeno Work in Progress Skladište,
Default Finished Goods Warehouse,Uobičajeno Gotovi proizvodi skladište,
Default Scrap Warehouse,Uobičajeno Scrap Warehouse,
-Over Production for Sales and Work Order,Prekomerna proizvodnja za prodaju i radni nalog,
Overproduction Percentage For Sales Order,Procenat prekomerne proizvodnje za porudžbinu prodaje,
Overproduction Percentage For Work Order,Procent prekomerne proizvodnje za radni nalog,
Other Settings,Ostale postavke,
Update BOM Cost Automatically,Ažurirajte BOM trošak automatski,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Automatsko ažuriranje troškova BOM-a putem Planera, na osnovu najnovije procene stope / cenovnika / poslednje stope sirovina.",
Material Request Plan Item,Zahtev za materijalni zahtev za materijal,
Material Request Type,Materijal Zahtjev Tip,
Material Issue,Materijal Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Cilj kvaliteta,
Monitoring Frequency,Frekvencija praćenja,
Weekday,Radnim danom,
-January-April-July-October,Januar-april-juli-oktobar,
-Revision and Revised On,Revizija i revizija dalje,
-Revision,Revizija,
-Revised On,Izmijenjeno,
Objectives,Ciljevi,
Quality Goal Objective,Cilj kvaliteta kvaliteta,
Objective,Cilj,
@@ -7619,7 +7566,6 @@
Processes,Procesi,
Quality Procedure Process,Proces postupka kvaliteta,
Process Description,Opis procesa,
-Child Procedure,Dječiji postupak,
Link existing Quality Procedure.,Povežite postojeći postupak kvaliteta.,
Additional Information,Dodatne informacije,
Quality Review Objective,Cilj pregleda kvaliteta,
@@ -7787,15 +7733,9 @@
Default Customer Group,Zadana grupa korisnika,
Default Territory,Zadani teritorij,
Close Opportunity After Days,Zatvori Opportunity Nakon nekoliko dana,
-Auto close Opportunity after 15 days,Auto blizu Opportunity nakon 15 dana,
Default Quotation Validity Days,Uobičajeni dani valute kvotiranja,
Sales Update Frequency,Frekvencija ažuriranja prodaje,
-How often should project and company be updated based on Sales Transactions.,Koliko često treba ažurirati projekat i kompaniju na osnovu prodajnih transakcija.,
Each Transaction,Svaka transakcija,
-Allow user to edit Price List Rate in transactions,Dopustite korisniku uređivanje cjenika u transakcijama,
-Allow multiple Sales Orders against a Customer's Purchase Order,Dopustite više prodajnih naloga protiv narudžbenicu Kupca,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Potvrditi prodajna cijena za artikl protiv kupovine objekta ili Vrednovanje Rate,
-Hide Customer's Tax Id from Sales Transactions,Sakriti poreza Id klijenta iz transakcija prodaje,
SMS Center,SMS centar,
Send To,Pošalji na adresu,
All Contact,Svi kontakti,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Proizvođači se koriste u Predmeti,
Limited to 12 characters,Ograničena na 12 znakova,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Postavi skladište,
-Sets 'For Warehouse' in each row of the Items table.,Postavlja 'Za skladište' u svaki red tabele Predmeti.,
-Requested For,Traženi Za,
Partially Ordered,Djelomično naređeno,
Transferred,prebačen,
% Ordered,% Poruceno,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Zadana kataloška mjerna jedinica,
Sample Retention Warehouse,Skladište za zadržavanje uzorka,
Default Valuation Method,Zadana metoda vrednovanja,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Postotak koju smiju primiti ili isporučiti više od naručene količine. Na primjer: Ako ste naručili 100 jedinica. i tvoj ispravak je 10% onda se smiju primati 110 jedinica.,
-Action if Quality inspection is not submitted,Akcija ako se ne podnese inspekcija kvaliteta,
Show Barcode Field,Pokaži Barcode Field,
Convert Item Description to Clean HTML,Pretvoriti stavku Opis za čišćenje HTML-a,
-Auto insert Price List rate if missing,Auto umetak Cjenik stopa ako nedostaje,
Allow Negative Stock,Dopustite negativnu zalihu,
Automatically Set Serial Nos based on FIFO,Automatski se postavlja rednim brojevima na osnovu FIFO,
-Set Qty in Transactions based on Serial No Input,Postavite količinu u transakcijama na osnovu Serijski broj ulaza,
Auto Material Request,Auto Materijal Zahtjev,
-Raise Material Request when stock reaches re-order level,Podignite Materijal Zahtjev kad dionica dosegne ponovno poredak razinu,
-Notify by Email on creation of automatic Material Request,Obavijesti putem e-pošte na stvaranje automatskog Materijal Zahtjeva,
Inter Warehouse Transfer Settings,Postavke prijenosa Inter Warehouse,
-Allow Material Transfer From Delivery Note and Sales Invoice,Omogućite prijenos materijala iz otpremnice i fakture o prodaji,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Omogućite prenos materijala sa računa o kupovini i računa o kupovini,
Freeze Stock Entries,Zamrzavanje Stock Unosi,
Stock Frozen Upto,Kataloški Frozen Upto,
-Freeze Stocks Older Than [Days],Freeze Dionice stariji od [ dana ],
-Role Allowed to edit frozen stock,Uloga dopuštenih urediti smrznute zalihe,
Batch Identification,Identifikacija serije,
Use Naming Series,Koristite nazive serije,
Naming Series Prefix,Prefiks naziva serije,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Račun kupnje trendovi,
Purchase Register,Kupnja Registracija,
Quotation Trends,Trendovi ponude,
-Quoted Item Comparison,Citirano Stavka Poređenje,
Received Items To Be Billed,Primljeni Proizvodi se naplaćuje,
Qty to Order,Količina za narudžbu,
Requested Items To Be Transferred,Traženi stavki za prijenos,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Odaberite skladište za zahtjeve za materijalom,
Transfer Materials For Warehouse {0},Transfer materijala za skladište {0},
Production Plan Material Request Warehouse,Skladište zahtjeva za planom proizvodnje,
-Set From Warehouse,Postavljeno iz skladišta,
-Source Warehouse (Material Transfer),Izvorno skladište (prijenos materijala),
Sets 'Source Warehouse' in each row of the items table.,Postavlja 'Izvorno skladište' u svaki red tablice stavki.,
Sets 'Target Warehouse' in each row of the items table.,Postavlja 'Target Warehouse' u svaki red tablice stavki.,
Show Cancelled Entries,Prikaži otkazane unose,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Usluga primljena, ali ne naplaćena",
Deferred Accounting Settings,Postavke odgođenog računovodstva,
Book Deferred Entries Based On,Rezervirajte odložene unose na osnovu,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ako je odabrano "Mjeseci", fiksni iznos knjižiti će se kao odgođeni prihod ili rashod za svaki mjesec, bez obzira na broj dana u mjesecu. Proportirat će se ako odgođeni prihodi ili rashodi ne budu knjiženi cijeli mjesec.",
Days,Dani,
Months,Mjeseci,
Book Deferred Entries Via Journal Entry,Rezervirajte unose putem dnevnika,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Ako ovo nije označeno, stvorit će se izravni GL unosi za knjiženje odgođenih prihoda / rashoda",
Submit Journal Entries,Pošaljite članke u časopisu,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Ako ovo nije označeno, unosi u dnevnik bit će spremljeni u stanje nacrta i morat će se slati ručno",
Enable Distributed Cost Center,Omogući distribuirano mjesto troškova,
@@ -8901,8 +8823,6 @@
Is Inter State,Je Inter State,
Purchase Details,Detalji kupovine,
Depreciation Posting Date,Datum knjiženja amortizacije,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Narudžbenica potrebna za fakturu i izradu računa,
-Purchase Receipt Required for Purchase Invoice Creation,Potvrda o kupovini potrebna za stvaranje računa za kupovinu,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Prema zadanim postavkama, ime dobavljača je postavljeno prema unesenom imenu dobavljača. Ako želite da dobavljače imenuje",
choose the 'Naming Series' option.,odaberite opciju 'Naming Series'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Konfigurišite zadani cjenik prilikom kreiranja nove transakcije kupovine. Cijene stavki će se preuzeti iz ovog cjenika.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Je komponenta poreza na dohodak,
Component properties and references ,Svojstva i reference komponenata,
Additional Salary ,Dodatna plata,
-Condtion and formula,Stanje i formula,
Unmarked days,Neoznačeni dani,
Absent Days,Dani odsutnosti,
Conditions and Formula variable and example,Uvjeti i varijabla formule i primjer,
Feedback By,Povratne informacije od,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.GGGG .-. MM .-. DD.-,
Manufacturing Section,Odjel za proizvodnju,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Prodajni nalog potreban je za fakturu prodaje i stvaranje naloga za isporuku,
-Delivery Note Required for Sales Invoice Creation,Za izradu fakture za prodaju potrebna je dostava,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Po defaultu, Korisničko ime je postavljeno prema punom imenu. Ako želite da kupce imenuje a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Konfigurirajte zadani cjenik prilikom kreiranja nove prodajne transakcije. Cijene stavki će se preuzeti iz ovog cjenika.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ako je ova opcija konfigurirana kao "Da", ERPNext će vas spriječiti da kreirate fakturu ili napomenu o isporuci bez prethodnog kreiranja narudžbenice. Ovu konfiguraciju može se nadjačati za određenog Kupca omogućavanjem potvrdnog okvira 'Omogući izradu fakture za prodaju bez prodajnog naloga' u masteru kupca.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} je uspješno dodan u sve odabrane teme.,
Topics updated,Teme ažurirane,
Academic Term and Program,Akademski termin i program,
-Last Stock Transaction for item {0} was on {1}.,Posljednja transakcija zaliha za stavku {0} bila je {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Transakcije dionicama za stavku {0} ne mogu se objaviti prije ovog vremena.,
Please remove this item and try to submit again or update the posting time.,Uklonite ovu stavku i pokušajte je ponovo poslati ili ažurirajte vrijeme objavljivanja.,
Failed to Authenticate the API key.,Autentifikacija API ključa nije uspjela.,
Invalid Credentials,Nevažeće vjerodajnice,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Molimo provjerite svoj ID klijenta i tajne vrijednosti,
Bank transaction creation error,Greška u kreiranju bankovne transakcije,
Unit of Measurement,Mjerna jedinica,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Red # {}: Stopa prodaje predmeta {} niža je od njegove {}. Stopa prodaje treba biti najmanje {},
Fiscal Year {0} Does Not Exist,Fiskalna godina {0} ne postoji,
Row # {0}: Returned Item {1} does not exist in {2} {3},Redak {0}: Vraćena stavka {1} ne postoji u {2} {3},
Valuation type charges can not be marked as Inclusive,Naknade za vrstu vrednovanja ne mogu se označiti kao sveobuhvatne,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Vrijeme odziva za {0} prioritet u redu {1} ne može biti veće od vremena razlučivanja.,
{0} is not enabled in {1},{0} nije omogućen u {1},
Group by Material Request,Grupiraj prema zahtjevu za materijal,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Red {0}: Za dobavljača {0} za slanje e-pošte potrebna je adresa e-pošte,
Email Sent to Supplier {0},E-pošta poslana dobavljaču {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Pristup zahtjevu za ponudu sa portala je onemogućen. Da biste omogućili pristup, omogućite ga u postavkama portala.",
Supplier Quotation {0} Created,Ponuda dobavljača {0} kreirana,
Valid till Date cannot be before Transaction Date,Važi do datuma ne može biti prije datuma transakcije,
+Unlink Advance Payment on Cancellation of Order,Prekinite vezu s avansnim plaćanjem nakon otkazivanja narudžbe,
+"Simple Python Expression, Example: territory != 'All Territories'","Jednostavan Python izraz, primjer: teritorij! = 'Sve teritorije'",
+Sales Contributions and Incentives,Doprinosi prodaji i podsticaji,
+Sourced by Supplier,Izvor dobavljača,
+Total weightage assigned should be 100%.<br>It is {0},Ukupna dodijeljena težina treba biti 100%.<br> {0} je,
+Account {0} exists in parent company {1}.,Račun {0} postoji u matičnoj kompaniji {1}.,
+"To overrule this, enable '{0}' in company {1}","Da biste ovo prevladali, omogućite '{0}' u kompaniji {1}",
+Invalid condition expression,Nevažeći izraz stanja,
+Please Select a Company First,Prvo odaberite kompaniju,
+Please Select Both Company and Party Type First,Molimo odaberite prvo vrstu kompanije i stranke,
+Provide the invoice portion in percent,Navedite dio fakture u procentima,
+Give number of days according to prior selection,Navedite broj dana prema prethodnom odabiru,
+Email Details,Detalji e-pošte,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Odaberite pozdrav za prijemnik. Npr. Gospodin, gospođa itd.",
+Preview Email,Pregled e-pošte,
+Please select a Supplier,Molimo odaberite dobavljača,
+Supplier Lead Time (days),Vrijeme isporuke dobavljača (dana),
+"Home, Work, etc.","Kuća, posao itd.",
+Exit Interview Held On,Izlazni intervju održan,
+Condition and formula,Stanje i formula,
+Sets 'Target Warehouse' in each row of the Items table.,Postavlja 'Ciljno skladište' u svaki red tabele Predmeti.,
+Sets 'Source Warehouse' in each row of the Items table.,Postavlja 'Izvorno skladište' u svaki red tabele Predmeti.,
+POS Register,POS registar,
+"Can not filter based on POS Profile, if grouped by POS Profile","Ne može se filtrirati na osnovu POS profila, ako je grupirano po POS profilu",
+"Can not filter based on Customer, if grouped by Customer","Ne može se filtrirati prema kupcu, ako ga grupiše kupac",
+"Can not filter based on Cashier, if grouped by Cashier","Ne može se filtrirati na osnovu blagajne, ako je grupirana po blagajni",
+Payment Method,Način plaćanja,
+"Can not filter based on Payment Method, if grouped by Payment Method","Ne može se filtrirati na osnovu načina plaćanja, ako je grupirano prema načinu plaćanja",
+Supplier Quotation Comparison,Usporedba ponuda dobavljača,
+Price per Unit (Stock UOM),Cijena po jedinici (zaliha UOM),
+Group by Supplier,Grupa prema dobavljaču,
+Group by Item,Grupiraj po stavkama,
+Remember to set {field_label}. It is required by {regulation}.,Ne zaboravite postaviti {field_label}. To zahtijeva {propis}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Datum upisa ne može biti pre datuma početka akademske godine {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Datum upisa ne može biti nakon datuma završetka akademskog roka {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Datum upisa ne može biti pre datuma početka akademskog roka {0},
+Future Posting Not Allowed,Objavljivanje u budućnosti nije dozvoljeno,
+"To enable Capital Work in Progress Accounting, ","Da bi se omogućilo računovodstvo kapitalnog rada u toku,",
+you must select Capital Work in Progress Account in accounts table,u tablici računa morate odabrati Račun kapitalnog rada u toku,
+You can also set default CWIP account in Company {},Također možete postaviti zadani CWIP račun u kompaniji {},
+The Request for Quotation can be accessed by clicking on the following button,Zahtjevu za ponudu možete pristupiti klikom na sljedeće dugme,
+Regards,Pozdrav,
+Please click on the following button to set your new password,Kliknite na sljedeći gumb da biste postavili novu lozinku,
+Update Password,Ažuriraj lozinku,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Red # {}: Stopa prodaje predmeta {} niža je od njegove {}. Prodaja {} treba biti najmanje {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Alternativno možete onemogućiti provjeru prodajne cijene u {} da biste zaobišli ovu provjeru.,
+Invalid Selling Price,Nevažeća prodajna cijena,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Adresa mora biti povezana sa kompanijom. Dodajte red za kompaniju u tabelu veza.,
+Company Not Linked,Kompanija nije povezana,
+Import Chart of Accounts from CSV / Excel files,Uvezite kontni plan iz CSV / Excel datoteka,
+Completed Qty cannot be greater than 'Qty to Manufacture',Završena količina ne može biti veća od 'Količina za proizvodnju',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Red {0}: Za dobavljača {1} za slanje e-pošte potrebna je adresa e-pošte,
+"If enabled, the system will post accounting entries for inventory automatically","Ako je omogućeno, sistem će automatski knjižiti knjigovodstvene evidencije zaliha",
+Accounts Frozen Till Date,Računi zamrznuti do datuma,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Knjigovodstvene stavke su zamrznute do danas. Nitko ne može stvarati ili mijenjati unose osim korisnika s ulogom navedenom u nastavku,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Dopuštena uloga za postavljanje zamrznutih računa i uređivanje zamrznutih unosa,
+Address used to determine Tax Category in transactions,Adresa koja se koristi za određivanje kategorije poreza u transakcijama,
+"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 ","Procenat koji vam je dozvoljen da naplatite više u odnosu na naručeni iznos. Na primjer, ako vrijednost narudžbe iznosi 100 USD za artikl, a tolerancija je postavljena na 10%, tada možete naplatiti do 110 USD",
+This role is allowed to submit transactions that exceed credit limits,Ovoj ulozi je dozvoljeno podnošenje transakcija koje premašuju kreditna ograničenja,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ako je odabrano "Mjeseci", fiksni iznos knjižiti će se kao odgođeni prihod ili rashod za svaki mjesec, bez obzira na broj dana u mjesecu. Proportirat će se ako odgođeni prihodi ili rashodi ne budu knjiženi cijeli mjesec",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Ako ovo nije označeno, stvorit će se izravni GL unosi za knjiženje odgođenih prihoda ili troškova",
+Show Inclusive Tax in Print,Prikaži uključeni porez u štampi,
+Only select this if you have set up the Cash Flow Mapper documents,Odaberite ovo samo ako ste postavili dokumente Mape tokova gotovine,
+Payment Channel,Kanal plaćanja,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Da li je narudžbenica potrebna za fakturisanje i izradu računa?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Da li je za izradu računa za kupovinu potrebna potvrda o kupovini?,
+Maintain Same Rate Throughout the Purchase Cycle,Održavajte istu stopu tokom ciklusa kupovine,
+Allow Item To Be Added Multiple Times in a Transaction,Omogućite dodavanje predmeta više puta u transakciji,
+Suppliers,Dobavljači,
+Send Emails to Suppliers,Pošaljite e-poštu dobavljačima,
+Select a Supplier,Odaberite dobavljača,
+Cannot mark attendance for future dates.,Nije moguće označiti prisustvo za buduće datume.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Želite li ažurirati prisustvo?<br> Prisutan: {0}<br> Odsutan: {1},
+Mpesa Settings,Mpesa Settings,
+Initiator Name,Ime inicijatora,
+Till Number,Do broja,
+Sandbox,Sandbox,
+ Online PassKey,Online PassKey,
+Security Credential,Sigurnosne vjerodajnice,
+Get Account Balance,Nabavite stanje na računu,
+Please set the initiator name and the security credential,Molimo postavite ime inicijatora i sigurnosne vjerodajnice,
+Inpatient Medication Entry,Stacionarni unos lijekova,
+HLC-IME-.YYYY.-,FHP-IME-.GGGG.-,
+Item Code (Drug),Šifra artikla (lijek),
+Medication Orders,Narudžbe lijekova,
+Get Pending Medication Orders,Nabavite lijekove na čekanju,
+Inpatient Medication Orders,Stacionarni lijekovi,
+Medication Warehouse,Skladište lijekova,
+Warehouse from where medication stock should be consumed,Skladište odakle treba potrošiti zalihe lijekova,
+Fetching Pending Medication Orders,Preuzimanje naloga za lijekove na čekanju,
+Inpatient Medication Entry Detail,Pojedinosti o ulazu u stacionarne lijekove,
+Medication Details,Detalji lijekova,
+Drug Code,Kod droge,
+Drug Name,Ime lijeka,
+Against Inpatient Medication Order,Protiv naloga za stacionarno liječenje,
+Against Inpatient Medication Order Entry,Protiv ulaza u stacionarne lijekove,
+Inpatient Medication Order,Stacionarni nalog za lijekove,
+HLC-IMO-.YYYY.-,FHP-IMO-.GGGG.-,
+Total Orders,Ukupno narudžbi,
+Completed Orders,Završene narudžbe,
+Add Medication Orders,Dodajte naredbe za lijekove,
+Adding Order Entries,Dodavanje unosa naloga,
+{0} medication orders completed,Završeno je {0} narudžbi lijekova,
+{0} medication order completed,{0} narudžba lijekova završena,
+Inpatient Medication Order Entry,Unos naloga za stacionarne lijekove,
+Is Order Completed,Da li je narudžba završena,
+Employee Records to Be Created By,Evidencija zaposlenih koju će kreirati,
+Employee records are created using the selected field,Evidencija zaposlenih kreira se pomoću izabranog polja,
+Don't send employee birthday reminders,Ne šaljite podsjetnike za rođendan zaposlenika,
+Restrict Backdated Leave Applications,Ograničite aplikacije za napuštanje sa zadnjim datumom,
+Sequence ID,ID sekvence,
+Sequence Id,Sekvenca Id,
+Allow multiple material consumptions against a Work Order,Omogućite višestruku potrošnju materijala prema radnom nalogu,
+Plan time logs outside Workstation working hours,Planirajte evidenciju vremena izvan radnog vremena radne stanice,
+Plan operations X days in advance,Planirajte operacije X dana unaprijed,
+Time Between Operations (Mins),Vrijeme između operacija (minuta),
+Default: 10 mins,Zadano: 10 min,
+Overproduction for Sales and Work Order,Prekomerna proizvodnja za prodaju i radni nalog,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Ažurirajte BOM troškove automatski putem planera, na osnovu najnovije stope procjene / stope cjenika / stope zadnje kupovine sirovina",
+Purchase Order already created for all Sales Order items,Narudžbenica je već kreirana za sve stavke narudžbenice,
+Select Items,Odaberite stavke,
+Against Default Supplier,Protiv zadanog dobavljača,
+Auto close Opportunity after the no. of days mentioned above,Automatsko zatvaranje prilika nakon br. dana gore spomenutih,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Da li je narudžbenica za kupovinu potrebna za izradu fakture i naloga za isporuku?,
+Is Delivery Note Required for Sales Invoice Creation?,Da li je za izradu fakture za prodaju potrebna dostavnica?,
+How often should Project and Company be updated based on Sales Transactions?,Koliko često treba ažurirati projekat i kompaniju na osnovu prodajnih transakcija?,
+Allow User to Edit Price List Rate in Transactions,Omogućite korisniku da uređuje cijenu cjenika u transakcijama,
+Allow Item to Be Added Multiple Times in a Transaction,Dopusti dodavanje predmeta u transakciji više puta,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Omogućite više naloga za prodaju u odnosu na narudžbenice kupca,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Potvrdite prodajnu cijenu za stavku naspram stope kupovine ili stope procjene,
+Hide Customer's Tax ID from Sales Transactions,Sakrijte poreski broj kupca iz prodajnih transakcija,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Procenat koji smijete primiti ili isporučiti više u odnosu na naručenu količinu. Na primjer, ako ste naručili 100 jedinica, a Vaš dodatak je 10%, tada možete primiti 110 jedinica.",
+Action If Quality Inspection Is Not Submitted,Akcija ako se inspekcija kvaliteta ne podnese,
+Auto Insert Price List Rate If Missing,Automatsko umetanje cijene cjenika ako nedostaje,
+Automatically Set Serial Nos Based on FIFO,Automatski postavi serijske brojeve na osnovu FIFO-a,
+Set Qty in Transactions Based on Serial No Input,Postavi količinu u transakcijama na osnovu serijskog unosa,
+Raise Material Request When Stock Reaches Re-order Level,Podignite zahtjev za materijal kada zalihe dosegnu nivo narudžbe,
+Notify by Email on Creation of Automatic Material Request,Obavijestite e-poštom o stvaranju automatskog zahtjeva za materijalom,
+Allow Material Transfer from Delivery Note to Sales Invoice,Omogućite prijenos materijala iz otpremnice na fakturu prodaje,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Omogućite prijenos materijala sa računa o kupovini na račun za kupovinu,
+Freeze Stocks Older Than (Days),Zamrznite zalihe starije od (dana),
+Role Allowed to Edit Frozen Stock,Dopuštena uloga za uređivanje smrznutih zaliha,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Neraspoređeni iznos Unosa za plaćanje {0} veći je od neraspoređenog iznosa Bankovne transakcije,
+Payment Received,Primljena uplata,
+Attendance cannot be marked outside of Academic Year {0},Prisustvo se ne može označiti van akademske godine {0},
+Student is already enrolled via Course Enrollment {0},Student je već upisan putem upisa na predmet {0},
+Attendance cannot be marked for future dates.,Prisustvo se ne može označiti za buduće datume.,
+Please add programs to enable admission application.,Dodajte programe kako biste omogućili prijavu.,
+The following employees are currently still reporting to {0}:,Sljedeći zaposlenici trenutno još uvijek izvještavaju {0}:,
+Please make sure the employees above report to another Active employee.,Molimo osigurajte da se gore navedeni zaposlenici prijave drugom aktivnom zaposleniku.,
+Cannot Relieve Employee,Ne mogu osloboditi zaposlenika,
+Please enter {0},Unesite {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Odaberite drugi način plaćanja. Mpesa ne podržava transakcije u valuti '{0}',
+Transaction Error,Greška u transakciji,
+Mpesa Express Transaction Error,Mpesa Express Transaction Greška,
+"Issue detected with Mpesa configuration, check the error logs for more details","Otkriven je problem s Mpesa konfiguracijom, za više detalja provjerite zapisnike grešaka",
+Mpesa Express Error,Mpesa Express greška,
+Account Balance Processing Error,Pogreška pri obradi stanja računa,
+Please check your configuration and try again,Provjerite svoju konfiguraciju i pokušajte ponovo,
+Mpesa Account Balance Processing Error,Greška u obradi stanja računa Mpesa,
+Balance Details,Detalji stanja,
+Current Balance,Trenutno stanje,
+Available Balance,Dostupno stanje,
+Reserved Balance,Rezervisano stanje,
+Uncleared Balance,Nerazjašnjeni bilans,
+Payment related to {0} is not completed,Isplata vezana za {0} nije završena,
+Row #{}: Item Code: {} is not available under warehouse {}.,Red # {}: Kod artikla: {} nije dostupan u skladištu {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Red # {}: Količina zaliha nije dovoljna za šifru artikla: {} ispod skladišta {}. Dostupna količina {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Red # {}: Odaberite serijski broj i seriju stavke: {} ili ga uklonite da biste dovršili transakciju.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Red # {}: Nije odabran serijski broj za stavku: {}. Odaberite jedan ili ga uklonite da biste dovršili transakciju.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Red # {}: Nije odabrana serija za stavku: {}. Odaberite grupu ili je uklonite da biste dovršili transakciju.,
+Payment amount cannot be less than or equal to 0,Iznos uplate ne može biti manji ili jednak 0,
+Please enter the phone number first,Prvo unesite broj telefona,
+Row #{}: {} {} does not exist.,Red # {}: {} {} ne postoji.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Redak {0}: {1} potreban je za kreiranje početnih {2} faktura,
+You had {} errors while creating opening invoices. Check {} for more details,Imali ste {} grešaka prilikom kreiranja faktura za otvaranje. Pogledajte {} za više detalja,
+Error Occured,Dogodila se greška,
+Opening Invoice Creation In Progress,Otvaranje fakture u toku,
+Creating {} out of {} {},Izrada {} od {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Serijski broj: {0}) ne može se potrošiti jer je rezerviran za potpuno popunjavanje prodajnog naloga {1}.,
+Item {0} {1},Stavka {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Posljednja transakcija zaliha za artikal {0} u skladištu {1} bila je {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Transakcije dionicama za stavku {0} u skladištu {1} ne mogu se objaviti prije ovog vremena.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Knjiženje budućih transakcija dionicama nije dopušteno zbog Nepromjenjive knjige,
+A BOM with name {0} already exists for item {1}.,BOM sa imenom {0} već postoji za stavku {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Jeste li preimenovali stavku? Molimo kontaktirajte administratora / tehničku podršku,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},U retku # {0}: ID sekvence {1} ne može biti manji od ID-a sekvence prethodnog reda {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) mora biti jednako {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, dovršite operaciju {1} prije operacije {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Ne možemo osigurati isporuku serijskim brojem jer se dodaje stavka {0} sa i bez osiguranja isporuke serijskim br.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Stavka {0} nema serijski broj. Samo serilizirani predmeti mogu isporučivati na osnovu serijskog broja,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Nije pronađena aktivna BOM za stavku {0}. Dostava serijskim brojem ne može se osigurati,
+No pending medication orders found for selected criteria,Nije pronađena nijedna narudžba lijekova za odabrane kriterije,
+From Date cannot be after the current date.,Od datuma ne može biti nakon trenutnog datuma.,
+To Date cannot be after the current date.,Do datuma ne može biti nakon trenutnog datuma.,
+From Time cannot be after the current time.,Iz vremena ne može biti nakon trenutnog vremena.,
+To Time cannot be after the current time.,To Time ne može biti nakon trenutnog vremena.,
+Stock Entry {0} created and ,Unos dionica {0} stvoren i,
+Inpatient Medication Orders updated successfully,Nalozi za stacionarne lijekove su uspješno ažurirani,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Red {0}: Ne može se stvoriti unos za stacionarne lijekove protiv otkazanog naloga za stacionarno liječenje {1},
+Row {0}: This Medication Order is already marked as completed,Redak {0}: Ovaj nalog za lijekove već je označen kao ispunjen,
+Quantity not available for {0} in warehouse {1},Količina nije dostupna za {0} u skladištu {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Omogućite Dozvoli negativne zalihe u postavkama zaliha ili kreirajte unos zaliha da biste nastavili.,
+No Inpatient Record found against patient {0},Nije pronađen nijedan stacionarni zapis protiv pacijenta {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Nalog stacionarnih lijekova {0} protiv susreta s pacijentima {1} već postoji.,
+Allow In Returns,Omogući povratak,
+Hide Unavailable Items,Sakrij nedostupne stavke,
+Apply Discount on Discounted Rate,Primijenite popust na sniženu stopu,
+Therapy Plan Template,Predložak plana terapije,
+Fetching Template Details,Preuzimanje podataka o predlošku,
+Linked Item Details,Povezani detalji predmeta,
+Therapy Types,Vrste terapije,
+Therapy Plan Template Detail,Pojedinosti predloška plana terapije,
+Non Conformance,Neusklađenost,
+Process Owner,Vlasnik procesa,
+Corrective Action,Korektivna akcija,
+Preventive Action,Preventivna akcija,
+Problem,Problem,
+Responsible,Odgovorno,
+Completion By,Završetak,
+Process Owner Full Name,Puno ime vlasnika procesa,
+Right Index,Desni indeks,
+Left Index,Lijevi indeks,
+Sub Procedure,Potprocedura,
+Passed,Prošao,
+Print Receipt,Potvrda o ispisu,
+Edit Receipt,Uredi potvrdu,
+Focus on search input,Usredotočite se na unos pretraživanja,
+Focus on Item Group filter,Usredotočite se na filter grupe predmeta,
+Checkout Order / Submit Order / New Order,Narudžba za plaćanje / Predaja naloga / Nova narudžba,
+Add Order Discount,Dodajte popust za narudžbinu,
+Item Code: {0} is not available under warehouse {1}.,Šifra artikla: {0} nije dostupno u skladištu {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Serijski brojevi nisu dostupni za artikl {0} u skladištu {1}. Pokušajte promijeniti skladište.,
+Fetched only {0} available serial numbers.,Preuzeto je samo {0} dostupnih serijskih brojeva.,
+Switch Between Payment Modes,Prebacivanje između načina plaćanja,
+Enter {0} amount.,Unesite iznos od {0}.,
+You don't have enough points to redeem.,Nemate dovoljno bodova za iskorištavanje.,
+You can redeem upto {0}.,Možete iskoristiti do {0}.,
+Enter amount to be redeemed.,Unesite iznos koji treba iskoristiti.,
+You cannot redeem more than {0}.,Ne možete iskoristiti više od {0}.,
+Open Form View,Otvorite prikaz obrasca,
+POS invoice {0} created succesfully,POS račun {0} je uspješno kreiran,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Količina zaliha nije dovoljna za šifru artikla: {0} ispod skladišta {1}. Dostupna količina {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Serijski broj: {0} je već prebačen na drugu POS fakturu.,
+Balance Serial No,Serijski br. Stanja,
+Warehouse: {0} does not belong to {1},Skladište: {0} ne pripada {1},
+Please select batches for batched item {0},Odaberite serije za serijsku stavku {0},
+Please select quantity on row {0},Odaberite količinu u retku {0},
+Please enter serial numbers for serialized item {0},Unesite serijske brojeve za serijsku stavku {0},
+Batch {0} already selected.,Paket {0} je već odabran.,
+Please select a warehouse to get available quantities,Odaberite skladište da biste dobili dostupne količine,
+"For transfer from source, selected quantity cannot be greater than available quantity","Za prijenos iz izvora, odabrana količina ne može biti veća od dostupne količine",
+Cannot find Item with this Barcode,Ne mogu pronaći predmet sa ovim crtičnim kodom,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} je obavezno. Možda zapis mjenjačnice nije kreiran za {1} do {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} je poslao sredstva povezana s tim. Morate otkazati imovinu da biste stvorili povrat kupovine.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Ovaj dokument nije moguće otkazati jer je povezan sa dostavljenim materijalom {0}. Otkažite ga da biste nastavili.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Red # {}: Serijski broj {} je već prebačen na drugu POS fakturu. Odaberite važeći serijski broj.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Red # {}: Serijski brojevi. {} Je već prebačen na drugu POS fakturu. Odaberite važeći serijski broj.,
+Item Unavailable,Predmet nije dostupan,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Red # {}: Serijski broj {} se ne može vratiti jer nije izvršen u originalnoj fakturi {},
+Please set default Cash or Bank account in Mode of Payment {},Postavite zadani gotovinski ili bankovni račun u načinu plaćanja {},
+Please set default Cash or Bank account in Mode of Payments {},Postavite zadani gotovinski ili bankovni račun u načinu plaćanja {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Molimo provjerite je li račun {} račun bilance stanja. Možete promijeniti roditeljski račun u račun bilansa stanja ili odabrati drugi račun.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Molimo provjerite je li račun {} račun koji se plaća. Promijenite vrstu računa u Plativo ili odaberite drugi račun.,
+Row {}: Expense Head changed to {} ,Red {}: Glava rashoda promijenjena u {},
+because account {} is not linked to warehouse {} ,jer račun {} nije povezan sa skladištem {},
+or it is not the default inventory account,ili to nije zadani račun zaliha,
+Expense Head Changed,Promijenjena glava rashoda,
+because expense is booked against this account in Purchase Receipt {},jer je račun evidentiran na ovom računu u potvrdi o kupovini {},
+as no Purchase Receipt is created against Item {}. ,jer se prema stavci {} ne kreira potvrda o kupovini.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,To se radi radi obračunavanja slučajeva kada se potvrda o kupovini kreira nakon fakture za kupovinu,
+Purchase Order Required for item {},Narudžbenica potrebna za stavku {},
+To submit the invoice without purchase order please set {} ,"Da biste predali račun bez narudžbenice, postavite {}",
+as {} in {},kao u {},
+Mandatory Purchase Order,Obavezna narudžbenica,
+Purchase Receipt Required for item {},Potvrda o kupovini za stavku {},
+To submit the invoice without purchase receipt please set {} ,"Da biste predali račun bez potvrde o kupovini, postavite {}",
+Mandatory Purchase Receipt,Obavezna potvrda o kupovini,
+POS Profile {} does not belongs to company {},POS profil {} ne pripada kompaniji {},
+User {} is disabled. Please select valid user/cashier,Korisnik {} je onemogućen. Odaberite valjanog korisnika / blagajnika,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Redak {{}: Originalna faktura {} fakture za povrat {} je {}.,
+Original invoice should be consolidated before or along with the return invoice.,Originalnu fakturu treba konsolidirati prije ili zajedno s povratnom fakturom.,
+You can add original invoice {} manually to proceed.,Možete nastaviti originalnu fakturu {} ručno da biste nastavili.,
+Please ensure {} account is a Balance Sheet account. ,Molimo provjerite je li račun {} račun bilance stanja.,
+You can change the parent account to a Balance Sheet account or select a different account.,Možete promijeniti roditeljski račun u račun bilansa stanja ili odabrati drugi račun.,
+Please ensure {} account is a Receivable account. ,Molimo provjerite je li račun} račun potraživanja.,
+Change the account type to Receivable or select a different account.,Promijenite vrstu računa u Potraživanje ili odaberite drugi račun.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} se ne može otkazati jer su iskorišteni bodovi za lojalnost iskorišteni. Prvo otkažite {} Ne {},
+already exists,već postoji,
+POS Closing Entry {} against {} between selected period,Zatvaranje unosa POS-a {} protiv {} između izabranog perioda,
+POS Invoice is {},POS račun je {},
+POS Profile doesn't matches {},POS profil se ne podudara sa {},
+POS Invoice is not {},POS račun nije {},
+POS Invoice isn't created by user {},POS račun ne kreira korisnik {},
+Row #{}: {},Red # {}: {},
+Invalid POS Invoices,Nevažeći POS računi,
+Please add the account to root level Company - {},Molimo dodajte račun korijenskom nivou kompanije - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Tokom kreiranja računa za kompaniju Child Child {0}, nadređeni račun {1} nije pronađen. Molimo kreirajte roditeljski račun u odgovarajućem COA",
+Account Not Found,Račun nije pronađen,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Prilikom kreiranja računa za Child Company {0}, roditeljski račun {1} je pronađen kao račun glavne knjige.",
+Please convert the parent account in corresponding child company to a group account.,Molimo konvertujte roditeljski račun u odgovarajućem podređenom preduzeću u grupni račun.,
+Invalid Parent Account,Nevažeći račun roditelja,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Preimenovanje je dozvoljeno samo preko matične kompanije {0}, kako bi se izbjegla neusklađenost.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Ako {0} {1} količinu predmeta {2}, shema {3} primijenit će se na stavku.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ako {0} {1} vrijedite stavku {2}, shema {3} primijenit će se na stavku.",
+"As the field {0} is enabled, the field {1} is mandatory.","Kako je polje {0} omogućeno, polje {1} je obavezno.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Kako je polje {0} omogućeno, vrijednost polja {1} trebala bi biti veća od 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Nije moguće isporučiti serijski broj {0} stavke {1} jer je rezervisan za puni popunjeni prodajni nalog {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Prodajni nalog {0} ima rezervaciju za artikal {1}, rezervisani {1} možete dostaviti samo protiv {0}.",
+{0} Serial No {1} cannot be delivered,{0} Serijski broj {1} nije moguće isporučiti,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Red {0}: Predmet podugovaranja je obavezan za sirovinu {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Budući da postoji dovoljno sirovina, zahtjev za materijal nije potreban za Skladište {0}.",
+" If you still want to proceed, please enable {0}.","Ako i dalje želite nastaviti, omogućite {0}.",
+The item referenced by {0} - {1} is already invoiced,Stavka na koju se poziva {0} - {1} već je fakturirana,
+Therapy Session overlaps with {0},Sjednica terapije preklapa se sa {0},
+Therapy Sessions Overlapping,Preklapanje terapijskih sesija,
+Therapy Plans,Planovi terapije,
+"Item Code, warehouse, quantity are required on row {0}","Šifra artikla, skladište, količina su obavezni na retku {0}",
+Get Items from Material Requests against this Supplier,Nabavite predmete od materijalnih zahtjeva protiv ovog dobavljača,
+Enable European Access,Omogućiti evropski pristup,
+Creating Purchase Order ...,Kreiranje narudžbenice ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Odaberite dobavljača od zadanih dobavljača dolje navedenih stavki. Nakon odabira, narudžbenica će se izvršiti samo za proizvode koji pripadaju odabranom dobavljaču.",
+Row #{}: You must select {} serial numbers for item {}.,Red # {}: Morate odabrati {} serijske brojeve za stavku {}.,
diff --git a/erpnext/translations/ca.csv b/erpnext/translations/ca.csv
index cc36c6f..18fa52a 100644
--- a/erpnext/translations/ca.csv
+++ b/erpnext/translations/ca.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Impost de tipus real no pot ser inclòs en el preu de l'article a la fila {0},
Add,Afegir,
Add / Edit Prices,Afegeix / Edita Preus,
-Add All Suppliers,Afegeix tots els proveïdors,
Add Comment,Afegir comentari,
Add Customers,Afegir Clients,
Add Employees,Afegir Empleats,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',No es pot deduir que és la categoria de 'de Valoració "o" Vaulation i Total',
"Cannot delete Serial No {0}, as it is used in stock transactions","No es pot eliminar de sèrie n {0}, ja que s'utilitza en les transaccions de valors",
Cannot enroll more than {0} students for this student group.,No es pot inscriure més de {0} estudiants d'aquest grup d'estudiants.,
-Cannot find Item with this barcode,No es pot trobar cap element amb aquest codi de barres,
Cannot find active Leave Period,No es pot trobar el període d'abandonament actiu,
Cannot produce more Item {0} than Sales Order quantity {1},No es pot produir més Article {0} que en la quantitat de comandes de client {1},
Cannot promote Employee with status Left,No es pot promocionar l'empleat amb estatus d'esquerra,
Cannot refer row number greater than or equal to current row number for this Charge type,No es pot fer referència número de la fila superior o igual al nombre de fila actual d'aquest tipus de càrrega,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,No es pot seleccionar el tipus de càrrega com 'Suma de la fila anterior' o 'Total de la fila anterior' per la primera fila,
-Cannot set a received RFQ to No Quote,No es pot establir una RFQ rebuda a cap quota,
Cannot set as Lost as Sales Order is made.,No es pot establir tan perdut com està feta d'ordres de venda.,
Cannot set authorization on basis of Discount for {0},No es pot establir l'autorització sobre la base de Descompte per {0},
Cannot set multiple Item Defaults for a company.,No es poden establir diversos valors per defecte d'elements per a una empresa.,
@@ -521,7 +518,6 @@
Chargeble,Càrrec,
Charges are updated in Purchase Receipt against each item,Els càrrecs s'actualitzen amb els rebuts de compra contra cada un dels articles,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Els càrrecs es distribuiran proporcionalment basen en Quantitat o import de l'article, segons la teva selecció",
-Chart Of Accounts,Pla General de Comptabilitat,
Chart of Cost Centers,Gràfic de centres de cost,
Check all,Marqueu totes les,
Checkout,caixa,
@@ -581,7 +577,6 @@
Compensatory Off,Compensatori,
Compensatory leave request days not in valid holidays,Dates de sol · licitud de baixa compensatòria no en vacances vàlides,
Complaint,Queixa,
-Completed Qty can not be greater than 'Qty to Manufacture',Completat Quantitat no pot ser major que 'Cant de Fabricació',
Completion Date,Data d'acabament,
Computer,Ordinador,
Condition,Condició,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Creació i gestió de resums de correu electrònic diàries, setmanals i mensuals.",
Create customer quotes,Crear cites de clients,
Create rules to restrict transactions based on values.,Crear regles per restringir les transaccions basades en valors.,
-Created By,Creat per,
Created {0} scorecards for {1} between: ,S'ha creat {0} quadres de paràgraf per {1} entre:,
Creating Company and Importing Chart of Accounts,Creació de l'empresa i importació de gràfics de comptes,
Creating Fees,Creació de tarifes,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,La transferència d'empleats no es pot enviar abans de la data de transferència,
Employee cannot report to himself.,Empleat no pot informar-se a si mateix.,
Employee relieved on {0} must be set as 'Left',Empleat rellevat en {0} ha de ser establert com 'Esquerra',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"L'estat de l'empleat no es pot configurar com a "esquerre", ja que els empleats següents estan informant actualment amb aquest empleat:",
Employee {0} already submited an apllication {1} for the payroll period {2},L'empleat {0} ja ha enviat un apllication {1} per al període de nòmina {2},
Employee {0} has already applied for {1} between {2} and {3} : ,L'empleat {0} ja ha sol·licitat {1} entre {2} i {3}:,
Employee {0} has no maximum benefit amount,L'empleat {0} no té cap benefici màxim,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Per a la fila {0}: introduïu el qty planificat,
"For {0}, only credit accounts can be linked against another debit entry","Per {0}, només els comptes de crèdit es poden vincular amb un altre seient de dèbit",
"For {0}, only debit accounts can be linked against another credit entry","Per {0}, només els comptes de dèbit poden ser enllaçats amb una altra entrada de crèdit",
-Form View,Vista de formularis,
Forum Activity,Activitat del fòrum,
Free item code is not selected,El codi de l’element gratuït no està seleccionat,
Freight and Forwarding Charges,Freight and Forwarding Charges,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Deixi no poden ser distribuïdes abans {0}, com a balanç de la llicència ja ha estat remès equipatge al futur registre d'assignació de permís {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Deixa no pot aplicar / cancel·lada abans de {0}, com a balanç de la llicència ja ha estat remès equipatge al futur registre d'assignació de permís {1}",
Leave of type {0} cannot be longer than {1},Una absència del tipus {0} no pot ser de més de {1},
-Leave the field empty to make purchase orders for all suppliers,Deixeu el camp buit per fer comandes de compra per a tots els proveïdors,
Leaves,Fulles,
Leaves Allocated Successfully for {0},Les fulles Numerat amb èxit per {0},
Leaves has been granted sucessfully,Les fulles s'han concedit amb èxit,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,No hi ha articles amb la llista de materials per a la fabricació de,
No Items with Bill of Materials.,No hi ha articles amb la factura de materials.,
No Permission,No permission,
-No Quote,Sense pressupost,
No Remarks,Sense Observacions,
No Result to submit,Cap resultat per enviar,
No Salary Structure assigned for Employee {0} on given date {1},No s'ha assignat cap estructura salarial assignada a l'empleat {0} en una data determinada {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,La superposició de les condicions trobades entre:,
Owner,Propietari,
PAN,PAN,
-PO already created for all sales order items,OP ja creat per a tots els articles de comanda de vendes,
POS,TPV,
POS Profile,POS Perfil,
POS Profile is required to use Point-of-Sale,El perfil de la TPV és obligatori per utilitzar Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Seleccioneu Tipus de Càrrec primer,
Please select Company,Seleccioneu de l'empresa,
Please select Company and Designation,Seleccioneu Companyia i Designació,
-Please select Company and Party Type first,Seleccioneu de l'empresa i el Partit Tipus primer,
Please select Company and Posting Date to getting entries,Seleccioneu Companyia i Data de publicació per obtenir entrades,
Please select Company first,Si us plau seleccioneu l'empresa primer,
Please select Completion Date for Completed Asset Maintenance Log,Seleccioneu Data de finalització del registre de manteniment d'actius completat,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Fila {0}: UOM factor de conversió és obligatori,
Row {0}: select the workstation against the operation {1},Fila {0}: seleccioneu l'estació de treball contra l'operació {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Fila {0}: {1} Nombres de sèrie obligatoris per a l'element {2}. Heu proporcionat {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,La fila {0}: {1} és necessària per crear les factures d'obertura {2},
Row {0}: {1} must be greater than 0,La fila {0}: {1} ha de ser superior a 0,
Row {0}: {1} {2} does not match with {3},Fila {0}: {1} {2} no coincideix amb {3},
Row {0}:Start Date must be before End Date,Fila {0}: Data d'inici ha de ser anterior Data de finalització,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Envieu un correu electrònic de revisió de la subvenció,
Send Now,Enviar ara,
Send SMS,Enviar SMS,
-Send Supplier Emails,Enviar missatges de correu electrònic del proveïdor,
Send mass SMS to your contacts,Enviar SMS massiu als seus contactes,
Sensitivity,Sensibilitat,
Sent,Enviat,
-Serial #,Serial #,
Serial No and Batch,Número de sèrie i de lot,
Serial No is mandatory for Item {0},Nombre de sèrie és obligatòria per Punt {0},
Serial No {0} does not belong to Batch {1},El número de sèrie {0} no pertany a Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,El nom de la teva empresa per a la qual està creant aquest sistema.,
The number of shares and the share numbers are inconsistent,El nombre d'accions i els números d'accions són incompatibles,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,El compte de la passarel·la de pagament del pla {0} és diferent del compte de la passarel·la de pagament en aquesta sol·licitud de pagament,
-The request for quotation can be accessed by clicking on the following link,La sol·licitud de cotització es pot accedir fent clic al següent enllaç,
The selected BOMs are not for the same item,Les llistes de materials seleccionats no són per al mateix article,
The selected item cannot have Batch,L'element seleccionat no pot tenir per lots,
The seller and the buyer cannot be the same,El venedor i el comprador no poden ser iguals,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Import total del component de benefici flexible {0} no ha de ser inferior al màxim de beneficis {1},
Total hours: {0},Total hores: {0},
Total leaves allocated is mandatory for Leave Type {0},Les fulles totals assignades són obligatòries per al tipus Leave {0},
-Total weightage assigned should be 100%. It is {0},El pes total assignat ha de ser 100%. És {0},
Total working hours should not be greater than max working hours {0},Total d'hores de treball no han de ser més grans que les hores de treball max {0},
Total {0} ({1}),Total {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Total d'{0} per a tots els elements és zero, pot ser que vostè ha de canviar a "Distribuir els càrrecs basats en '",
@@ -3316,7 +3299,6 @@
What do you need help with?,En què necessites ajuda?,
What does it do?,Què fa?,
Where manufacturing operations are carried.,On es realitzen les operacions de fabricació.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Durant la creació d'un compte per a la companyia infantil {0}, no s'ha trobat el compte pare {1}. Creeu el compte pare al COA corresponent",
White,Blanc,
Wire Transfer,Transferència bancària,
WooCommerce Products,Productes WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,S'han creat {0} variants.,
{0} {1} created,{0} {1} creat,
{0} {1} does not exist,{0} {1} no existeix,
-{0} {1} does not exist.,{0} {1} no existeix.,
{0} {1} has been modified. Please refresh.,"{0} {1} ha estat modificat. Si us plau, actualitzia",
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} no s'ha presentat, de manera que l'acció no es pot completar",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} està associat a {2}, però el compte de partit és {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} no existeix,
{0}: {1} not found in Invoice Details table,{0}: {1} no es troba a Detalls de la factura taula,
{} of {},{} de {},
+Assigned To,Assignat a,
Chat,Chat,
Completed By,Completat amb,
Conditions,Condicions,
@@ -3506,7 +3488,9 @@
Merge with existing,Combinar amb existent,
Office,Oficina,
Orientation,Orientació,
+Parent,Pare,
Passive,Passiu,
+Payment Failed,Error en el pagament,
Percent,Per cent,
Permanent,permanent,
Personal,Personal,
@@ -3544,7 +3528,6 @@
Company field is required,El camp de l'empresa és obligatori,
Creating Dimensions...,Creació de dimensions ...,
Duplicate entry against the item code {0} and manufacturer {1},Duplicar l'entrada amb el codi de l'article {0} i el fabricant {1},
-Import Chart Of Accounts from CSV / Excel files,Importa el gràfic de comptes de fitxers CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN no vàlid. L'entrada que heu introduït no coincideix amb el format GSTIN per a titulars d'UIN o proveïdors de serveis OIDAR no residents,
Invoice Grand Total,Factura total total,
Last carbon check date cannot be a future date,L'última data de revisió del carboni no pot ser una data futura,
@@ -3556,6 +3539,7 @@
Show {0},Mostra {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caràcters especials, excepte "-", "#", ".", "/", "{" I "}" no estan permesos en nomenar sèries",
Target Details,Detalls de l'objectiu,
+{0} already has a Parent Procedure {1}.,{0} ja té un procediment progenitor {1}.,
API,API,
Annual,Anual,
Approved,Aprovat,
@@ -3572,6 +3556,8 @@
No data to export,No hi ha dades a exportar,
Portrait,Retrat,
Print Heading,Imprimir Capçalera,
+Scheduler Inactive,Planificador inactiu,
+Scheduler is inactive. Cannot import data.,El planificador està inactiu. No es poden importar dades.,
Show Document,Mostra el document,
Show Traceback,Mostra el seguiment,
Video,Vídeo,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Creeu una inspecció de qualitat per a l'element {0},
Creating Accounts...,Creació de comptes ...,
Creating bank entries...,Creació d'entrades bancàries ...,
-Creating {0},S'està creant {0},
Credit limit is already defined for the Company {0},El límit de crèdit ja està definit per a l'empresa {0},
Ctrl + Enter to submit,Ctrl + Enter per enviar,
Ctrl+Enter to submit,Ctrl + Intro per enviar,
@@ -3921,7 +3906,6 @@
Plaid public token error,Error de testimoni públic de l'escriptura,
Plaid transactions sync error,Error de sincronització de transaccions amb plaid,
Please check the error log for details about the import errors,Consulteu el registre d’errors per obtenir més detalls sobre els errors d’importació,
-Please click on the following link to set your new password,"Si us plau, feu clic al següent enllaç per configurar la nova contrasenya",
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,<b>Creeu la configuració de DATEV</b> per a l'empresa <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Creeu l’entrada del diari d’ajust per l’import {0}.,
Please do not create more than 500 items at a time,No creeu més de 500 articles alhora,
@@ -3997,6 +3981,7 @@
Release date must be in the future,La data de llançament ha de ser en el futur,
Relieving Date must be greater than or equal to Date of Joining,La data de alleujament ha de ser superior o igual a la data d'adhesió,
Rename,Canviar el nom,
+Rename Not Allowed,Canvia de nom no permès,
Repayment Method is mandatory for term loans,El mètode de reemborsament és obligatori per a préstecs a termini,
Repayment Start Date is mandatory for term loans,La data d’inici del reemborsament és obligatòria per als préstecs a termini,
Report Item,Informe,
@@ -4043,7 +4028,6 @@
Select All,Selecciona tot,
Select Difference Account,Seleccioneu el compte de diferències,
Select a Default Priority.,Seleccioneu una prioritat per defecte.,
-Select a Supplier from the Default Supplier List of the items below.,Seleccioneu un proveïdor de la llista de proveïdors predeterminada dels articles següents.,
Select a company,Seleccioneu una empresa,
Select finance book for the item {0} at row {1},Seleccioneu un llibre de finances per a l'element {0} de la fila {1},
Select only one Priority as Default.,Seleccioneu només una prioritat com a predeterminada.,
@@ -4247,7 +4231,6 @@
Actual ,Reial,
Add to cart,Afegir a la cistella,
Budget,Pressupost,
-Chart Of Accounts Importer,Gràfic de l'importador de comptes,
Chart of Accounts,Taula de comptes,
Customer database.,Base de dades de clients.,
Days Since Last order,Dies des de la darrera comanda,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Data de finalització no pot ser inferior a data d'inici,
For Default Supplier (Optional),Per proveïdor predeterminat (opcional),
From date cannot be greater than To date,Des de la data no pot ser superior a la data,
-Get items from,Obtenir articles de,
Group by,Agrupar per,
In stock,En estoc,
Item name,Nom de l'article,
@@ -4532,32 +4514,22 @@
Accounts Settings,Ajustaments de comptabilitat,
Settings for Accounts,Ajustaments de Comptes,
Make Accounting Entry For Every Stock Movement,Feu Entrada Comptabilitat Per Cada moviment d'estoc,
-"If enabled, the system will post accounting entries for inventory automatically.","Si està activat, el sistema comptabilitza els assentaments comptables per a l'inventari automàticament.",
-Accounts Frozen Upto,Comptes bloquejats fins a,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Assentament comptable congelat fins ara, ningú pot fer / modificar entrada excepte paper s'especifica a continuació.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Paper deixa forjar congelats Comptes i editar les entrades congelades,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Els usuaris amb aquest rol poden establir comptes bloquejats i crear/modificar els assentaments comptables contra els comptes bloquejats,
Determine Address Tax Category From,Determineu la categoria d’impost d’adreces de,
-Address used to determine Tax Category in transactions.,Adreça utilitzada per determinar la categoria d’impost en les transaccions.,
Over Billing Allowance (%),Percentatge de facturació superior (%),
-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 for $110.,"Percentatge de facturació superior a l’import sol·licitat. Per exemple: si el valor de la comanda és de 100 dòlars per a un article i la tolerància s’estableix com a 10%, podreu facturar per 110 $.",
Credit Controller,Credit Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,Rol al que es permet presentar les transaccions que excedeixin els límits de crèdit establerts.,
Check Supplier Invoice Number Uniqueness,Comprovar Proveïdor Nombre de factura Singularitat,
Make Payment via Journal Entry,Fa el pagament via entrada de diari,
Unlink Payment on Cancellation of Invoice,Desvinculació de Pagament a la cancel·lació de la factura,
-Unlink Advance Payment on Cancelation of Order,Desconnectar de pagament anticipat per cancel·lació de la comanda,
Book Asset Depreciation Entry Automatically,Llibre d'Actius entrada Depreciació automàticament,
Automatically Add Taxes and Charges from Item Tax Template,Afegiu automàticament impostos i càrrecs de la plantilla d’impost d’ítems,
Automatically Fetch Payment Terms,Recupera automàticament els termes de pagament,
-Show Inclusive Tax In Print,Mostra impostos inclosos en impressió,
Show Payment Schedule in Print,Mostra el calendari de pagaments a la impressió,
Currency Exchange Settings,Configuració de canvi de divises,
Allow Stale Exchange Rates,Permet els tipus d'intercanvi moderats,
Stale Days,Stale Days,
Report Settings,Configuració de l'informe,
Use Custom Cash Flow Format,Utilitzeu el format de flux de caixa personalitzat,
-Only select if you have setup Cash Flow Mapper documents,Seleccioneu només si heu configurat els documents del cartera de flux d'efectiu,
Allowed To Transact With,Permès transitar amb,
SWIFT number,Número SWIFT,
Branch Code,Codi de sucursal,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Grup de Clients,
POS Field,Camp POS,
POS Item Group,POS Grup d'articles,
-[Select],[Seleccionar],
Company Address,Direcció de l'empresa,
Update Stock,Actualització de Stock,
Ignore Pricing Rule,Ignorar Regla preus,
@@ -5495,8 +5466,6 @@
Supplier Naming By,NOmenament de proveïdors per,
Default Supplier Group,Grup de proveïdors per defecte,
Default Buying Price List,Llista de preus per defecte,
-Maintain same rate throughout purchase cycle,Mantenir mateix ritme durant tot el cicle de compra,
-Allow Item to be added multiple times in a transaction,Permetre article a afegir diverses vegades en una transacció,
Backflush Raw Materials of Subcontract Based On,Contenidors de matèries primeres de subcontractació basades en,
Material Transferred for Subcontract,Material transferit per subcontractar,
Over Transfer Allowance (%),Indemnització de transferència (%),
@@ -5540,7 +5509,6 @@
Current Stock,Estoc actual,
PUR-RFQ-.YYYY.-,PUR-RFQ -YYYY.-,
For individual supplier,Per proveïdor individual,
-Supplier Detail,Detall del proveïdor,
Link to Material Requests,Enllaç a sol·licituds de material,
Message for Supplier,Missatge per als Proveïdors,
Request for Quotation Item,Sol·licitud de Cotització d'articles,
@@ -6481,7 +6449,6 @@
Appraisal Template,Plantilla d'Avaluació,
For Employee Name,Per Nom de l'Empleat,
Goals,Objectius,
-Calculate Total Score,Calcular Puntuació total,
Total Score (Out of 5),Puntuació total (de 5),
"Any other remarks, noteworthy effort that should go in the records.","Altres observacions, esforç notable que ha d'anar en els registres.",
Appraisal Goal,Avaluació Meta,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Raons per deixar el,
Leave Encashed?,Leave Encashed?,
Encashment Date,Data Cobrament,
-Exit Interview Details,Detalls de l'entrevista final,
-Held On,Held On,
-Reason for Resignation,Motiu del cessament,
-Better Prospects,Millors perspectives,
-Health Concerns,Problemes de Salut,
New Workplace,Nou lloc de treball,
HR-EAD-.YYYY.-,HR-EAD -YYYY.-,
Returned Amount,Import retornat,
@@ -6740,10 +6702,7 @@
Employee Settings,Configuració dels empleats,
Retirement Age,Edat de jubilació,
Enter retirement age in years,Introdueixi l'edat de jubilació en anys,
-Employee Records to be created by,Registres d'empleats a ser creats per,
-Employee record is created using selected field. ,Es crea el registre d'empleat utilitzant el camp seleccionat.,
Stop Birthday Reminders,Aturar recordatoris d'aniversari,
-Don't send Employee Birthday Reminders,No envieu Empleat recordatoris d'aniversari,
Expense Approver Mandatory In Expense Claim,Aprovació de despeses obligatòria en la reclamació de despeses,
Payroll Settings,Ajustaments de Nòmines,
Leave,Marxa,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Deixeu l'aprovació obligatòria a l'aplicació Deixar,
Show Leaves Of All Department Members In Calendar,Mostra fulles de tots els membres del departament al calendari,
Auto Leave Encashment,Encens automàtic de permís,
-Restrict Backdated Leave Application,Restringiu la sol·licitud d'excedència retardada,
Hiring Settings,Configuració de la contractació,
Check Vacancies On Job Offer Creation,Comproveu les vacants en la creació d’oferta de feina,
Identification Document Type,Tipus de document d'identificació,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Ajustaments de Manufactura,
Raw Materials Consumption,Consum de matèries primeres,
Allow Multiple Material Consumption,Permet el consum de diversos materials,
-Allow multiple Material Consumption against a Work Order,Permet el consum múltiple de material contra una comanda de treball,
Backflush Raw Materials Based On,Backflush matèries primeres Based On,
Material Transferred for Manufacture,Material transferit per a la Fabricació,
Capacity Planning,Planificació de la capacitat,
Disable Capacity Planning,Desactiva la planificació de la capacitat,
Allow Overtime,Permetre Overtime,
-Plan time logs outside Workstation Working Hours.,Planegi registres de temps fora de les hores de treball Estació de treball.,
Allow Production on Holidays,Permetre Producció en Vacances,
Capacity Planning For (Days),Planificació de la capacitat per a (Dies),
-Try planning operations for X days in advance.,Intenta operacions per a la planificació de X dies d'antelació.,
-Time Between Operations (in mins),Temps entre operacions (en minuts),
-Default 10 mins,Per defecte 10 minuts,
Default Warehouses for Production,Magatzems per a la producció,
Default Work In Progress Warehouse,Per defecte Work In Progress Magatzem,
Default Finished Goods Warehouse,Defecte Acabat Productes Magatzem,
Default Scrap Warehouse,Magatzem de ferralla predeterminat,
-Over Production for Sales and Work Order,Sobre producció per ordre de vendes i treball,
Overproduction Percentage For Sales Order,Percentatge de superproducció per a l'ordre de vendes,
Overproduction Percentage For Work Order,Percentatge de sobreproducció per ordre de treball,
Other Settings,altres ajustos,
Update BOM Cost Automatically,Actualitza el cost de la BOM automàticament,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Actualitza el cost de la BOM automàticament mitjançant Scheduler, en funció de la taxa de valoració / tarifa de preu més recent / la darrera tarifa de compra de matèries primeres.",
Material Request Plan Item,Material del pla de sol·licitud de material,
Material Request Type,Material de Sol·licitud Tipus,
Material Issue,Material Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Objectiu de qualitat,
Monitoring Frequency,Freqüència de seguiment,
Weekday,Dia de la setmana,
-January-April-July-October,Gener-abril-juliol-octubre,
-Revision and Revised On,Revisat i revisat,
-Revision,Revisió,
-Revised On,Revisat el dia,
Objectives,Objectius,
Quality Goal Objective,Objectiu de Qualitat,
Objective,Objectiu,
@@ -7619,7 +7566,6 @@
Processes,Processos,
Quality Procedure Process,Procés de procediment de qualitat,
Process Description,Descripció del procés,
-Child Procedure,Procediment infantil,
Link existing Quality Procedure.,Enllaça el procediment de qualitat existent.,
Additional Information,Informació adicional,
Quality Review Objective,Objectiu de revisió de qualitat,
@@ -7787,15 +7733,9 @@
Default Customer Group,Grup predeterminat Client,
Default Territory,Territori per defecte,
Close Opportunity After Days,Tancar Oportunitat Després Dies,
-Auto close Opportunity after 15 days,Tancament automàtic després de 15 dies d'Oportunitats,
Default Quotation Validity Days,Dates de validesa de cotització per defecte,
Sales Update Frequency,Freqüència d'actualització de vendes,
-How often should project and company be updated based on Sales Transactions.,Amb quina freqüència s'ha de projectar i actualitzar l'empresa en funció de les transaccions comercials.,
Each Transaction,Cada transacció,
-Allow user to edit Price List Rate in transactions,Permetre a l'usuari editar la Llista de Preus de Tarifa en transaccions,
-Allow multiple Sales Orders against a Customer's Purchase Order,Permetre diverses ordres de venda en contra d'un client Ordre de Compra,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Validar preu de venda per a l'article contra la Tarifa de compra o taxa de valorització,
-Hide Customer's Tax Id from Sales Transactions,Amaga ID d'Impostos del client segons Transaccions de venda,
SMS Center,Centre d'SMS,
Send To,Enviar a,
All Contact,Tots els contactes,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Fabricants utilitzats en articles,
Limited to 12 characters,Limitat a 12 caràcters,
MAT-MR-.YYYY.-,MAT-MR.- AAAA.-,
-Set Warehouse,Establir magatzem,
-Sets 'For Warehouse' in each row of the Items table.,Estableix "Per a magatzem" a cada fila de la taula Elements.,
-Requested For,Requerida Per,
Partially Ordered,Parcialment ordenat,
Transferred,transferit,
% Ordered,Demanem%,
@@ -8407,24 +8344,14 @@
Default Stock UOM,UDM d'estoc predeterminat,
Sample Retention Warehouse,Mostres de retenció de mostres,
Default Valuation Method,Mètode de valoració predeterminat,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Percentatge que se li permet rebre o lliurar més en contra de la quantitat demanada. Per exemple: Si vostè ha demanat 100 unitats. i el subsidi és de 10%, llavors se li permet rebre 110 unitats.",
-Action if Quality inspection is not submitted,Acció si no es presenta la inspecció de qualitat,
Show Barcode Field,Mostra Camp de codi de barres,
Convert Item Description to Clean HTML,Converteix la descripció de l'element per netejar HTML,
-Auto insert Price List rate if missing,Acte inserit taxa Llista de Preus si falta,
Allow Negative Stock,Permetre existències negatives,
Automatically Set Serial Nos based on FIFO,Ajusta automàticament els números de sèrie basat en FIFO,
-Set Qty in Transactions based on Serial No Input,Establir Qty en les transaccions basades en la entrada sense sèrie,
Auto Material Request,Sol·licitud de material automàtica,
-Raise Material Request when stock reaches re-order level,Llevant Sol·licitud de material quan l'acció arriba al nivell de re-ordre,
-Notify by Email on creation of automatic Material Request,Notificació per correu electrònic a la creació de la Sol·licitud de materials automàtica,
Inter Warehouse Transfer Settings,Configuració de la transferència entre magatzems,
-Allow Material Transfer From Delivery Note and Sales Invoice,Permet la transferència de material des de l’albarà i la factura de venda,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Permet la transferència de material des del rebut de compra i la factura de compra,
Freeze Stock Entries,Freeze Imatges entrades,
Stock Frozen Upto,Estoc bloquejat fins a,
-Freeze Stocks Older Than [Days],Congela els estocs més vells de [dies],
-Role Allowed to edit frozen stock,Paper animals d'editar estoc congelat,
Batch Identification,Identificació per lots,
Use Naming Series,Utilitzeu la sèrie de noms,
Naming Series Prefix,Assignació de noms del prefix de la sèrie,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Purchase Receipt Trends,
Purchase Register,Compra de Registre,
Quotation Trends,Quotation Trends,
-Quoted Item Comparison,Citat article Comparació,
Received Items To Be Billed,Articles rebuts per a facturar,
Qty to Order,Quantitat de comanda,
Requested Items To Be Transferred,Articles sol·licitats per a ser transferits,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Seleccioneu un magatzem per a sol·licituds de material,
Transfer Materials For Warehouse {0},Transferència de materials per a magatzem {0},
Production Plan Material Request Warehouse,Pla de producció Sol·licitud de material Magatzem,
-Set From Warehouse,Establert des del magatzem,
-Source Warehouse (Material Transfer),Magatzem font (transferència de material),
Sets 'Source Warehouse' in each row of the items table.,Estableix "Magatzem font" a cada fila de la taula d'elements.,
Sets 'Target Warehouse' in each row of the items table.,Estableix "Magatzem objectiu" a cada fila de la taula d'elements.,
Show Cancelled Entries,Mostra les entrades cancel·lades,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Servei rebut però no facturat,
Deferred Accounting Settings,Configuració de comptabilitat diferida,
Book Deferred Entries Based On,Llibre d'entrades diferides basades en,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Si se selecciona "Mesos", es reservarà l'import fix com a despeses o ingressos diferits per a cada mes, independentment del nombre de dies d'un mes. Es prorratejarà si no es registren ingressos o despeses diferits durant tot un mes.",
Days,Dies,
Months,Mesos,
Book Deferred Entries Via Journal Entry,Entrades diferides de llibres mitjançant entrada de diari,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Si no es marca aquesta opció, es crearan entrades GL directes per reservar ingressos / despeses diferides",
Submit Journal Entries,Enviar entrades de diari,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Si no es marca aquesta opció, les entrades de diari es desaran en un esborrany i s’hauran d’enviar manualment",
Enable Distributed Cost Center,Activa el centre de costos distribuït,
@@ -8901,8 +8823,6 @@
Is Inter State,És Inter State,
Purchase Details,Detalls de la compra,
Depreciation Posting Date,Data de publicació de l’amortització,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Es requereix una comanda de compra per a la creació de factures i rebuts de compra,
-Purchase Receipt Required for Purchase Invoice Creation,Es requereix un comprovant de compra per a la creació de factures de compra,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Per defecte, el nom del proveïdor s’estableix segons el nom del proveïdor introduït. Si voleu que els proveïdors siguin nomenats per un",
choose the 'Naming Series' option.,trieu l'opció "Sèrie de noms".,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Configureu la llista de preus predeterminada quan creeu una nova transacció de compra. Els preus dels articles s’obtindran d’aquesta llista de preus.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,És un component de l'Impost sobre la Renda,
Component properties and references ,Propietats i referències dels components,
Additional Salary ,Salari addicional,
-Condtion and formula,Condició i fórmula,
Unmarked days,Dies sense marcar,
Absent Days,Dies absents,
Conditions and Formula variable and example,Condició i variable de fórmula i exemple,
Feedback By,Opinió de,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.AAAA .-. MM .-. DD.-,
Manufacturing Section,Secció de fabricació,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Es requereix una comanda de venda per a la creació de factures i lliuraments de lliurament,
-Delivery Note Required for Sales Invoice Creation,Es requereix un lliurament per a la creació de factures de vendes,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Per defecte, el nom del client s'estableix segons el nom complet introduït. Si voleu que els clients siguin nomenats per un",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Configureu la llista de preus predeterminada quan creeu una nova transacció de vendes. Els preus dels articles s’obtindran d’aquesta llista de preus.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Si aquesta opció està configurada com a "Sí", ERPNext us impedirà crear una factura de venda o una nota de lliurament sense crear primer una comanda de venda. Aquesta configuració es pot anul·lar per a un client concret si activeu la casella de selecció "Permet la creació de factures de venda sense comanda de venda" al mestre del client.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} s'ha afegit correctament a tots els temes seleccionats.,
Topics updated,Temes actualitzats,
Academic Term and Program,Terme acadèmic i programa,
-Last Stock Transaction for item {0} was on {1}.,La darrera transacció de valors de l'article {0} va ser el {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Les transaccions borsàries de l'article {0} no es poden publicar abans d'aquest moment.,
Please remove this item and try to submit again or update the posting time.,Elimineu aquest element i proveu d'enviar-lo de nou o actualitzeu l'hora de publicació.,
Failed to Authenticate the API key.,No s'ha pogut autenticar la clau API.,
Invalid Credentials,Credencials no vàlides,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Comproveu el vostre identificador de client Plaid i els valors secrets,
Bank transaction creation error,Error de creació de transaccions bancàries,
Unit of Measurement,Unitat de mesura,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Fila núm. {}: El percentatge de venda de l'article {} és inferior al seu {}. El percentatge de vendes ha de ser mínim {},
Fiscal Year {0} Does Not Exist,L’any fiscal {0} no existeix,
Row # {0}: Returned Item {1} does not exist in {2} {3},Fila núm. {0}: l'article retornat {1} no existeix a {2} {3},
Valuation type charges can not be marked as Inclusive,Els càrrecs per tipus de taxació no es poden marcar com a Inclosius,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,El temps de resposta per a la {0} prioritat de la fila {1} no pot ser superior al temps de resolució.,
{0} is not enabled in {1},{0} no està habilitat a {1},
Group by Material Request,Agrupa per petició de material,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Fila {0}: per al proveïdor {0}, cal enviar una adreça de correu electrònic",
Email Sent to Supplier {0},Correu electrònic enviat al proveïdor {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","L'accés a la sol·licitud de pressupost des del portal està desactivat. Per permetre l'accés, activeu-lo a Configuració del portal.",
Supplier Quotation {0} Created,S'ha creat la cotització del proveïdor {0},
Valid till Date cannot be before Transaction Date,La data vàlida fins a la data no pot ser anterior a la data de la transacció,
+Unlink Advance Payment on Cancellation of Order,Desenllaçar el pagament anticipat de la cancel·lació de la comanda,
+"Simple Python Expression, Example: territory != 'All Territories'","Expressió simple de Python, exemple: territori! = "Tots els territoris"",
+Sales Contributions and Incentives,Contribucions a la venda i incentius,
+Sourced by Supplier,Proveït pel proveïdor,
+Total weightage assigned should be 100%.<br>It is {0},El pes total assignat ha de ser del 100%.<br> És {0},
+Account {0} exists in parent company {1}.,El compte {0} existeix a l'empresa matriu {1}.,
+"To overrule this, enable '{0}' in company {1}","Per anul·lar això, activeu "{0}" a l'empresa {1}",
+Invalid condition expression,Expressió de condició no vàlida,
+Please Select a Company First,Seleccioneu primer una empresa,
+Please Select Both Company and Party Type First,Seleccioneu primer el tipus d’empresa i de festa,
+Provide the invoice portion in percent,Proporcioneu la part de la factura en percentatge,
+Give number of days according to prior selection,Indiqueu el nombre de dies segons la selecció prèvia,
+Email Details,Detalls del correu electrònic,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Seleccioneu una felicitació per al receptor. Per exemple, senyor, senyora, etc.",
+Preview Email,Vista prèvia del correu electrònic,
+Please select a Supplier,Seleccioneu un proveïdor,
+Supplier Lead Time (days),Temps de lliurament del proveïdor (dies),
+"Home, Work, etc.","Llar, feina, etc.",
+Exit Interview Held On,Surt de l'entrevista realitzada,
+Condition and formula,Condició i fórmula,
+Sets 'Target Warehouse' in each row of the Items table.,Estableix "Magatzem objectiu" a cada fila de la taula Elements.,
+Sets 'Source Warehouse' in each row of the Items table.,Estableix "Magatzem font" a cada fila de la taula Elements.,
+POS Register,Registre TPV,
+"Can not filter based on POS Profile, if grouped by POS Profile","No es pot filtrar segons el perfil de TPV, si s'agrupa per perfil de TPV",
+"Can not filter based on Customer, if grouped by Customer","No es pot filtrar en funció del client, si s'agrupa per client",
+"Can not filter based on Cashier, if grouped by Cashier","No es pot filtrar segons el Caixer, si s'agrupa per Caixer",
+Payment Method,Mètode de pagament,
+"Can not filter based on Payment Method, if grouped by Payment Method","No es pot filtrar en funció del mètode de pagament, si s'agrupa per mètode de pagament",
+Supplier Quotation Comparison,Comparació de pressupostos de proveïdors,
+Price per Unit (Stock UOM),Preu per unitat (UOM d’estoc),
+Group by Supplier,Grup per proveïdor,
+Group by Item,Agrupa per ítem,
+Remember to set {field_label}. It is required by {regulation}.,Recordeu establir {field_label}. És obligatori per {reglament}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},La data d'inscripció no pot ser anterior a la data d'inici de l'any acadèmic {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},La data d'inscripció no pot ser posterior a la data de finalització del període acadèmic {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},La data d'inscripció no pot ser anterior a la data d'inici del període acadèmic {0},
+Future Posting Not Allowed,No es permeten publicacions futures,
+"To enable Capital Work in Progress Accounting, ","Per activar la comptabilitat de treballs en capital,",
+you must select Capital Work in Progress Account in accounts table,heu de seleccionar el compte de capital en curs a la taula de comptes,
+You can also set default CWIP account in Company {},També podeu definir un compte CWIP predeterminat a Company {},
+The Request for Quotation can be accessed by clicking on the following button,Es pot accedir a la sol·licitud de pressupost fent clic al botó següent,
+Regards,Salutacions,
+Please click on the following button to set your new password,Feu clic al botó següent per configurar la vostra nova contrasenya,
+Update Password,Actualitza la contrasenya,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Fila núm. {}: El percentatge de vendes de l'article {} és inferior al seu {}. La venda {} hauria de ser mínima {},
+You can alternatively disable selling price validation in {} to bypass this validation.,També podeu desactivar la validació de preus de venda a {} per evitar aquesta validació.,
+Invalid Selling Price,Preu de venda no vàlid,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,L’adreça ha d’estar vinculada a una empresa. Afegiu una fila per a Empresa a la taula Enllaços.,
+Company Not Linked,Empresa no vinculada,
+Import Chart of Accounts from CSV / Excel files,Importeu un pla de comptes de fitxers CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',La quantitat completada no pot ser superior a "Quantitat per fabricar",
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Fila {0}: per al proveïdor {1}, cal enviar una adreça electrònica per enviar un correu electrònic",
+"If enabled, the system will post accounting entries for inventory automatically","Si està activat, el sistema publicarà automàticament les entrades comptables per a l'inventari",
+Accounts Frozen Till Date,Comptes Frozen fins a la data,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Les entrades comptables estan congelades fins aquesta data. Ningú pot crear o modificar entrades excepte usuaris amb el rol especificat a continuació,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Funció permesa per establir comptes congelats i editar entrades congelades,
+Address used to determine Tax Category in transactions,Adreça utilitzada per determinar la categoria fiscal en les transaccions,
+"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 ","El percentatge que se us permet facturar més per l'import ordenat. Per exemple, si el valor de la comanda és de 100 USD per a un article i la tolerància s'estableix en un 10%, podeu facturar fins a 110 USD.",
+This role is allowed to submit transactions that exceed credit limits,Aquesta funció permet enviar transaccions que superin els límits de crèdit,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Si se selecciona "Mesos", es reservarà una quantitat fixa com a ingrés o despesa diferida per a cada mes, independentment del nombre de dies d'un mes. Es prorratejarà si no es registren ingressos o despeses diferits durant tot un mes",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Si no es marca aquesta opció, es crearan entrades GL directes per registrar els ingressos o despeses diferits",
+Show Inclusive Tax in Print,Mostrar impostos inclosos a la impressió,
+Only select this if you have set up the Cash Flow Mapper documents,Seleccioneu aquesta opció només si heu configurat els documents del Mapeador de fluxos d'efectiu,
+Payment Channel,Canal de pagament,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Es requereix una comanda de compra per a la creació de factures i rebuts de compra?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Es requereix un rebut de compra per a la creació de factures de compra?,
+Maintain Same Rate Throughout the Purchase Cycle,Mantingueu la mateixa tarifa durant tot el cicle de compra,
+Allow Item To Be Added Multiple Times in a Transaction,Permet afegir l'article diverses vegades en una transacció,
+Suppliers,Proveïdors,
+Send Emails to Suppliers,Enviar correus electrònics als proveïdors,
+Select a Supplier,Seleccioneu un proveïdor,
+Cannot mark attendance for future dates.,No es pot marcar l'assistència per a properes dates.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Voleu actualitzar l'assistència?<br> Present: {0}<br> Absent: {1},
+Mpesa Settings,Configuració de Mpesa,
+Initiator Name,Nom de l'iniciador,
+Till Number,Fins al número,
+Sandbox,Sandbox,
+ Online PassKey,PassKey en línia,
+Security Credential,Credencial de seguretat,
+Get Account Balance,Obteniu el saldo del compte,
+Please set the initiator name and the security credential,Definiu el nom de l'iniciador i la credencial de seguretat,
+Inpatient Medication Entry,Entrada de medicaments hospitalaris,
+HLC-IME-.YYYY.-,HLC-IME-.AAAA.-,
+Item Code (Drug),Codi de l'article (droga),
+Medication Orders,Comandes de medicaments,
+Get Pending Medication Orders,Obteniu comandes de medicaments pendents,
+Inpatient Medication Orders,Comandes de medicaments hospitalaris,
+Medication Warehouse,Magatzem de medicaments,
+Warehouse from where medication stock should be consumed,Magatzem des d'on s'ha de consumir material de medicació,
+Fetching Pending Medication Orders,Recuperació de comandes de medicaments pendents,
+Inpatient Medication Entry Detail,Detall d’entrada de medicaments hospitalaris,
+Medication Details,Detalls de la medicació,
+Drug Code,Codi de drogues,
+Drug Name,Nom del medicament,
+Against Inpatient Medication Order,Ordre contra la medicació hospitalària,
+Against Inpatient Medication Order Entry,Contra l’entrada d’ordre de medicaments hospitalaris,
+Inpatient Medication Order,Ordre de medicació hospitalària,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Total de comandes,
+Completed Orders,Comandes completades,
+Add Medication Orders,Afegiu comandes de medicaments,
+Adding Order Entries,Afegint entrades de comanda,
+{0} medication orders completed,S'han completat {0} comandes de medicaments,
+{0} medication order completed,S'ha completat la {0} comanda de medicament,
+Inpatient Medication Order Entry,Entrada d’ordres de medicaments hospitalaris,
+Is Order Completed,S'ha completat la comanda,
+Employee Records to Be Created By,Registres d'empleats a crear,
+Employee records are created using the selected field,Els registres dels empleats es creen mitjançant el camp seleccionat,
+Don't send employee birthday reminders,No envieu recordatoris d’aniversari dels empleats,
+Restrict Backdated Leave Applications,Restringeix les sol·licituds d'abandonament actualitzades,
+Sequence ID,Identificador de seqüència,
+Sequence Id,Id. De seqüència,
+Allow multiple material consumptions against a Work Order,Permetre diversos consums de material contra una comanda de treball,
+Plan time logs outside Workstation working hours,Planifiqueu els registres horaris fora de l’horari laboral de l’estació de treball,
+Plan operations X days in advance,Planifiqueu les operacions X dies abans,
+Time Between Operations (Mins),Temps entre operacions (minuts),
+Default: 10 mins,Per defecte: 10 minuts,
+Overproduction for Sales and Work Order,Superproducció per a vendes i ordres de treball,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Actualitzeu el cost de la llista de material automàticament mitjançant el planificador, en funció de la darrera taxa de valoració / tarifa de llista de preus / taxa de darrera compra de matèries primeres",
+Purchase Order already created for all Sales Order items,La comanda de compra ja s'ha creat per a tots els articles de la comanda de venda,
+Select Items,Seleccioneu elements,
+Against Default Supplier,Contra el proveïdor predeterminat,
+Auto close Opportunity after the no. of days mentioned above,Tancament automàtic Oportunitat després del núm. de dies esmentats anteriorment,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Cal fer una comanda de venda per a la creació de factures i lliuraments de lliurament?,
+Is Delivery Note Required for Sales Invoice Creation?,Cal fer un lliurament per a la creació de factures de vendes?,
+How often should Project and Company be updated based on Sales Transactions?,Amb quina freqüència s'han d'actualitzar Project i Companyia en funció de les transaccions de vendes?,
+Allow User to Edit Price List Rate in Transactions,Permetre a l'usuari editar la tarifa de llista de preus en transaccions,
+Allow Item to Be Added Multiple Times in a Transaction,Permet afegir l'article diverses vegades en una transacció,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Permetre diverses comandes de venda contra una comanda de compra d'un client,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Valideu el preu de venda de l’article contra la taxa de compra o la taxa de valoració,
+Hide Customer's Tax ID from Sales Transactions,Amaga l'identificador fiscal del client de les transaccions de vendes,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","El percentatge que se us permet rebre o lliurar més en relació amb la quantitat demanada. Per exemple, si heu demanat 100 unitats i el vostre subsidi és del 10%, podreu rebre 110 unitats.",
+Action If Quality Inspection Is Not Submitted,Acció si no s'envia la inspecció de qualitat,
+Auto Insert Price List Rate If Missing,Insereix una tarifa de llista de preus si falta,
+Automatically Set Serial Nos Based on FIFO,Estableix automàticament els números de sèrie basats en FIFO,
+Set Qty in Transactions Based on Serial No Input,Definiu la quantitat a les transaccions basades en cap entrada de sèrie,
+Raise Material Request When Stock Reaches Re-order Level,Augmenteu la sol·licitud de material quan l'estoc assoleixi el nivell de reordenació,
+Notify by Email on Creation of Automatic Material Request,Notifiqueu per correu electrònic la creació de sol·licitud automàtica de material,
+Allow Material Transfer from Delivery Note to Sales Invoice,Permet la transferència de material des de l’albarà a la factura de venda,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Permet la transferència de material des del rebut de compra a la factura de compra,
+Freeze Stocks Older Than (Days),Congelar les existències de més de (dies),
+Role Allowed to Edit Frozen Stock,Rol permès per editar material congelat,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,L'import no assignat de l'entrada de pagament {0} és superior a l'import no assignat de la transacció bancària,
+Payment Received,Pagament rebut,
+Attendance cannot be marked outside of Academic Year {0},No es pot marcar l'assistència fora del curs acadèmic {0},
+Student is already enrolled via Course Enrollment {0},L'estudiant ja està inscrit a través de la matrícula del curs {0},
+Attendance cannot be marked for future dates.,No es pot marcar l'assistència per a dates futures.,
+Please add programs to enable admission application.,Afegiu programes per habilitar la sol·licitud d'admissió.,
+The following employees are currently still reporting to {0}:,"Actualment, els empleats següents segueixen informant a {0}:",
+Please make sure the employees above report to another Active employee.,Assegureu-vos que els empleats anteriors informin a un altre empleat actiu.,
+Cannot Relieve Employee,No es pot alleujar els empleats,
+Please enter {0},Introduïu {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Seleccioneu una altra forma de pagament. Mpesa no admet transaccions en moneda "{0}",
+Transaction Error,Error de transacció,
+Mpesa Express Transaction Error,Error de transacció Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details",Problema detectat amb la configuració de Mpesa. Consulteu els registres d'errors per obtenir més informació,
+Mpesa Express Error,Error Mpesa Express,
+Account Balance Processing Error,Error de processament del saldo del compte,
+Please check your configuration and try again,Comproveu la configuració i torneu-ho a provar,
+Mpesa Account Balance Processing Error,Error de processament del saldo del compte Mpesa,
+Balance Details,Detalls del saldo,
+Current Balance,Balanç actual,
+Available Balance,Saldo disponible,
+Reserved Balance,Saldo reservat,
+Uncleared Balance,Saldo no esborrat,
+Payment related to {0} is not completed,El pagament relacionat amb {0} no s'ha completat,
+Row #{}: Item Code: {} is not available under warehouse {}.,Fila núm. {}: Codi d'article: {} no està disponible al magatzem {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Fila núm. {}: Quantitat d'estoc insuficient per al codi de l'article: {} sota magatzem {}. Quantitat disponible {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Fila núm. {}: Seleccioneu un número de sèrie i feu un lot contra l'element: {} o traieu-lo per completar la transacció.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Fila núm. {}: No s'ha seleccionat cap número de sèrie per a l'element: {}. Seleccioneu-ne un o suprimiu-lo per completar la transacció.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Fila núm. {}: No s'ha seleccionat cap lot per a l'element: {}. Seleccioneu un lot o traieu-lo per completar la transacció.,
+Payment amount cannot be less than or equal to 0,L’import del pagament no pot ser inferior ni igual a 0,
+Please enter the phone number first,Introduïu primer el número de telèfon,
+Row #{}: {} {} does not exist.,Fila núm. {}: {} {} No existeix.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Fila núm. {0}: {1} és necessària per crear les factures d'obertura {2},
+You had {} errors while creating opening invoices. Check {} for more details,Teníeu {} errors en crear les factures d'obertura. Consulteu {} per obtenir més informació,
+Error Occured,S'ha produït un error,
+Opening Invoice Creation In Progress,Obertura de la creació de factures en curs,
+Creating {} out of {} {},S'està creant {} de {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(El número de sèrie: {0}) no es pot consumir, ja que es reserva per completar la comanda de vendes {1}.",
+Item {0} {1},Element {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,La darrera transacció de valors de l'article {0} al magatzem {1} va ser el {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Les transaccions en estoc de l'article {0} al magatzem {1} no es poden publicar abans d'aquest moment.,
+Posting future stock transactions are not allowed due to Immutable Ledger,No es permet la publicació de futures transaccions d’accions a causa del llibre immutable,
+A BOM with name {0} already exists for item {1}.,Ja existeix una llista de materials amb el nom {0} per a l'element {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Heu canviat el nom de l'element? Poseu-vos en contacte amb l’administrador / assistència tècnica,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},A la fila núm. {0}: l'identificador de seqüència {1} no pot ser inferior a l'identificador de seqüència de fila anterior {2},
+The {0} ({1}) must be equal to {2} ({3}),El valor {0} ({1}) ha de ser igual a {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, completeu l'operació {1} abans de l'operació {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"No es pot garantir el lliurament pel número de sèrie, ja que s'afegeix l'article {0} amb i sense Garantir el lliurament pel número de sèrie.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,L'element {0} no té cap número de sèrie. Només es poden lliurar els articles serialitzats segons el número de sèrie,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,No s'ha trobat cap llista de materials activa per a l'element {0}. No es pot garantir el lliurament per número de sèrie,
+No pending medication orders found for selected criteria,No s'han trobat comandes de medicaments pendents per als criteris seleccionats,
+From Date cannot be after the current date.,Data de sortida no pot ser posterior a la data actual.,
+To Date cannot be after the current date.,Fins a la data no pot ser posterior a la data actual.,
+From Time cannot be after the current time.,From Time no pot ser posterior a l'hora actual.,
+To Time cannot be after the current time.,To Time no pot ser posterior a l'hora actual.,
+Stock Entry {0} created and ,S'ha creat l'entrada de valors {0} i,
+Inpatient Medication Orders updated successfully,Les comandes de medicaments interns s’han actualitzat correctament,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Fila {0}: no es pot crear una entrada de medicament hospitalari contra una comanda de medicament hospitalari cancel·lada {1},
+Row {0}: This Medication Order is already marked as completed,Fila {0}: aquesta comanda de medicaments ja està marcada com a completada,
+Quantity not available for {0} in warehouse {1},Quantitat no disponible per a {0} al magatzem {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Habiliteu Permet l'acció negativa a la configuració d'estoc o creeu l'entrada d'estoc per continuar.,
+No Inpatient Record found against patient {0},No s'ha trobat cap registre d'hospitalització del pacient {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Ja existeix una ordre de medicació hospitalària {0} contra la trobada de pacients {1}.,
+Allow In Returns,Permetre devolucions,
+Hide Unavailable Items,Amaga els elements no disponibles,
+Apply Discount on Discounted Rate,Apliqueu un descompte en la tarifa amb descompte,
+Therapy Plan Template,Plantilla de pla de teràpia,
+Fetching Template Details,S'estan obtenint els detalls de la plantilla,
+Linked Item Details,Detalls de l’enllaç enllaçat,
+Therapy Types,Tipus de teràpia,
+Therapy Plan Template Detail,Detall de plantilla de pla de teràpia,
+Non Conformance,No conformitat,
+Process Owner,Propietari del procés,
+Corrective Action,Acció correctiva,
+Preventive Action,Acció preventiva,
+Problem,Problema,
+Responsible,Responsable,
+Completion By,Finalització per,
+Process Owner Full Name,Nom complet del propietari del procés,
+Right Index,Índex correcte,
+Left Index,Índex esquerre,
+Sub Procedure,Subprocediment,
+Passed,Aprovat,
+Print Receipt,Imprimir el resguard,
+Edit Receipt,Edita el rebut,
+Focus on search input,Centreu-vos en l’entrada de cerca,
+Focus on Item Group filter,Centreu-vos en el filtre del grup d’elements,
+Checkout Order / Submit Order / New Order,Comanda de compra / Enviar comanda / Comanda nova,
+Add Order Discount,Afegiu un descompte de comanda,
+Item Code: {0} is not available under warehouse {1}.,Codi de l'article: {0} no està disponible al magatzem {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Els números de sèrie no estan disponibles per a l'article {0} al magatzem {1}. Proveu de canviar de magatzem.,
+Fetched only {0} available serial numbers.,S'han obtingut només {0} números de sèrie disponibles.,
+Switch Between Payment Modes,Canvia entre els modes de pagament,
+Enter {0} amount.,Introduïu l'import de {0}.,
+You don't have enough points to redeem.,No teniu prou punts per bescanviar.,
+You can redeem upto {0}.,Podeu bescanviar fins a {0}.,
+Enter amount to be redeemed.,Introduïu l'import a canviar.,
+You cannot redeem more than {0}.,No podeu bescanviar més de {0}.,
+Open Form View,Obre la vista de formulari,
+POS invoice {0} created succesfully,La factura TPV {0} s'ha creat correctament,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Quantitat d’estoc insuficient per al codi de l’article: {0} al magatzem {1}. Quantitat disponible {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,No de sèrie: {0} ja s'ha transaccionat a una altra factura TPV.,
+Balance Serial No,Núm. De sèrie de saldo,
+Warehouse: {0} does not belong to {1},Magatzem: {0} no pertany a {1},
+Please select batches for batched item {0},Seleccioneu lots per a l'element per lots {0},
+Please select quantity on row {0},Seleccioneu la quantitat a la fila {0},
+Please enter serial numbers for serialized item {0},Introduïu els números de sèrie de l'element serialitzat {0},
+Batch {0} already selected.,El lot {0} ja està seleccionat.,
+Please select a warehouse to get available quantities,Seleccioneu un magatzem per obtenir les quantitats disponibles,
+"For transfer from source, selected quantity cannot be greater than available quantity","Per a la transferència des de la font, la quantitat seleccionada no pot ser superior a la quantitat disponible",
+Cannot find Item with this Barcode,No es pot trobar un element amb aquest codi de barres,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} és obligatori. Potser el registre de canvi de moneda no es crea de {1} a {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} ha enviat recursos que hi estan vinculats. Heu de cancel·lar els actius per crear la devolució de la compra.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"No es pot cancel·lar aquest document, ja que està enllaçat amb el recurs enviat {0}. Cancel·leu-lo per continuar.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Fila núm. {}: El número de sèrie {} ja s'ha transaccionat a una altra factura TPV. Seleccioneu el número de sèrie vàlid.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Fila núm. {}: Els números de sèrie {} ja s'han transaccionat a una altra factura TPV. Seleccioneu el número de sèrie vàlid.,
+Item Unavailable,Article no disponible,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Fila núm. {}: No es pot retornar el número de sèrie {}, ja que no es va transmetre a la factura original {}",
+Please set default Cash or Bank account in Mode of Payment {},Establiu el compte bancari o efectiu per defecte al mode de pagament {},
+Please set default Cash or Bank account in Mode of Payments {},Establiu el compte bancari o efectiu per defecte al mode de pagaments {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Assegureu-vos que el compte {} és un compte de balanç. Podeu canviar el compte principal per un compte de balanç o seleccionar un altre compte.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Assegureu-vos que el compte {} és un compte de pagament. Canvieu el tipus de compte a Pagable o seleccioneu un altre compte.,
+Row {}: Expense Head changed to {} ,Fila {}: el cap de despesa ha canviat a {},
+because account {} is not linked to warehouse {} ,perquè el compte {} no està enllaçat amb el magatzem {},
+or it is not the default inventory account,o no és el compte d'inventari predeterminat,
+Expense Head Changed,Cap de despesa canviat,
+because expense is booked against this account in Purchase Receipt {},perquè la despesa es reserva en aquest compte al rebut de compra {},
+as no Purchase Receipt is created against Item {}. ,ja que no es crea cap rebut de compra contra l'article {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Això es fa per gestionar la comptabilitat dels casos en què es crea el rebut de compra després de la factura de compra,
+Purchase Order Required for item {},Cal fer una comanda de compra per a l'article {},
+To submit the invoice without purchase order please set {} ,"Per enviar la factura sense comanda de compra, configureu {}",
+as {} in {},com a {},
+Mandatory Purchase Order,Ordre de compra obligatòria,
+Purchase Receipt Required for item {},Cal comprovar el comprovant de l'article {},
+To submit the invoice without purchase receipt please set {} ,"Per enviar la factura sense comprovant de compra, configureu {}",
+Mandatory Purchase Receipt,Rebut de compra obligatori,
+POS Profile {} does not belongs to company {},El perfil de TPV {} no pertany a l'empresa {},
+User {} is disabled. Please select valid user/cashier,L'usuari {} està desactivat. Seleccioneu un usuari / caixer vàlid,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Fila núm. {}: La factura original {} de la factura de devolució {} és {}.,
+Original invoice should be consolidated before or along with the return invoice.,La factura original s’ha de consolidar abans o junt amb la factura de devolució.,
+You can add original invoice {} manually to proceed.,Podeu afegir la factura original {} manualment per continuar.,
+Please ensure {} account is a Balance Sheet account. ,Assegureu-vos que el compte {} és un compte de balanç.,
+You can change the parent account to a Balance Sheet account or select a different account.,Podeu canviar el compte principal per un compte de balanç o seleccionar un altre compte.,
+Please ensure {} account is a Receivable account. ,Assegureu-vos que el compte {} és un compte per cobrar.,
+Change the account type to Receivable or select a different account.,Canvieu el tipus de compte a Cobrar o seleccioneu un altre compte.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} no es pot cancel·lar ja que s'han bescanviat els Punts de fidelitat guanyats. Primer cancel·leu el {} No {},
+already exists,ja existeix,
+POS Closing Entry {} against {} between selected period,Entrada de tancament de TPV {} contra {} entre el període seleccionat,
+POS Invoice is {},La factura TPV és {},
+POS Profile doesn't matches {},El perfil de TPV no coincideix amb {},
+POS Invoice is not {},La factura TPV no és {},
+POS Invoice isn't created by user {},L'usuari {} no crea la factura TPV,
+Row #{}: {},Fila núm. {}: {},
+Invalid POS Invoices,Factures de TPV no vàlides,
+Please add the account to root level Company - {},Afegiu el compte a l'empresa de nivell root - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","En crear un compte per a Child Company {0}, no s'ha trobat el compte principal {1}. Creeu el compte principal al COA corresponent",
+Account Not Found,Compte no trobat,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","En crear un compte per a Child Company {0}, el compte principal {1} es va trobar com a compte de llibres majors.",
+Please convert the parent account in corresponding child company to a group account.,Convertiu el compte principal de l'empresa secundària corresponent en un compte de grup.,
+Invalid Parent Account,Compte principal no vàlid,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",Només es permet canviar el nom a través de l'empresa matriu {0} per evitar desajustos.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Si {0} {1} quantitats de l'article {2}, l'aplicació {3} s'aplicarà a l'article.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Si {0} {1} valeu l'article {2}, l'aplicació {3} s'aplicarà a l'element.",
+"As the field {0} is enabled, the field {1} is mandatory.","Com que el camp {0} està habilitat, el camp {1} és obligatori.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Com que el camp {0} està habilitat, el valor del camp {1} ha de ser superior a 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"No es pot lliurar el número de sèrie {0} de l'article {1}, ja que està reservat per omplir la comanda de venda {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",La comanda de vendes {0} té reserva per a l'article {1}; només podeu enviar reservades {1} contra {0}.,
+{0} Serial No {1} cannot be delivered,{0} No de sèrie {1} no es pot lliurar,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Fila {0}: l'element subcontractat és obligatori per a la matèria primera {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Com que hi ha prou matèries primeres, la sol·licitud de material no és necessària per a Magatzem {0}.",
+" If you still want to proceed, please enable {0}.","Si encara voleu continuar, activeu {0}.",
+The item referenced by {0} - {1} is already invoiced,L'element a què fa referència {0} - {1} ja està facturat,
+Therapy Session overlaps with {0},La sessió de teràpia es coincideix amb {0},
+Therapy Sessions Overlapping,Sessions de teràpia superposades,
+Therapy Plans,Plans de teràpia,
+"Item Code, warehouse, quantity are required on row {0}","El codi de l'article, el magatzem, la quantitat són obligatoris a la fila {0}",
+Get Items from Material Requests against this Supplier,Obteniu articles de sol·licituds de material contra aquest proveïdor,
+Enable European Access,Activa l'accés europeu,
+Creating Purchase Order ...,S'està creant una comanda de compra ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Seleccioneu un proveïdor dels proveïdors predeterminats dels articles següents. En seleccionar-lo, es farà una Comanda de compra únicament contra articles pertanyents al Proveïdor seleccionat.",
+Row #{}: You must select {} serial numbers for item {}.,Fila núm. {}: Heu de seleccionar {} números de sèrie de l'element {}.,
diff --git a/erpnext/translations/cs.csv b/erpnext/translations/cs.csv
index 5b149b0..705e471 100644
--- a/erpnext/translations/cs.csv
+++ b/erpnext/translations/cs.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Aktuální typ daň nemůže být zahrnutý v ceně Položka v řádku {0},
Add,Přidat,
Add / Edit Prices,Přidat / Upravit ceny,
-Add All Suppliers,Přidat všechny dodavatele,
Add Comment,Přidat komentář,
Add Customers,Přidat zákazníky,
Add Employees,Přidejte Zaměstnanci,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Nemůže odečíst, pokud kategorie je pro "ocenění" nebo "Vaulation a Total"",
"Cannot delete Serial No {0}, as it is used in stock transactions","Nelze odstranit Pořadové číslo {0}, který se používá na skladě transakcích",
Cannot enroll more than {0} students for this student group.,Nemůže přihlásit více než {0} studentů na této studentské skupiny.,
-Cannot find Item with this barcode,Nelze najít položku s tímto čárovým kódem,
Cannot find active Leave Period,Nelze najít aktivní období dovolené,
Cannot produce more Item {0} than Sales Order quantity {1},Nelze produkují více položku {0} než prodejní objednávky množství {1},
Cannot promote Employee with status Left,Zaměstnanec se stavem vlevo nelze podpořit,
Cannot refer row number greater than or equal to current row number for this Charge type,Nelze odkazovat číslo řádku větší nebo rovnou aktuální číslo řádku pro tento typ Charge,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"Nelze vybrat druh náboje jako ""On předchozí řady Částka"" nebo ""On předchozí řady Celkem"" pro první řadu",
-Cannot set a received RFQ to No Quote,Nelze nastavit přijatou RFQ na Žádnou nabídku,
Cannot set as Lost as Sales Order is made.,"Nelze nastavit jako Ztraceno, protože je přijata objednávka.",
Cannot set authorization on basis of Discount for {0},Nelze nastavit oprávnění na základě Sleva pro {0},
Cannot set multiple Item Defaults for a company.,Nelze nastavit více položek Výchozí pro společnost.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Poplatky jsou aktualizovány v dokladu o koupi na každou položku,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Poplatky budou rozděleny úměrně na základě položky Množství nebo částkou, dle Vašeho výběru",
-Chart Of Accounts,Diagram účtů,
Chart of Cost Centers,Diagram nákladových středisek,
Check all,Zkontrolovat vše,
Checkout,Odhlásit se,
@@ -581,7 +577,6 @@
Compensatory Off,Vyrovnávací Off,
Compensatory leave request days not in valid holidays,Kompenzační prázdniny nejsou v platných prázdninách,
Complaint,Stížnost,
-Completed Qty can not be greater than 'Qty to Manufacture',"Dokončené množství nemůže být větší než ""Množství do výroby""",
Completion Date,Dokončení Datum,
Computer,Počítač,
Condition,Podmínka,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Vytvářet a spravovat denní, týdenní a měsíční e-mailové digest.",
Create customer quotes,Vytvořit citace zákazníků,
Create rules to restrict transactions based on values.,Vytvoření pravidla pro omezení transakce na základě hodnot.,
-Created By,Vytvořeno (kým),
Created {0} scorecards for {1} between: ,Vytvořili {0} skóre pro {1} mezi:,
Creating Company and Importing Chart of Accounts,Vytváření firemních a importních účtů,
Creating Fees,Vytváření poplatků,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Převod zaměstnanců nelze předložit před datem převodu,
Employee cannot report to himself.,Zaměstnanec nemůže odpovídat sám sobě.,
Employee relieved on {0} must be set as 'Left',"Zaměstnanec úlevu na {0} musí být nastaven jako ""Left""",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Stav zaměstnance nelze nastavit na „Vlevo“, protože následující zaměstnanci v současné době hlásí tomuto zaměstnanci:",
Employee {0} already submited an apllication {1} for the payroll period {2},Zaměstnanec {0} již podal žádost o platbu {2} {1},
Employee {0} has already applied for {1} between {2} and {3} : ,Zaměstnanec {0} již požádal {1} mezi {2} a {3}:,
Employee {0} has no maximum benefit amount,Zaměstnanec {0} nemá maximální částku prospěchu,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Pro řádek {0}: Zadejte plánované množství,
"For {0}, only credit accounts can be linked against another debit entry","Pro {0}, tak úvěrové účty mohou být propojeny na jinou položku debetní",
"For {0}, only debit accounts can be linked against another credit entry","Pro {0}, tak debetní účty mohou být spojeny proti jinému připsání",
-Form View,Zobrazení formuláře,
Forum Activity,Aktivita fóra,
Free item code is not selected,Volný kód položky není vybrán,
Freight and Forwarding Charges,Nákladní a Spediční Poplatky,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Dovolená nemůže být přiděleny před {0}, protože rovnováha dovolené již bylo carry-předávány v budoucí přidělení dovolenou záznamu {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Nechte nelze aplikovat / zrušena před {0}, protože rovnováha dovolené již bylo carry-předávány v budoucí přidělení dovolenou záznamu {1}",
Leave of type {0} cannot be longer than {1},Absence typu {0} nemůže být delší než {1},
-Leave the field empty to make purchase orders for all suppliers,"Ponechte prázdné pole, abyste mohli objednávat všechny dodavatele",
Leaves,Listy,
Leaves Allocated Successfully for {0},Dovolená úspěšně přidělena {0},
Leaves has been granted sucessfully,List byl úspěšně udělen,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Žádné položky s Billem materiálů k výrobě,
No Items with Bill of Materials.,Žádné položky s kusovníkem.,
No Permission,Nemáte oprávnění,
-No Quote,Žádná citace,
No Remarks,Žádné poznámky,
No Result to submit,Žádný výsledek k odeslání,
No Salary Structure assigned for Employee {0} on given date {1},Žádná struktura výdělku pro zaměstnance {0} v daný den {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Překrývající podmínky nalezeno mezi:,
Owner,Majitel,
PAN,PÁNEV,
-PO already created for all sales order items,PO již vytvořeno pro všechny položky prodejní objednávky,
POS,POS,
POS Profile,POS Profile,
POS Profile is required to use Point-of-Sale,Profil POS je vyžadován pro použití prodejního místa,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,"Prosím, vyberte druh tarifu první",
Please select Company,"Prosím, vyberte Company",
Please select Company and Designation,Vyberte prosím společnost a označení,
-Please select Company and Party Type first,Vyberte první společnost a Party Typ,
Please select Company and Posting Date to getting entries,Zvolte prosím datum společnosti a datum odevzdání,
Please select Company first,"Prosím, vyberte první firma",
Please select Completion Date for Completed Asset Maintenance Log,Zvolte datum dokončení dokončeného protokolu údržby aktiv,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Řádek {0}: UOM Konverzní faktor je povinné,
Row {0}: select the workstation against the operation {1},Řádek {0}: vyberte pracovní stanici proti operaci {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Řádek {0}: {1} Sériová čísla vyžadovaná pro položku {2}. Poskytli jste {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Řádek {0}: {1} je zapotřebí pro vytvoření faktur otevření {2},
Row {0}: {1} must be greater than 0,Řádek {0}: {1} musí být větší než 0,
Row {0}: {1} {2} does not match with {3},Řádek {0}: {1} {2} se neshoduje s {3},
Row {0}:Start Date must be before End Date,"Row {0}: datum zahájení, musí být před koncem roku Datum",
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Odeslání e-mailu o revizi grantu,
Send Now,Odeslat nyní,
Send SMS,Pošlete SMS,
-Send Supplier Emails,Poslat Dodavatel e-maily,
Send mass SMS to your contacts,Posílat hromadné SMS vašim kontaktům,
Sensitivity,Citlivost,
Sent,Odesláno,
-Serial #,Serial #,
Serial No and Batch,Pořadové číslo a Batch,
Serial No is mandatory for Item {0},Pořadové číslo je povinná k bodu {0},
Serial No {0} does not belong to Batch {1},Sériové číslo {0} nepatří do skupiny Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Název vaší společnosti, pro kterou nastavení tohoto systému.",
The number of shares and the share numbers are inconsistent,Počet akcií a čísla akcií je nekonzistentní,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Účet platební brány v plánu {0} se liší od účtu platební brány v této žádosti o platbu,
-The request for quotation can be accessed by clicking on the following link,Žádost o cenovou nabídku lze přistupovat kliknutím na následující odkaz,
The selected BOMs are not for the same item,Vybrané kusovníky nejsou stejné položky,
The selected item cannot have Batch,Vybraná položka nemůže mít dávku,
The seller and the buyer cannot be the same,Prodávající a kupující nemohou být stejní,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Celková částka pružné výhody {0} by neměla být menší než maximální dávka {1},
Total hours: {0},Celkem hodin: {0},
Total leaves allocated is mandatory for Leave Type {0},Celkový počet přidělených listů je povinný pro typ dovolené {0},
-Total weightage assigned should be 100%. It is {0},Celková weightage přiřazen by měla být 100%. Je {0},
Total working hours should not be greater than max working hours {0},Celkem pracovní doba by neměla být větší než maximální pracovní doby {0},
Total {0} ({1}),Celkem {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Celkem {0} pro všechny položky je nula, může být byste měli změnit "Rozdělte poplatků založený na"",
@@ -3316,7 +3299,6 @@
What do you need help with?,S čím potřebuješ pomoci?,
What does it do?,Co to dělá?,
Where manufacturing operations are carried.,"Tam, kde jsou výrobní operace prováděny.",
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Při vytváření účtu pro podřízenou společnost {0} nebyl nadřazený účet {1} nalezen. Vytvořte prosím nadřazený účet v odpovídající COA,
White,Bílá,
Wire Transfer,Bankovní převod,
WooCommerce Products,Produkty WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,Vytvořeny varianty {0}.,
{0} {1} created,{0} {1} vytvořil,
{0} {1} does not exist,{0} {1} neexistuje,
-{0} {1} does not exist.,{0} {1} neexistuje.,
{0} {1} has been modified. Please refresh.,{0} {1} byl změněn. Prosím aktualizujte.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} nebyla odeslána, takže akce nemůže být dokončena",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} je přidružena k {2}, ale účet stran je {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} neexistuje,
{0}: {1} not found in Invoice Details table,{0}: {1} nebyla nalezena v tabulce Podrobnosti Faktury,
{} of {},{} z {},
+Assigned To,Přiřazeno (komu),
Chat,Chat,
Completed By,Dokončeno,
Conditions,Podmínky,
@@ -3506,7 +3488,9 @@
Merge with existing,Sloučit s existujícím,
Office,Kancelář,
Orientation,Orientace,
+Parent,Nadřazeno,
Passive,Pasivní,
+Payment Failed,Platba selhala,
Percent,Procento,
Permanent,Trvalý,
Personal,Osobní,
@@ -3544,7 +3528,6 @@
Company field is required,Pole společnosti je povinné,
Creating Dimensions...,Vytváření dimenzí ...,
Duplicate entry against the item code {0} and manufacturer {1},Duplicitní zadání oproti kódu položky {0} a výrobci {1},
-Import Chart Of Accounts from CSV / Excel files,Importujte graf účtů ze souborů CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Neplatný GSTIN! Zadaný vstup neodpovídá formátu GSTIN pro držitele UIN nebo nerezidentní poskytovatele služeb OIDAR,
Invoice Grand Total,Faktura celkem celkem,
Last carbon check date cannot be a future date,Datum poslední kontroly uhlíku nemůže být budoucí,
@@ -3556,6 +3539,7 @@
Show {0},Zobrazit {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Zvláštní znaky kromě "-", "#", ".", "/", "{" A "}" nejsou v názvových řadách povoleny",
Target Details,Podrobnosti o cíli,
+{0} already has a Parent Procedure {1}.,{0} již má rodičovský postup {1}.,
API,API,
Annual,Roční,
Approved,Schválený,
@@ -3572,6 +3556,8 @@
No data to export,Žádné údaje k exportu,
Portrait,Portrét,
Print Heading,Tisk záhlaví,
+Scheduler Inactive,Plánovač neaktivní,
+Scheduler is inactive. Cannot import data.,Plánovač je neaktivní. Nelze importovat data.,
Show Document,Zobrazit dokument,
Show Traceback,Zobrazit Traceback,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Vytvořit kontrolu kvality pro položku {0},
Creating Accounts...,Vytváření účtů ...,
Creating bank entries...,Vytváření bankovních záznamů ...,
-Creating {0},Vytváření {0},
Credit limit is already defined for the Company {0},Úvěrový limit je již pro společnost definován {0},
Ctrl + Enter to submit,Ctrl + Enter k odeslání,
Ctrl+Enter to submit,Ctrl + Enter pro odeslání,
@@ -3921,7 +3906,6 @@
Plaid public token error,Plaid public token error,
Plaid transactions sync error,Chyba synchronizace plaidních transakcí,
Please check the error log for details about the import errors,Podrobnosti o chybách importu naleznete v protokolu chyb,
-Please click on the following link to set your new password,"Prosím klikněte na následující odkaz, pro nastavení nového hesla",
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Vytvořte prosím <b>nastavení DATEV</b> pro společnost <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Vytvořte prosím opravný zápis do deníku o částku {0},
Please do not create more than 500 items at a time,Nevytvářejte více než 500 položek najednou,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Datum vydání musí být v budoucnosti,
Relieving Date must be greater than or equal to Date of Joining,Datum vydání musí být větší nebo rovno Datum připojení,
Rename,Přejmenovat,
+Rename Not Allowed,Přejmenovat není povoleno,
Repayment Method is mandatory for term loans,Způsob splácení je povinný pro termínované půjčky,
Repayment Start Date is mandatory for term loans,Datum zahájení splácení je povinné pro termínované půjčky,
Report Item,Položka sestavy,
@@ -4043,7 +4028,6 @@
Select All,Vybrat vše,
Select Difference Account,Vyberte rozdílový účet,
Select a Default Priority.,Vyberte výchozí prioritu.,
-Select a Supplier from the Default Supplier List of the items below.,Vyberte dodavatele z výchozího seznamu dodavatelů níže uvedených položek.,
Select a company,Vyberte společnost,
Select finance book for the item {0} at row {1},Vyberte finanční knihu pro položku {0} v řádku {1},
Select only one Priority as Default.,Jako výchozí vyberte pouze jednu prioritu.,
@@ -4247,7 +4231,6 @@
Actual ,Aktuální,
Add to cart,Přidat do košíku,
Budget,Rozpočet,
-Chart Of Accounts Importer,Dovozce grafů účtů,
Chart of Accounts,Graf účtů,
Customer database.,Databáze zákazníků.,
Days Since Last order,Počet dnů od poslední objednávky,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Datum ukončení nesmí být menší než datum zahájení,
For Default Supplier (Optional),Výchozí dodavatel (volitelné),
From date cannot be greater than To date,Od Datum nemůže být větší než Datum,
-Get items from,Položka získaná z,
Group by,Seskupit podle,
In stock,Na skladě,
Item name,Název položky,
@@ -4532,32 +4514,22 @@
Accounts Settings,Nastavení účtu,
Settings for Accounts,Nastavení účtů,
Make Accounting Entry For Every Stock Movement,Ujistěte se účetní položka pro každý pohyb zásob,
-"If enabled, the system will post accounting entries for inventory automatically.","Pokud je povoleno, bude systém odesílat účetní položky k zásobám automaticky.",
-Accounts Frozen Upto,Účty Frozen aľ,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Účetní záznam zmrazeny až do tohoto data, nikdo nemůže dělat / upravit položku kromě role uvedeno níže.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Role povoleno nastavit zmrazené účty a upravit Mražené Příspěvky,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Uživatelé s touto rolí se mohou nastavit na zmrazené účty a vytvořit / upravit účetní zápisy proti zmrazených účtů,
Determine Address Tax Category From,Určete kategorii daně z adresy od,
-Address used to determine Tax Category in transactions.,Adresa použitá k určení daňové kategorie v transakcích.,
Over Billing Allowance (%),Příplatek za fakturaci (%),
-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 for $110.,"Procento, které máte možnost vyúčtovat více oproti objednané částce. Například: Pokud je hodnota objednávky 100 $ pro položku a tolerance je nastavena na 10%, pak máte možnost vyúčtovat za 110 $.",
Credit Controller,Credit Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,"Role, která se nechá podat transakcí, které přesahují úvěrové limity.",
Check Supplier Invoice Number Uniqueness,"Zkontrolujte, zda dodavatelské faktury Počet Jedinečnost",
Make Payment via Journal Entry,Provést platbu přes Journal Entry,
Unlink Payment on Cancellation of Invoice,Odpojit Platba o zrušení faktury,
-Unlink Advance Payment on Cancelation of Order,Odpojte zálohy na zrušení objednávky,
Book Asset Depreciation Entry Automatically,Zúčtování odpisu majetku na účet automaticky,
Automatically Add Taxes and Charges from Item Tax Template,Automaticky přidávat daně a poplatky ze šablony položky daně,
Automatically Fetch Payment Terms,Automaticky načíst platební podmínky,
-Show Inclusive Tax In Print,Zobrazit inkluzivní daň v tisku,
Show Payment Schedule in Print,Zobrazit plán placení v tisku,
Currency Exchange Settings,Nastavení směnného kurzu,
Allow Stale Exchange Rates,Povolit stávající kurzy měn,
Stale Days,Stale Days,
Report Settings,Nastavení přehledů,
Use Custom Cash Flow Format,Použijte formát vlastní peněžní toky,
-Only select if you have setup Cash Flow Mapper documents,"Zvolte pouze, pokud máte nastavené dokumenty pro mapování cash flow",
Allowed To Transact With,Povoleno k transakci s,
SWIFT number,Číslo SWIFT,
Branch Code,Kód pobočky,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Customer Group,
POS Field,Pole POS,
POS Item Group,POS položky Group,
-[Select],[Vybrat],
Company Address,adresa společnosti,
Update Stock,Aktualizace skladem,
Ignore Pricing Rule,Ignorovat Ceny pravidlo,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Dodavatel Pojmenování By,
Default Supplier Group,Výchozí skupina dodavatelů,
Default Buying Price List,Výchozí Nákup Ceník,
-Maintain same rate throughout purchase cycle,Udržovat stejnou sazbu po celou kupní cyklu,
-Allow Item to be added multiple times in a transaction,"Povolit položky, které se přidávají vícekrát v transakci",
Backflush Raw Materials of Subcontract Based On,Backflush Suroviny subdodávky založené na,
Material Transferred for Subcontract,Materiál převedený na subdodávky,
Over Transfer Allowance (%),Příspěvek na převody (%),
@@ -5540,7 +5509,6 @@
Current Stock,Current skladem,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Pro jednotlivé dodavatele,
-Supplier Detail,dodavatel Detail,
Link to Material Requests,Odkaz na materiálové požadavky,
Message for Supplier,Zpráva pro dodavatele,
Request for Quotation Item,Žádost o cenovou nabídku výtisku,
@@ -6481,7 +6449,6 @@
Appraisal Template,Posouzení Template,
For Employee Name,Pro jméno zaměstnance,
Goals,Cíle,
-Calculate Total Score,Vypočítat Celková skóre,
Total Score (Out of 5),Celkové skóre (Out of 5),
"Any other remarks, noteworthy effort that should go in the records.","Jakékoli jiné poznámky, pozoruhodné úsilí, které by měly jít v záznamech.",
Appraisal Goal,Posouzení Goal,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Důvod Leaving,
Leave Encashed?,Dovolená proplacena?,
Encashment Date,Inkaso Datum,
-Exit Interview Details,Exit Rozhovor Podrobnosti,
-Held On,Které se konalo dne,
-Reason for Resignation,Důvod rezignace,
-Better Prospects,Lepší vyhlídky,
-Health Concerns,Zdravotní Obavy,
New Workplace,Nové pracoviště,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Vrácená částka,
@@ -6740,10 +6702,7 @@
Employee Settings,Nastavení zaměstnanců,
Retirement Age,Duchodovy vek,
Enter retirement age in years,Zadejte věk odchodu do důchodu v letech,
-Employee Records to be created by,"Zaměstnanec Záznamy, které vytvořil",
-Employee record is created using selected field. ,Záznam Zaměstnanec je vytvořena pomocí vybrané pole.,
Stop Birthday Reminders,Zastavit připomenutí narozenin,
-Don't send Employee Birthday Reminders,Neposílejte zaměstnance připomenutí narozenin,
Expense Approver Mandatory In Expense Claim,Povinnost pojistitele výdajů v nárocích na výdaje,
Payroll Settings,Nastavení Mzdové,
Leave,Odejít,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Povolení odchody je povinné v aplikaci Nechat,
Show Leaves Of All Department Members In Calendar,Zobrazit listy všech členů katedry v kalendáři,
Auto Leave Encashment,Automatické ponechání inkasa,
-Restrict Backdated Leave Application,Omezte aplikaci Backdated Leave,
Hiring Settings,Nastavení najímání,
Check Vacancies On Job Offer Creation,Zkontrolujte volná místa při vytváření pracovních nabídek,
Identification Document Type,Identifikační typ dokumentu,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Výrobní nastavení,
Raw Materials Consumption,Spotřeba surovin,
Allow Multiple Material Consumption,Povolte vícenásobnou spotřebu materiálu,
-Allow multiple Material Consumption against a Work Order,Povolit vícenásobnou spotřebu materiálu proti pracovní zakázce,
Backflush Raw Materials Based On,Se zpětným suroviny na základě,
Material Transferred for Manufacture,Převádí jaderný materiál pro Výroba,
Capacity Planning,Plánování kapacit,
Disable Capacity Planning,Zakázat plánování kapacity,
Allow Overtime,Povolit Přesčasy,
-Plan time logs outside Workstation Working Hours.,Naplánujte čas protokoly mimo Workstation pracovních hodin.,
Allow Production on Holidays,Povolit Výrobu při dovolené,
Capacity Planning For (Days),Plánování kapacit Pro (dny),
-Try planning operations for X days in advance.,Zkuste plánování operací pro X dní předem.,
-Time Between Operations (in mins),Doba mezi operací (v min),
-Default 10 mins,Výchozí 10 min,
Default Warehouses for Production,Výchozí sklady pro výrobu,
Default Work In Progress Warehouse,Výchozí práci ve skladu Progress,
Default Finished Goods Warehouse,Výchozí sklad hotových výrobků,
Default Scrap Warehouse,Výchozí sklad šrotu,
-Over Production for Sales and Work Order,Over Production for Sales and Work Order,
Overproduction Percentage For Sales Order,Procento nadvýroby pro objednávku prodeje,
Overproduction Percentage For Work Order,Procento nadvýroby pro pracovní pořadí,
Other Settings,další nastavení,
Update BOM Cost Automatically,Aktualizovat cenu BOM automaticky,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Aktualizujte náklady na BOM automaticky pomocí programu Plánovač, založený na nejnovější hodnotící sazbě / ceníku / posledním nákupu surovin.",
Material Request Plan Item,Položka materiálu požadovaného plánu,
Material Request Type,Materiál Typ požadavku,
Material Issue,Material Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Kvalitní cíl,
Monitoring Frequency,Frekvence monitorování,
Weekday,Všední den,
-January-April-July-October,Leden-duben-červenec-říjen,
-Revision and Revised On,Revize a revize dne,
-Revision,Revize,
-Revised On,Revidováno dne,
Objectives,Cíle,
Quality Goal Objective,Cíl kvality,
Objective,Objektivní,
@@ -7619,7 +7566,6 @@
Processes,Procesy,
Quality Procedure Process,Proces řízení kvality,
Process Description,Popis procesu,
-Child Procedure,Postup dítěte,
Link existing Quality Procedure.,Propojte stávající postup kvality.,
Additional Information,dodatečné informace,
Quality Review Objective,Cíl kontroly kvality,
@@ -7787,15 +7733,9 @@
Default Customer Group,Výchozí Customer Group,
Default Territory,Výchozí Territory,
Close Opportunity After Days,V blízkosti Příležitost po několika dnech,
-Auto close Opportunity after 15 days,Auto v blízkosti Příležitost po 15 dnech,
Default Quotation Validity Days,Výchozí dny platnosti kotací,
Sales Update Frequency,Frekvence aktualizace prodeje,
-How often should project and company be updated based on Sales Transactions.,Jak často by měl být projekt a společnost aktualizovány na základě prodejních transakcí.,
Each Transaction,Každé Transakce,
-Allow user to edit Price List Rate in transactions,Povolit uživateli upravovat Ceník Cena při transakcích,
-Allow multiple Sales Orders against a Customer's Purchase Order,Povolit více Prodejní objednávky proti Zákazníka Objednávky,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Ověření prodejní ceny položky proti nákupní ceně nebo ocenění,
-Hide Customer's Tax Id from Sales Transactions,Inkognito daně zákazníka z prodejních transakcí,
SMS Center,SMS centrum,
Send To,Odeslat,
All Contact,Vše Kontakt,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Výrobci používané v bodech,
Limited to 12 characters,Omezeno na 12 znaků,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Nastavit sklad,
-Sets 'For Warehouse' in each row of the Items table.,Nastaví v každém řádku tabulky „For Warehouse“.,
-Requested For,Požadovaných pro,
Partially Ordered,Částečně objednáno,
Transferred,Přestoupil,
% Ordered,% objednáno,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Výchozí Skladem UOM,
Sample Retention Warehouse,Úložiště uchovávání vzorků,
Default Valuation Method,Výchozí metoda ocenění,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Procento máte možnost přijímat nebo dodávat více proti objednaného množství. Například: Pokud jste si objednali 100 kusů. a váš příspěvek je 10%, pak máte možnost získat 110 jednotek.",
-Action if Quality inspection is not submitted,"Akce, pokud není předložena kontrola kvality",
Show Barcode Field,Show čárového kódu Field,
Convert Item Description to Clean HTML,Převést položku Popis k vyčištění HTML,
-Auto insert Price List rate if missing,"Auto vložka Ceník sazba, pokud chybí",
Allow Negative Stock,Povolit Negativní Sklad,
Automatically Set Serial Nos based on FIFO,Automaticky nastavit sériových čísel na základě FIFO,
-Set Qty in Transactions based on Serial No Input,Nastavte počet transakcí na základě sériového č. Vstupu,
Auto Material Request,Auto materiálu Poptávka,
-Raise Material Request when stock reaches re-order level,Zvýšit Materiál vyžádání při stock dosáhne úrovně re-order,
-Notify by Email on creation of automatic Material Request,Upozornit e-mailem na tvorbu automatických Materiál Poptávka,
Inter Warehouse Transfer Settings,Nastavení přenosu Inter Warehouse,
-Allow Material Transfer From Delivery Note and Sales Invoice,Povolit přenos materiálu z dodacího listu a prodejní faktury,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Povolit převod materiálu z dokladu o nákupu a faktury za nákup,
Freeze Stock Entries,Freeze Stock Příspěvky,
Stock Frozen Upto,Reklamní Frozen aľ,
-Freeze Stocks Older Than [Days],Freeze Zásoby Starší než [dny],
-Role Allowed to edit frozen stock,Role povoleno upravovat zmrazené zásoby,
Batch Identification,Identifikace šarže,
Use Naming Series,Používejte sérii pojmenování,
Naming Series Prefix,Pojmenování předpony řady,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Doklad o koupi Trendy,
Purchase Register,Nákup Register,
Quotation Trends,Uvozovky Trendy,
-Quoted Item Comparison,Citoval Položka Porovnání,
Received Items To Be Billed,"Přijaté položek, které mají být účtovány",
Qty to Order,Množství k objednávce,
Requested Items To Be Transferred,Požadované položky mají být převedeny,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Vyberte sklad pro požadavky na materiál,
Transfer Materials For Warehouse {0},Přenos materiálů do skladu {0},
Production Plan Material Request Warehouse,Sklad požadavku na materiál výrobního plánu,
-Set From Warehouse,Nastaveno ze skladu,
-Source Warehouse (Material Transfer),Zdrojový sklad (přenos materiálu),
Sets 'Source Warehouse' in each row of the items table.,Nastaví v každém řádku tabulky položek „Zdrojový sklad“.,
Sets 'Target Warehouse' in each row of the items table.,Nastaví v každém řádku tabulky položek „Target Warehouse“.,
Show Cancelled Entries,Zobrazit zrušené položky,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Služba přijata, ale není účtována",
Deferred Accounting Settings,Nastavení odloženého účetnictví,
Book Deferred Entries Based On,Zarezervujte odložené položky na základě,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Pokud je vybrána možnost „Měsíce“, bude pevná částka zaúčtována jako odložený výnos nebo výdaj za každý měsíc bez ohledu na počet dní v měsíci. Pokud nebudou odložené výnosy nebo výdaje rezervovány na celý měsíc, budou rozděleny podle nákladů.",
Days,Dny,
Months,Měsíce,
Book Deferred Entries Via Journal Entry,Zarezervujte si odložené položky prostřednictvím záznamu v deníku,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Pokud toto políčko nezaškrtnete, budou vytvořeny přímé položky GL k zaúčtování odložených výnosů / výdajů",
Submit Journal Entries,Odeslat položky deníku,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Pokud není zaškrtnuto, budou se deníkové záznamy ukládat ve stavu konceptu a budou muset být odeslány ručně",
Enable Distributed Cost Center,Povolit distribuované nákladové středisko,
@@ -8901,8 +8823,6 @@
Is Inter State,Je Inter State,
Purchase Details,Podrobnosti o nákupu,
Depreciation Posting Date,Datum zaúčtování odpisů,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Nákupní objednávka požadovaná pro vytvoření nákupní faktury a vytvoření účtenky,
-Purchase Receipt Required for Purchase Invoice Creation,Potvrzení o nákupu požadované pro vytvoření faktury za nákup,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Ve výchozím nastavení je název dodavatele nastaven podle zadaného názvu dodavatele. Pokud chcete, aby Dodavatelé byli pojmenováni a",
choose the 'Naming Series' option.,vyberte možnost „Pojmenování série“.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Při vytváření nové nákupní transakce nakonfigurujte výchozí ceník. Ceny položek budou načteny z tohoto ceníku.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Je složkou daně z příjmu,
Component properties and references ,Vlastnosti komponent a odkazy,
Additional Salary ,Dodatečný plat,
-Condtion and formula,Podmínky a vzorec,
Unmarked days,Neoznačené dny,
Absent Days,Chybějící dny,
Conditions and Formula variable and example,Podmínky a proměnná vzorce a příklad,
Feedback By,Zpětná vazba od,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.RRRR .-. MM .-. DD.-,
Manufacturing Section,Sekce výroby,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Pro vytvoření prodejní faktury a dodacího listu je vyžadována prodejní objednávka,
-Delivery Note Required for Sales Invoice Creation,Pro vytvoření prodejní faktury je nutný dodací list,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Ve výchozím nastavení je jméno zákazníka nastaveno podle zadaného celého jména. Pokud chcete, aby zákazníci byli pojmenováni a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Při vytváření nové prodejní transakce nakonfigurujte výchozí ceník. Ceny položek budou načteny z tohoto ceníku.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Pokud je tato možnost nakonfigurována na „Ano“, ERPNext vám zabrání ve vytvoření prodejní faktury nebo dodacího listu, aniž byste nejprve vytvořili prodejní objednávku. Tuto konfiguraci lze pro konkrétního zákazníka přepsat povolením zaškrtávacího políčka „Povolit vytvoření prodejní faktury bez prodejní objednávky“ v hlavním okně zákazníka.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} byl úspěšně přidán do všech vybraných témat.,
Topics updated,Témata aktualizována,
Academic Term and Program,Akademický termín a program,
-Last Stock Transaction for item {0} was on {1}.,Poslední skladová transakce u položky {0} proběhla {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Skladové transakce s položkou {0} nelze do této doby zaúčtovat.,
Please remove this item and try to submit again or update the posting time.,Odeberte tuto položku a zkuste ji odeslat znovu nebo aktualizujte čas zveřejnění.,
Failed to Authenticate the API key.,Ověření klíče API se nezdařilo.,
Invalid Credentials,Neplatná pověření,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Zkontrolujte prosím ID klienta a tajné hodnoty,
Bank transaction creation error,Chyba při vytváření bankovní transakce,
Unit of Measurement,Jednotka měření,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Řádek {}: Míra prodeje pro položku {} je nižší než její {}. Míra prodeje by měla být alespoň {},
Fiscal Year {0} Does Not Exist,Fiskální rok {0} neexistuje,
Row # {0}: Returned Item {1} does not exist in {2} {3},Řádek č. {0}: Vrácená položka {1} neexistuje v doméně {2} {3},
Valuation type charges can not be marked as Inclusive,Poplatky typu ocenění nelze označit jako inkluzivní,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Doba odezvy pro {0} prioritu v řádku {1} nesmí být větší než doba rozlišení.,
{0} is not enabled in {1},{0} není povolen v {1},
Group by Material Request,Seskupit podle požadavku na materiál,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Řádek {0}: U dodavatele {0} je pro odesílání e-mailů vyžadována e-mailová adresa,
Email Sent to Supplier {0},E-mail odeslaný dodavateli {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Přístup k žádosti o nabídku z portálu je zakázán. Chcete-li povolit přístup, povolte jej v nastavení portálu.",
Supplier Quotation {0} Created,Nabídka dodavatele {0} vytvořena,
Valid till Date cannot be before Transaction Date,Platnost do data nemůže být před datem transakce,
+Unlink Advance Payment on Cancellation of Order,Zrušit propojení zálohy při zrušení objednávky,
+"Simple Python Expression, Example: territory != 'All Territories'","Jednoduchý výraz v Pythonu, příklad: Teritorium! = 'Všechna území'",
+Sales Contributions and Incentives,Příspěvky na prodej a pobídky,
+Sourced by Supplier,Zdroj od dodavatele,
+Total weightage assigned should be 100%.<br>It is {0},Celková přidělená hmotnost by měla být 100%.<br> Je to {0},
+Account {0} exists in parent company {1}.,Účet {0} existuje v mateřské společnosti {1}.,
+"To overrule this, enable '{0}' in company {1}","Chcete-li to potlačit, povolte ve společnosti {1} „{0}“",
+Invalid condition expression,Neplatný výraz podmínky,
+Please Select a Company First,Nejprve vyberte společnost,
+Please Select Both Company and Party Type First,Nejprve vyberte prosím společnost a typ strany,
+Provide the invoice portion in percent,Uveďte část faktury v procentech,
+Give number of days according to prior selection,Uveďte počet dní podle předchozího výběru,
+Email Details,E-mailové podrobnosti,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Vyberte pozdrav pro příjemce. Např. Pan, paní atd.",
+Preview Email,Náhled e-mailu,
+Please select a Supplier,Vyberte prosím dodavatele,
+Supplier Lead Time (days),Dodací lhůta dodavatele (dny),
+"Home, Work, etc.","Domov, práce atd.",
+Exit Interview Held On,Exit Interview Holded On,
+Condition and formula,Stav a vzorec,
+Sets 'Target Warehouse' in each row of the Items table.,Nastaví v každém řádku tabulky položek „Cílový sklad“.,
+Sets 'Source Warehouse' in each row of the Items table.,Nastaví „Zdrojový sklad“ v každém řádku tabulky Položky.,
+POS Register,POS registr,
+"Can not filter based on POS Profile, if grouped by POS Profile","Nelze filtrovat na základě POS profilu, pokud je seskupen podle POS profilu",
+"Can not filter based on Customer, if grouped by Customer","Nelze filtrovat na základě zákazníka, pokud je seskupen podle zákazníka",
+"Can not filter based on Cashier, if grouped by Cashier","Nelze filtrovat podle pokladníka, pokud je seskupen podle pokladníka",
+Payment Method,Způsob platby,
+"Can not filter based on Payment Method, if grouped by Payment Method","Nelze filtrovat podle způsobu platby, pokud jsou seskupeny podle způsobu platby",
+Supplier Quotation Comparison,Porovnání nabídky dodavatele,
+Price per Unit (Stock UOM),Cena za jednotku (MJ na skladě),
+Group by Supplier,Seskupit podle dodavatele,
+Group by Item,Seskupit podle položky,
+Remember to set {field_label}. It is required by {regulation}.,Nezapomeňte nastavit {field_label}. Vyžaduje to {nařízení}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Datum zápisu nesmí být dříve než datum zahájení akademického roku {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Datum zápisu nesmí být po datu ukončení akademického období {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Datum zápisu nemůže být dříve než datum zahájení akademického období {0},
+Future Posting Not Allowed,Budoucí zveřejňování příspěvků není povoleno,
+"To enable Capital Work in Progress Accounting, ","Chcete-li povolit průběžné účtování kapitálu,",
+you must select Capital Work in Progress Account in accounts table,v tabulce účtů musíte vybrat Účet rozpracovaného kapitálu,
+You can also set default CWIP account in Company {},Ve společnosti {} můžete také nastavit výchozí účet CWIP,
+The Request for Quotation can be accessed by clicking on the following button,Požadavek na nabídku je přístupný kliknutím na následující tlačítko,
+Regards,pozdravy,
+Please click on the following button to set your new password,Kliknutím na následující tlačítko nastavíte nové heslo,
+Update Password,Aktualizujte heslo,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Řádek {}: Míra prodeje pro položku {} je nižší než její {}. Prodej {} by měl být alespoň {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Alternativně můžete deaktivovat ověření prodejní ceny v {} a toto ověření obejít.,
+Invalid Selling Price,Neplatná prodejní cena,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Adresu je třeba propojit se společností. V tabulce Odkazy přidejte řádek pro Společnost.,
+Company Not Linked,Společnost není propojena,
+Import Chart of Accounts from CSV / Excel files,Importujte účtovou osnovu ze souborů CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',Dokončené množství nemůže být větší než „Množství do výroby“,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Řádek {0}: U dodavatele {1} je pro odeslání e-mailu vyžadována e-mailová adresa,
+"If enabled, the system will post accounting entries for inventory automatically","Pokud je povoleno, systém automaticky zaúčtuje účetní položky inventáře",
+Accounts Frozen Till Date,Účty zmrazené do data,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Účetní položky jsou až do tohoto data zmrazeny. Nikdo nemůže vytvářet ani upravovat položky kromě uživatelů s rolí uvedenou níže,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Role umožňovala nastavovat zmrazené účty a upravovat zmrazené položky,
+Address used to determine Tax Category in transactions,Adresa použitá k určení daňové kategorie v transakcích,
+"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 ","Procento, které můžete účtovat více oproti objednané částce. Pokud je například hodnota objednávky u položky 100 $ a tolerance je nastavena na 10%, můžete fakturovat až 110 $",
+This role is allowed to submit transactions that exceed credit limits,"Tato role může odesílat transakce, které překračují kreditní limity",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Pokud je vybrána možnost „Měsíce“, bude pevná částka zaúčtována jako odložený výnos nebo výdaj za každý měsíc bez ohledu na počet dní v měsíci. Pokud nebudou odložené výnosy nebo výdaje rezervovány na celý měsíc, bude poměrná část rozdělena",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Pokud toto políčko nezaškrtnete, budou vytvořeny přímé položky GL, aby se zaúčtovaly odložené výnosy nebo náklady",
+Show Inclusive Tax in Print,Zobrazit inkluzivní daň v tisku,
+Only select this if you have set up the Cash Flow Mapper documents,"Tuto možnost vyberte, pouze pokud jste nastavili dokumenty Mapovače peněžních toků",
+Payment Channel,Platební kanál,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Je nákupní objednávka vyžadována pro vytvoření nákupní faktury a vytvoření účtenky?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Je pro vytvoření faktury za nákup vyžadováno potvrzení o nákupu?,
+Maintain Same Rate Throughout the Purchase Cycle,Udržujte stejnou míru po celou dobu nákupního cyklu,
+Allow Item To Be Added Multiple Times in a Transaction,Povolit vícekrát přidání položky v transakci,
+Suppliers,Dodavatelé,
+Send Emails to Suppliers,Posílejte e-maily dodavatelům,
+Select a Supplier,Vyberte dodavatele,
+Cannot mark attendance for future dates.,Nelze označit docházku pro budoucí data.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Chcete aktualizovat docházku?<br> Současnost: {0}<br> Nepřítomen: {1},
+Mpesa Settings,Nastavení Mpesa,
+Initiator Name,Název iniciátora,
+Till Number,Do čísla,
+Sandbox,Pískoviště,
+ Online PassKey,Online PassKey,
+Security Credential,Bezpečnostní pověření,
+Get Account Balance,Získejte zůstatek na účtu,
+Please set the initiator name and the security credential,Nastavte prosím jméno iniciátora a bezpečnostní pověření,
+Inpatient Medication Entry,Lůžková léčba,
+HLC-IME-.YYYY.-,HLC-IME-.RRRR.-,
+Item Code (Drug),Kód položky (Droga),
+Medication Orders,Objednávky na léky,
+Get Pending Medication Orders,Získejte nevyřízené objednávky na léky,
+Inpatient Medication Orders,Příkazy k hospitalizaci pacientů,
+Medication Warehouse,Sklad léků,
+Warehouse from where medication stock should be consumed,"Sklad, ze kterého by se měl spotřebovat lék",
+Fetching Pending Medication Orders,Načítání nevyřízených objednávek na léky,
+Inpatient Medication Entry Detail,Podrobnosti o vstupu do ústavní léčby,
+Medication Details,Podrobnosti o léčbě,
+Drug Code,Lékový zákon,
+Drug Name,Název drogy,
+Against Inpatient Medication Order,Proti příkazu k hospitalizaci,
+Against Inpatient Medication Order Entry,Proti zadání objednávky lůžkových léků,
+Inpatient Medication Order,Objednávka léků pro stacionáře,
+HLC-IMO-.YYYY.-,HLC-IMO-.RRRR.-,
+Total Orders,Celkový počet objednávek,
+Completed Orders,Dokončené objednávky,
+Add Medication Orders,Přidejte objednávky na léky,
+Adding Order Entries,Přidání položek objednávky,
+{0} medication orders completed,{0} objednávky léků dokončeny,
+{0} medication order completed,{0} objednávka léků dokončena,
+Inpatient Medication Order Entry,Zadání objednávky ústavní léčby,
+Is Order Completed,Je objednávka dokončena,
+Employee Records to Be Created By,"Záznamy zaměstnanců, které mají být vytvořeny",
+Employee records are created using the selected field,Pomocí vybraného pole se vytvářejí záznamy o zaměstnancích,
+Don't send employee birthday reminders,Neposílejte zaměstnancům připomenutí narozenin,
+Restrict Backdated Leave Applications,Omezit zpětné použití aplikací,
+Sequence ID,ID sekvence,
+Sequence Id,ID sekvence,
+Allow multiple material consumptions against a Work Order,Povolte vícenásobnou spotřebu materiálu oproti pracovní objednávce,
+Plan time logs outside Workstation working hours,Plánujte časové protokoly mimo pracovní dobu pracovní stanice,
+Plan operations X days in advance,Plánujte operace X dní předem,
+Time Between Operations (Mins),Čas mezi operacemi (min),
+Default: 10 mins,Výchozí: 10 minut,
+Overproduction for Sales and Work Order,Nadprodukce pro prodej a pracovní objednávku,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",Aktualizujte náklady kusovníku automaticky pomocí plánovače na základě nejnovějšího kurzu ocenění / ceníku / posledního nákupu surovin,
+Purchase Order already created for all Sales Order items,Objednávka již byla vytvořena pro všechny položky prodejní objednávky,
+Select Items,Vyberte položky,
+Against Default Supplier,Proti výchozímu dodavateli,
+Auto close Opportunity after the no. of days mentioned above,Automatické uzavření příležitosti po č. dnů uvedených výše,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Je prodejní objednávka požadována pro vytvoření prodejní faktury a dodacího listu?,
+Is Delivery Note Required for Sales Invoice Creation?,Je pro vytvoření prodejní faktury vyžadován dodací list?,
+How often should Project and Company be updated based on Sales Transactions?,Jak často by měl být projekt a společnost aktualizován na základě prodejních transakcí?,
+Allow User to Edit Price List Rate in Transactions,Umožnit uživateli upravit ceník v transakcích,
+Allow Item to Be Added Multiple Times in a Transaction,Povolit přidání položky vícekrát do transakce,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Povolit více objednávek odběratele proti objednávce zákazníka,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Ověření prodejní ceny zboží v porovnání s kupní sazbou nebo mírou ocenění,
+Hide Customer's Tax ID from Sales Transactions,Skrýt DIČ zákazníka z prodejních transakcí,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Procento, které máte povoleno přijímat nebo doručovat více oproti objednanému množství. Například pokud jste si objednali 100 jednotek a váš příspěvek je 10%, můžete přijímat 110 jednotek.",
+Action If Quality Inspection Is Not Submitted,"Akce, pokud není předložena kontrola kvality",
+Auto Insert Price List Rate If Missing,"Automaticky vložit ceník, pokud chybí",
+Automatically Set Serial Nos Based on FIFO,Automaticky nastavit sériová čísla na základě FIFO,
+Set Qty in Transactions Based on Serial No Input,Nastavit množství v transakcích na základě sériového bez vstupu,
+Raise Material Request When Stock Reaches Re-order Level,"Zvýšení požadavku na materiál, když skladové zásoby dosáhnou úrovně opětovné objednávky",
+Notify by Email on Creation of Automatic Material Request,Upozornit e-mailem na vytvoření automatického požadavku na materiál,
+Allow Material Transfer from Delivery Note to Sales Invoice,Povolit přenos materiálu z dodacího listu do prodejní faktury,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Povolit převod materiálu z dokladu o nákupu do faktury za nákup,
+Freeze Stocks Older Than (Days),Zmrazit zásoby starší než (dny),
+Role Allowed to Edit Frozen Stock,Úloha povolena k úpravě zmrazeného zboží,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Nepřidělená částka položky platby {0} je větší než nepřidělená částka bankovní transakce,
+Payment Received,Platba přijata,
+Attendance cannot be marked outside of Academic Year {0},Účast nelze označit mimo akademický rok {0},
+Student is already enrolled via Course Enrollment {0},Student je již zaregistrován prostřednictvím zápisu do kurzu {0},
+Attendance cannot be marked for future dates.,Docházku nelze označit pro budoucí data.,
+Please add programs to enable admission application.,"Chcete-li povolit žádost o přijetí, přidejte programy.",
+The following employees are currently still reporting to {0}:,Následující zaměstnanci se aktuálně stále hlásí u uživatele {0}:,
+Please make sure the employees above report to another Active employee.,"Ujistěte se, že se výše uvedení zaměstnanci hlásí jinému aktivnímu zaměstnanci.",
+Cannot Relieve Employee,Nelze osvobodit zaměstnance,
+Please enter {0},Zadejte prosím {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Vyberte jinou platební metodu. Společnost Mpesa nepodporuje transakce v měně „{0}“,
+Transaction Error,Chyba transakce,
+Mpesa Express Transaction Error,Chyba transakce Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Zjištěn problém s konfigurací Mpesa, další podrobnosti najdete v protokolech chyb",
+Mpesa Express Error,Chyba Mpesa Express,
+Account Balance Processing Error,Chyba zpracování zůstatku účtu,
+Please check your configuration and try again,Zkontrolujte konfiguraci a zkuste to znovu,
+Mpesa Account Balance Processing Error,Chyba zpracování zůstatku účtu Mpesa,
+Balance Details,Detaily zůstatku,
+Current Balance,Aktuální zůstatek,
+Available Balance,Dostupná částka,
+Reserved Balance,Rezervovaný zůstatek,
+Uncleared Balance,Nejasný zůstatek,
+Payment related to {0} is not completed,Platba související s {0} není dokončena,
+Row #{}: Item Code: {} is not available under warehouse {}.,Řádek č. {}: Kód položky: {} není k dispozici ve skladu {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Řádek {{}: Množství skladu nestačí pro kód položky: {} ve skladu {}. Dostupné množství {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Řádek # {}: Vyberte sériové číslo a proveďte dávku proti položce: {} nebo ji odstraňte a transakce se dokončí.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"Řádek č. {}: U položky nebylo vybráno sériové číslo: {}. Chcete-li transakci dokončit, vyberte jednu nebo ji odeberte.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Řádek č. {}: U položky nebyla vybrána žádná dávka: {}. K dokončení transakce vyberte dávku nebo ji odeberte.,
+Payment amount cannot be less than or equal to 0,Částka platby nesmí být menší nebo rovna 0,
+Please enter the phone number first,Nejprve zadejte telefonní číslo,
+Row #{}: {} {} does not exist.,Řádek {}: {} {} neexistuje.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Řádek č. {0}: {1} je vyžadován k vytvoření úvodních {2} faktur,
+You had {} errors while creating opening invoices. Check {} for more details,Při vytváření otevírání faktur jste měli chyby {}. Další podrobnosti najdete na stránce {},
+Error Occured,Vyskytla se chyba,
+Opening Invoice Creation In Progress,Probíhá zahájení vytváření faktury,
+Creating {} out of {} {},Vytváření {} z {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Serial No: {0}) cannot be consumed as it's reserverd to fullfill sales order {1}.,
+Item {0} {1},Položka {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Poslední skladová transakce u položky {0} ve skladu {1} proběhla dne {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Skladové transakce pro položku {0} ve skladu {1} nelze zaúčtovat dříve.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Zúčtování budoucích transakcí s akciemi není povoleno kvůli Immutable Ledger,
+A BOM with name {0} already exists for item {1}.,Kusovník s názvem {0} již pro položku {1} existuje.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Přejmenovali jste položku? Kontaktujte prosím administrátorskou / technickou podporu,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},V řádku č. {0}: ID sekvence {1} nesmí být menší než ID sekvence v předchozím řádku {2},
+The {0} ({1}) must be equal to {2} ({3}),Hodnota {0} ({1}) se musí rovnat {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, dokončete operaci {1} před operací {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Nelze zajistit doručení sériovým číslem, protože položka {0} je přidána s nebo bez Zajistit doručení sériovým číslem",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Položka {0} nemá sériové číslo. Na základě sériového čísla mohou být doručovány pouze serializované položky,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Pro položku {0} nebyl nalezen žádný aktivní kusovník. Nelze zajistit dodání sériovým číslem,
+No pending medication orders found for selected criteria,Pro vybraná kritéria nebyla nalezena žádná nevyřízená objednávka léků,
+From Date cannot be after the current date.,Od data nemůže být po aktuálním datu.,
+To Date cannot be after the current date.,Do data nemůže být po aktuálním datu.,
+From Time cannot be after the current time.,Z času nemůže být po aktuálním čase.,
+To Time cannot be after the current time.,Do času nemůže být po aktuálním čase.,
+Stock Entry {0} created and ,Skladová položka {0} vytvořena a,
+Inpatient Medication Orders updated successfully,Objednávky léků pro hospitalizované pacienty byly úspěšně aktualizovány,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Řádek {0}: Nelze vytvořit záznam o hospitalizaci u zrušené objednávky léčby u hospitalizovaných pacientů {1},
+Row {0}: This Medication Order is already marked as completed,Řádek {0}: Tato objednávka léku je již označena jako dokončená,
+Quantity not available for {0} in warehouse {1},Množství není k dispozici pro {0} ve skladu {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"Chcete-li pokračovat, povolte možnost Povolit negativní akcie v nastavení akcií nebo vytvořte položku Stock.",
+No Inpatient Record found against patient {0},Proti pacientovi {0} nebyl nalezen záznam o hospitalizaci,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Příkaz k hospitalizaci {0} proti setkání pacientů {1} již existuje.,
+Allow In Returns,Povolit vrácení,
+Hide Unavailable Items,Skrýt nedostupné položky,
+Apply Discount on Discounted Rate,Uplatnit slevu na zlevněnou sazbu,
+Therapy Plan Template,Šablona plánu terapie,
+Fetching Template Details,Načítání podrobností šablony,
+Linked Item Details,Podrobnosti propojené položky,
+Therapy Types,Typy terapie,
+Therapy Plan Template Detail,Detail šablony plánu léčby,
+Non Conformance,Neshoda,
+Process Owner,Vlastník procesu,
+Corrective Action,Nápravné opatření,
+Preventive Action,Preventivní akce,
+Problem,Problém,
+Responsible,Odpovědný,
+Completion By,Dokončení do,
+Process Owner Full Name,Celé jméno vlastníka procesu,
+Right Index,Správný index,
+Left Index,Levý rejstřík,
+Sub Procedure,Dílčí postup,
+Passed,Prošel,
+Print Receipt,Tisk účtenky,
+Edit Receipt,Upravit potvrzení,
+Focus on search input,Zaměřte se na vstup vyhledávání,
+Focus on Item Group filter,Zaměřte se na filtr Skupiny položek,
+Checkout Order / Submit Order / New Order,Pokladna Objednávka / Odeslat objednávku / Nová objednávka,
+Add Order Discount,Přidejte slevu na objednávku,
+Item Code: {0} is not available under warehouse {1}.,Kód položky: {0} není k dispozici ve skladu {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Sériová čísla nejsou u položky {0} ve skladu {1} k dispozici. Zkuste změnit sklad.,
+Fetched only {0} available serial numbers.,Načteno pouze {0} dostupných sériových čísel.,
+Switch Between Payment Modes,Přepínání mezi režimy platby,
+Enter {0} amount.,Zadejte částku {0}.,
+You don't have enough points to redeem.,Nemáte dostatek bodů k uplatnění.,
+You can redeem upto {0}.,Můžete uplatnit až {0}.,
+Enter amount to be redeemed.,Zadejte částku k uplatnění.,
+You cannot redeem more than {0}.,Nelze uplatnit více než {0}.,
+Open Form View,Otevřete formulářové zobrazení,
+POS invoice {0} created succesfully,POS faktura {0} vytvořena úspěšně,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Skladové množství nestačí pro kód položky: {0} ve skladu {1}. Dostupné množství {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Sériové číslo: {0} již bylo převedeno do jiné faktury POS.,
+Balance Serial No,Sériové číslo zůstatku,
+Warehouse: {0} does not belong to {1},Sklad: {0} nepatří do {1},
+Please select batches for batched item {0},Vyberte dávky pro dávkovou položku {0},
+Please select quantity on row {0},Vyberte prosím množství na řádku {0},
+Please enter serial numbers for serialized item {0},Zadejte sériová čísla pro serializovanou položku {0},
+Batch {0} already selected.,Dávka {0} je již vybrána.,
+Please select a warehouse to get available quantities,"Chcete-li získat dostupná množství, vyberte sklad",
+"For transfer from source, selected quantity cannot be greater than available quantity",U přenosu ze zdroje nemůže být vybrané množství větší než dostupné množství,
+Cannot find Item with this Barcode,Nelze najít položku s tímto čárovým kódem,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} je povinné. Možná není vytvořen záznam směnárny pro {1} až {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} odeslal aktiva s ním spojená. Chcete-li vytvořit návratnost nákupu, musíte aktiva zrušit.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Tento dokument nelze zrušit, protože je propojen s odeslaným dílem {0}. Chcete-li pokračovat, zrušte jej.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Řádek {}: Sériové číslo {} již byl převeden do jiné faktury POS. Vyberte prosím platné sériové číslo.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Řádek # {}: Sériová čísla {} již byla převedena do jiné faktury POS. Vyberte prosím platné sériové číslo.,
+Item Unavailable,Zboží není k dispozici,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Řádek č. {}: Sériové číslo {} nelze vrátit, protože nebylo provedeno v původní faktuře {}",
+Please set default Cash or Bank account in Mode of Payment {},V platebním režimu nastavte výchozí hotovost nebo bankovní účet {},
+Please set default Cash or Bank account in Mode of Payments {},V platebním režimu prosím nastavte výchozí hotovostní nebo bankovní účet {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Ujistěte se, že účet {} je účet v rozvaze. Mateřský účet můžete změnit na účet v rozvaze nebo vybrat jiný účet.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Ujistěte se, že účet {} je splatným účtem. Změňte typ účtu na Splatný nebo vyberte jiný účet.",
+Row {}: Expense Head changed to {} ,Řádek {}: Hlava výdajů změněna na {},
+because account {} is not linked to warehouse {} ,protože účet {} není propojen se skladem {},
+or it is not the default inventory account,nebo to není výchozí účet inventáře,
+Expense Head Changed,Výdajová hlava změněna,
+because expense is booked against this account in Purchase Receipt {},protože výdaj je zaúčtován proti tomuto účtu v dokladu o nákupu {},
+as no Purchase Receipt is created against Item {}. ,protože u položky {} není vytvořen žádný doklad o nákupu.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"To se provádí za účelem účtování v případech, kdy je po nákupní faktuře vytvořen nákupní doklad",
+Purchase Order Required for item {},U položky {} je požadována nákupní objednávka,
+To submit the invoice without purchase order please set {} ,"Chcete-li odeslat fakturu bez objednávky, nastavte {}",
+as {} in {},jako v {},
+Mandatory Purchase Order,Povinná nákupní objednávka,
+Purchase Receipt Required for item {},U položky {} je vyžadováno potvrzení o nákupu,
+To submit the invoice without purchase receipt please set {} ,"Chcete-li odeslat fakturu bez dokladu o nákupu, nastavte {}",
+Mandatory Purchase Receipt,Povinné potvrzení o nákupu,
+POS Profile {} does not belongs to company {},POS profil {} nepatří společnosti {},
+User {} is disabled. Please select valid user/cashier,Uživatel {} je deaktivován. Vyberte prosím platného uživatele / pokladníka,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Řádek {}: Původní faktura {} ze zpáteční faktury {} je {}.,
+Original invoice should be consolidated before or along with the return invoice.,Původní faktura by měla být sloučena před nebo spolu se zpětnou fakturou.,
+You can add original invoice {} manually to proceed.,"Chcete-li pokračovat, můžete přidat původní fakturu {} ručně.",
+Please ensure {} account is a Balance Sheet account. ,"Ujistěte se, že účet {} je účet v rozvaze.",
+You can change the parent account to a Balance Sheet account or select a different account.,Mateřský účet můžete změnit na účet v rozvaze nebo vybrat jiný účet.,
+Please ensure {} account is a Receivable account. ,"Ujistěte se, že účet {} je pohledávkovým účtem.",
+Change the account type to Receivable or select a different account.,Změňte typ účtu na Přijatelné nebo vyberte jiný účet.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"Službu {} nelze zrušit, protože byly uplatněny získané věrnostní body. Nejprve zrušte {} Ne {}",
+already exists,již existuje,
+POS Closing Entry {} against {} between selected period,Uzavírací vstup POS {} proti {} mezi vybraným obdobím,
+POS Invoice is {},POS faktura je {},
+POS Profile doesn't matches {},POS profil neodpovídá {},
+POS Invoice is not {},POS faktura není {},
+POS Invoice isn't created by user {},Faktura POS není vytvořena uživatelem {},
+Row #{}: {},Řádek #{}: {},
+Invalid POS Invoices,Neplatné faktury POS,
+Please add the account to root level Company - {},Přidejte účet do společnosti na kořenové úrovni - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Při vytváření účtu pro podřízenou společnost {0} nebyl nadřazený účet {1} nalezen. Vytvořte prosím nadřazený účet v odpovídajícím certifikátu pravosti,
+Account Not Found,Účet nenalezen,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",Při vytváření účtu pro podřízenou společnost {0} byl nadřazený účet {1} nalezen jako účet hlavní knihy.,
+Please convert the parent account in corresponding child company to a group account.,Převeďte prosím nadřazený účet v odpovídající podřízené společnosti na skupinový účet.,
+Invalid Parent Account,Neplatný nadřazený účet,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Přejmenování je povoleno pouze prostřednictvím mateřské společnosti {0}, aby nedošlo k nesouladu.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Pokud {0} {1} množství položky {2}, bude na položku použito schéma {3}.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Pokud {0} {1} máte hodnotu položky {2}, použije se na položku schéma {3}.",
+"As the field {0} is enabled, the field {1} is mandatory.","Protože je pole {0} povoleno, je pole {1} povinné.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Protože je pole {0} povoleno, měla by být hodnota pole {1} větší než 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Nelze doručit sériové číslo {0} položky {1}, protože je vyhrazeno k vyplnění prodejní objednávky {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Zakázka odběratele {0} má rezervaci pro položku {1}, můžete doručit pouze rezervovanou {1} proti {0}.",
+{0} Serial No {1} cannot be delivered,{0} Sériové číslo {1} nelze doručit,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Řádek {0}: Subdodavatelská položka je u suroviny povinná {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Jelikož je k dispozici dostatek surovin, není požadavek na materiál pro sklad {0} vyžadován.",
+" If you still want to proceed, please enable {0}.","Pokud přesto chcete pokračovat, povolte {0}.",
+The item referenced by {0} - {1} is already invoiced,"Položka, na kterou odkazuje {0} - {1}, je již fakturována",
+Therapy Session overlaps with {0},Terapie se překrývá s {0},
+Therapy Sessions Overlapping,Terapeutické relace se překrývají,
+Therapy Plans,Terapeutické plány,
+"Item Code, warehouse, quantity are required on row {0}","Na řádku {0} je vyžadován kód položky, sklad, množství",
+Get Items from Material Requests against this Supplier,Získejte položky z materiálových požadavků vůči tomuto dodavateli,
+Enable European Access,Povolit evropský přístup,
+Creating Purchase Order ...,Vytváření nákupní objednávky ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",Vyberte dodavatele z výchozích dodavatelů níže uvedených položek. Při výběru bude provedena objednávka pouze na položky patřící vybranému dodavateli.,
+Row #{}: You must select {} serial numbers for item {}.,Řádek # {}: Musíte vybrat {} sériová čísla pro položku {}.,
diff --git a/erpnext/translations/da.csv b/erpnext/translations/da.csv
index b077869..c0d0146 100644
--- a/erpnext/translations/da.csv
+++ b/erpnext/translations/da.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},"Faktiske type skat, kan ikke indgå i vare sats i række {0}",
Add,Tilføj,
Add / Edit Prices,Tilføj / Rediger Priser,
-Add All Suppliers,Tilføj alle leverandører,
Add Comment,Tilføj kommentar,
Add Customers,Tilføj kunder,
Add Employees,Tilføj medarbejdere,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Kan ikke fratrække når kategori er for "Værdiansættelse" eller "Vaulation og Total ',
"Cannot delete Serial No {0}, as it is used in stock transactions","Kan ikke slette serienummer {0}, eftersom det bruges på lagertransaktioner",
Cannot enroll more than {0} students for this student group.,Kan ikke tilmelde mere end {0} studerende til denne elevgruppe.,
-Cannot find Item with this barcode,Kan ikke finde varen med denne stregkode,
Cannot find active Leave Period,Kan ikke finde aktiv afgangsperiode,
Cannot produce more Item {0} than Sales Order quantity {1},Kan ikke producere mere Item {0} end Sales Order mængde {1},
Cannot promote Employee with status Left,Kan ikke fremme medarbejder med status til venstre,
Cannot refer row number greater than or equal to current row number for this Charge type,Kan ikke henvise rækken tal større end eller lig med aktuelle række nummer til denne Charge typen,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Kan ikke vælge charge type som 'On Forrige Row Beløb' eller 'On Forrige Row alt "for første række,
-Cannot set a received RFQ to No Quote,Kan ikke indstille en modtaget RFQ til No Quote,
Cannot set as Lost as Sales Order is made.,Kan ikke indstilles som Lost som Sales Order er foretaget.,
Cannot set authorization on basis of Discount for {0},Kan ikke sætte godkendelse på grundlag af Rabat for {0},
Cannot set multiple Item Defaults for a company.,Kan ikke indstille flere standardindstillinger for en virksomhed.,
@@ -521,7 +518,6 @@
Chargeble,chargeble,
Charges are updated in Purchase Receipt against each item,Afgifter er opdateret i købskvitteringen for hver enkelt vare,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Afgifter vil blive fordelt forholdsmæssigt baseret på post qty eller mængden, som pr dit valg",
-Chart Of Accounts,Kontoplan,
Chart of Cost Centers,Diagram af omkostningssteder,
Check all,Vælg alle,
Checkout,bestilling,
@@ -581,7 +577,6 @@
Compensatory Off,Kompenserende Off,
Compensatory leave request days not in valid holidays,Forsøgsfrihed anmodningsdage ikke i gyldige helligdage,
Complaint,Symptom,
-Completed Qty can not be greater than 'Qty to Manufacture',Afsluttet Antal kan ikke være større end 'antal til Fremstilling',
Completion Date,Afslutning Dato,
Computer,Computer,
Condition,Tilstand,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Opret og administrér de daglige, ugentlige og månedlige e-mail-nyhedsbreve.",
Create customer quotes,Opret tilbud til kunder,
Create rules to restrict transactions based on values.,Oprette regler til at begrænse transaktioner baseret på værdier.,
-Created By,Oprettet af,
Created {0} scorecards for {1} between: ,Oprettet {0} scorecards for {1} mellem:,
Creating Company and Importing Chart of Accounts,Oprettelse af firma og import af kontoplan,
Creating Fees,Oprettelse af gebyrer,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Medarbejderoverførsel kan ikke indsendes før overførselsdato,
Employee cannot report to himself.,Medarbejder kan ikke referere til sig selv.,
Employee relieved on {0} must be set as 'Left',Medarbejder lettet på {0} skal indstilles som "Left",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Medarbejderstatus kan ikke indstilles til 'Venstre', da følgende medarbejdere i øjeblikket rapporterer til denne medarbejder:",
Employee {0} already submited an apllication {1} for the payroll period {2},Medarbejder {0} har allerede indgivet en ansøgning {1} for lønningsperioden {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Medarbejder {0} har allerede ansøgt om {1} mellem {2} og {3}:,
Employee {0} has no maximum benefit amount,Medarbejder {0} har ingen maksimal ydelsesbeløb,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,For række {0}: Indtast Planlagt antal,
"For {0}, only credit accounts can be linked against another debit entry",For {0} kan kun kredit konti knyttes mod en anden debet post,
"For {0}, only debit accounts can be linked against another credit entry",For {0} kan kun betalingskort konti knyttes mod en anden kredit post,
-Form View,Formularvisning,
Forum Activity,Forumaktivitet,
Free item code is not selected,Gratis varekode er ikke valgt,
Freight and Forwarding Charges,Fragt og Forwarding Afgifter,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Fravær kan ikke fordeles inden {0}, da fraværssaldoen allerede har været carry-fremsendt i fremtiden orlov tildeling rekord {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Fravær kan ikke anvendes/annulleres før {0}, da fraværssaldoen allerede har været carry-fremsendt i fremtiden orlov tildeling rekord {1}",
Leave of type {0} cannot be longer than {1},Fravær af typen {0} må ikke vare længere end {1},
-Leave the field empty to make purchase orders for all suppliers,Lad feltet være tomt for at foretage indkøbsordrer for alle leverandører,
Leaves,Blade,
Leaves Allocated Successfully for {0},Fravær blev succesfuldt tildelt til {0},
Leaves has been granted sucessfully,Blade er blevet givet succesfuldt,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Ingen stykliste-varer at fremstille,
No Items with Bill of Materials.,Ingen varer med materialeregning.,
No Permission,Ingen tilladelse,
-No Quote,Intet citat,
No Remarks,Ingen bemærkninger,
No Result to submit,Intet resultat at indsende,
No Salary Structure assigned for Employee {0} on given date {1},Ingen lønstrukturer tildelt medarbejder {0} på en given dato {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Overlappende betingelser fundet mellem:,
Owner,Ejer,
PAN,PANDE,
-PO already created for all sales order items,PO allerede oprettet for alle salgsordre elementer,
POS,Kassesystem,
POS Profile,Kassesystemprofil,
POS Profile is required to use Point-of-Sale,POS-profil er påkrævet for at bruge Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Vælg Charge Type først,
Please select Company,Vælg firma,
Please select Company and Designation,Vælg venligst Firma og Betegnelse,
-Please select Company and Party Type first,Vælg Virksomhed og Selskabstype først,
Please select Company and Posting Date to getting entries,Vælg venligst Company og Posting Date for at få poster,
Please select Company first,Vælg venligst firma først,
Please select Completion Date for Completed Asset Maintenance Log,Vælg venligst Afslutningsdato for Udfyldt Asset Maintenance Log,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Række {0}: Enhedskode-konverteringsfaktor er obligatorisk,
Row {0}: select the workstation against the operation {1},Række {0}: Vælg arbejdsstationen imod operationen {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Række {0}: {1} Serienumre er nødvendige for punkt {2}. Du har angivet {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Række {0}: {1} er påkrævet for at oprette åbningen {2} fakturaer,
Row {0}: {1} must be greater than 0,Række {0}: {1} skal være større end 0,
Row {0}: {1} {2} does not match with {3},Række {0}: {1} {2} passer ikke med {3},
Row {0}:Start Date must be before End Date,Række {0}: Start dato skal være før slutdato,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Send Grant Review Email,
Send Now,Send nu,
Send SMS,Send SMS,
-Send Supplier Emails,Send Leverandør Emails,
Send mass SMS to your contacts,Send masse-SMS til dine kontakter,
Sensitivity,Følsomhed,
Sent,Sent,
-Serial #,Serienummer,
Serial No and Batch,Serienummer og parti,
Serial No is mandatory for Item {0},Serienummer er obligatorisk for vare {0},
Serial No {0} does not belong to Batch {1},Serienummer {0} tilhører ikke Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Navnet på dit firma, som du oprette i dette system.",
The number of shares and the share numbers are inconsistent,Antallet af aktier og aktienumrene er inkonsekvente,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Betalingsgateway-kontoen i plan {0} er forskellig fra betalingsgateway-kontoen i denne betalingsanmodning,
-The request for quotation can be accessed by clicking on the following link,Tilbudsforespørgslen findes ved at klikke på følgende link,
The selected BOMs are not for the same item,De valgte styklister er ikke for den samme vare,
The selected item cannot have Batch,Den valgte vare kan ikke have parti,
The seller and the buyer cannot be the same,Sælgeren og køberen kan ikke være det samme,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Det samlede beløb for fleksibel fordel {0} bør ikke være mindre end maksimale fordele {1},
Total hours: {0},Total time: {0},
Total leaves allocated is mandatory for Leave Type {0},Samlet antal tildelte blade er obligatoriske for Forladetype {0},
-Total weightage assigned should be 100%. It is {0},Samlet weightage tildelt skulle være 100%. Det er {0},
Total working hours should not be greater than max working hours {0},Arbejdstid i alt bør ikke være større end maksimal arbejdstid {0},
Total {0} ({1}),I alt {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","I alt {0} for alle punkter er nul, kan være du skal ændre "Fordel afgifter baseret på '",
@@ -3316,7 +3299,6 @@
What do you need help with?,Hvad har du brug for hjælp til?,
What does it do?,Hvad gør det?,
Where manufacturing operations are carried.,Hvor fremstillingsprocesser gennemføres.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Mens du opretter konto for børneselskab {0}, blev moderkonto {1} ikke fundet. Opret venligst den overordnede konto i den tilsvarende COA",
White,hvid,
Wire Transfer,Bankoverførsel,
WooCommerce Products,WooCommerce-produkter,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} varianter oprettet.,
{0} {1} created,{0} {1} oprettet,
{0} {1} does not exist,{0} {1} findes ikke,
-{0} {1} does not exist.,{0} {1} eksisterer ikke.,
{0} {1} has been modified. Please refresh.,{0} {1} er blevet ændret. Venligst opdater.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} er ikke indsendt, så handlingen kan ikke gennemføres",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} er forbundet med {2}, men Selskabskonto er {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} eksisterer ikke,
{0}: {1} not found in Invoice Details table,{0}: {1} ikke fundet i fakturedetaljer tabel,
{} of {},{} af {},
+Assigned To,Tildelt til,
Chat,Chat,
Completed By,Færdiggjort af,
Conditions,Betingelser,
@@ -3506,7 +3488,9 @@
Merge with existing,Sammenlæg med eksisterende,
Office,Kontor,
Orientation,Orientering,
+Parent,Parent,
Passive,Inaktiv,
+Payment Failed,Betaling mislykkedes,
Percent,procent,
Permanent,Permanent,
Personal,Personlig,
@@ -3544,7 +3528,6 @@
Company field is required,Virksomhedsfelt er påkrævet,
Creating Dimensions...,Opretter dimensioner ...,
Duplicate entry against the item code {0} and manufacturer {1},Kopiér indtastning mod varekoden {0} og producenten {1},
-Import Chart Of Accounts from CSV / Excel files,Importer oversigt over konti fra CSV / Excel-filer,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,"Ugyldig GSTIN! Det input, du har indtastet, stemmer ikke overens med GSTIN-formatet for UIN-indehavere eller ikke-residente OIDAR-tjenesteudbydere",
Invoice Grand Total,Faktura Grand Total,
Last carbon check date cannot be a future date,Sidste dato for kulstofkontrol kan ikke være en fremtidig dato,
@@ -3556,6 +3539,7 @@
Show {0},Vis {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Specialtegn undtagen "-", "#", ".", "/", "{" Og "}" er ikke tilladt i navngivningsserier",
Target Details,Måldetaljer,
+{0} already has a Parent Procedure {1}.,{0} har allerede en overordnet procedure {1}.,
API,API,
Annual,Årligt,
Approved,godkendt,
@@ -3572,6 +3556,8 @@
No data to export,Ingen data at eksportere,
Portrait,Portræt,
Print Heading,Overskrift,
+Scheduler Inactive,Planlægning inaktiv,
+Scheduler is inactive. Cannot import data.,Scheduler er inaktiv. Data kan ikke importeres.,
Show Document,Vis dokument,
Show Traceback,Vis traceback,
Video,video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Opret kvalitetskontrol for vare {0},
Creating Accounts...,Opretter konti ...,
Creating bank entries...,Opretter bankposter ...,
-Creating {0},Oprettelse af {0},
Credit limit is already defined for the Company {0},Kreditgrænsen er allerede defineret for virksomheden {0},
Ctrl + Enter to submit,Ctrl + Enter for at indsende,
Ctrl+Enter to submit,Ctrl + Enter for at indsende,
@@ -3921,7 +3906,6 @@
Plaid public token error,Plaid public token error,
Plaid transactions sync error,Fejl i synkronisering af pladetransaktioner,
Please check the error log for details about the import errors,Kontroller fejlloggen for detaljer om importfejl,
-Please click on the following link to set your new password,Klik på følgende link for at indstille din nye adgangskode,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Opret venligst <b>DATEV-indstillinger</b> for firma <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Opret venligst justering af journalindtastning for beløb {0},
Please do not create more than 500 items at a time,Opret venligst ikke mere end 500 varer ad gangen,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Udgivelsesdato skal være i fremtiden,
Relieving Date must be greater than or equal to Date of Joining,Fritagelsesdato skal være større end eller lig med tiltrædelsesdato,
Rename,Omdøb,
+Rename Not Allowed,Omdøb ikke tilladt,
Repayment Method is mandatory for term loans,Tilbagebetalingsmetode er obligatorisk for kortfristede lån,
Repayment Start Date is mandatory for term loans,Startdato for tilbagebetaling er obligatorisk for kortfristede lån,
Report Item,Rapporter element,
@@ -4043,7 +4028,6 @@
Select All,Vælg alt,
Select Difference Account,Vælg Difference Account,
Select a Default Priority.,Vælg en standardprioritet.,
-Select a Supplier from the Default Supplier List of the items below.,Vælg en leverandør fra standardleverandørlisten med nedenstående varer.,
Select a company,Vælg et firma,
Select finance book for the item {0} at row {1},Vælg finansbog for varen {0} i række {1},
Select only one Priority as Default.,Vælg kun en prioritet som standard.,
@@ -4247,7 +4231,6 @@
Actual ,Faktiske,
Add to cart,Føj til indkøbsvogn,
Budget,Budget,
-Chart Of Accounts Importer,Kontoplan for importør,
Chart of Accounts,Kontoplan,
Customer database.,Kundedatabase.,
Days Since Last order,Dage siden sidste ordre,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Slutdato kan ikke være mindre end startdato,
For Default Supplier (Optional),For standardleverandør (valgfrit),
From date cannot be greater than To date,Fra dato ikke kan være større end til dato,
-Get items from,Hent varer fra,
Group by,Sortér efter,
In stock,På lager,
Item name,Varenavn,
@@ -4532,32 +4514,22 @@
Accounts Settings,Kontoindstillinger,
Settings for Accounts,Indstillinger for regnskab,
Make Accounting Entry For Every Stock Movement,Lav Regnskab indtastning For hver Stock Movement,
-"If enabled, the system will post accounting entries for inventory automatically.","Hvis aktiveret, vil systemet sende bogføring for opgørelse automatisk.",
-Accounts Frozen Upto,Regnskab låst op til,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Kontering frosset op til denne dato, kan ingen gøre / ændre post undtagen rolle angivet nedenfor.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Rolle Tilladt til Indstil Frosne Konti og Rediger Frosne Entries,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Brugere med denne rolle får lov til at sætte indefrosne konti og oprette / ændre regnskabsposter mod indefrosne konti,
Determine Address Tax Category From,Bestem adresse-skatskategori fra,
-Address used to determine Tax Category in transactions.,Adresse brugt til at bestemme skatskategori i transaktioner.,
Over Billing Allowance (%),Over faktureringsgodtgørelse (%),
-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 for $110.,"Procentdel, du har lov til at fakturere mere over det bestilte beløb. For eksempel: Hvis ordreværdien er $ 100 for en vare, og tolerancen er indstillet til 10%, har du lov til at fakturere $ 110.",
Credit Controller,Credit Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,"Rolle, som får lov til at indsende transaktioner, der overstiger kredit grænser.",
Check Supplier Invoice Number Uniqueness,Tjek entydigheden af leverandørfakturanummeret,
Make Payment via Journal Entry,Foretag betaling via kassekladden,
Unlink Payment on Cancellation of Invoice,Fjern link Betaling ved Annullering af faktura,
-Unlink Advance Payment on Cancelation of Order,Fjern tilknytning til forskud ved annullering af ordre,
Book Asset Depreciation Entry Automatically,Bogføring af aktivernes afskrivning automatisk,
Automatically Add Taxes and Charges from Item Tax Template,Tilføj automatisk skatter og afgifter fra vareskatteskabelonen,
Automatically Fetch Payment Terms,Hent automatisk betalingsbetingelser,
-Show Inclusive Tax In Print,Vis inklusiv skat i tryk,
Show Payment Schedule in Print,Vis betalingsplan i udskrivning,
Currency Exchange Settings,Valutavekslingsindstillinger,
Allow Stale Exchange Rates,Tillad forældede valutakurser,
Stale Days,Forældede dage,
Report Settings,Rapportindstillinger,
Use Custom Cash Flow Format,Brug Custom Cash Flow Format,
-Only select if you have setup Cash Flow Mapper documents,"Vælg kun, hvis du har opsætningen Cash Flow Mapper-dokumenter",
Allowed To Transact With,Tilladt at transagere med,
SWIFT number,SWIFT-nummer,
Branch Code,Branchkode,
@@ -4940,7 +4912,6 @@
POS Customer Group,Kassesystem-kundegruppe,
POS Field,POS felt,
POS Item Group,Kassesystem-varegruppe,
-[Select],[Vælg],
Company Address,Virksomhedsadresse,
Update Stock,Opdatering Stock,
Ignore Pricing Rule,Ignorér prisfastsættelsesregel,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Leverandørnavngivning af,
Default Supplier Group,Standardleverandørgruppe,
Default Buying Price List,Standard indkøbsprisliste,
-Maintain same rate throughout purchase cycle,Bevar samme sats i hele køb cyklus,
-Allow Item to be added multiple times in a transaction,Tillad vare der skal tilføjes flere gange i en transaktion,
Backflush Raw Materials of Subcontract Based On,Backflush råmaterialer af underentreprise baseret på,
Material Transferred for Subcontract,Materialet overført til underentreprise,
Over Transfer Allowance (%),Overførselsgodtgørelse (%),
@@ -5540,7 +5509,6 @@
Current Stock,Aktuel lagerbeholdning,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Til individuel leverandør,
-Supplier Detail,Leverandør Detail,
Link to Material Requests,Link til materialeanmodninger,
Message for Supplier,Besked til leverandøren,
Request for Quotation Item,Anmodning om tilbud Varer,
@@ -6481,7 +6449,6 @@
Appraisal Template,Vurderingsskabelon,
For Employee Name,Til medarbejdernavn,
Goals,Mål,
-Calculate Total Score,Beregn Total Score,
Total Score (Out of 5),Samlet score (ud af 5),
"Any other remarks, noteworthy effort that should go in the records.","Alle andre bemærkninger, bemærkelsesværdigt indsats, skal gå i registrene.",
Appraisal Goal,Vurderingsmål,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Årsag til Leaving,
Leave Encashed?,Skal fravær udbetales?,
Encashment Date,Indløsningsdato,
-Exit Interview Details,Exit Interview Detaljer,
-Held On,Held On,
-Reason for Resignation,Årsag til Udmeldelse,
-Better Prospects,Bedre udsigter,
-Health Concerns,Sundhedsmæssige betænkeligheder,
New Workplace,Ny Arbejdsplads,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Returneret beløb,
@@ -6740,10 +6702,7 @@
Employee Settings,Medarbejderindstillinger,
Retirement Age,Pensionsalder,
Enter retirement age in years,Indtast pensionsalderen i år,
-Employee Records to be created by,Medarbejdere skal oprettes af,
-Employee record is created using selected field. ,Medarbejder rekord er oprettet ved hjælp valgte felt.,
Stop Birthday Reminders,Stop Fødselsdag Påmindelser,
-Don't send Employee Birthday Reminders,Send ikke medarbejderfødselsdags- påmindelser,
Expense Approver Mandatory In Expense Claim,Expense Approver Obligatorisk i Expense Claim,
Payroll Settings,Lønindstillinger,
Leave,Forlade,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Forlad godkendelsesprocedure,
Show Leaves Of All Department Members In Calendar,Vis blade af alle afdelingsmedlemmer i kalender,
Auto Leave Encashment,Automatisk forladt kabinet,
-Restrict Backdated Leave Application,Begræns ansøgning om forældet orlov,
Hiring Settings,Ansættelse af indstillinger,
Check Vacancies On Job Offer Creation,Tjek ledige stillinger ved oprettelse af jobtilbud,
Identification Document Type,Identifikationsdokumenttype,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Produktion Indstillinger,
Raw Materials Consumption,Forbrug af råvarer,
Allow Multiple Material Consumption,Tillad flere forbrug af materiale,
-Allow multiple Material Consumption against a Work Order,Tillad flere materialforbrug mod en arbejdsordre,
Backflush Raw Materials Based On,Backflush råstoffer baseret på,
Material Transferred for Manufacture,Materiale Overført til Fremstilling,
Capacity Planning,Kapacitetsplanlægning,
Disable Capacity Planning,Deaktiver kapacitetsplanlægning,
Allow Overtime,Tillad overarbejde,
-Plan time logs outside Workstation Working Hours.,Planlæg tid logs uden Workstation arbejdstid.,
Allow Production on Holidays,Tillad produktion på helligdage,
Capacity Planning For (Days),Kapacitet Planlægning For (dage),
-Try planning operations for X days in advance.,Prøv at planlægge operationer for X dage i forvejen.,
-Time Between Operations (in mins),Time Between Operations (i minutter),
-Default 10 mins,Standard 10 min,
Default Warehouses for Production,Standard lagerhuse til produktion,
Default Work In Progress Warehouse,Standard varer-i-arbejde-lager,
Default Finished Goods Warehouse,Standard færdigvarer Warehouse,
Default Scrap Warehouse,Standard skrotlager,
-Over Production for Sales and Work Order,Overproduktion til salg og arbejdsordre,
Overproduction Percentage For Sales Order,Overproduktionsprocent for salgsordre,
Overproduction Percentage For Work Order,Overproduktionsprocent for arbejdsordre,
Other Settings,Andre indstillinger,
Update BOM Cost Automatically,Opdater BOM omkostninger automatisk,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Opdater BOM omkostninger automatisk via Scheduler, baseret på seneste værdiansættelsesrate / prisliste sats / sidste købspris for råvarer.",
Material Request Plan Item,Materialeforespørgsel Planlægning,
Material Request Type,Materialeanmodningstype,
Material Issue,Materiale Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Kvalitetsmål,
Monitoring Frequency,Overvågningsfrekvens,
Weekday,Ugedag,
-January-April-July-October,Januar til april juli til oktober,
-Revision and Revised On,Revision og revideret på,
-Revision,Revision,
-Revised On,Revideret den,
Objectives,mål,
Quality Goal Objective,Kvalitetsmål Mål,
Objective,Objektiv,
@@ -7619,7 +7566,6 @@
Processes,Processer,
Quality Procedure Process,Kvalitetsprocedure,
Process Description,Procesbeskrivelse,
-Child Procedure,Børneprocedure,
Link existing Quality Procedure.,Kobl den eksisterende kvalitetsprocedure.,
Additional Information,Yderligere Information,
Quality Review Objective,Mål for kvalitetsgennemgang,
@@ -7787,15 +7733,9 @@
Default Customer Group,Standard kundegruppe,
Default Territory,Standardområde,
Close Opportunity After Days,Luk salgsmulighed efter dage,
-Auto close Opportunity after 15 days,Luk automatisk salgsmulighed efter 15 dage,
Default Quotation Validity Days,Standard Quotation Gyldighedsdage,
Sales Update Frequency,Salgsopdateringsfrekvens,
-How often should project and company be updated based on Sales Transactions.,Hvor ofte skal projektet og virksomheden opdateres baseret på salgstransaktioner.,
Each Transaction,Hver transaktion,
-Allow user to edit Price List Rate in transactions,Tillad brugeren at redigere prislistesatsen i transaktioner,
-Allow multiple Sales Orders against a Customer's Purchase Order,Tillad flere salgsordrer mod kundens indkøbsordre,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Godkend salgspris for vare mod købspris eller værdiansættelsespris,
-Hide Customer's Tax Id from Sales Transactions,Skjul kundens CVR-nummer fra salgstransaktioner,
SMS Center,SMS-center,
Send To,Send til,
All Contact,Alle Kontakt,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,"Producenter, der anvendes i artikler",
Limited to 12 characters,Begrænset til 12 tegn,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Indstil lager,
-Sets 'For Warehouse' in each row of the Items table.,Indstiller 'For lager' i hver række i tabellen Varer.,
-Requested For,Anmodet om,
Partially Ordered,Delvist bestilt,
Transferred,overført,
% Ordered,% Bestilt,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Standard lagerenhed,
Sample Retention Warehouse,Prøveopbevaringslager,
Default Valuation Method,Standard værdiansættelsesmetode,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Procentdel, du får lov til at modtage eller levere mere mod den bestilte mængde. For eksempel: Hvis du har bestilt 100 enheder. og din Allowance er 10%, så du får lov til at modtage 110 enheder.",
-Action if Quality inspection is not submitted,"Handling, hvis kvalitetskontrol ikke er sendt",
Show Barcode Field,Vis stregkodefelter,
Convert Item Description to Clean HTML,Konverter varebeskrivelse for at rydde HTML,
-Auto insert Price List rate if missing,"Auto insert Prisliste sats, hvis der mangler",
Allow Negative Stock,Tillad negativ lagerbeholdning,
Automatically Set Serial Nos based on FIFO,Angiv serienumrene automatisk baseret på FIFO-princippet,
-Set Qty in Transactions based on Serial No Input,Indstil antal i transaktioner baseret på serienummerindgang,
Auto Material Request,Automatisk materialeanmodning,
-Raise Material Request when stock reaches re-order level,Start materialeanmodningen når lagerbestanden når genbestilningsniveauet,
-Notify by Email on creation of automatic Material Request,Give besked på e-mail om oprettelse af automatiske materialeanmodninger,
Inter Warehouse Transfer Settings,Indstillinger for interlageroverførsel,
-Allow Material Transfer From Delivery Note and Sales Invoice,Tillad materialeoverførsel fra leveringsnota og salgsfaktura,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Tillad materialeoverførsel fra købsmodtagelse og købsfaktura,
Freeze Stock Entries,Frys Stock Entries,
Stock Frozen Upto,Stock Frozen Op,
-Freeze Stocks Older Than [Days],Frys Stocks Ældre end [dage],
-Role Allowed to edit frozen stock,Rolle Tilladt at redigere frosne lager,
Batch Identification,Batchidentifikation,
Use Naming Series,Brug navngivningsserie,
Naming Series Prefix,Navngivning Serie Prefix,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Købskvittering Tendenser,
Purchase Register,Indkøb Register,
Quotation Trends,Tilbud trends,
-Quoted Item Comparison,Sammenligning Citeret Vare,
Received Items To Be Billed,Modtagne varer skal faktureres,
Qty to Order,Antal til ordre,
Requested Items To Be Transferred,"Anmodet Varer, der skal overføres",
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Vælg lager til materialeanmodninger,
Transfer Materials For Warehouse {0},Overfør materiale til lager {0},
Production Plan Material Request Warehouse,Produktionsplan Materialeanmodningslager,
-Set From Warehouse,Sæt fra lager,
-Source Warehouse (Material Transfer),Kildelager (overførsel af materiale),
Sets 'Source Warehouse' in each row of the items table.,Indstiller 'Source Warehouse' i hver række i varetabellen.,
Sets 'Target Warehouse' in each row of the items table.,Indstiller 'Target Warehouse' i hver række i varetabellen.,
Show Cancelled Entries,Vis annullerede poster,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Tjeneste modtaget, men ikke faktureret",
Deferred Accounting Settings,Udskudte regnskabsindstillinger,
Book Deferred Entries Based On,Book udskudte poster baseret på,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Hvis der vælges "Måneder", bogføres det faste beløb som udskudt omsætning eller udgift for hver måned uanset antal dage i en måned. Proreres, hvis udskudt omsætning eller udgift ikke er bogført i en hel måned.",
Days,Dage,
Months,Måneder,
Book Deferred Entries Via Journal Entry,Book udskudte poster via journalindlæg,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Hvis dette ikke er markeret, oprettes der direkte GL-poster for at reservere udskudt omsætning / udgift",
Submit Journal Entries,Indsend journalindlæg,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Hvis dette ikke er markeret, gemmes journalposter i kladdetilstand og skal indsendes manuelt",
Enable Distributed Cost Center,Aktivér distribueret omkostningscenter,
@@ -8901,8 +8823,6 @@
Is Inter State,Er mellemstat,
Purchase Details,Købsoplysninger,
Depreciation Posting Date,Dato for afskrivning,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Indkøbsordre krævet til indkøb af faktura og modtagelse af kvittering,
-Purchase Receipt Required for Purchase Invoice Creation,Købskvittering krævet til oprettelse af købsfaktura,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Som standard er leverandørnavnet indstillet i henhold til det indtastede leverandørnavn. Hvis du ønsker, at leverandører skal navngives af en",
choose the 'Naming Series' option.,vælg 'Navngivningsserie'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,"Konfigurer standardprislisten, når du opretter en ny købstransaktion. Varepriser hentes fra denne prisliste.",
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Er indkomstskatkomponent,
Component properties and references ,Komponentegenskaber og referencer,
Additional Salary ,Yderligere løn,
-Condtion and formula,Konduktion og formel,
Unmarked days,Umarkerede dage,
Absent Days,Fraværende dage,
Conditions and Formula variable and example,Betingelser og formelvariabel og eksempel,
Feedback By,Feedback af,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Produktionssektion,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Salgsordre krævet til oprettelse af salgsfaktura og leveringsnote,
-Delivery Note Required for Sales Invoice Creation,Leveringsnote påkrævet til oprettelse af salgsfaktura,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Som standard er kundenavnet indstillet i henhold til det indtastede fulde navn. Hvis du ønsker, at kunder skal navngives af en",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,"Konfigurer standardprislisten, når du opretter en ny salgstransaktion. Varepriser hentes fra denne prisliste.",
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Hvis denne indstilling er konfigureret 'Ja', forhindrer ERPNext dig i at oprette en salgsfaktura eller en leveringsnote uden først at oprette en salgsordre. Denne konfiguration kan tilsidesættes for en bestemt kunde ved at aktivere afkrydsningsfeltet 'Tillad oprettelse af salgsfaktura uden salgsordre' i kundemasteren.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} er føjet til alle de valgte emner med succes.,
Topics updated,Emner opdateret,
Academic Term and Program,Akademisk termin og program,
-Last Stock Transaction for item {0} was on {1}.,Sidste lagertransaktion for varen {0} var den {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Lagertransaktioner for vare {0} kan ikke bogføres før dette tidspunkt.,
Please remove this item and try to submit again or update the posting time.,"Fjern denne vare, og prøv at indsende igen eller opdater opdateringstidspunktet.",
Failed to Authenticate the API key.,Kunne ikke godkende API-nøglen.,
Invalid Credentials,Ugyldige legitimationsoplysninger,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Kontroller dit Plaid-klient-id og hemmelige værdier,
Bank transaction creation error,Fejl ved oprettelse af banktransaktioner,
Unit of Measurement,Måleenhed,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Række nr. {}: Sælgeraten for varen {} er lavere end dens {}. Sælgesatsen skal være mindst {},
Fiscal Year {0} Does Not Exist,Regnskabsår {0} eksisterer ikke,
Row # {0}: Returned Item {1} does not exist in {2} {3},Række nr. {0}: Returneret vare {1} findes ikke i {2} {3},
Valuation type charges can not be marked as Inclusive,Gebyrer for værdiansættelse kan ikke markeres som inklusiv,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Svartid for {0} prioritet i række {1} kan ikke være længere end opløsningstid.,
{0} is not enabled in {1},{0} er ikke aktiveret i {1},
Group by Material Request,Gruppér efter materialeanmodning,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Række {0}: For leverandør {0} kræves e-mail-adresse for at sende e-mail,
Email Sent to Supplier {0},E-mail sendt til leverandør {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",Adgangen til anmodning om tilbud fra portal er deaktiveret. For at give adgang skal du aktivere den i portalindstillinger.,
Supplier Quotation {0} Created,Leverandørstilbud {0} Oprettet,
Valid till Date cannot be before Transaction Date,Gyldig till-dato kan ikke være før transaktionsdato,
+Unlink Advance Payment on Cancellation of Order,Fjern link til forskud ved annullering af ordren,
+"Simple Python Expression, Example: territory != 'All Territories'","Enkel Python-udtryk, Eksempel: territorium! = 'Alle territorier'",
+Sales Contributions and Incentives,Salgsbidrag og incitamenter,
+Sourced by Supplier,Oprindelig fra leverandør,
+Total weightage assigned should be 100%.<br>It is {0},Den samlede tildelte vægt skal være 100%.<br> Det er {0},
+Account {0} exists in parent company {1}.,Konto {0} findes i moderselskabet {1}.,
+"To overrule this, enable '{0}' in company {1}",For at tilsidesætte dette skal du aktivere '{0}' i firmaet {1},
+Invalid condition expression,Ugyldigt udtryk for tilstand,
+Please Select a Company First,Vælg først et firma,
+Please Select Both Company and Party Type First,Vælg både firma og festtype først,
+Provide the invoice portion in percent,Angiv fakturadelen i procent,
+Give number of days according to prior selection,Angiv antal dage i henhold til forudgående valg,
+Email Details,E-mail-oplysninger,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Vælg en hilsen til modtageren. F.eks. Hr., Fru osv.",
+Preview Email,Eksempel på e-mail,
+Please select a Supplier,Vælg en leverandør,
+Supplier Lead Time (days),Leveringstid (dage),
+"Home, Work, etc.","Hjem, arbejde osv.",
+Exit Interview Held On,Afslut interview afholdt,
+Condition and formula,Tilstand og formel,
+Sets 'Target Warehouse' in each row of the Items table.,Indstiller 'Target Warehouse' i hver række i varetabellen.,
+Sets 'Source Warehouse' in each row of the Items table.,Indstiller 'Source Warehouse' i hver række i tabellen Items.,
+POS Register,POS-register,
+"Can not filter based on POS Profile, if grouped by POS Profile","Kan ikke filtrere baseret på POS-profil, hvis grupperet efter POS-profil",
+"Can not filter based on Customer, if grouped by Customer","Kan ikke filtrere baseret på kunde, hvis grupperet efter kunde",
+"Can not filter based on Cashier, if grouped by Cashier","Kan ikke filtrere baseret på kasser, hvis grupperet efter kasser",
+Payment Method,Betalingsmetode,
+"Can not filter based on Payment Method, if grouped by Payment Method","Kan ikke filtrere baseret på betalingsmetode, hvis grupperet efter betalingsmetode",
+Supplier Quotation Comparison,Sammenligning af tilbud fra leverandører,
+Price per Unit (Stock UOM),Pris pr. Enhed (lager UOM),
+Group by Supplier,Grupper efter leverandør,
+Group by Item,Gruppér efter vare,
+Remember to set {field_label}. It is required by {regulation}.,Husk at indstille {field_label}. Det kræves af {regulering}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Tilmeldingsdato kan ikke være før startdatoen for det akademiske år {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Tilmeldingsdato kan ikke være efter slutdatoen for den akademiske periode {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Tilmeldingsdato kan ikke være før startdatoen for den akademiske periode {0},
+Future Posting Not Allowed,Fremtidig udstationering ikke tilladt,
+"To enable Capital Work in Progress Accounting, ","For at aktivere Capital Work in Progress Accounting,",
+you must select Capital Work in Progress Account in accounts table,du skal vælge Capital Work in Progress konto i kontotabellen,
+You can also set default CWIP account in Company {},Du kan også indstille CWIP-standardkonto i Company {},
+The Request for Quotation can be accessed by clicking on the following button,Anmodningen om tilbud kan fås ved at klikke på følgende knap,
+Regards,Hilsen,
+Please click on the following button to set your new password,Klik på følgende knap for at indstille din nye adgangskode,
+Update Password,Opdater adgangskode,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Række nr. {}: Sælgeraten for varen {} er lavere end dens {}. Salg {} skal mindst være {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Du kan alternativt deaktivere validering af salgspris i {} for at omgå denne validering.,
+Invalid Selling Price,Ugyldig salgspris,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Adresse skal knyttes til et firma. Tilføj en række for firma i tabellen Links.,
+Company Not Linked,Virksomhed ikke tilknyttet,
+Import Chart of Accounts from CSV / Excel files,Importer kontoplan fra CSV / Excel-filer,
+Completed Qty cannot be greater than 'Qty to Manufacture',Udført antal kan ikke være større end 'Antal til fremstilling',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Række {0}: For leverandør {1} kræves e-mail-adresse for at sende en e-mail,
+"If enabled, the system will post accounting entries for inventory automatically","Hvis det er aktiveret, bogfører systemet automatisk regnskabsposter for beholdningen",
+Accounts Frozen Till Date,Konti frossen till dato,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Regnskabsposter er frosset indtil denne dato. Ingen kan oprette eller ændre poster undtagen brugere med rollen angivet nedenfor,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Roll tilladt til at indstille frosne konti og redigere frosne poster,
+Address used to determine Tax Category in transactions,"Adresse, der bruges til at bestemme skattekategori i transaktioner",
+"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 ","Den procentdel, du har lov til at fakturere mere mod det bestilte beløb. For eksempel, hvis ordreværdien er $ 100 for en vare, og tolerancen er sat til 10%, har du lov til at fakturere op til $ 110",
+This role is allowed to submit transactions that exceed credit limits,"Denne rolle er tilladt at indsende transaktioner, der overstiger kreditgrænser",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Hvis der vælges "Måneder", bogføres et fast beløb som udskudt omsætning eller udgift for hver måned uanset antallet af dage i en måned. Det vil blive forholdsmæssigt beregnet, hvis udskudt omsætning eller udgift ikke er bogført i en hel måned",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Hvis dette ikke er markeret, oprettes direkte GL-poster for at bogføre udskudt omsætning eller udgift",
+Show Inclusive Tax in Print,Vis inklusiv skat i tryk,
+Only select this if you have set up the Cash Flow Mapper documents,"Vælg kun dette, hvis du har konfigureret Cash Flow Mapper-dokumenterne",
+Payment Channel,Betalingskanal,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Er indkøbsordre påkrævet for indkøb af faktura og modtagelse af kvittering?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Er købskvittering påkrævet for oprettelse af købsfaktura?,
+Maintain Same Rate Throughout the Purchase Cycle,Oprethold samme hastighed gennem hele indkøbscyklussen,
+Allow Item To Be Added Multiple Times in a Transaction,"Tillad, at varen tilføjes flere gange i en transaktion",
+Suppliers,Leverandører,
+Send Emails to Suppliers,Send e-mails til leverandører,
+Select a Supplier,Vælg en leverandør,
+Cannot mark attendance for future dates.,Kan ikke markere fremmøde til fremtidige datoer.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Vil du opdatere fremmøde?<br> Til stede: {0}<br> Fraværende: {1},
+Mpesa Settings,Mpesa-indstillinger,
+Initiator Name,Initiativtagernavn,
+Till Number,Till nummer,
+Sandbox,Sandkasse,
+ Online PassKey,Online PassKey,
+Security Credential,Sikkerhedsoplysninger,
+Get Account Balance,Få kontosaldo,
+Please set the initiator name and the security credential,Indstil initiatornavnet og sikkerhedsoplysningerne,
+Inpatient Medication Entry,Indlæggelse af lægemiddelindlæg,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Varekode (narkotika),
+Medication Orders,Medicinordrer,
+Get Pending Medication Orders,Få ventende medicinordrer,
+Inpatient Medication Orders,Indlæggelsesmedicinske ordrer,
+Medication Warehouse,Medicinlager,
+Warehouse from where medication stock should be consumed,"Lager, hvorfra medicinlager skal forbruges",
+Fetching Pending Medication Orders,Henter afventende medicinordrer,
+Inpatient Medication Entry Detail,Indlæggelsesdetalje for indlæggelse af medicin,
+Medication Details,Medicinoplysninger,
+Drug Code,Narkotikakode,
+Drug Name,Lægemiddelnavn,
+Against Inpatient Medication Order,Mod indlæggelsesmedicinsk ordre,
+Against Inpatient Medication Order Entry,Mod indlæggelsesmedicinsk ordreindgang,
+Inpatient Medication Order,Bestilling til indlæggelse af medicin,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Samlede ordrer,
+Completed Orders,Gennemførte ordrer,
+Add Medication Orders,Tilføj medicinordrer,
+Adding Order Entries,Tilføjelse af ordreindgange,
+{0} medication orders completed,{0} medicinordrer afsluttet,
+{0} medication order completed,{0} medicinordren er afsluttet,
+Inpatient Medication Order Entry,Indlæggelse af ordre til indlæggelse af medicin,
+Is Order Completed,Er ordren gennemført,
+Employee Records to Be Created By,"Medarbejderoptegnelser, der skal oprettes af",
+Employee records are created using the selected field,Medarbejderregistreringer oprettes ved hjælp af det valgte felt,
+Don't send employee birthday reminders,Send ikke medarbejderens fødselsdagspåmindelser,
+Restrict Backdated Leave Applications,Begræns Backdaterede orlovsapplikationer,
+Sequence ID,Sekvens-ID,
+Sequence Id,Sekvens Id,
+Allow multiple material consumptions against a Work Order,Tillad flere materielle forbrug mod en arbejdsordre,
+Plan time logs outside Workstation working hours,Planlæg tidslogfiler uden for arbejdstids arbejdstid,
+Plan operations X days in advance,Planlæg operationer X dage i forvejen,
+Time Between Operations (Mins),Tid mellem operationer (minutter),
+Default: 10 mins,Standard: 10 minutter,
+Overproduction for Sales and Work Order,Overproduktion til salg og arbejdsordre,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Opdater styklisteomkostninger automatisk via planlægger, baseret på den seneste værdiansættelsesrate / prislistehastighed / sidste købsrate for råvarer",
+Purchase Order already created for all Sales Order items,"Indkøbsordre, der allerede er oprettet for alle salgsordrer",
+Select Items,Vælg emner,
+Against Default Supplier,Mod standardleverandør,
+Auto close Opportunity after the no. of days mentioned above,Automatisk lukning af mulighed efter nr. af de ovennævnte dage,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Er salgsordre påkrævet for oprettelse af salgsfaktura og leveringsnote?,
+Is Delivery Note Required for Sales Invoice Creation?,Er leveringsnote påkrævet for oprettelse af salgsfaktura?,
+How often should Project and Company be updated based on Sales Transactions?,Hvor ofte skal Project og Company opdateres baseret på salgstransaktioner?,
+Allow User to Edit Price List Rate in Transactions,Tillad bruger at redigere prislistehastighed i transaktioner,
+Allow Item to Be Added Multiple Times in a Transaction,"Tillad, at varen tilføjes flere gange i en transaktion",
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Tillad flere salgsordrer mod en kundes indkøbsordre,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Valider salgsprisen for varen mod købs- eller vurderingssats,
+Hide Customer's Tax ID from Sales Transactions,Skjul kundens skatte-id fra salgstransaktioner,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Den procentdel, du har lov til at modtage eller levere mere mod den bestilte mængde. For eksempel, hvis du har bestilt 100 enheder, og din kvote er 10%, har du lov til at modtage 110 enheder.",
+Action If Quality Inspection Is Not Submitted,"Handling, hvis der ikke indsendes kvalitetsinspektion",
+Auto Insert Price List Rate If Missing,"Indsæt automatisk prisliste, hvis der mangler",
+Automatically Set Serial Nos Based on FIFO,Indstil automatisk serienumre baseret på FIFO,
+Set Qty in Transactions Based on Serial No Input,Indstil antal i transaktioner baseret på seriel intet input,
+Raise Material Request When Stock Reaches Re-order Level,"Hæv materialeanmodning, når lager når ombestillingsniveau",
+Notify by Email on Creation of Automatic Material Request,Meddel via e-mail om oprettelse af automatisk materialeanmodning,
+Allow Material Transfer from Delivery Note to Sales Invoice,Tillad materialeoverførsel fra leveringsnote til salgsfaktura,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Tillad væsentlig overførsel fra købskvittering til købsfaktura,
+Freeze Stocks Older Than (Days),"Frys lager, der er ældre end (dage)",
+Role Allowed to Edit Frozen Stock,Roll tilladt til at redigere frossen bestand,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Det ikke-allokerede beløb af betalingsindgang {0} er større end banktransaktionens ikke-tildelte beløb,
+Payment Received,Betaling modtaget,
+Attendance cannot be marked outside of Academic Year {0},Deltagelse kan ikke markeres uden for akademisk år {0},
+Student is already enrolled via Course Enrollment {0},Studerende er allerede tilmeldt via kursusindmelding {0},
+Attendance cannot be marked for future dates.,Deltagelse kan ikke markeres for fremtidige datoer.,
+Please add programs to enable admission application.,Tilføj venligst programmer for at muliggøre optagelsesansøgning.,
+The following employees are currently still reporting to {0}:,Følgende medarbejdere rapporterer i øjeblikket stadig til {0}:,
+Please make sure the employees above report to another Active employee.,"Sørg for, at medarbejderne ovenfor rapporterer til en anden aktiv medarbejder.",
+Cannot Relieve Employee,Kan ikke frigøre medarbejder,
+Please enter {0},Indtast venligst {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Vælg en anden betalingsmetode. Mpesa understøtter ikke transaktioner i valutaen '{0}',
+Transaction Error,Transaktionsfejl,
+Mpesa Express Transaction Error,Mpesa Express-transaktionsfejl,
+"Issue detected with Mpesa configuration, check the error logs for more details","Problem registreret med Mpesa-konfiguration, tjek fejllogfilerne for flere detaljer",
+Mpesa Express Error,Mpesa Express-fejl,
+Account Balance Processing Error,Fejl ved behandling af kontosaldo,
+Please check your configuration and try again,"Kontroller din konfiguration, og prøv igen",
+Mpesa Account Balance Processing Error,Fejl ved behandling af Mpesa-kontosaldo,
+Balance Details,Balanceoplysninger,
+Current Balance,Nuværende balance,
+Available Balance,Disponibel saldo,
+Reserved Balance,Reserveret saldo,
+Uncleared Balance,Uklart balance,
+Payment related to {0} is not completed,Betaling relateret til {0} er ikke afsluttet,
+Row #{}: Item Code: {} is not available under warehouse {}.,Række nr. {}: Varekode: {} er ikke tilgængelig under lager {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Række nr. {}: Mængde på lager ikke til varekode: {} under lager {}. Tilgængelig mængde {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Række nr. {}: Vælg et serienummer og et parti mod varen: {} eller fjern det for at gennemføre transaktionen.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"Række nr. {}: Intet serienummer er valgt mod elementet: {}. Vælg en, eller fjern den for at gennemføre transaktionen.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,"Række nr. {}: Der er ikke valgt nogen batch mod element: {}. Vælg et parti, eller fjern det for at gennemføre transaktionen.",
+Payment amount cannot be less than or equal to 0,Betalingsbeløbet kan ikke være mindre end eller lig med 0,
+Please enter the phone number first,Indtast først telefonnummeret,
+Row #{}: {} {} does not exist.,Række nr. {}: {} {} Findes ikke.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Række nr. {0}: {1} kræves for at oprette de indledende {2} fakturaer,
+You had {} errors while creating opening invoices. Check {} for more details,Du havde {} fejl under oprettelsen af åbningsfakturaer. Se {} for at få flere oplysninger,
+Error Occured,Fejl opstået,
+Opening Invoice Creation In Progress,Åbning af oprettelse af faktura i gang,
+Creating {} out of {} {},Opretter {} ud af {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Serienr.: {0}) kan ikke forbruges, da den er forbeholdt fuld udfylde salgsordre {1}.",
+Item {0} {1},Vare {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Sidste lagertransaktion for vare {0} under lager {1} var den {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Lagertransaktioner for vare {0} under lager {1} kan ikke bogføres før dette tidspunkt.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Det er ikke tilladt at bogføre fremtidige aktietransaktioner på grund af Immutable Ledger,
+A BOM with name {0} already exists for item {1}.,Der findes allerede en stykliste med navnet {0} for varen {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Omdøbte du varen? Kontakt administrator / teknisk support,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},I række nr. {0}: sekvens-id'et {1} kan ikke være mindre end det foregående rækkefølge-id {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) skal være lig med {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, fuldfør operationen {1} før operationen {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Kan ikke sikre levering med serienummer, da vare {0} er tilføjet med og uden at sikre levering ved serienummer.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Vare {0} har ikke serienr. Kun serilialiserede varer kan leveres baseret på serienummer,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Ingen aktiv stykliste fundet for element {0}. Levering med serienr. Kan ikke sikres,
+No pending medication orders found for selected criteria,Der blev ikke fundet nogen ventende medicinordrer til udvalgte kriterier,
+From Date cannot be after the current date.,Fra dato kan ikke være efter den aktuelle dato.,
+To Date cannot be after the current date.,Til dato kan ikke være efter den aktuelle dato.,
+From Time cannot be after the current time.,Fra tid kan ikke være efter det aktuelle tidspunkt.,
+To Time cannot be after the current time.,To Time kan ikke være efter det aktuelle tidspunkt.,
+Stock Entry {0} created and ,Lagerpost {0} oprettet og,
+Inpatient Medication Orders updated successfully,Indlægsmedicinske ordrer opdateret,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Række {0}: Kan ikke oprette indlæggelse af indlæggelsesmedicin mod annulleret bestilling af indlæggelsesmedicin {1},
+Row {0}: This Medication Order is already marked as completed,Række {0}: Denne medicinordre er allerede markeret som afsluttet,
+Quantity not available for {0} in warehouse {1},"Mængde, der ikke er tilgængeligt for {0} på lageret {1}",
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"Aktivér Tillad negativ beholdning i lagerindstillinger, eller opret lagerindgang for at fortsætte.",
+No Inpatient Record found against patient {0},Der blev ikke fundet nogen indlæggelsesjournal over patienten {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Der findes allerede en ordre om indlæggelse af medicin {0} mod patientmøde {1}.,
+Allow In Returns,Tillad returnerer,
+Hide Unavailable Items,Skjul ikke-tilgængelige poster,
+Apply Discount on Discounted Rate,Anvend rabat på nedsat sats,
+Therapy Plan Template,Terapiplan skabelon,
+Fetching Template Details,Henter skabelondetaljer,
+Linked Item Details,Sammenkædede varedetaljer,
+Therapy Types,Terapi Typer,
+Therapy Plan Template Detail,Terapi plan skabelon detaljer,
+Non Conformance,Manglende overensstemmelse,
+Process Owner,Proces ejer,
+Corrective Action,Korrigerende handling,
+Preventive Action,Forebyggende handling,
+Problem,Problem,
+Responsible,Ansvarlig,
+Completion By,Afslutning af,
+Process Owner Full Name,Processejerens fulde navn,
+Right Index,Højre indeks,
+Left Index,Venstre indeks,
+Sub Procedure,Underprocedure,
+Passed,Bestået,
+Print Receipt,Udskriv kvittering,
+Edit Receipt,Rediger kvittering,
+Focus on search input,Fokuser på søgeinput,
+Focus on Item Group filter,Fokuser på varegruppefilter,
+Checkout Order / Submit Order / New Order,Kasseordre / Afgiv ordre / Ny ordre,
+Add Order Discount,Tilføj ordrerabat,
+Item Code: {0} is not available under warehouse {1}.,Varekode: {0} er ikke tilgængelig under lageret {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Serienumre er ikke tilgængelige for vare {0} under lager {1}. Prøv at skifte lager.,
+Fetched only {0} available serial numbers.,Hentede kun {0} tilgængelige serienumre.,
+Switch Between Payment Modes,Skift mellem betalingsformer,
+Enter {0} amount.,Indtast {0} beløb.,
+You don't have enough points to redeem.,Du har ikke nok point til at indløse.,
+You can redeem upto {0}.,Du kan indløse op til {0}.,
+Enter amount to be redeemed.,"Indtast det beløb, der skal indløses.",
+You cannot redeem more than {0}.,Du kan ikke indløse mere end {0}.,
+Open Form View,Åbn formularvisning,
+POS invoice {0} created succesfully,POS-faktura {0} oprettet med succes,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Lagermængde ikke nok til varekode: {0} under lager {1}. Tilgængelig mængde {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Serienr.: {0} er allerede blevet overført til en anden POS-faktura.,
+Balance Serial No,Balance Serienr,
+Warehouse: {0} does not belong to {1},Lager: {0} tilhører ikke {1},
+Please select batches for batched item {0},Vælg batcher til batchvaren {0},
+Please select quantity on row {0},Vælg antal på række {0},
+Please enter serial numbers for serialized item {0},Indtast serienumre for serienummeret {0},
+Batch {0} already selected.,Batch {0} er allerede valgt.,
+Please select a warehouse to get available quantities,Vælg et lager for at få tilgængelige mængder,
+"For transfer from source, selected quantity cannot be greater than available quantity",For overførsel fra kilde kan den valgte mængde ikke være større end den tilgængelige mængde,
+Cannot find Item with this Barcode,Kan ikke finde element med denne stregkode,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} er obligatorisk. Måske oprettes der ikke valutaudveksling for {1} til {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} har indsendt aktiver tilknyttet det. Du skal annullere aktiverne for at oprette køberetur.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Dette dokument kan ikke annulleres, da det er knyttet til det indsendte aktiv {0}. Annuller det for at fortsætte.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Række nr. {}: Serienr. {} Er allerede overført til en anden POS-faktura. Vælg gyldigt serienummer.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Række nr. {}: Serienumre. {} Er allerede blevet overført til en anden POS-faktura. Vælg gyldigt serienummer.,
+Item Unavailable,Varen er ikke tilgængelig,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Række nr. {}: Serienr. {} Kan ikke returneres, da den ikke blev behandlet i original faktura {}",
+Please set default Cash or Bank account in Mode of Payment {},Indstil standard kontanter eller bankkonto i betalingsmetode {},
+Please set default Cash or Bank account in Mode of Payments {},Angiv standard kontanter eller bankkonto i betalingsmetode {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Sørg for, at {} kontoen er en balancekonto. Du kan ændre moderkontoen til en balancekonto eller vælge en anden konto.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Sørg for, at {} kontoen er en konto, der skal betales. Skift kontotype til Betales, eller vælg en anden konto.",
+Row {}: Expense Head changed to {} ,Række {}: Omkostningshoved ændret til {},
+because account {} is not linked to warehouse {} ,fordi konto {} ikke er knyttet til lager {},
+or it is not the default inventory account,eller det er ikke standardlagerkontoen,
+Expense Head Changed,Omkostningshoved ændret,
+because expense is booked against this account in Purchase Receipt {},fordi udgift bogføres på denne konto i købskvittering {},
+as no Purchase Receipt is created against Item {}. ,da der ikke oprettes nogen købskvittering mod varen {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Dette gøres for at håndtere bogføring af tilfælde, hvor købsmodtagelse oprettes efter købsfaktura",
+Purchase Order Required for item {},Indkøbsordre påkrævet for vare {},
+To submit the invoice without purchase order please set {} ,For at indsende fakturaen uden indkøbsordre skal du angive {},
+as {} in {},som i {},
+Mandatory Purchase Order,Obligatorisk indkøbsordre,
+Purchase Receipt Required for item {},Købskvittering påkrævet for vare {},
+To submit the invoice without purchase receipt please set {} ,For at indsende fakturaen uden købskvittering skal du angive {},
+Mandatory Purchase Receipt,Obligatorisk købskvittering,
+POS Profile {} does not belongs to company {},POS-profil {} tilhører ikke firma {},
+User {} is disabled. Please select valid user/cashier,Bruger {} er deaktiveret. Vælg gyldig bruger / kasserer,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Række nr. {}: Originalfaktura {} af returfaktura {} er {}.,
+Original invoice should be consolidated before or along with the return invoice.,Originalfaktura skal konsolideres før eller sammen med returfakturaen.,
+You can add original invoice {} manually to proceed.,Du kan tilføje originalfaktura {} manuelt for at fortsætte.,
+Please ensure {} account is a Balance Sheet account. ,"Sørg for, at {} kontoen er en balancekonto.",
+You can change the parent account to a Balance Sheet account or select a different account.,Du kan ændre moderkontoen til en balancekonto eller vælge en anden konto.,
+Please ensure {} account is a Receivable account. ,"Sørg for, at {} kontoen er en konto, der kan modtages.",
+Change the account type to Receivable or select a different account.,"Skift kontotype til Modtagelig, eller vælg en anden konto.",
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"{} kan ikke annulleres, da de optjente loyalitetspoint er blevet indløst. Annuller først {} Nej {}",
+already exists,eksisterer allerede,
+POS Closing Entry {} against {} between selected period,POS-afslutningspost {} mod {} mellem den valgte periode,
+POS Invoice is {},POS-faktura er {},
+POS Profile doesn't matches {},POS-profil matcher ikke {},
+POS Invoice is not {},POS-faktura er ikke {},
+POS Invoice isn't created by user {},POS-faktura oprettes ikke af brugeren {},
+Row #{}: {},Række nr. {}: {},
+Invalid POS Invoices,Ugyldige POS-fakturaer,
+Please add the account to root level Company - {},Føj kontoen til rodniveau Virksomhed - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Under oprettelsen af en konto til Child Company {0} blev forældrekontoen {1} ikke fundet. Opret forældrekontoen i den tilsvarende COA,
+Account Not Found,Konto ikke fundet,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",Under oprettelsen af en konto til Child Company {0} blev forældrekontoen {1} fundet som en hovedkontokonto.,
+Please convert the parent account in corresponding child company to a group account.,Konverter moderkontoen i det tilsvarende underordnede selskab til en gruppekonto.,
+Invalid Parent Account,Ugyldig moderkonto,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",Omdøbning er kun tilladt via moderselskabet {0} for at undgå uoverensstemmelse.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Hvis du {0} {1} mængder af varen {2}, anvendes ordningen {3} på varen.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Hvis du {0} {1} har værdi {2}, anvendes ordningen {3} på varen.",
+"As the field {0} is enabled, the field {1} is mandatory.","Da feltet {0} er aktiveret, er feltet {1} obligatorisk.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Da feltet {0} er aktiveret, skal værdien af feltet {1} være mere end 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Kan ikke levere serienummer {0} af varen {1}, da den er forbeholdt fuldt udfyldt salgsordre {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Salgsordre {0} har reservation for varen {1}, du kan kun levere reserveret {1} mod {0}.",
+{0} Serial No {1} cannot be delivered,{0} Serienummer {1} kan ikke leveres,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Række {0}: Vare i underentreprise er obligatorisk for råmaterialet {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Da der er tilstrækkelige råmaterialer, kræves der ikke materialeanmodning til lager {0}.",
+" If you still want to proceed, please enable {0}.","Hvis du stadig vil fortsætte, skal du aktivere {0}.",
+The item referenced by {0} - {1} is already invoiced,"Den vare, der henvises til af {0} - {1}, faktureres allerede",
+Therapy Session overlaps with {0},Terapisession overlapper med {0},
+Therapy Sessions Overlapping,Terapisessioner overlapper hinanden,
+Therapy Plans,Terapiplaner,
+"Item Code, warehouse, quantity are required on row {0}","Varekode, lager, antal kræves i række {0}",
+Get Items from Material Requests against this Supplier,Få varer fra materialeanmodninger mod denne leverandør,
+Enable European Access,Aktiver europæisk adgang,
+Creating Purchase Order ...,Opretter indkøbsordre ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Vælg en leverandør fra standardleverandørerne af nedenstående varer. Ved valg foretages en indkøbsordre kun mod varer, der tilhører den valgte leverandør.",
+Row #{}: You must select {} serial numbers for item {}.,Række nr. {}: Du skal vælge {} serienumre for varen {}.,
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index 8196d6c..ca03a78 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -13,7 +13,7 @@
'Total','Gesamtbetrag',
'Update Stock' can not be checked because items are not delivered via {0},"""Lager aktualisieren"" kann nicht ausgewählt werden, da Artikel nicht über {0} geliefert wurden",
'Update Stock' cannot be checked for fixed asset sale,Beim Verkauf von Anlagevermögen darf 'Lagerbestand aktualisieren' nicht ausgewählt sein.,
-) for {0},) para {0},
+) for {0},) für {0},
1 exact match.,1 genaue Übereinstimmung.,
90-Above,Über 90,
A Customer Group exists with same name please change the Customer name or rename the Customer Group,Eine Kundengruppe mit dem gleichen Namen existiert bereits. Bitte den Kundennamen ändern oder die Kundengruppe umbenennen,
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Tatsächliche Steuerart kann nicht im Artikelpreis in Zeile {0} beinhaltet sein,
Add,Hinzufügen,
Add / Edit Prices,Preise hinzufügen / bearbeiten,
-Add All Suppliers,Alle Lieferanten hinzufügen,
Add Comment,Kommentar hinzufügen,
Add Customers,Kunden hinzufügen,
Add Employees,Mitarbeiter hinzufügen,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Kann nicht abschreiben, wenn die Kategorie ""Bewertung"" oder ""Bewertung und Total 'ist",
"Cannot delete Serial No {0}, as it is used in stock transactions","Die Seriennummer {0} kann nicht gelöscht werden, da sie in Lagertransaktionen verwendet wird",
Cannot enroll more than {0} students for this student group.,Kann nicht mehr als {0} Studenten für diese Studentengruppe einschreiben.,
-Cannot find Item with this barcode,Artikel mit diesem Barcode kann nicht gefunden werden,
Cannot find active Leave Period,Aktive Abwesenheitszeit kann nicht gefunden werden,
Cannot produce more Item {0} than Sales Order quantity {1},"Es können nicht mehr Artikel {0} produziert werden, als die über Kundenaufträge bestellte Stückzahl {1}",
Cannot promote Employee with status Left,Mitarbeiter mit Status "Links" kann nicht gefördert werden,
Cannot refer row number greater than or equal to current row number for this Charge type,"Für diese Berechnungsart kann keine Zeilennummern zugeschrieben werden, die größer oder gleich der aktuellen Zeilennummer ist",
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"Die Berechnungsart kann für die erste Zeile nicht auf ""bezogen auf Menge der vorhergenden Zeile"" oder auf ""bezogen auf Gesamtmenge der vorhergenden Zeile"" gesetzt werden",
-Cannot set a received RFQ to No Quote,"Kann einen empfangenen RFQ nicht auf ""kein Zitat"" setzen.",
Cannot set as Lost as Sales Order is made.,"Kann nicht als verloren gekennzeichnet werden, da ein Kundenauftrag dazu existiert.",
Cannot set authorization on basis of Discount for {0},Genehmigung kann nicht auf der Basis des Rabattes für {0} festgelegt werden,
Cannot set multiple Item Defaults for a company.,Es können nicht mehrere Artikelstandards für ein Unternehmen festgelegt werden.,
@@ -496,7 +493,7 @@
Cart is Empty,Der Warenkorb ist leer,
Case No(s) already in use. Try from Case No {0},Fall-Nr. (n) bereits in Verwendung. Versuchen Sie eine Fall-Nr. ab {0},
Cash,Bargeld,
-Cash Flow Statement,Geldflussrechnung,
+Cash Flow Statement,Kapitalflussrechnung,
Cash Flow from Financing,Cashflow aus Finanzierung,
Cash Flow from Investing,Cashflow aus Investitionen,
Cash Flow from Operations,Cashflow aus Geschäftstätigkeit,
@@ -521,7 +518,6 @@
Chargeble,Belastung,
Charges are updated in Purchase Receipt against each item,Kosten werden im Kaufbeleg für jede Position aktualisiert,
"Charges will be distributed proportionately based on item qty or amount, as per your selection",Die Kosten werden gemäß Ihrer Wahl anteilig verteilt basierend auf Artikelmenge oder -preis,
-Chart Of Accounts,Kontenplan,
Chart of Cost Centers,Kostenstellenplan,
Check all,Alle prüfen,
Checkout,Kasse,
@@ -530,7 +526,7 @@
Cheque/Reference No,Scheck-/ Referenznummer,
Cheques Required,Überprüfungen erforderlich,
Cheques and Deposits incorrectly cleared,Schecks und Kautionen fälschlicherweise gelöscht,
-Child Task exists for this Task. You can not delete this Task.,Für diese Aufgabe existiert eine untergeordnete Aufgabe. Sie können diese Aufgabe daher nicht löschen.,
+Child Task exists for this Task. You can not delete this Task.,Für diesen Vorgang existiert ein untergeordneter Vorgang. Sie können diesen daher nicht löschen.,
Child nodes can be only created under 'Group' type nodes,Unterknoten können nur unter Gruppenknoten erstellt werden.,
Child warehouse exists for this warehouse. You can not delete this warehouse.,Für dieses Lager existieren untergordnete Lager vorhanden. Sie können dieses Lager daher nicht löschen.,
Circular Reference Error,Zirkelschluss-Fehler,
@@ -539,7 +535,7 @@
Claimed Amount,Anspruchsbetrag,
Clay,Lehm,
Clear filters,Filter löschen,
-Clear values,Klare Werte,
+Clear values,Werte löschen,
Clearance Date,Abrechnungsdatum,
Clearance Date not mentioned,Abrechnungsdatum nicht erwähnt,
Clearance Date updated,Abrechnungsdatum aktualisiert,
@@ -581,7 +577,6 @@
Compensatory Off,Ausgleich für,
Compensatory leave request days not in valid holidays,"Tage des Ausgleichsurlaubs, die nicht in den gültigen Feiertagen sind",
Complaint,Beschwerde,
-Completed Qty can not be greater than 'Qty to Manufacture',"Gefertigte Menge kann nicht größer sein als ""Menge für Herstellung""",
Completion Date,Fertigstellungstermin,
Computer,Rechner,
Condition,Zustand,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Tägliche, wöchentliche und monatliche E-Mail-Berichte erstellen und verwalten",
Create customer quotes,Kunden Angebote erstellen,
Create rules to restrict transactions based on values.,Regeln erstellen um Transaktionen auf Basis von Werten zu beschränken,
-Created By,Erstellt von,
Created {0} scorecards for {1} between: ,Erstellte {0} Scorecards für {1} zwischen:,
Creating Company and Importing Chart of Accounts,Firma anlegen und Kontenplan importieren,
Creating Fees,Gebühren anlegen,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Employee Transfer kann nicht vor dem Übertragungstermin eingereicht werden,
Employee cannot report to himself.,Mitarbeiter können nicht an sich selbst Bericht erstatten,
Employee relieved on {0} must be set as 'Left',"Freigestellter Angestellter {0} muss als ""entlassen"" gekennzeichnet werden",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Der Mitarbeiterstatus kann nicht auf "Links" gesetzt werden, da folgende Mitarbeiter diesem Mitarbeiter derzeit Bericht erstatten:",
Employee {0} already submited an apllication {1} for the payroll period {2},Mitarbeiter {0} hat bereits eine Bewerbung {1} für die Abrechnungsperiode {2} eingereicht,
Employee {0} has already applied for {1} between {2} and {3} : ,Der Mitarbeiter {0} hat bereits einen Antrag auf {1} zwischen {2} und {3} gestellt:,
Employee {0} has no maximum benefit amount,Der Mitarbeiter {0} hat keinen maximalen Leistungsbetrag,
@@ -986,7 +979,7 @@
Excise Invoice,Verbrauch Rechnung,
Execution,Ausführung,
Executive Search,Direktsuche,
-Expand All,Alle erweitern,
+Expand All,Alle ausklappen,
Expected Delivery Date,Geplanter Liefertermin,
Expected Delivery Date should be after Sales Order Date,Voraussichtlicher Liefertermin sollte nach Kundenauftragsdatum erfolgen,
Expected End Date,Voraussichtliches Enddatum,
@@ -1042,7 +1035,7 @@
Finance Book,Finanzbuch,
Financial / accounting year.,Finanz-/Rechnungsjahr,
Financial Services,Finanzdienstleistungen,
-Financial Statements,Jahresabschluss,
+Financial Statements,Finanzberichte,
Financial Year,Geschäftsjahr,
Finish,Fertig,
Finished Good,Gut beendet,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Für Zeile {0}: Geben Sie die geplante Menge ein,
"For {0}, only credit accounts can be linked against another debit entry",Für {0} können nur Habenkonten mit einer weiteren Sollbuchung verknüpft werden,
"For {0}, only debit accounts can be linked against another credit entry",Für {0} können nur Sollkonten mit einer weiteren Habenbuchung verknüpft werden,
-Form View,Formularansicht,
Forum Activity,Forum Aktivität,
Free item code is not selected,Freier Artikelcode ist nicht ausgewählt,
Freight and Forwarding Charges,Fracht- und Versandkosten,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Da der Resturlaub bereits in den zukünftigen Datensatz für Urlaube {1} übertragen wurde, kann der Urlaub nicht vor {0} zugeteilt werden.",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Da der Resturlaub bereits in den zukünftigen Datensatz für Urlaube {1} übertragen wurde, kann der Urlaub nicht vor {0} genehmigt/abgelehnt werden.",
Leave of type {0} cannot be longer than {1},Abwesenheit vom Typ {0} kann nicht länger sein als {1},
-Leave the field empty to make purchase orders for all suppliers,"Lassen Sie das Feld leer, um Bestellungen für alle Lieferanten zu tätigen",
Leaves,Blätter,
Leaves Allocated Successfully for {0},Erfolgreich zugewiesene Abwesenheiten für {0},
Leaves has been granted sucessfully,Urlaub wurde genehmigt,
@@ -1667,7 +1658,7 @@
New BOM,Neue Stückliste,
New Batch ID (Optional),Neue Batch-ID (optional),
New Batch Qty,Neue Batch-Menge,
-New Company,Neues Unternehmen,
+New Company,Neues Unternehmen anlegen,
New Cost Center Name,Neuer Kostenstellenname,
New Customer Revenue,Neuer Kundenumsatz,
New Customers,neue Kunden,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Keine Elemente mit Bill of Materials zu Herstellung,
No Items with Bill of Materials.,Keine Artikel mit Stückliste.,
No Permission,Keine Berechtigung,
-No Quote,Kein Zitat,
No Remarks,Keine Anmerkungen,
No Result to submit,Kein Ergebnis zur Einreichung,
No Salary Structure assigned for Employee {0} on given date {1},Keine Gehaltsstruktur für Mitarbeiter {0} am angegebenen Datum {1} zugewiesen,
@@ -1803,7 +1793,7 @@
Opening Date and Closing Date should be within same Fiscal Year,Eröffnungsdatum und Abschlussdatum sollten im gleichen Geschäftsjahr sein,
Opening Date should be before Closing Date,Eröffnungsdatum sollte vor dem Abschlussdatum liegen,
Opening Entry Journal,Eröffnungseintragsjournal,
-Opening Invoice Creation Tool,Öffnen des Rechnungserstellungswerkzeugs,
+Opening Invoice Creation Tool,Offene Rechnungen übertragen,
Opening Invoice Item,Rechnungsposition öffnen,
Opening Invoices,Rechnungen öffnen,
Opening Invoices Summary,Rechnungszusammenfassung öffnen,
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Überlagernde Bedingungen gefunden zwischen:,
Owner,Besitzer,
PAN,PFANNE,
-PO already created for all sales order items,Bestellung wurde bereits für alle Kundenauftragspositionen angelegt,
POS,Verkaufsstelle,
POS Profile,Verkaufsstellen-Profil,
POS Profile is required to use Point-of-Sale,"POS-Profil ist erforderlich, um Point-of-Sale zu verwenden",
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Bitte zuerst Chargentyp auswählen,
Please select Company,Bitte Unternehmen auswählen,
Please select Company and Designation,Bitte wählen Sie Unternehmen und Stelle,
-Please select Company and Party Type first,Bitte zuerst Unternehmen und Gruppentyp auswählen,
Please select Company and Posting Date to getting entries,"Bitte wählen Sie Unternehmen und Buchungsdatum, um Einträge zu erhalten",
Please select Company first,Bitte zuerst Unternehmen auswählen,
Please select Completion Date for Completed Asset Maintenance Log,Bitte wählen Sie Fertigstellungsdatum für das abgeschlossene Wartungsprotokoll für den Vermögenswert,
@@ -2223,7 +2211,7 @@
Projected Qty,Projizierte Menge,
Projected Quantity Formula,Formel für projizierte Menge,
Projects,Projekte,
-Property,Eigentum,
+Property,Eigenschaft,
Property already added,Die Eigenschaft wurde bereits hinzugefügt,
Proposal Writing,Verfassen von Angeboten,
Proposal/Price Quote,Angebot / Preis Angebot,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Zeile {0}: Umrechnungsfaktor für Maßeinheit ist zwingend erforderlich,
Row {0}: select the workstation against the operation {1},Zeile {0}: Wählen Sie die Arbeitsstation für die Operation {1} aus.,
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Zeile {0}: {1} Für den Eintrag {2} benötigte Seriennummern. Du hast {3} zur Verfügung gestellt.,
-Row {0}: {1} is required to create the Opening {2} Invoices,"Zeile {0}: {1} ist erforderlich, um die Rechnungseröffnung {2} zu erstellen",
Row {0}: {1} must be greater than 0,Zeile {0}: {1} muss größer als 0 sein,
Row {0}: {1} {2} does not match with {3},Zeile {0}: {1} {2} stimmt nicht mit {3} überein,
Row {0}:Start Date must be before End Date,Zeile {0}: Startdatum muss vor dem Enddatum liegen,
@@ -2536,7 +2523,7 @@
Sales Invoice {0} must be cancelled before cancelling this Sales Order,Ausgangsrechnung {0} muss vor Stornierung dieses Kundenauftrags abgebrochen werden,
Sales Manager,Vertriebsleiter,
Sales Master Manager,Hauptvertriebsleiter,
-Sales Order,Kundenauftrag,
+Sales Order,Auftragsbestätigung,
Sales Order Item,Kundenauftrags-Artikel,
Sales Order required for Item {0},Kundenauftrag für den Artikel {0} erforderlich,
Sales Order to Payment,Vom Kundenauftrag zum Zahlungseinang,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Senden Sie Grant Review E-Mail,
Send Now,Jetzt senden,
Send SMS,SMS verschicken,
-Send Supplier Emails,Lieferantenemails senden,
Send mass SMS to your contacts,Massen-SMS an Kontakte versenden,
Sensitivity,Empfindlichkeit,
Sent,Gesendet,
-Serial #,Serien #,
Serial No and Batch,Seriennummer und Chargen,
Serial No is mandatory for Item {0},Seriennummer ist für Artikel {0} zwingend erforderlich,
Serial No {0} does not belong to Batch {1},Seriennr. {0} gehört nicht zu Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Firma des Unternehmens, für das dieses System eingerichtet wird.",
The number of shares and the share numbers are inconsistent,Die Anzahl der Aktien und die Aktienanzahl sind inkonsistent,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Das Zahlungsgatewaykonto in Plan {0} unterscheidet sich von dem Zahlungsgatewaykonto in dieser Zahlungsanforderung,
-The request for quotation can be accessed by clicking on the following link,Die Angebotsanfrage kann durch einen Klick auf den folgenden Link abgerufen werden,
The selected BOMs are not for the same item,Die ausgewählten Stücklisten sind nicht für den gleichen Artikel,
The selected item cannot have Batch,Der ausgewählte Artikel kann keine Charge haben,
The seller and the buyer cannot be the same,Der Verkäufer und der Käufer können nicht identisch sein,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Der Gesamtbetrag der flexiblen Leistungskomponente {0} sollte nicht unter dem Höchstbetrag der Leistungen {1} liegen.,
Total hours: {0},Stundenzahl: {0},
Total leaves allocated is mandatory for Leave Type {0},Die Gesamtzahl der zugewiesenen Blätter ist für Abwesenheitsart {0} erforderlich.,
-Total weightage assigned should be 100%. It is {0},Summe der zugeordneten Gewichtungen sollte 100% sein. Sie ist {0},
Total working hours should not be greater than max working hours {0},Insgesamt Arbeitszeit sollte nicht größer sein als die maximale Arbeitszeit {0},
Total {0} ({1}),Insgesamt {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Insgesamt {0} für alle Elemente gleich Null ist, sein kann, sollten Sie "Verteilen Gebühren auf der Grundlage" ändern",
@@ -3316,7 +3299,6 @@
What do you need help with?,Wofür benötigen Sie Hilfe?,
What does it do?,Unternehmenszweck,
Where manufacturing operations are carried.,"Ort, an dem Arbeitsgänge der Fertigung ablaufen.",
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Beim Erstellen des Kontos für die untergeordnete Firma {0} wurde das übergeordnete Konto {1} nicht gefunden. Bitte erstellen Sie das übergeordnete Konto in der entsprechenden COA,
White,Weiß,
Wire Transfer,Überweisung,
WooCommerce Products,WooCommerce-Produkte,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} Varianten erstellt.,
{0} {1} created,{0} {1} erstellt,
{0} {1} does not exist,{0} {1} existiert nicht,
-{0} {1} does not exist.,{0} {1} existiert nicht.,
{0} {1} has been modified. Please refresh.,{0} {1} wurde geändert. Bitte aktualisieren.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} sind nicht gebucht, deshalb kann die Aktion nicht abgeschlossen werden",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} ist mit {2} verbunden, aber das Gegenkonto ist {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} existiert nicht,
{0}: {1} not found in Invoice Details table,{0}: {1} nicht in der Rechnungs-Details-Tabelle gefunden,
{} of {},{} von {},
+Assigned To,Zugewiesen zu,
Chat,Unterhaltung,
Completed By,Vervollständigt von,
Conditions,Bedingungen,
@@ -3506,7 +3488,9 @@
Merge with existing,Mit Existierenden zusammenführen,
Office,Büro,
Orientation,Orientierung,
+Parent,Übergeordnetes Element,
Passive,Passiv,
+Payment Failed,Bezahlung fehlgeschlagen,
Percent,Prozent,
Permanent,Dauerhaft,
Personal,Persönlich,
@@ -3544,7 +3528,6 @@
Company field is required,Firmenfeld ist erforderlich,
Creating Dimensions...,Dimensionen erstellen ...,
Duplicate entry against the item code {0} and manufacturer {1},Doppelte Eingabe gegen Artikelcode {0} und Hersteller {1},
-Import Chart Of Accounts from CSV / Excel files,Kontenplan aus CSV / Excel-Dateien importieren,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Ungültige GSTIN! Die von Ihnen eingegebene Eingabe stimmt nicht mit dem GSTIN-Format für UIN-Inhaber oder gebietsfremde OIDAR-Dienstanbieter überein,
Invoice Grand Total,Rechnungssumme,
Last carbon check date cannot be a future date,Das Datum der letzten Kohlenstoffprüfung kann kein zukünftiges Datum sein,
@@ -3556,6 +3539,7 @@
Show {0},{0} anzeigen,
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Sonderzeichen außer "-", "#", ".", "/", "{" Und "}" sind bei der Benennung von Serien nicht zulässig",
Target Details,Zieldetails,
+{0} already has a Parent Procedure {1}.,{0} hat bereits eine übergeordnete Prozedur {1}.,
API,API,
Annual,Jährlich,
Approved,Genehmigt,
@@ -3572,6 +3556,8 @@
No data to export,Keine zu exportierenden Daten,
Portrait,Porträt,
Print Heading,Druckkopf,
+Scheduler Inactive,Scheduler Inaktiv,
+Scheduler is inactive. Cannot import data.,Scheduler ist inaktiv. Daten können nicht importiert werden.,
Show Document,Dokument anzeigen,
Show Traceback,Traceback anzeigen,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Qualitätsprüfung für Artikel {0} anlegen,
Creating Accounts...,Konten erstellen ...,
Creating bank entries...,Bankeinträge werden erstellt ...,
-Creating {0},Erstellen von {0},
Credit limit is already defined for the Company {0},Kreditlimit für das Unternehmen ist bereits definiert {0},
Ctrl + Enter to submit,Strg + Eingabetaste zum Senden,
Ctrl+Enter to submit,Strg + Enter zum Senden,
@@ -3921,7 +3906,6 @@
Plaid public token error,Plaid public token error,
Plaid transactions sync error,Synchronisierungsfehler für Plaid-Transaktionen,
Please check the error log for details about the import errors,Überprüfen Sie das Fehlerprotokoll auf Details zu den Importfehlern,
-Please click on the following link to set your new password,Bitte auf die folgende Verknüpfung klicken um ein neues Passwort zu setzen,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Bitte erstellen Sie <b>DATEV-Einstellungen</b> für Firma <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Bitte erstellen Sie eine Berichtigung für den Betrag {0}.,
Please do not create more than 500 items at a time,Bitte erstellen Sie nicht mehr als 500 Artikel gleichzeitig,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Das Erscheinungsdatum muss in der Zukunft liegen,
Relieving Date must be greater than or equal to Date of Joining,Das Ablösungsdatum muss größer oder gleich dem Beitrittsdatum sein,
Rename,Umbenennen,
+Rename Not Allowed,Umbenennen nicht erlaubt,
Repayment Method is mandatory for term loans,Die Rückzahlungsmethode ist für befristete Darlehen obligatorisch,
Repayment Start Date is mandatory for term loans,Das Startdatum der Rückzahlung ist für befristete Darlehen obligatorisch,
Report Item,Artikel melden,
@@ -4043,7 +4028,6 @@
Select All,Alles auswählen,
Select Difference Account,Wählen Sie Differenzkonto,
Select a Default Priority.,Wählen Sie eine Standardpriorität.,
-Select a Supplier from the Default Supplier List of the items below.,Wählen Sie aus der Liste der Standardlieferanten einen Lieferanten aus.,
Select a company,Wählen Sie eine Firma aus,
Select finance book for the item {0} at row {1},Wählen Sie das Finanzbuch für das Element {0} in Zeile {1} aus.,
Select only one Priority as Default.,Wählen Sie nur eine Priorität als Standard aus.,
@@ -4073,7 +4057,7 @@
Show Warehouse-wise Stock,Lagerbestand anzeigen,
Size,Größe,
Something went wrong while evaluating the quiz.,Bei der Auswertung des Quiz ist ein Fehler aufgetreten.,
-Sr,Nr,
+Sr,Pos,
Start,Start,
Start Date cannot be before the current date,Startdatum darf nicht vor dem aktuellen Datum liegen,
Start Time,Startzeit,
@@ -4209,7 +4193,7 @@
Barcode,Barcode,
Bold,Fett gedruckt,
Center,Zentrieren,
-Clear,klar,
+Clear,Löschen,
Comment,Kommentar,
Comments,Kommentare,
DocType,DocType,
@@ -4247,7 +4231,6 @@
Actual ,Tatsächlich,
Add to cart,In den Warenkorb legen,
Budget,Budget,
-Chart Of Accounts Importer,Kontenplan-Importeur,
Chart of Accounts,Kontenplan,
Customer database.,Kundendatenbank.,
Days Since Last order,Tage seit dem letzten Auftrag,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Das Enddatum darf nicht kleiner als das Startdatum sein,
For Default Supplier (Optional),Für Standardlieferanten (optional),
From date cannot be greater than To date,Das Ab-Datum kann nicht größer als das Bis-Datum sein,
-Get items from,Holen Sie Elemente aus,
Group by,Gruppieren nach,
In stock,Auf Lager,
Item name,Artikelname,
@@ -4532,32 +4514,22 @@
Accounts Settings,Konteneinstellungen,
Settings for Accounts,Konteneinstellungen,
Make Accounting Entry For Every Stock Movement,Eine Buchung für jede Lagerbewegung erstellen,
-"If enabled, the system will post accounting entries for inventory automatically.","Wenn aktiviert, bucht das System Bestandsbuchungen automatisch.",
-Accounts Frozen Upto,Konten gesperrt bis,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",Buchung wurde bis zu folgendem Zeitpunkt gesperrt. Bearbeiten oder ändern kann nur die Person in unten stehender Rolle.,
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Rolle darf Konten sperren und gesperrte Buchungen bearbeiten,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Benutzer mit dieser Rolle sind berechtigt Konten zu sperren und Buchungen zu gesperrten Konten zu erstellen/verändern,
Determine Address Tax Category From,Adresssteuerkategorie bestimmen von,
-Address used to determine Tax Category in transactions.,Adresse zur Bestimmung der Steuerkategorie in Transaktionen.,
Over Billing Allowance (%),Mehr als Abrechnungsbetrag (%),
-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 for $110.,"Prozentsatz, zu dem Sie mehr als den bestellten Betrag in Rechnung stellen dürfen. Beispiel: Wenn der Bestellwert für einen Artikel 100 US-Dollar beträgt und die Toleranz auf 10% festgelegt ist, können Sie 110 US-Dollar in Rechnung stellen.",
Credit Controller,Kredit-Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,"Rolle, welche Transaktionen, die das gesetzte Kreditlimit überschreiten, übertragen darf.",
Check Supplier Invoice Number Uniqueness,"Aktivieren, damit dieselbe Lieferantenrechnungsnummer nur einmal vorkommen kann",
Make Payment via Journal Entry,Zahlung über Journaleintrag,
Unlink Payment on Cancellation of Invoice,Zahlung bei Stornierung der Rechnung aufheben,
-Unlink Advance Payment on Cancelation of Order,Verknüpfung der Vorauszahlung bei Stornierung der Bestellung aufheben,
Book Asset Depreciation Entry Automatically,Vermögensabschreibung automatisch verbuchen,
Automatically Add Taxes and Charges from Item Tax Template,Steuern und Gebühren aus Artikelsteuervorlage automatisch hinzufügen,
Automatically Fetch Payment Terms,Zahlungsbedingungen automatisch abrufen,
-Show Inclusive Tax In Print,Bruttopreise beim Druck anzeigen,
Show Payment Schedule in Print,Zeige Zahlungstermin in Drucken,
Currency Exchange Settings,Einstellungen Währungsumtausch,
Allow Stale Exchange Rates,Alte Wechselkurse zulassen,
Stale Days,Stale Tage,
Report Settings,Berichteinstellungen,
Use Custom Cash Flow Format,Benutzerdefiniertes Cashflow-Format verwenden,
-Only select if you have setup Cash Flow Mapper documents,"Wählen Sie nur aus, wenn Sie Cash Flow Mapper-Dokumente eingerichtet haben",
Allowed To Transact With,Erlaubt Transaktionen mit,
SWIFT number,SWIFT-Nummer,
Branch Code,Bankleitzahl / BIC,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Kundengruppe,
POS Field,POS-Feld,
POS Item Group,POS Artikelgruppe,
-[Select],[Auswählen],
Company Address,Anschrift des Unternehmens,
Update Stock,Lagerbestand aktualisieren,
Ignore Pricing Rule,Preisregel ignorieren,
@@ -5048,7 +5019,7 @@
Additional Discount,Zusätzlicher Rabatt,
Apply Additional Discount On,Zusätzlichen Rabatt gewähren auf,
Additional Discount Amount (Company Currency),Zusätzlicher Rabatt (Unternehmenswährung),
-Additional Discount Percentage,Zusätzlicher Rabattprozentsatz,
+Additional Discount Percentage,Zusätzlicher Rabatt in Prozent,
Additional Discount Amount,Zusätzlicher Rabattbetrag,
Grand Total (Company Currency),Gesamtbetrag (Unternehmenswährung),
Rounding Adjustment (Company Currency),Rundung (Unternehmenswährung),
@@ -5495,8 +5466,6 @@
Supplier Naming By,Bezeichnung des Lieferanten nach,
Default Supplier Group,Standardlieferantengruppe,
Default Buying Price List,Standard-Einkaufspreisliste,
-Maintain same rate throughout purchase cycle,Gleiche Preise während des gesamten Einkaufszyklus beibehalten,
-Allow Item to be added multiple times in a transaction,"Zulassen, dass ein Artikel mehrfach in einer Transaktion hinzugefügt werden kann",
Backflush Raw Materials of Subcontract Based On,Rückmeldung der Rohmaterialien des Untervertrages basierend auf,
Material Transferred for Subcontract,Material für den Untervertrag übertragen,
Over Transfer Allowance (%),Überweisungstoleranz (%),
@@ -5540,7 +5509,6 @@
Current Stock,Aktueller Lagerbestand,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Für einzelne Anbieter,
-Supplier Detail,Lieferant Details,
Link to Material Requests,Link zu Materialanfragen,
Message for Supplier,Nachricht für Lieferanten,
Request for Quotation Item,Angebotsanfrage Artikel,
@@ -6481,7 +6449,6 @@
Appraisal Template,Bewertungsvorlage,
For Employee Name,Für Mitarbeiter-Name,
Goals,Ziele,
-Calculate Total Score,Gesamtwertung berechnen,
Total Score (Out of 5),Gesamtwertung (max 5),
"Any other remarks, noteworthy effort that should go in the records.","Sonstige wichtige Anmerkungen, die in die Datensätze aufgenommen werden sollten.",
Appraisal Goal,Bewertungsziel,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Grund für den Austritt,
Leave Encashed?,Urlaub eingelöst?,
Encashment Date,Inkassodatum,
-Exit Interview Details,Details zum Austrittsgespräch,
-Held On,Festgehalten am,
-Reason for Resignation,Kündigungsgrund,
-Better Prospects,Bessere Vorhersage,
-Health Concerns,Gesundheitsfragen,
New Workplace,Neuer Arbeitsplatz,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Rückgabebetrag,
@@ -6740,10 +6702,7 @@
Employee Settings,Mitarbeitereinstellungen,
Retirement Age,Rentenalter,
Enter retirement age in years,Geben Sie das Rentenalter in Jahren,
-Employee Records to be created by,Mitarbeiter-Datensätze werden erstellt nach,
-Employee record is created using selected field. ,Mitarbeiter-Datensatz wird erstellt anhand des ausgewählten Feldes.,
Stop Birthday Reminders,Geburtstagserinnerungen ausschalten,
-Don't send Employee Birthday Reminders,Keine Mitarbeitergeburtstagserinnerungen senden,
Expense Approver Mandatory In Expense Claim,Auslagengenehmiger in Spesenabrechnung erforderlich,
Payroll Settings,Einstellungen zur Gehaltsabrechnung,
Leave,Verlassen,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Berechtigungsauslöser in Abwesenheitsanwendung auslassen,
Show Leaves Of All Department Members In Calendar,Abwesenheiten aller Abteilungsmitglieder im Kalender anzeigen,
Auto Leave Encashment,Automatisches Verlassen der Einlösung,
-Restrict Backdated Leave Application,Zurückdatierten Urlaubsantrag einschränken,
Hiring Settings,Einstellungen vornehmen,
Check Vacancies On Job Offer Creation,Stellenangebote bei der Erstellung von Stellenangeboten prüfen,
Identification Document Type,Ausweistyp,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Fertigungseinstellungen,
Raw Materials Consumption,Rohstoffverbrauch,
Allow Multiple Material Consumption,Mehrfachen Materialverbrauch zulassen,
-Allow multiple Material Consumption against a Work Order,Mehrfache Materialverbrauch für einen Arbeitsauftrag zulassen,
Backflush Raw Materials Based On,Rückmeldung Rohmaterialien auf Basis von,
Material Transferred for Manufacture,Material zur Herstellung übertragen,
Capacity Planning,Kapazitätsplanung,
Disable Capacity Planning,Kapazitätsplanung deaktivieren,
Allow Overtime,Überstunden zulassen,
-Plan time logs outside Workstation Working Hours.,Zeiten außerhalb der normalen Arbeitszeiten am Arbeitsplatz zulassen.,
Allow Production on Holidays,Fertigung im Urlaub zulassen,
Capacity Planning For (Days),Kapazitätsplanung für (Tage),
-Try planning operations for X days in advance.,Arbeitsgänge für X Tage im Voraus planen.,
-Time Between Operations (in mins),Zeit zwischen den Arbeitsgängen (in Minuten),
-Default 10 mins,Standard 10 Minuten,
Default Warehouses for Production,Standardlager für die Produktion,
Default Work In Progress Warehouse,Standard-Fertigungslager,
Default Finished Goods Warehouse,Standard-Fertigwarenlager,
Default Scrap Warehouse,Standard-Schrottlager,
-Over Production for Sales and Work Order,Überproduktion für Verkauf und Fertigungsauftrag,
Overproduction Percentage For Sales Order,Überproduktionsprozentsatz für Kundenauftrag,
Overproduction Percentage For Work Order,Überproduktionsprozentsatz für Arbeitsauftrag,
Other Settings,Weitere Einstellungen,
Update BOM Cost Automatically,Stücklisten-Kosten automatisch aktualisieren,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Automatische Aktualisierung der Stücklistenkosten über den Scheduler, basierend auf dem aktuellen Bewertungskurs / Preislistenkurs / letzten Einkaufskurs der Rohstoffe.",
Material Request Plan Item,Materialanforderung Planelement,
Material Request Type,Materialanfragetyp,
Material Issue,Materialentnahme,
@@ -7603,10 +7554,6 @@
Quality Goal,Qualitätsziel,
Monitoring Frequency,Überwachungsfrequenz,
Weekday,Wochentag,
-January-April-July-October,Januar-April-Juli-Oktober,
-Revision and Revised On,Revision und Überarbeitet am,
-Revision,Revision,
-Revised On,Überarbeitet am,
Objectives,Ziele,
Quality Goal Objective,Qualitätsziel Ziel,
Objective,Zielsetzung,
@@ -7619,7 +7566,6 @@
Processes,Prozesse,
Quality Procedure Process,Qualitätsprozess,
Process Description,Prozessbeschreibung,
-Child Procedure,Untergeordnete Prozedur,
Link existing Quality Procedure.,Bestehendes Qualitätsverfahren verknüpfen.,
Additional Information,zusätzliche Information,
Quality Review Objective,Qualitätsüberprüfungsziel,
@@ -7787,15 +7733,9 @@
Default Customer Group,Standardkundengruppe,
Default Territory,Standardregion,
Close Opportunity After Days,Chance schließen nach (in Tagen),
-Auto close Opportunity after 15 days,Chance nach 15 Tagen automatisch schließen,
Default Quotation Validity Days,Standard-Angebotsgültigkeitstage,
Sales Update Frequency,Umsatzaktualisierungsfrequenz,
-How often should project and company be updated based on Sales Transactions.,Wie oft sollten Projekt und Unternehmen basierend auf Verkaufstransaktionen aktualisiert werden?,
Each Transaction,Jede Transaktion,
-Allow user to edit Price List Rate in transactions,"Benutzer erlauben, die Preisliste in Transaktionen zu bearbeiten",
-Allow multiple Sales Orders against a Customer's Purchase Order,Zusammenfassen mehrerer Kundenaufträge zu einer Kundenbestellung erlauben,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Bestätigen Sie den Verkaufspreis für den Posten gegen den Einkaufspreis oder Bewertungskurs,
-Hide Customer's Tax Id from Sales Transactions,Ausblenden Kundensteuernummer aus Verkaufstransaktionen,
SMS Center,SMS-Center,
Send To,Senden an,
All Contact,Alle Kontakte,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Hersteller im Artikel verwendet,
Limited to 12 characters,Limitiert auf 12 Zeichen,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Lager einstellen,
-Sets 'For Warehouse' in each row of the Items table.,Legt 'Für Lager' in jeder Zeile der Artikeltabelle fest.,
-Requested For,Angefordert für,
Partially Ordered,Teilweise bestellt,
Transferred,Übergeben,
% Ordered,% bestellt,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Standardlagermaßeinheit,
Sample Retention Warehouse,Beispiel Retention Warehouse,
Default Valuation Method,Standard-Bewertungsmethode,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Zur bestellten Menge zusätzlich zulässiger Prozentsatz, der angenommen oder geliefert werden kann. Beispiel: Wenn 100 Einheiten bestellt wurden, und die erlaubte Spanne 10 % beträgt, dann können 110 Einheiten angenommen werden.",
-Action if Quality inspection is not submitted,"Maßnahme, wenn keine Qualitätsprüfung vorliegt",
Show Barcode Field,Anzeigen Barcode-Feld,
Convert Item Description to Clean HTML,Elementbeschreibung in HTML bereinigen,
-Auto insert Price List rate if missing,"Preisliste automatisch einfügen, wenn sie fehlt",
Allow Negative Stock,Negativen Lagerbestand zulassen,
Automatically Set Serial Nos based on FIFO,Automatisch Seriennummern auf Basis FIFO einstellen,
-Set Qty in Transactions based on Serial No Input,Legen Sie Menge in Transaktionen basierend auf Serial No Input fest,
Auto Material Request,Automatische Materialanfrage,
-Raise Material Request when stock reaches re-order level,"Materialanfrage erstellen, wenn der Lagerbestand unter einen Wert sinkt",
-Notify by Email on creation of automatic Material Request,Bei Erstellung einer automatischen Materialanfrage per E-Mail benachrichtigen,
Inter Warehouse Transfer Settings,Inter Warehouse Transfer-Einstellungen,
-Allow Material Transfer From Delivery Note and Sales Invoice,Materialübertragung von Lieferschein und Verkaufsrechnung zulassen,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Materialübertragung vom Kaufbeleg und der Kaufrechnung zulassen,
Freeze Stock Entries,Lagerbuchungen sperren,
Stock Frozen Upto,Bestand gesperrt bis,
-Freeze Stocks Older Than [Days],Bestände älter als [Tage] sperren,
-Role Allowed to edit frozen stock,Rolle darf gesperrten Bestand bearbeiten,
Batch Identification,Chargenidentifikation,
Use Naming Series,Nummernkreis verwenden,
Naming Series Prefix,Präfix Nummernkreis,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Trendanalyse Kaufbelege,
Purchase Register,Übersicht über Einkäufe,
Quotation Trends,Trendanalyse Angebote,
-Quoted Item Comparison,Vergleich angebotener Artikel,
Received Items To Be Billed,"Von Lieferanten gelieferte Artikel, die noch abgerechnet werden müssen",
Qty to Order,Zu bestellende Menge,
Requested Items To Be Transferred,"Angeforderte Artikel, die übertragen werden sollen",
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Wählen Sie Lager für Materialanfragen,
Transfer Materials For Warehouse {0},Material für Lager übertragen {0},
Production Plan Material Request Warehouse,Produktionsplan Materialanforderungslager,
-Set From Warehouse,Aus dem Lager einstellen,
-Source Warehouse (Material Transfer),Quelllager (Materialtransfer),
Sets 'Source Warehouse' in each row of the items table.,Legt 'Source Warehouse' in jeder Zeile der Artikeltabelle fest.,
Sets 'Target Warehouse' in each row of the items table.,"Füllt das Feld ""Ziel Lager"" in allen Positionen der folgenden Tabelle.",
Show Cancelled Entries,Abgebrochene Einträge anzeigen,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Service erhalten, aber nicht in Rechnung gestellt",
Deferred Accounting Settings,Aufgeschobene Buchhaltungseinstellungen,
Book Deferred Entries Based On,Buch verzögerte Einträge basierend auf,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Wenn "Monate" ausgewählt ist, wird der feste Betrag unabhängig von der Anzahl der Tage in einem Monat als abgegrenzte Einnahmen oder Ausgaben für jeden Monat gebucht. Wird anteilig berechnet, wenn abgegrenzte Einnahmen oder Ausgaben nicht für einen ganzen Monat gebucht werden.",
Days,Tage,
Months,Monate,
Book Deferred Entries Via Journal Entry,Buch verzögerte Einträge über Journaleintrag,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Wenn diese Option nicht aktiviert ist, werden direkte FIBU-Einträge erstellt, um die abgegrenzten Einnahmen / Ausgaben zu buchen",
Submit Journal Entries,Journaleinträge senden,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Wenn dieses Kontrollkästchen deaktiviert ist, werden Journaleinträge in einem Entwurfsstatus gespeichert und müssen manuell übermittelt werden",
Enable Distributed Cost Center,Aktivieren Sie die verteilte Kostenstelle,
@@ -8901,8 +8823,6 @@
Is Inter State,Ist zwischenstaatlich,
Purchase Details,Einzelheiten zum Kauf,
Depreciation Posting Date,Buchungsdatum der Abschreibung,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Bestellung für die Erstellung der Kaufrechnung und des Belegs erforderlich,
-Purchase Receipt Required for Purchase Invoice Creation,Kaufbeleg für die Erstellung der Kaufrechnung erforderlich,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Standardmäßig wird der Lieferantenname gemäß dem eingegebenen Lieferantennamen festgelegt. Wenn Sie möchten, dass Lieferanten von a benannt werden",
choose the 'Naming Series' option.,Wählen Sie die Option "Naming Series".,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Konfigurieren Sie die Standardpreisliste beim Erstellen einer neuen Kauftransaktion. Artikelpreise werden aus dieser Preisliste abgerufen.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Ist Einkommensteuerkomponente,
Component properties and references ,Komponenteneigenschaften und Referenzen,
Additional Salary ,Zusätzliches Gehalt,
-Condtion and formula,Zustand und Formel,
Unmarked days,Nicht markierte Tage,
Absent Days,Abwesende Tage,
Conditions and Formula variable and example,Bedingungen und Formelvariable und Beispiel,
Feedback By,Feedback von,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Fertigungsabteilung,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Kundenauftrag für die Erstellung von Kundenrechnungen und Lieferscheinen erforderlich,
-Delivery Note Required for Sales Invoice Creation,Lieferschein für die Erstellung der Verkaufsrechnung erforderlich,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Standardmäßig wird der Kundenname gemäß dem eingegebenen vollständigen Namen festgelegt. Wenn Sie möchten, dass Kunden von a benannt werden",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Konfigurieren Sie die Standardpreisliste beim Erstellen einer neuen Verkaufstransaktion. Artikelpreise werden aus dieser Preisliste abgerufen.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Wenn diese Option auf "Ja" konfiguriert ist, verhindert ERPNext, dass Sie eine Verkaufsrechnung oder einen Lieferschein erstellen, ohne zuvor einen Kundenauftrag zu erstellen. Diese Konfiguration kann für einen bestimmten Kunden überschrieben werden, indem das Kontrollkästchen "Erstellung von Verkaufsrechnungen ohne Kundenauftrag zulassen" im Kundenstamm aktiviert wird.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} wurde allen ausgewählten Themen erfolgreich hinzugefügt.,
Topics updated,Themen aktualisiert,
Academic Term and Program,Akademisches Semester und Programm,
-Last Stock Transaction for item {0} was on {1}.,Die letzte Lagertransaktion für Artikel {0} war am {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Lagertransaktionen für Artikel {0} können nicht vor diesem Zeitpunkt gebucht werden.,
Please remove this item and try to submit again or update the posting time.,"Bitte entfernen Sie diesen Artikel und versuchen Sie erneut, ihn zu senden oder die Buchungszeit zu aktualisieren.",
Failed to Authenticate the API key.,Fehler beim Authentifizieren des API-Schlüssels.,
Invalid Credentials,Ungültige Anmeldeinformationen,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Bitte überprüfen Sie Ihre Plaid-Client-ID und Ihre geheimen Werte,
Bank transaction creation error,Fehler beim Erstellen der Banküberweisung,
Unit of Measurement,Maßeinheit,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Zeile # {}: Die Verkaufsrate für Artikel {} ist niedriger als die {}. Die Verkaufsrate sollte mindestens {} betragen,
Fiscal Year {0} Does Not Exist,Geschäftsjahr {0} existiert nicht,
Row # {0}: Returned Item {1} does not exist in {2} {3},Zeile # {0}: Zurückgegebenes Element {1} ist in {2} {3} nicht vorhanden,
Valuation type charges can not be marked as Inclusive,Bewertungsgebühren können nicht als Inklusiv gekennzeichnet werden,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Die Antwortzeit für die Priorität {0} in Zeile {1} darf nicht größer als die Auflösungszeit sein.,
{0} is not enabled in {1},{0} ist in {1} nicht aktiviert,
Group by Material Request,Nach Materialanforderung gruppieren,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Zeile {0}: Für Lieferant {0} ist zum Senden von E-Mails eine E-Mail-Adresse erforderlich,
Email Sent to Supplier {0},E-Mail an Lieferanten gesendet {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Der Zugriff auf die Angebotsanfrage vom Portal ist deaktiviert. Um den Zugriff zuzulassen, aktivieren Sie ihn in den Portaleinstellungen.",
Supplier Quotation {0} Created,Lieferantenangebot {0} Erstellt,
Valid till Date cannot be before Transaction Date,Gültig bis Datum kann nicht vor dem Transaktionsdatum liegen,
+Unlink Advance Payment on Cancellation of Order,Deaktivieren Sie die Vorauszahlung bei Stornierung der Bestellung,
+"Simple Python Expression, Example: territory != 'All Territories'","Einfacher Python-Ausdruck, Beispiel: Territorium! = 'Alle Territorien'",
+Sales Contributions and Incentives,Verkaufsbeiträge und Anreize,
+Sourced by Supplier,Vom Lieferanten bezogen,
+Total weightage assigned should be 100%.<br>It is {0},Das zugewiesene Gesamtgewicht sollte 100% betragen.<br> Es ist {0},
+Account {0} exists in parent company {1}.,Konto {0} existiert in der Muttergesellschaft {1}.,
+"To overrule this, enable '{0}' in company {1}","Um dies zu überschreiben, aktivieren Sie '{0}' in Firma {1}",
+Invalid condition expression,Ungültiger Bedingungsausdruck,
+Please Select a Company First,Bitte wählen Sie zuerst eine Firma aus,
+Please Select Both Company and Party Type First,Bitte wählen Sie zuerst Firmen- und Partytyp aus,
+Provide the invoice portion in percent,Geben Sie den Rechnungsanteil in Prozent an,
+Give number of days according to prior selection,Geben Sie die Anzahl der Tage gemäß vorheriger Auswahl an,
+Email Details,E-Mail-Details,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Wählen Sie eine Begrüßung für den Empfänger. ZB Herr, Frau usw.",
+Preview Email,Vorschau E-Mail,
+Please select a Supplier,Bitte wählen Sie einen Lieferanten aus,
+Supplier Lead Time (days),Vorlaufzeit des Lieferanten (Tage),
+"Home, Work, etc.","Zuhause, Arbeit usw.",
+Exit Interview Held On,Beenden Sie das Interview,
+Condition and formula,Zustand und Formel,
+Sets 'Target Warehouse' in each row of the Items table.,Legt 'Ziellager' in jeder Zeile der Elementtabelle fest.,
+Sets 'Source Warehouse' in each row of the Items table.,Legt 'Source Warehouse' in jeder Zeile der Items-Tabelle fest.,
+POS Register,POS-Register,
+"Can not filter based on POS Profile, if grouped by POS Profile","Kann nicht basierend auf dem POS-Profil filtern, wenn nach POS-Profil gruppiert",
+"Can not filter based on Customer, if grouped by Customer","Kann nicht nach Kunden filtern, wenn nach Kunden gruppiert",
+"Can not filter based on Cashier, if grouped by Cashier","Kann nicht nach Kassierer filtern, wenn nach Kassierer gruppiert",
+Payment Method,Zahlungsmethode,
+"Can not filter based on Payment Method, if grouped by Payment Method","Kann nicht nach Zahlungsmethode filtern, wenn nach Zahlungsmethode gruppiert",
+Supplier Quotation Comparison,Vergleich der Lieferantenangebote,
+Price per Unit (Stock UOM),Preis pro Einheit (Lager UOM),
+Group by Supplier,Nach Lieferanten gruppieren,
+Group by Item,Nach Artikel gruppieren,
+Remember to set {field_label}. It is required by {regulation}.,"Denken Sie daran, {field_label} zu setzen. Es wird von {Regulation} verlangt.",
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Das Einschreibedatum darf nicht vor dem Startdatum des akademischen Jahres liegen {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Das Einschreibungsdatum darf nicht nach dem Enddatum des akademischen Semesters liegen {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Das Einschreibungsdatum darf nicht vor dem Startdatum des akademischen Semesters liegen {0},
+Future Posting Not Allowed,Zukünftiges Posten nicht erlaubt,
+"To enable Capital Work in Progress Accounting, ",So aktivieren Sie die Kapitalabrechnung,
+you must select Capital Work in Progress Account in accounts table,Sie müssen in der Kontentabelle das Konto "Kapital in Bearbeitung" auswählen,
+You can also set default CWIP account in Company {},Sie können auch das Standard-CWIP-Konto in Firma {} festlegen,
+The Request for Quotation can be accessed by clicking on the following button,"Sie können auf die Angebotsanfrage zugreifen, indem Sie auf die folgende Schaltfläche klicken",
+Regards,Grüße,
+Please click on the following button to set your new password,"Bitte klicken Sie auf die folgende Schaltfläche, um Ihr neues Passwort festzulegen",
+Update Password,Passwort erneuern,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Zeile # {}: Die Verkaufsrate für Artikel {} ist niedriger als die {}. Der Verkauf von {} sollte mindestens {} sein,
+You can alternatively disable selling price validation in {} to bypass this validation.,"Alternativ können Sie die Validierung des Verkaufspreises in {} deaktivieren, um diese Validierung zu umgehen.",
+Invalid Selling Price,Ungültiger Verkaufspreis,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Die Adresse muss mit einem Unternehmen verknüpft sein. Bitte fügen Sie eine Zeile für Firma in die Tabelle Links ein.,
+Company Not Linked,Firma nicht verbunden,
+Import Chart of Accounts from CSV / Excel files,Kontenplan aus CSV / Excel-Dateien importieren,
+Completed Qty cannot be greater than 'Qty to Manufacture',Die abgeschlossene Menge darf nicht größer sein als die Menge bis zur Herstellung.,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Zeile {0}: Für Lieferant {1} ist eine E-Mail-Adresse erforderlich, um eine E-Mail zu senden",
+"If enabled, the system will post accounting entries for inventory automatically","Wenn aktiviert, bucht das System automatisch Buchhaltungseinträge für das Inventar",
+Accounts Frozen Till Date,Konten bis zum Datum eingefroren,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Buchhaltungseinträge werden bis zu diesem Datum eingefroren. Niemand außer Benutzern mit der unten angegebenen Rolle kann Einträge erstellen oder ändern,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,"Rolle erlaubt, eingefrorene Konten festzulegen und eingefrorene Einträge zu bearbeiten",
+Address used to determine Tax Category in transactions,Adresse zur Bestimmung der Steuerkategorie in Transaktionen,
+"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 ","Der Prozentsatz, den Sie mehr gegen den bestellten Betrag abrechnen dürfen. Wenn der Bestellwert für einen Artikel beispielsweise 100 US-Dollar beträgt und die Toleranz auf 10% festgelegt ist, können Sie bis zu 110 US-Dollar in Rechnung stellen",
+This role is allowed to submit transactions that exceed credit limits,"Diese Rolle darf Transaktionen einreichen, die Kreditlimits überschreiten",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Wenn "Monate" ausgewählt ist, wird ein fester Betrag als abgegrenzte Einnahmen oder Ausgaben für jeden Monat gebucht, unabhängig von der Anzahl der Tage in einem Monat. Es wird anteilig berechnet, wenn abgegrenzte Einnahmen oder Ausgaben nicht für einen ganzen Monat gebucht werden",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Wenn diese Option nicht aktiviert ist, werden direkte FIBU-Einträge erstellt, um abgegrenzte Einnahmen oder Ausgaben zu buchen",
+Show Inclusive Tax in Print,Inklusive Steuern im Druck anzeigen,
+Only select this if you have set up the Cash Flow Mapper documents,"Wählen Sie diese Option nur, wenn Sie die Cash Flow Mapper-Dokumente eingerichtet haben",
+Payment Channel,Zahlungskanal,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Ist für die Erstellung von Kaufrechnungen und Quittungen eine Bestellung erforderlich?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Ist für die Erstellung der Kaufrechnung ein Kaufbeleg erforderlich?,
+Maintain Same Rate Throughout the Purchase Cycle,Behalten Sie den gleichen Preis während des gesamten Kaufzyklus bei,
+Allow Item To Be Added Multiple Times in a Transaction,"Zulassen, dass ein Element in einer Transaktion mehrmals hinzugefügt wird",
+Suppliers,Lieferanten,
+Send Emails to Suppliers,Senden Sie E-Mails an Lieferanten,
+Select a Supplier,Wählen Sie einen Lieferanten aus,
+Cannot mark attendance for future dates.,Die Teilnahme an zukünftigen Daten kann nicht markiert werden.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Möchten Sie die Teilnahme aktualisieren?<br> Anwesend: {0}<br> Abwesend: {1},
+Mpesa Settings,Mpesa-Einstellungen,
+Initiator Name,Initiatorname,
+Till Number,Bis Nummer,
+Sandbox,Sandkasten,
+ Online PassKey,Online PassKey,
+Security Credential,Sicherheitsnachweis,
+Get Account Balance,Kontostand abrufen,
+Please set the initiator name and the security credential,Bitte legen Sie den Initiatornamen und den Sicherheitsnachweis fest,
+Inpatient Medication Entry,Eintritt in stationäre Medikamente,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Artikelcode (Medikament),
+Medication Orders,Medikamentenbestellungen,
+Get Pending Medication Orders,Erhalten Sie ausstehende Medikamentenbestellungen,
+Inpatient Medication Orders,Bestellungen für stationäre Medikamente,
+Medication Warehouse,Medikamentenlager,
+Warehouse from where medication stock should be consumed,"Lager, von dem aus der Medikamentenbestand konsumiert werden soll",
+Fetching Pending Medication Orders,Ausstehende ausstehende Medikamentenbestellungen abrufen,
+Inpatient Medication Entry Detail,Eintragsdetail für stationäre Medikamente,
+Medication Details,Medikamentendetails,
+Drug Code,Drogencode,
+Drug Name,Medikamentenname,
+Against Inpatient Medication Order,Gegen die Bestellung von stationären Medikamenten,
+Against Inpatient Medication Order Entry,Gegen stationäre Medikamentenbestellung,
+Inpatient Medication Order,Bestellung von stationären Medikamenten,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Bestellungen insgesamt,
+Completed Orders,Abgeschlossene Bestellungen,
+Add Medication Orders,Medikamentenbestellungen hinzufügen,
+Adding Order Entries,Auftragseingaben hinzufügen,
+{0} medication orders completed,{0} Medikamentenbestellungen abgeschlossen,
+{0} medication order completed,{0} Medikamentenbestellung abgeschlossen,
+Inpatient Medication Order Entry,Auftragserfassung für stationäre Medikamente,
+Is Order Completed,Ist die Bestellung abgeschlossen?,
+Employee Records to Be Created By,"Mitarbeiterdatensätze, die erstellt werden sollen von",
+Employee records are created using the selected field,Mitarbeiterdatensätze werden mit dem ausgewählten Feld erstellt,
+Don't send employee birthday reminders,Senden Sie keine Geburtstagserinnerungen an Mitarbeiter,
+Restrict Backdated Leave Applications,Zurückdatierte Urlaubsanträge einschränken,
+Sequence ID,Sequenz-ID,
+Sequence Id,Sequenz-ID,
+Allow multiple material consumptions against a Work Order,Ermöglichen Sie mehrere Materialverbräuche für einen Arbeitsauftrag,
+Plan time logs outside Workstation working hours,Planen Sie Zeitprotokolle außerhalb der Arbeitszeit der Workstation,
+Plan operations X days in advance,Planen Sie den Betrieb X Tage im Voraus,
+Time Between Operations (Mins),Zeit zwischen Operationen (Minuten),
+Default: 10 mins,Standard: 10 Minuten,
+Overproduction for Sales and Work Order,Überproduktion für Kunden- und Arbeitsauftrag,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Aktualisieren Sie die Stücklistenkosten automatisch über den Planer, basierend auf der neuesten Bewertungsrate / Preislistenrate / letzten Kaufrate der Rohstoffe",
+Purchase Order already created for all Sales Order items,Bestellung bereits für alle Kundenauftragspositionen angelegt,
+Select Items,Gegenstände auswählen,
+Against Default Supplier,Gegen Standardlieferanten,
+Auto close Opportunity after the no. of days mentioned above,Gelegenheit zum automatischen Schließen nach der Nr. der oben genannten Tage,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Ist ein Kundenauftrag für die Erstellung von Kundenrechnungen und Lieferscheinen erforderlich?,
+Is Delivery Note Required for Sales Invoice Creation?,Ist für die Erstellung der Verkaufsrechnung ein Lieferschein erforderlich?,
+How often should Project and Company be updated based on Sales Transactions?,Wie oft sollten Projekt und Unternehmen basierend auf Verkaufstransaktionen aktualisiert werden?,
+Allow User to Edit Price List Rate in Transactions,Benutzer darf Preisliste in Transaktionen bearbeiten,
+Allow Item to Be Added Multiple Times in a Transaction,"Zulassen, dass ein Element in einer Transaktion mehrmals hinzugefügt wird",
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Erlauben Sie mehrere Kundenaufträge für die Bestellung eines Kunden,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Überprüfen Sie den Verkaufspreis für den Artikel anhand der Kauf- oder Bewertungsrate,
+Hide Customer's Tax ID from Sales Transactions,Steuer-ID des Kunden vor Verkaufstransaktionen ausblenden,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Der Prozentsatz, den Sie mehr gegen die bestellte Menge erhalten oder liefern dürfen. Wenn Sie beispielsweise 100 Einheiten bestellt haben und Ihre Zulage 10% beträgt, können Sie 110 Einheiten erhalten.",
+Action If Quality Inspection Is Not Submitted,Maßnahme Wenn keine Qualitätsprüfung eingereicht wird,
+Auto Insert Price List Rate If Missing,"Preisliste automatisch einfügen, falls fehlt",
+Automatically Set Serial Nos Based on FIFO,Seriennummern basierend auf FIFO automatisch einstellen,
+Set Qty in Transactions Based on Serial No Input,Stellen Sie die Menge in Transaktionen basierend auf Seriennummer ohne Eingabe ein,
+Raise Material Request When Stock Reaches Re-order Level,"Erhöhen Sie die Materialanforderung, wenn der Lagerbestand die Nachbestellmenge erreicht",
+Notify by Email on Creation of Automatic Material Request,Benachrichtigen Sie per E-Mail über die Erstellung einer automatischen Materialanforderung,
+Allow Material Transfer from Delivery Note to Sales Invoice,Materialübertragung vom Lieferschein zur Verkaufsrechnung zulassen,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Materialübertragung vom Kaufbeleg zur Kaufrechnung zulassen,
+Freeze Stocks Older Than (Days),Aktien einfrieren älter als (Tage),
+Role Allowed to Edit Frozen Stock,Rolle darf eingefrorenes Material bearbeiten,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Der nicht zugewiesene Betrag der Zahlungseingabe {0} ist größer als der nicht zugewiesene Betrag der Banküberweisung,
+Payment Received,Zahlung erhalten,
+Attendance cannot be marked outside of Academic Year {0},Die Teilnahme kann nicht außerhalb des akademischen Jahres {0} markiert werden.,
+Student is already enrolled via Course Enrollment {0},Der Student ist bereits über die Kursanmeldung {0} eingeschrieben.,
+Attendance cannot be marked for future dates.,Die Teilnahme kann für zukünftige Termine nicht markiert werden.,
+Please add programs to enable admission application.,"Bitte fügen Sie Programme hinzu, um den Zulassungsantrag zu aktivieren.",
+The following employees are currently still reporting to {0}:,Die folgenden Mitarbeiter berichten derzeit noch an {0}:,
+Please make sure the employees above report to another Active employee.,"Bitte stellen Sie sicher, dass die oben genannten Mitarbeiter einem anderen aktiven Mitarbeiter Bericht erstatten.",
+Cannot Relieve Employee,Mitarbeiter kann nicht entlastet werden,
+Please enter {0},Bitte geben Sie {0} ein,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Bitte wählen Sie eine andere Zahlungsmethode. Mpesa unterstützt keine Transaktionen in der Währung '{0}'.,
+Transaction Error,Transaktionsfehler,
+Mpesa Express Transaction Error,Mpesa Express-Transaktionsfehler,
+"Issue detected with Mpesa configuration, check the error logs for more details",Bei der Mpesa-Konfiguration festgestelltes Problem. Überprüfen Sie die Fehlerprotokolle auf weitere Details,
+Mpesa Express Error,Mpesa Express-Fehler,
+Account Balance Processing Error,Fehler bei der Verarbeitung des Kontostands,
+Please check your configuration and try again,Bitte überprüfen Sie Ihre Konfiguration und versuchen Sie es erneut,
+Mpesa Account Balance Processing Error,Mpesa-Kontostand-Verarbeitungsfehler,
+Balance Details,Kontostanddetails,
+Current Balance,Aktueller Saldo,
+Available Balance,Verfügbares Guthaben,
+Reserved Balance,Reservierter Saldo,
+Uncleared Balance,Ungeklärtes Gleichgewicht,
+Payment related to {0} is not completed,Die Zahlung für {0} ist nicht abgeschlossen,
+Row #{}: Item Code: {} is not available under warehouse {}.,Zeile # {}: Artikelcode: {} ist unter Lager {} nicht verfügbar.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Zeile # {}: Lagermenge reicht nicht für Artikelcode: {} unter Lager {}. Verfügbare Anzahl {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,"Zeile # {}: Bitte wählen Sie eine Seriennummer und stapeln Sie sie gegen Artikel: {} oder entfernen Sie sie, um die Transaktion abzuschließen.",
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"Zeile # {}: Keine Seriennummer für Element ausgewählt: {}. Bitte wählen Sie eine aus oder entfernen Sie sie, um die Transaktion abzuschließen.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,"Zeile # {}: Kein Stapel für Element ausgewählt: {}. Bitte wählen Sie einen Stapel aus oder entfernen Sie ihn, um die Transaktion abzuschließen.",
+Payment amount cannot be less than or equal to 0,Der Zahlungsbetrag darf nicht kleiner oder gleich 0 sein,
+Please enter the phone number first,Bitte geben Sie zuerst die Telefonnummer ein,
+Row #{}: {} {} does not exist.,Zeile # {}: {} {} existiert nicht.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,"Zeile # {0}: {1} ist erforderlich, um die Eröffnungsrechnungen {2} zu erstellen",
+You had {} errors while creating opening invoices. Check {} for more details,Beim Erstellen von Eröffnungsrechnungen sind {} Fehler aufgetreten. Überprüfen Sie {} auf weitere Details,
+Error Occured,Fehler aufgetreten,
+Opening Invoice Creation In Progress,Öffnen der Rechnungserstellung läuft,
+Creating {} out of {} {},{} Aus {} {} erstellen,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Seriennummer: {0}) kann nicht verwendet werden, da es zum Ausfüllen des Kundenauftrags {1} reserviert ist.",
+Item {0} {1},Gegenstand {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Die letzte Lagertransaktion für Artikel {0} unter Lager {1} war am {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Lagertransaktionen für Artikel {0} unter Lager {1} können nicht vor diesem Zeitpunkt gebucht werden.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Das Buchen zukünftiger Lagertransaktionen ist aufgrund des unveränderlichen Hauptbuchs nicht zulässig,
+A BOM with name {0} already exists for item {1}.,Für Artikel {1} ist bereits eine Stückliste mit dem Namen {0} vorhanden.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Haben Sie den Artikel umbenannt? Bitte wenden Sie sich an den Administrator / technischen Support,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},In Zeile # {0}: Die Sequenz-ID {1} darf nicht kleiner sein als die vorherige Zeilen-Sequenz-ID {2}.,
+The {0} ({1}) must be equal to {2} ({3}),Die {0} ({1}) muss gleich {2} ({3}) sein.,
+"{0}, complete the operation {1} before the operation {2}.","{0}, schließen Sie die Operation {1} vor der Operation {2} ab.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Die Lieferung per Seriennummer kann nicht sichergestellt werden, da Artikel {0} mit und ohne Lieferung per Seriennummer hinzugefügt wird.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Artikel {0} hat keine Seriennummer. Nur serilialisierte Artikel können basierend auf der Seriennummer geliefert werden,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Für Artikel {0} wurde keine aktive Stückliste gefunden. Die Lieferung per Seriennummer kann nicht gewährleistet werden,
+No pending medication orders found for selected criteria,Für ausgewählte Kriterien wurden keine ausstehenden Medikamentenbestellungen gefunden,
+From Date cannot be after the current date.,Ab Datum kann nicht nach dem aktuellen Datum liegen.,
+To Date cannot be after the current date.,Bis Datum kann nicht nach dem aktuellen Datum liegen.,
+From Time cannot be after the current time.,Von Zeit kann nicht nach der aktuellen Zeit sein.,
+To Time cannot be after the current time.,Zu Zeit kann nicht nach der aktuellen Zeit sein.,
+Stock Entry {0} created and ,Bestandsbuchung {0} erstellt und,
+Inpatient Medication Orders updated successfully,Bestellungen für stationäre Medikamente wurden erfolgreich aktualisiert,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Zeile {0}: Eintrag für stationäre Medikamente kann nicht für stornierte Bestellung für stationäre Medikamente erstellt werden {1},
+Row {0}: This Medication Order is already marked as completed,Zeile {0}: Diese Medikamentenbestellung ist bereits als abgeschlossen markiert,
+Quantity not available for {0} in warehouse {1},Menge für {0} im Lager {1} nicht verfügbar,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"Bitte aktivieren Sie Negative Bestände in Bestandseinstellungen zulassen oder erstellen Sie eine Bestandserfassung, um fortzufahren.",
+No Inpatient Record found against patient {0},Keine stationäre Akte gegen Patient {0} gefunden,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Es besteht bereits eine stationäre Medikamentenanweisung {0} gegen die Patientenbegegnung {1}.,
+Allow In Returns,Rückgabe zulassen,
+Hide Unavailable Items,Nicht verfügbare Elemente ausblenden,
+Apply Discount on Discounted Rate,Wenden Sie einen Rabatt auf den ermäßigten Preis an,
+Therapy Plan Template,Therapieplanvorlage,
+Fetching Template Details,Vorlagendetails abrufen,
+Linked Item Details,Verknüpfte Artikeldetails,
+Therapy Types,Therapietypen,
+Therapy Plan Template Detail,Detail der Therapieplanvorlage,
+Non Conformance,Nichtkonformität,
+Process Owner,Prozessverantwortlicher,
+Corrective Action,Korrekturmaßnahme,
+Preventive Action,Präventivmaßnahmen,
+Problem,Problem,
+Responsible,Verantwortlich,
+Completion By,Fertigstellung durch,
+Process Owner Full Name,Vollständiger Name des Prozessinhabers,
+Right Index,Richtiger Index,
+Left Index,Linker Index,
+Sub Procedure,Unterprozedur,
+Passed,Bestanden,
+Print Receipt,Druckeingang,
+Edit Receipt,Beleg bearbeiten,
+Focus on search input,Konzentrieren Sie sich auf die Sucheingabe,
+Focus on Item Group filter,Fokus auf Artikelgruppenfilter,
+Checkout Order / Submit Order / New Order,Kaufabwicklung / Bestellung abschicken / Neue Bestellung,
+Add Order Discount,Bestellrabatt hinzufügen,
+Item Code: {0} is not available under warehouse {1}.,Artikelcode: {0} ist unter Lager {1} nicht verfügbar.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Seriennummern für Artikel {0} unter Lager {1} nicht verfügbar. Bitte versuchen Sie das Lager zu wechseln.,
+Fetched only {0} available serial numbers.,Es wurden nur {0} verfügbare Seriennummern abgerufen.,
+Switch Between Payment Modes,Zwischen Zahlungsmodi wechseln,
+Enter {0} amount.,Geben Sie den Betrag {0} ein.,
+You don't have enough points to redeem.,Sie haben nicht genug Punkte zum Einlösen.,
+You can redeem upto {0}.,Sie können bis zu {0} einlösen.,
+Enter amount to be redeemed.,Geben Sie den einzulösenden Betrag ein.,
+You cannot redeem more than {0}.,Sie können nicht mehr als {0} einlösen.,
+Open Form View,Öffnen Sie die Formularansicht,
+POS invoice {0} created succesfully,POS-Rechnung {0} erfolgreich erstellt,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Lagermenge nicht ausreichend für Artikelcode: {0} unter Lager {1}. Verfügbare Menge {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Seriennummer: {0} wurde bereits in eine andere POS-Rechnung übertragen.,
+Balance Serial No,Balance Seriennr,
+Warehouse: {0} does not belong to {1},Lager: {0} gehört nicht zu {1},
+Please select batches for batched item {0},Bitte wählen Sie Chargen für Chargenartikel {0} aus,
+Please select quantity on row {0},Bitte wählen Sie die Menge in Zeile {0},
+Please enter serial numbers for serialized item {0},Bitte geben Sie die Seriennummern für den serialisierten Artikel {0} ein.,
+Batch {0} already selected.,Stapel {0} bereits ausgewählt.,
+Please select a warehouse to get available quantities,"Bitte wählen Sie ein Lager aus, um verfügbare Mengen zu erhalten",
+"For transfer from source, selected quantity cannot be greater than available quantity",Bei der Übertragung von der Quelle darf die ausgewählte Menge nicht größer als die verfügbare Menge sein,
+Cannot find Item with this Barcode,Artikel mit diesem Barcode kann nicht gefunden werden,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} ist obligatorisch. Möglicherweise wird kein Währungsumtauschdatensatz für {1} bis {2} erstellt.,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} hat damit verknüpfte Assets eingereicht. Sie müssen die Assets stornieren, um eine Kaufrendite zu erstellen.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Dieses Dokument kann nicht storniert werden, da es mit dem übermittelten Asset {0} verknüpft ist. Bitte stornieren Sie es, um fortzufahren.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Zeile # {}: Seriennummer {} wurde bereits in eine andere POS-Rechnung übertragen. Bitte wählen Sie eine gültige Seriennummer.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Zeile # {}: Seriennummern. {} Wurde bereits in eine andere POS-Rechnung übertragen. Bitte wählen Sie eine gültige Seriennummer.,
+Item Unavailable,Artikel nicht verfügbar,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Zeile # {}: Seriennummer {} kann nicht zurückgegeben werden, da sie nicht in der Originalrechnung {} abgewickelt wurde",
+Please set default Cash or Bank account in Mode of Payment {},Bitte setzen Sie das Standard-Bargeld- oder Bankkonto im Zahlungsmodus {},
+Please set default Cash or Bank account in Mode of Payments {},Bitte setzen Sie das Standard-Bargeld- oder Bankkonto im Zahlungsmodus {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Bitte stellen Sie sicher, dass das Konto {} ein Bilanzkonto ist. Sie können das übergeordnete Konto in ein Bilanzkonto ändern oder ein anderes Konto auswählen.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Bitte stellen Sie sicher, dass das Konto {} ein zahlbares Konto ist. Ändern Sie den Kontotyp in "Verbindlichkeiten" oder wählen Sie ein anderes Konto aus.",
+Row {}: Expense Head changed to {} ,Zeile {}: Ausgabenkopf geändert in {},
+because account {} is not linked to warehouse {} ,weil das Konto {} nicht mit dem Lager {} verknüpft ist,
+or it is not the default inventory account,oder es ist nicht das Standard-Inventarkonto,
+Expense Head Changed,Ausgabenkopf geändert,
+because expense is booked against this account in Purchase Receipt {},weil die Kosten für dieses Konto im Kaufbeleg {} gebucht werden,
+as no Purchase Receipt is created against Item {}. ,da für Artikel {} kein Kaufbeleg erstellt wird.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Dies erfolgt zur Abrechnung von Fällen, in denen der Kaufbeleg nach der Kaufrechnung erstellt wird",
+Purchase Order Required for item {},Bestellung erforderlich für Artikel {},
+To submit the invoice without purchase order please set {} ,"Um die Rechnung ohne Bestellung einzureichen, setzen Sie bitte {}",
+as {} in {},wie in {},
+Mandatory Purchase Order,Obligatorische Bestellung,
+Purchase Receipt Required for item {},Kaufbeleg für Artikel {} erforderlich,
+To submit the invoice without purchase receipt please set {} ,"Um die Rechnung ohne Kaufbeleg einzureichen, setzen Sie bitte {}",
+Mandatory Purchase Receipt,Obligatorischer Kaufbeleg,
+POS Profile {} does not belongs to company {},Das POS-Profil {} gehört nicht zur Firma {},
+User {} is disabled. Please select valid user/cashier,Benutzer {} ist deaktiviert. Bitte wählen Sie einen gültigen Benutzer / Kassierer aus,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Zeile # {}: Die Originalrechnung {} der Rücksenderechnung {} ist {}.,
+Original invoice should be consolidated before or along with the return invoice.,Die Originalrechnung sollte vor oder zusammen mit der Rückrechnung konsolidiert werden.,
+You can add original invoice {} manually to proceed.,"Sie können die Originalrechnung {} manuell hinzufügen, um fortzufahren.",
+Please ensure {} account is a Balance Sheet account. ,"Bitte stellen Sie sicher, dass das Konto {} ein Bilanzkonto ist.",
+You can change the parent account to a Balance Sheet account or select a different account.,Sie können das übergeordnete Konto in ein Bilanzkonto ändern oder ein anderes Konto auswählen.,
+Please ensure {} account is a Receivable account. ,"Bitte stellen Sie sicher, dass das Konto {} ein Forderungskonto ist.",
+Change the account type to Receivable or select a different account.,Ändern Sie den Kontotyp in "Forderung" oder wählen Sie ein anderes Konto aus.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"{} kann nicht storniert werden, da die gesammelten Treuepunkte eingelöst wurden. Brechen Sie zuerst das {} Nein {} ab",
+already exists,ist bereits vorhanden,
+POS Closing Entry {} against {} between selected period,POS Closing Entry {} gegen {} zwischen dem ausgewählten Zeitraum,
+POS Invoice is {},POS-Rechnung ist {},
+POS Profile doesn't matches {},POS-Profil stimmt nicht mit {} überein,
+POS Invoice is not {},POS-Rechnung ist nicht {},
+POS Invoice isn't created by user {},Die POS-Rechnung wird nicht vom Benutzer {} erstellt,
+Row #{}: {},Reihe #{}: {},
+Invalid POS Invoices,Ungültige POS-Rechnungen,
+Please add the account to root level Company - {},Bitte fügen Sie das Konto der Root-Ebene Company - {} hinzu,
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Beim Erstellen eines Kontos für die untergeordnete Firma {0} wurde das übergeordnete Konto {1} nicht gefunden. Bitte erstellen Sie das übergeordnete Konto in der entsprechenden COA,
+Account Not Found,Konto nicht gefunden,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",Beim Erstellen eines Kontos für die untergeordnete Firma {0} wurde das übergeordnete Konto {1} als Sachkonto gefunden.,
+Please convert the parent account in corresponding child company to a group account.,Bitte konvertieren Sie das Elternkonto in der entsprechenden Kinderfirma in ein Gruppenkonto.,
+Invalid Parent Account,Ungültiges übergeordnetes Konto,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Das Umbenennen ist nur über die Muttergesellschaft {0} zulässig, um Fehlanpassungen zu vermeiden.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Wenn Sie {0} {1} Mengen des Artikels {2} haben, wird das Schema {3} auf den Artikel angewendet.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Wenn Sie {0} {1} Gegenstand {2} wert sind, wird das Schema {3} auf den Gegenstand angewendet.",
+"As the field {0} is enabled, the field {1} is mandatory.","Da das Feld {0} aktiviert ist, ist das Feld {1} obligatorisch.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Wenn das Feld {0} aktiviert ist, sollte der Wert des Feldes {1} größer als 1 sein.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Die Seriennummer {0} von Artikel {1} kann nicht geliefert werden, da sie für die Erfüllung des Kundenauftrags {2} reserviert ist.",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Kundenauftrag {0} hat eine Reservierung für den Artikel {1}, Sie können reservierte {1} nur gegen {0} liefern.",
+{0} Serial No {1} cannot be delivered,{0} Seriennummer {1} kann nicht zugestellt werden,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Zeile {0}: Unterauftragsartikel sind für den Rohstoff {1} obligatorisch.,
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Da genügend Rohstoffe vorhanden sind, ist für Warehouse {0} keine Materialanforderung erforderlich.",
+" If you still want to proceed, please enable {0}.","Wenn Sie dennoch fortfahren möchten, aktivieren Sie bitte {0}.",
+The item referenced by {0} - {1} is already invoiced,"Der Artikel, auf den {0} - {1} verweist, wird bereits in Rechnung gestellt",
+Therapy Session overlaps with {0},Die Therapiesitzung überschneidet sich mit {0},
+Therapy Sessions Overlapping,Überlappende Therapiesitzungen,
+Therapy Plans,Therapiepläne,
+"Item Code, warehouse, quantity are required on row {0}","Artikelcode, Lager, Menge sind in Zeile {0} erforderlich.",
+Get Items from Material Requests against this Supplier,Erhalten Sie Artikel aus Materialanfragen gegen diesen Lieferanten,
+Enable European Access,Ermöglichen Sie den europäischen Zugang,
+Creating Purchase Order ...,Bestellung anlegen ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Wählen Sie einen Lieferanten aus den Standardlieferanten der folgenden Artikel aus. Bei der Auswahl erfolgt eine Bestellung nur für Artikel, die dem ausgewählten Lieferanten gehören.",
+Row #{}: You must select {} serial numbers for item {}.,Zeile # {}: Sie müssen {} Seriennummern für Artikel {} auswählen.,
diff --git a/erpnext/translations/el.csv b/erpnext/translations/el.csv
index ec5a1be..acf5db5 100644
--- a/erpnext/translations/el.csv
+++ b/erpnext/translations/el.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Πραγματική φορολογική του τύπου δεν μπορεί να περιλαμβάνεται στην τιμή Θέση στη γραμμή {0},
Add,Προσθήκη,
Add / Edit Prices,Προσθήκη / Επεξεργασία τιμών,
-Add All Suppliers,Προσθήκη όλων των προμηθευτών,
Add Comment,Πρόσθεσε σχόλιο,
Add Customers,Προσθέστε πελάτες,
Add Employees,Προσθέστε Υπαλλήλους,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',δεν μπορεί να εκπέσει όταν η κατηγορία είναι για την «Αποτίμηση» ή «Vaulation και Total»,
"Cannot delete Serial No {0}, as it is used in stock transactions","Δεν μπορείτε να διαγράψετε Αύξων αριθμός {0}, όπως χρησιμοποιείται στις συναλλαγές μετοχών",
Cannot enroll more than {0} students for this student group.,Δεν μπορούν να εγγραφούν περισσότερες από {0} μαθητές για αυτή την ομάδα των σπουδαστών.,
-Cannot find Item with this barcode,Δεν είναι δυνατή η εύρεση αντικειμένου με αυτόν τον γραμμωτό κώδικα,
Cannot find active Leave Period,Δεν είναι δυνατή η εύρεση ενεργής περιόδου άδειας,
Cannot produce more Item {0} than Sales Order quantity {1},Δεν γίνεται να παραχθούν είδη {0} περισσότερα από την ποσότητα παραγγελίας πώλησης {1},
Cannot promote Employee with status Left,Δεν είναι δυνατή η προώθηση του υπαλλήλου με κατάσταση αριστερά,
Cannot refer row number greater than or equal to current row number for this Charge type,Δεν μπορεί να παραπέμψει τον αριθμό σειράς μεγαλύτερο ή ίσο με τον τρέχοντα αριθμό γραμμής για αυτόν τον τύπο επιβάρυνσης,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Δεν μπορείτε να επιλέξετε τον τύπο επιβάρυνσης ως ποσό προηγούμενης γραμμής ή σύνολο προηγούμενης γραμμής για την πρώτη γραμμή,
-Cannot set a received RFQ to No Quote,Δεν είναι δυνατή η ρύθμιση ενός ληφθέντος RFQ σε καμία παράθεση,
Cannot set as Lost as Sales Order is made.,"Δεν μπορεί να οριστεί ως απολεσθέν, καθώς έχει γίνει παραγγελία πώλησης.",
Cannot set authorization on basis of Discount for {0},Δεν είναι δυνατός ο ορισμός της άδειας με βάση την έκπτωση για {0},
Cannot set multiple Item Defaults for a company.,Δεν είναι δυνατή η ρύθμιση πολλών προεπιλογών στοιχείων για μια εταιρεία.,
@@ -521,7 +518,6 @@
Chargeble,Χρεώσιμο,
Charges are updated in Purchase Receipt against each item,Οι επιβαρύνσεις ενημερώνονται στην απόδειξη αγοράς για κάθε είδος,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Οι επιβαρύνσεις θα κατανεμηθούν αναλογικά, σύμφωνα με την ποσότητα ή το ποσό του είδους, σύμφωνα με την επιλογή σας",
-Chart Of Accounts,Λογιστικό Σχέδιο,
Chart of Cost Centers,Διάγραμμα των κέντρων κόστους,
Check all,Ελεγξε τα ολα,
Checkout,Αποχώρηση,
@@ -581,7 +577,6 @@
Compensatory Off,Αντισταθμιστικά απενεργοποιημένα,
Compensatory leave request days not in valid holidays,Οι ημερήσιες αποζημιώσεις αντιστάθμισης δεν ισχύουν σε έγκυρες αργίες,
Complaint,Καταγγελία,
-Completed Qty can not be greater than 'Qty to Manufacture',Η ολοκληρωμένη ποσότητα δεν μπορεί να είναι μεγαλύτερη από την «ποσότητα για κατασκευή»,
Completion Date,Ημερομηνία ολοκλήρωσης,
Computer,Ηλεκτρονικός υπολογιστής,
Condition,Συνθήκη,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Δημιουργία και διαχείριση ημερησίων, εβδομαδιαίων και μηνιαίων ενημερώσεν email.",
Create customer quotes,Δημιουργία εισαγωγικά πελατών,
Create rules to restrict transactions based on values.,Δημιουργία κανόνων για τον περιορισμό των συναλλαγών που βασίζονται σε αξίες.,
-Created By,Δημιουργήθηκε από,
Created {0} scorecards for {1} between: ,Δημιουργήθηκαν {0} scorecards για {1} μεταξύ:,
Creating Company and Importing Chart of Accounts,Δημιουργία Εταιρείας και Εισαγωγή Λογαριασμού,
Creating Fees,Δημιουργία τελών,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Η μεταφορά των εργαζομένων δεν μπορεί να υποβληθεί πριν από την ημερομηνία μεταφοράς,
Employee cannot report to himself.,Ο υπάλληλος δεν μπορεί να αναφέρει στον ευατό του.,
Employee relieved on {0} must be set as 'Left',Υπάλληλος ελεύθερος για {0} πρέπει να οριστεί ως έχει φύγει,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Η κατάσταση του υπαλλήλου δεν μπορεί να οριστεί σε "Αριστερά", καθώς οι παρακάτω υπάλληλοι αναφέρουν αυτήν την περίοδο σε αυτόν τον υπάλληλο:",
Employee {0} already submited an apllication {1} for the payroll period {2},Ο υπάλληλος {0} έχει ήδη υποβάλει μια εφαρμογή {1} για την περίοδο μισθοδοσίας {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Ο εργαζόμενος {0} έχει ήδη υποβάλει αίτηση για {1} μεταξύ {2} και {3}:,
Employee {0} has no maximum benefit amount,Ο υπάλληλος {0} δεν έχει μέγιστο όφελος,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Για τη σειρά {0}: Εισάγετε προγραμματισμένη ποσότητα,
"For {0}, only credit accounts can be linked against another debit entry","Για {0}, μόνο πιστωτικοί λογαριασμοί μπορούν να συνδέονται με άλλες καταχωρήσεις χρέωσης",
"For {0}, only debit accounts can be linked against another credit entry","Για {0}, μόνο χρεωστικοί λογαριασμοί μπορούν να συνδέονται με άλλες καταχωρήσεις πίστωσης",
-Form View,Προβολή μορφής,
Forum Activity,Δραστηριότητα Forum,
Free item code is not selected,Ο ελεύθερος κωδικός είδους δεν έχει επιλεγεί,
Freight and Forwarding Charges,Χρεώσεις μεταφοράς και προώθησης,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Η άδεια δεν μπορεί να χορηγείται πριν {0}, η ισορροπία άδεια έχει ήδη μεταφοράς διαβιβάζεται στο μέλλον ρεκόρ χορήγηση άδειας {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Αφήστε που δεν μπορούν να εφαρμοστούν / ακυρωθεί πριν {0}, η ισορροπία άδεια έχει ήδη μεταφοράς διαβιβάζεται στο μέλλον ρεκόρ χορήγηση άδειας {1}",
Leave of type {0} cannot be longer than {1},Η άδεια του τύπου {0} δεν μπορεί να είναι μεγαλύτερη από {1},
-Leave the field empty to make purchase orders for all suppliers,Αφήστε το πεδίο κενό για να κάνετε παραγγελίες αγοράς για όλους τους προμηθευτές,
Leaves,Φύλλα,
Leaves Allocated Successfully for {0},Οι άδειες κατανεμήθηκαν επιτυχώς για {0},
Leaves has been granted sucessfully,Τα φύλλα έχουν χορηγηθεί με επιτυχία,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Δεν Αντικείμενα με τον Bill Υλικών για Κατασκευή,
No Items with Bill of Materials.,Δεν υπάρχουν στοιχεία με το νομοσχέδιο.,
No Permission,Δεν έχετε άδεια,
-No Quote,Δεν υπάρχει παράθεση,
No Remarks,Δεν βρέθηκαν παρατηρήσεις,
No Result to submit,Δεν υπάρχει αποτέλεσμα για υποβολή,
No Salary Structure assigned for Employee {0} on given date {1},Δεν δομή μισθοδοσίας για τον υπάλληλο {0} σε δεδομένη ημερομηνία {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Βρέθηκαν συνθήκες που επικαλύπτονται μεταξύ:,
Owner,Ιδιοκτήτης,
PAN,ΤΗΓΑΝΙ,
-PO already created for all sales order items,Δημιουργήθηκε ήδη για όλα τα στοιχεία της παραγγελίας,
POS,POS,
POS Profile,POS Προφίλ,
POS Profile is required to use Point-of-Sale,Το POS Profile απαιτείται για να χρησιμοποιηθεί το σημείο πώλησης,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Παρακαλώ επιλέξτε πρώτα τύπο επιβάρυνσης,
Please select Company,Επιλέξτε Εταιρεία,
Please select Company and Designation,Επιλέξτε Εταιρεία και ονομασία,
-Please select Company and Party Type first,Παρακαλώ επιλέξτε πρώτα εταιρεία και τύπο συμβαλλόμενου,
Please select Company and Posting Date to getting entries,Επιλέξτε Εταιρεία και ημερομηνία δημοσίευσης για να λάβετε καταχωρήσεις,
Please select Company first,Επιλέξτε την εταιρεία πρώτα,
Please select Completion Date for Completed Asset Maintenance Log,Παρακαλούμε επιλέξτε Ημερομηνία ολοκλήρωσης για το αρχείο καταγραφής ολοκλήρωσης περιουσιακών στοιχείων,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Σειρά {0}: UOM Συντελεστής μετατροπής είναι υποχρεωτική,
Row {0}: select the workstation against the operation {1},Γραμμή {0}: επιλέξτε τη θέση εργασίας σε σχέση με τη λειτουργία {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Σειρά {0}: {1} Σειριακοί αριθμοί που απαιτούνται για το στοιχείο {2}. Παρέχετε {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Σειρά {0}: {1} απαιτείται για να δημιουργήσετε τα Ανοίγματα {2} Τιμολόγια,
Row {0}: {1} must be greater than 0,Η σειρά {0}: {1} πρέπει να είναι μεγαλύτερη από 0,
Row {0}: {1} {2} does not match with {3},Γραμμή {0}: {1} {2} δεν ταιριάζει με το {3},
Row {0}:Start Date must be before End Date,Γραμμή {0} : η ημερομηνία έναρξης πρέπει να είναι προγενέστερη της ημερομηνίας λήξης,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου επισκόπησης,
Send Now,Αποστολή τώρα,
Send SMS,Αποστολή SMS,
-Send Supplier Emails,Αποστολή Emails Προμηθευτής,
Send mass SMS to your contacts,Αποστολή μαζικών SMS στις επαφές σας,
Sensitivity,Ευαισθησία,
Sent,Εστάλη,
-Serial #,Σειριακός αριθμός #,
Serial No and Batch,Αύξων αριθμός παρτίδας και,
Serial No is mandatory for Item {0},Ο σειριακός αριθμός είναι απαραίτητος για το είδος {0},
Serial No {0} does not belong to Batch {1},Ο αριθμός σειράς {0} δεν ανήκει στην Παρτίδα {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Το όνομα της εταιρείας σας για την οποία εγκαθιστάτε αυτό το σύστημα.,
The number of shares and the share numbers are inconsistent,Ο αριθμός των μετοχών και οι αριθμοί μετοχών είναι ασυμβίβαστοι,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Ο λογαριασμός πύλης πληρωμής στο πρόγραμμα {0} διαφέρει από τον λογαριασμό της πύλης πληρωμής σε αυτό το αίτημα πληρωμής,
-The request for quotation can be accessed by clicking on the following link,Το αίτημα για προσφορά μπορεί να προσπελαστεί κάνοντας κλικ στον παρακάτω σύνδεσμο,
The selected BOMs are not for the same item,Τα επιλεγμένα BOMs δεν είναι για το ίδιο στοιχείο,
The selected item cannot have Batch,Το επιλεγμένο είδος δεν μπορεί να έχει παρτίδα,
The seller and the buyer cannot be the same,Ο πωλητής και ο αγοραστής δεν μπορούν να είναι οι ίδιοι,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Το συνολικό ποσό της ευέλικτης συνιστώσας παροχών {0} δεν πρέπει να είναι μικρότερο από τα μέγιστα οφέλη {1},
Total hours: {0},Σύνολο ωρών: {0},
Total leaves allocated is mandatory for Leave Type {0},Το σύνολο των κατανεμημένων φύλλων είναι υποχρεωτικό για τον Τύπο Αδείας {0},
-Total weightage assigned should be 100%. It is {0},Το σύνολο βάρους πού έχει ανατεθεί έπρεπε να είναι 100 %. Είναι {0},
Total working hours should not be greater than max working hours {0},Οι συνολικές ώρες εργασίας δεν πρέπει να είναι μεγαλύτερη από το ωράριο εργασίας max {0},
Total {0} ({1}),Σύνολο {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Σύνολο {0} για όλα τα στοιχεία είναι μηδέν, μπορεί να πρέπει να αλλάξει »Μοιράστε τελών με βάση το '",
@@ -3316,7 +3299,6 @@
What do you need help with?,Σε τι χρειάζεσαι βοήθεια?,
What does it do?,Τι κάνει;,
Where manufacturing operations are carried.,Που γίνονται οι μεταποιητικές εργασίες,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Κατά τη δημιουργία λογαριασμού για την εταιρεία {0} παιδιού, ο γονικός λογαριασμός {1} δεν βρέθηκε. Δημιουργήστε το γονικό λογαριασμό σε αντίστοιχο COA",
White,λευκό,
Wire Transfer,Μεταφορά καλωδίων,
WooCommerce Products,Προϊόντα WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} δημιουργήθηκαν παραλλαγές.,
{0} {1} created,{0} {1} δημιουργήθηκε,
{0} {1} does not exist,{0} {1} δεν υπάρχει,
-{0} {1} does not exist.,{0} {1} δεν υπάρχει.,
{0} {1} has been modified. Please refresh.,{0} {1} Έχει τροποποιηθεί. Παρακαλώ ανανεώστε.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} δεν έχει υποβληθεί, οπότε η ενέργεια δεν μπορεί να ολοκληρωθεί",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} συνδέεται με {2}, αλλά Λογαριασμός συμβαλλόμενου είναι {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} δεν υπάρχει,
{0}: {1} not found in Invoice Details table,{0}: {1} Δεν βρέθηκε στον πίνακα στοιχείων τιμολογίου,
{} of {},{} του {},
+Assigned To,Ανατέθηκε σε,
Chat,Κουβέντα,
Completed By,Ολοκληρώθηκε από,
Conditions,Συνθήκες,
@@ -3506,7 +3488,9 @@
Merge with existing,Συγχώνευση με τις υπάρχουσες,
Office,Γραφείο,
Orientation,Προσανατολισμός,
+Parent,Γονέας,
Passive,Αδρανής,
+Payment Failed,Η πληρωμή απέτυχε,
Percent,Τοις εκατό,
Permanent,Μόνιμος,
Personal,Προσωπικός,
@@ -3544,7 +3528,6 @@
Company field is required,Απαιτείται πεδίο εταιρείας,
Creating Dimensions...,Δημιουργία διαστάσεων ...,
Duplicate entry against the item code {0} and manufacturer {1},Διπλότυπη καταχώρηση έναντι του κωδικού {0} και του κατασκευαστή {1},
-Import Chart Of Accounts from CSV / Excel files,Εισαγωγή πίνακα λογαριασμών από αρχεία CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Μη έγκυρο GSTIN! Η είσοδος που έχετε εισάγει δεν αντιστοιχεί στη μορφή GSTIN για τους κατόχους UIN ή για τους παροχείς υπηρεσιών OIDAR που δεν είναι κατοίκους,
Invoice Grand Total,Συνολικό τιμολόγιο,
Last carbon check date cannot be a future date,Η τελευταία ημερομηνία ελέγχου άνθρακα δεν μπορεί να είναι μελλοντική ημερομηνία,
@@ -3556,6 +3539,7 @@
Show {0},Εμφάνιση {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Ειδικοί χαρακτήρες εκτός από "-", "#", ".", "/", "" Και "}" δεν επιτρέπονται στη σειρά ονομασίας",
Target Details,Στοιχεία στόχου,
+{0} already has a Parent Procedure {1}.,{0} έχει ήδη μια διαδικασία γονέα {1}.,
API,API,
Annual,Ετήσιος,
Approved,Εγκρίθηκε,
@@ -3572,6 +3556,8 @@
No data to export,Δεν υπάρχουν δεδομένα για εξαγωγή,
Portrait,Πορτρέτο,
Print Heading,Εκτύπωση κεφαλίδας,
+Scheduler Inactive,Χρονοδιάγραμμα αδρανής,
+Scheduler is inactive. Cannot import data.,Ο προγραμματιστής είναι ανενεργός. Δεν είναι δυνατή η εισαγωγή δεδομένων.,
Show Document,Εμφάνιση εγγράφου,
Show Traceback,Εμφάνιση ανίχνευσης,
Video,βίντεο,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Δημιουργία επιθεώρησης ποιότητας για το στοιχείο {0},
Creating Accounts...,Δημιουργία λογαριασμών ...,
Creating bank entries...,Δημιουργία τραπεζικών εγγραφών ...,
-Creating {0},Δημιουργία {0},
Credit limit is already defined for the Company {0},Το πιστωτικό όριο έχει ήδη καθοριστεί για την Εταιρεία {0},
Ctrl + Enter to submit,Ctrl + Enter για υποβολή,
Ctrl+Enter to submit,Ctrl + Enter για υποβολή,
@@ -3921,7 +3906,6 @@
Plaid public token error,Σφάλμα κοινόχρηστου συμβόλου,
Plaid transactions sync error,Σφάλμα συγχρονισμού πλαστών συναλλαγών,
Please check the error log for details about the import errors,Ελέγξτε το αρχείο καταγραφής σφαλμάτων για λεπτομέρειες σχετικά με τα σφάλματα εισαγωγής,
-Please click on the following link to set your new password,Παρακαλώ κάντε κλικ στον παρακάτω σύνδεσμο για να ορίσετε νέο κωδικό πρόσβασης,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Δημιουργήστε τις <b>ρυθμίσεις DATEV</b> για την εταιρεία <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Δημιουργήστε εγγραφή εγγραφής προσαρμογής για ποσό {0},
Please do not create more than 500 items at a time,Μην δημιουργείτε περισσότερα από 500 στοιχεία τη φορά,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Η ημερομηνία κυκλοφορίας πρέπει να είναι στο μέλλον,
Relieving Date must be greater than or equal to Date of Joining,Η ημερομηνία ανακούφισης πρέπει να είναι μεγαλύτερη ή ίση με την Ημερομηνία Σύνδεσης,
Rename,Μετονομασία,
+Rename Not Allowed,Μετονομασία Δεν επιτρέπεται,
Repayment Method is mandatory for term loans,Η μέθοδος αποπληρωμής είναι υποχρεωτική για δάνεια με διάρκεια,
Repayment Start Date is mandatory for term loans,Η ημερομηνία έναρξης αποπληρωμής είναι υποχρεωτική για τα δάνεια με διάρκεια,
Report Item,Στοιχείο αναφοράς,
@@ -4043,7 +4028,6 @@
Select All,Επιλέξτε All,
Select Difference Account,Επιλέξτε Λογαριασμό Διαφοράς,
Select a Default Priority.,Επιλέξτε μια προεπιλεγμένη προτεραιότητα.,
-Select a Supplier from the Default Supplier List of the items below.,Επιλέξτε έναν προμηθευτή από την Προκαθορισμένη λίστα προμηθευτών των παρακάτω στοιχείων.,
Select a company,Επιλέξτε μια εταιρεία,
Select finance book for the item {0} at row {1},Επιλέξτε βιβλίο χρηματοδότησης για το στοιχείο {0} στη σειρά {1},
Select only one Priority as Default.,Επιλέξτε μόνο μία προτεραιότητα ως προεπιλογή.,
@@ -4247,7 +4231,6 @@
Actual ,Πραγματικός,
Add to cart,Προσθήκη στο καλάθι,
Budget,Προϋπολογισμός,
-Chart Of Accounts Importer,Λογαριασμός Εισαγωγέας,
Chart of Accounts,Λογιστικό Σχέδιο,
Customer database.,Βάση δεδομένων πελατών.,
Days Since Last order,Ημέρες από την τελευταία σειρά,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Η ημερομηνία λήξης δεν μπορεί να είναι προγενέστερη της ημερομηνίας έναρξης,
For Default Supplier (Optional),Για προεπιλεγμένο προμηθευτή (προαιρετικό),
From date cannot be greater than To date,Από την ημερομηνία αυτή δεν μπορεί να είναι μεταγενέστερη από την έως ημερομηνία,
-Get items from,Πάρτε τα στοιχεία από,
Group by,Ομαδοποίηση κατά,
In stock,Σε απόθεμα,
Item name,Όνομα είδους,
@@ -4532,32 +4514,22 @@
Accounts Settings,Ρυθμίσεις λογαριασμών,
Settings for Accounts,Ρυθμίσεις για τους λογαριασμούς,
Make Accounting Entry For Every Stock Movement,Δημιούργησε λογιστική καταχώρηση για κάθε κίνηση αποθέματος,
-"If enabled, the system will post accounting entries for inventory automatically.","Εάν είναι ενεργοποιημένο, το σύστημα θα καταχωρεί λογιστικές εγγραφές για την απογραφή αυτόματα.",
-Accounts Frozen Upto,Παγωμένοι λογαριασμοί μέχρι,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Η λογιστική εγγραφή έχει παγώσει μέχρι την ημερομηνία αυτή, κανείς δεν μπορεί να κάνει / τροποποιήσει καταχωρήσεις, εκτός από τον ρόλο που καθορίζεται παρακάτω.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Ο ρόλος επιτρέπεται να καθορίζει παγωμένους λογαριασμούς & να επεξεργάζετε παγωμένες καταχωρήσεις,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Οι χρήστες με αυτό το ρόλο μπορούν να καθορίζουν δεσμευμένους λογαριασμούς και τη δημιουργία / τροποποίηση των λογιστικών εγγραφών δεσμευμένων λογαριασμών,
Determine Address Tax Category From,Προσδιορίστε τη φορολογική κατηγορία διευθύνσεων από,
-Address used to determine Tax Category in transactions.,Διεύθυνση που χρησιμοποιείται για τον προσδιορισμό της φορολογικής κατηγορίας στις συναλλαγές.,
Over Billing Allowance (%),Επίδομα χρέωσης (%),
-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 for $110.,Ποσοστό σας επιτρέπεται να χρεώσετε περισσότερο έναντι του παραγγελθέντος ποσού. Για παράδειγμα: Εάν η τιμή της παραγγελίας είναι $ 100 για ένα στοιχείο και η ανοχή ορίζεται ως 10% τότε μπορείτε να χρεώσετε για $ 110.,
Credit Controller,Ελεγκτής πίστωσης,
-Role that is allowed to submit transactions that exceed credit limits set.,Ρόλος που έχει τη δυνατότητα να υποβάλει τις συναλλαγές που υπερβαίνουν τα όρια πίστωσης.,
Check Supplier Invoice Number Uniqueness,Ελέγξτε Προμηθευτής Αριθμός Τιμολογίου Μοναδικότητα,
Make Payment via Journal Entry,Κάντε Πληρωμή μέσω Εφημερίδα Έναρξη,
Unlink Payment on Cancellation of Invoice,Αποσύνδεση Πληρωμή κατά την ακύρωσης της Τιμολόγιο,
-Unlink Advance Payment on Cancelation of Order,Αποσύνδεση της προκαταβολής με την ακύρωση της παραγγελίας,
Book Asset Depreciation Entry Automatically,Αποσβέσεις εγγύησης λογαριασμού βιβλίων αυτόματα,
Automatically Add Taxes and Charges from Item Tax Template,Αυτόματη προσθήκη φόρων και χρεώσεων από το πρότυπο φόρου αντικειμένων,
Automatically Fetch Payment Terms,Αυτόματη εξαγωγή όρων πληρωμής,
-Show Inclusive Tax In Print,Εμφάνιση αποκλειστικού φόρου στην εκτύπωση,
Show Payment Schedule in Print,Εμφάνιση χρονοδιαγράμματος πληρωμών στην εκτύπωση,
Currency Exchange Settings,Ρυθμίσεις ανταλλαγής νομισμάτων,
Allow Stale Exchange Rates,Να επιτρέπεται η μετατροπή σε Stale Exchange Rate,
Stale Days,Στατικές μέρες,
Report Settings,Ρυθμίσεις αναφοράς,
Use Custom Cash Flow Format,Χρησιμοποιήστε την προσαρμοσμένη μορφή ροής μετρητών,
-Only select if you have setup Cash Flow Mapper documents,Επιλέξτε μόνο εάν έχετε εγκαταστήσει έγγραφα χαρτογράφησης ροών ροής μετρητών,
Allowed To Transact With,Επιτρέπεται να γίνεται συναλλαγή με,
SWIFT number,Αριθμός SWIFT,
Branch Code,Κωδικός υποκαταστήματος,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Ομάδα Πελατών,
POS Field,Πεδίο POS,
POS Item Group,POS Θέση του Ομίλου,
-[Select],[ Επιλέξτε ],
Company Address,Διεύθυνση εταιρείας,
Update Stock,Ενημέρωση αποθέματος,
Ignore Pricing Rule,Αγνοήστε τον κανόνα τιμολόγησης,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Ονοματοδοσία προμηθευτή βάσει,
Default Supplier Group,Προεπιλεγμένη ομάδα προμηθευτών,
Default Buying Price List,Προεπιλεγμένος τιμοκατάλογος αγορών,
-Maintain same rate throughout purchase cycle,Διατηρήστε ίδια τιμολόγηση καθ'όλο τον κύκλο αγορών,
-Allow Item to be added multiple times in a transaction,Επιτρέψτε στοιχείου να προστεθούν πολλές φορές σε μια συναλλαγή,
Backflush Raw Materials of Subcontract Based On,Backflush Πρώτες ύλες της υπεργολαβίας με βάση,
Material Transferred for Subcontract,Μεταφερόμενο υλικό για υπεργολαβία,
Over Transfer Allowance (%),Επίδομα υπεράνω μεταφοράς (%),
@@ -5540,7 +5509,6 @@
Current Stock,Τρέχον απόθεμα,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Για μεμονωμένο προμηθευτή,
-Supplier Detail,Προμηθευτής Λεπτομέρειες,
Link to Material Requests,Σύνδεσμος για αιτήματα υλικού,
Message for Supplier,Μήνυμα για την Προμηθευτής,
Request for Quotation Item,Αίτηση Προσφοράς Είδους,
@@ -6481,7 +6449,6 @@
Appraisal Template,Πρότυπο αξιολόγησης,
For Employee Name,Για το όνομα υπαλλήλου,
Goals,Στόχοι,
-Calculate Total Score,Υπολογισμός συνολικής βαθμολογίας,
Total Score (Out of 5),Συνολική βαθμολογία (από 5),
"Any other remarks, noteworthy effort that should go in the records.","Οποιεσδήποτε άλλες παρατηρήσεις, αξιοσημείωτη προσπάθεια που πρέπει να πάει στα αρχεία.",
Appraisal Goal,Στόχος αξιολόγησης,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Αιτιολογία αποχώρησης,
Leave Encashed?,Η άδεια εισπράχθηκε;,
Encashment Date,Ημερομηνία εξαργύρωσης,
-Exit Interview Details,Λεπτομέρειες συνέντευξης εξόδου,
-Held On,Πραγματοποιήθηκε την,
-Reason for Resignation,Αιτία παραίτησης,
-Better Prospects,Καλύτερες προοπτικές,
-Health Concerns,Ανησυχίες για την υγεία,
New Workplace,Νέος χώρος εργασίας,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Επιστρεφόμενο ποσό,
@@ -6740,10 +6702,7 @@
Employee Settings,Ρυθμίσεις των υπαλλήλων,
Retirement Age,Ηλικία συνταξιοδότησης,
Enter retirement age in years,Εισάγετε την ηλικία συνταξιοδότησης στα χρόνια,
-Employee Records to be created by,Εγγραφές των υπαλλήλων που πρόκειται να δημιουργηθούν από,
-Employee record is created using selected field. ,Η Εγγραφή υπαλλήλου δημιουργείται χρησιμοποιώντας το επιλεγμένο πεδίο.,
Stop Birthday Reminders,Διακοπή υπενθυμίσεων γενεθλίων,
-Don't send Employee Birthday Reminders,Μην στέλνετε υπενθυμίσεις γενεθλίων υπαλλήλου,
Expense Approver Mandatory In Expense Claim,Έγκριση δαπανών Υποχρεωτική αξίωση,
Payroll Settings,Ρυθμίσεις μισθοδοσίας,
Leave,Αδεια,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Απαλλαγή από την υποχρέωση προσέγγισης υποχρεωτική στην άδεια,
Show Leaves Of All Department Members In Calendar,Εμφάνιση φύλλων όλων των μελών του Τμήματος στο Ημερολόγιο,
Auto Leave Encashment,Αυτόματη εγκατάλειψη,
-Restrict Backdated Leave Application,Περιορίστε το Backdated Leave Application,
Hiring Settings,Ρυθμίσεις πρόσληψης,
Check Vacancies On Job Offer Creation,Ελέγξτε τις κενές θέσεις στη δημιουργία προσφοράς εργασίας,
Identification Document Type,Τύπος εγγράφου αναγνώρισης,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Ρυθμίσεις παραγωγής,
Raw Materials Consumption,Κατανάλωση Πρώτων Υλών,
Allow Multiple Material Consumption,Επιτρέψτε πολλαπλή κατανάλωση υλικού,
-Allow multiple Material Consumption against a Work Order,Επιτρέψτε την πολλαπλή κατανάλωση υλικού έναντι μιας εντολής εργασίας,
Backflush Raw Materials Based On,Backflush πρώτων υλών Βάσει των,
Material Transferred for Manufacture,Υλικό το οποίο μεταφέρεται για την Κατασκευή,
Capacity Planning,Σχεδιασμός Χωρητικότητα,
Disable Capacity Planning,Απενεργοποιήστε τον προγραμματισμό χωρητικότητας,
Allow Overtime,Επιτρέψτε Υπερωρίες,
-Plan time logs outside Workstation Working Hours.,Προγραμματίστε κούτσουρα χρόνο εκτός των ωρών εργασίας του σταθμού εργασίας.,
Allow Production on Holidays,Επίτρεψε παραγωγή σε αργίες,
Capacity Planning For (Days),Ο προγραμματισμός της δυναμικότητας Για (Ημέρες),
-Try planning operations for X days in advance.,Δοκιμάστε τον προγραμματισμό εργασιών για το X ημέρες νωρίτερα.,
-Time Between Operations (in mins),Χρόνου μεταξύ των λειτουργιών (σε λεπτά),
-Default 10 mins,Προεπιλογή 10 λεπτά,
Default Warehouses for Production,Προκαθορισμένες αποθήκες παραγωγής,
Default Work In Progress Warehouse,Προεπιλογή Work In Progress Αποθήκη,
Default Finished Goods Warehouse,Προεπιλογή Έτοιμα προϊόντα Αποθήκη,
Default Scrap Warehouse,Προεπιλεγμένη αποθήκη αποκομμάτων,
-Over Production for Sales and Work Order,Παραγωγή για Πωλήσεις και Παραγγελία Εργασίας,
Overproduction Percentage For Sales Order,Ποσοστό υπερπαραγωγής για παραγγελία πώλησης,
Overproduction Percentage For Work Order,Ποσοστό υπερπαραγωγής για παραγγελία εργασίας,
Other Settings,άλλες ρυθμίσεις,
Update BOM Cost Automatically,Ενημέρωση κόστους BOM αυτόματα,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Ενημέρωση κόστους BOM αυτόματα μέσω Scheduler, με βάση το τελευταίο ποσοστό αποτίμησης / τιμοκαταλόγου / τελευταίο ποσοστό αγοράς πρώτων υλών.",
Material Request Plan Item,Στοιχείο Σχεδίου Αίτησης Υλικού,
Material Request Type,Τύπος αίτησης υλικού,
Material Issue,Υλικά Θέματος,
@@ -7603,10 +7554,6 @@
Quality Goal,Στόχος ποιότητας,
Monitoring Frequency,Συχνότητα παρακολούθησης,
Weekday,Καθημερινή,
-January-April-July-October,Ιανουάριος-Απρίλιος-Ιούλιος-Οκτώβριος,
-Revision and Revised On,Αναθεώρηση και αναθεωρήθηκε στις,
-Revision,Αναθεώρηση,
-Revised On,Αναθεωρημένη On,
Objectives,Στόχοι,
Quality Goal Objective,Στόχος στόχου ποιότητας,
Objective,Σκοπός,
@@ -7619,7 +7566,6 @@
Processes,Διαδικασίες,
Quality Procedure Process,Διαδικασία ποιοτικής διαδικασίας,
Process Description,Περιγραφή διαδικασίας,
-Child Procedure,Διαδικασία παιδιού,
Link existing Quality Procedure.,Συνδέστε την υφιστάμενη διαδικασία ποιότητας.,
Additional Information,Επιπλέον πληροφορίες,
Quality Review Objective,Στόχος αναθεώρησης της ποιότητας,
@@ -7787,15 +7733,9 @@
Default Customer Group,Προεπιλεγμένη ομάδα πελατών,
Default Territory,Προεπιλεγμένη περιοχή,
Close Opportunity After Days,Κλείστε Ευκαιρία μετά από μέρες,
-Auto close Opportunity after 15 days,Αυτόματη κοντά Ευκαιρία μετά από 15 ημέρες,
Default Quotation Validity Days,Προεπιλεγμένες ημέρες ισχύος της προσφοράς,
Sales Update Frequency,Συχνότητα ενημέρωσης πωλήσεων,
-How often should project and company be updated based on Sales Transactions.,Πόσο συχνά πρέπει να ενημερώνεται το έργο και η εταιρεία με βάση τις Συναλλαγές Πωλήσεων.,
Each Transaction,Κάθε συναλλαγή,
-Allow user to edit Price List Rate in transactions,Επίτρεψε στο χρήστη να επεξεργάζεται τιμές τιμοκατάλογου στις συναλλαγές,
-Allow multiple Sales Orders against a Customer's Purchase Order,Επιτρέψτε πολλαπλές Παραγγελίες εναντίον παραγγελίας του Πελάτη,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Επικυρώνει τιμή πώλησης για τη θέση ενάντια Purchase Rate ή αποτίμησης Rate,
-Hide Customer's Tax Id from Sales Transactions,Απόκρυψη ΑΦΜ του πελάτη από συναλλαγές Πωλήσεις,
SMS Center,Κέντρο SMS,
Send To,Αποστολή προς,
All Contact,Όλες οι επαφές,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Κατασκευαστές που χρησιμοποιούνται στα σημεία,
Limited to 12 characters,Περιορίζεται σε 12 χαρακτήρες,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Ορισμός αποθήκης,
-Sets 'For Warehouse' in each row of the Items table.,Ορίζει «Για αποθήκη» σε κάθε σειρά του πίνακα αντικειμένων.,
-Requested For,Ζητήθηκαν για,
Partially Ordered,Εν μέρει παραγγελία,
Transferred,Μεταφέρθηκε,
% Ordered,% Παραγγέλθηκαν,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Προεπιλεγμένη Μ.Μ. Αποθέματος,
Sample Retention Warehouse,Αποθήκη διατήρησης δειγμάτων,
Default Valuation Method,Προεπιλεγμένη μέθοδος αποτίμησης,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Ποσοστό που επιτρέπεται να παραληφθεί ή να παραδοθεί περισσότερο από την ποσότητα παραγγελίας. Για παράδειγμα: εάν έχετε παραγγείλει 100 μονάδες. Και το επίδομα σας είναι 10%, τότε θα μπορούν να παραληφθούν 110 μονάδες.",
-Action if Quality inspection is not submitted,Ενέργεια εάν δεν υποβληθεί έλεγχος ποιότητας,
Show Barcode Field,Εμφάνιση Barcode πεδίο,
Convert Item Description to Clean HTML,Μετατροπή περιγραφής στοιχείου για καθαρισμό HTML,
-Auto insert Price List rate if missing,Αυτόματη ένθετο ποσοστό Τιμοκατάλογος αν λείπει,
Allow Negative Stock,Επίτρεψε αρνητικό απόθεμα,
Automatically Set Serial Nos based on FIFO,Αυτόματη Ρύθμιση αύξοντες αριθμούς με βάση FIFO,
-Set Qty in Transactions based on Serial No Input,Ορισμός ποσότητας στις συναλλαγές με βάση την αύξουσα σειρά εισόδου,
Auto Material Request,Αυτόματη αίτηση υλικού,
-Raise Material Request when stock reaches re-order level,Δημιουργία αιτήματος υλικού όταν το απόθεμα φτάνει το επίπεδο για επαναπαραγγελία,
-Notify by Email on creation of automatic Material Request,Ειδοποίηση μέσω email σχετικά με την αυτόματη δημιουργία αιτήσης υλικού,
Inter Warehouse Transfer Settings,Ρυθμίσεις μεταφοράς μεταξύ αποθήκης,
-Allow Material Transfer From Delivery Note and Sales Invoice,Να επιτρέπεται η μεταφορά υλικού από το σημείωμα παράδοσης και το τιμολόγιο πωλήσεων,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Να επιτρέπεται η μεταφορά υλικού από την απόδειξη αγοράς και το τιμολόγιο αγοράς,
Freeze Stock Entries,Πάγωμα καταχωρήσεων αποθέματος,
Stock Frozen Upto,Παγωμένο απόθεμα μέχρι,
-Freeze Stocks Older Than [Days],Πάγωμα αποθεμάτων παλαιότερα από [ημέρες],
-Role Allowed to edit frozen stock,Ο ρόλος έχει τη δυνατότητα επεξεργασίας παγωμένου απόθεματος,
Batch Identification,Αναγνώριση παρτίδας,
Use Naming Series,Χρησιμοποιήστε τη σειρά ονομάτων,
Naming Series Prefix,Ονομασία πρόθεμα σειράς,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Τάσεις αποδεικτικού παραλαβής αγοράς,
Purchase Register,Ταμείο αγορών,
Quotation Trends,Τάσεις προσφορών,
-Quoted Item Comparison,Εισηγμένες Στοιχείο Σύγκριση,
Received Items To Be Billed,Είδη που παραλήφθηκαν και πρέπει να τιμολογηθούν,
Qty to Order,Ποσότητα για παραγγελία,
Requested Items To Be Transferred,Είδη που ζητήθηκε να μεταφερθούν,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Επιλέξτε αποθήκη για αιτήματα υλικών,
Transfer Materials For Warehouse {0},Μεταφορά υλικών για αποθήκη {0},
Production Plan Material Request Warehouse,Πρόγραμμα παραγωγής Υλικό Αίτημα Αποθήκη,
-Set From Warehouse,Ορισμός από την αποθήκη,
-Source Warehouse (Material Transfer),Αποθήκη πηγής (μεταφορά υλικού),
Sets 'Source Warehouse' in each row of the items table.,Ορίζει το "Source Warehouse" σε κάθε σειρά του πίνακα αντικειμένων.,
Sets 'Target Warehouse' in each row of the items table.,Ορίζει το «Target Warehouse» σε κάθε σειρά του πίνακα αντικειμένων.,
Show Cancelled Entries,Εμφάνιση ακυρωμένων καταχωρήσεων,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Η υπηρεσία ελήφθη αλλά δεν χρεώθηκε,
Deferred Accounting Settings,Αναβαλλόμενες ρυθμίσεις λογιστικής,
Book Deferred Entries Based On,Βιβλίο αναβαλλόμενων καταχωρίσεων βάσει,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Εάν επιλεγεί "Μήνες", τότε το σταθερό ποσό θα καταχωρηθεί ως αναβαλλόμενο έσοδο ή έξοδο για κάθε μήνα, ανεξάρτητα από τον αριθμό ημερών σε ένα μήνα. Θα υπολογιστεί αναλογικά εάν τα αναβαλλόμενα έσοδα ή έξοδα δεν δεσμευτούν για έναν ολόκληρο μήνα.",
Days,Μέρες,
Months,Μήνες,
Book Deferred Entries Via Journal Entry,Κράτηση αναβαλλόμενων καταχωρίσεων μέσω καταχώρησης ημερολογίου,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Εάν αυτό δεν είναι επιλεγμένο, θα δημιουργηθούν απευθείας καταχωρίσεις GL για την κράτηση Αναβαλλόμενων εσόδων / εξόδων",
Submit Journal Entries,Υποβολή καταχωρίσεων περιοδικού,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Εάν αυτό δεν είναι επιλεγμένο, οι καταχωρίσεις περιοδικών θα αποθηκευτούν σε κατάσταση πρόχειρου και θα πρέπει να υποβληθούν χειροκίνητα",
Enable Distributed Cost Center,Ενεργοποίηση Κέντρου κατανεμημένου κόστους,
@@ -8901,8 +8823,6 @@
Is Inter State,Είναι το Inter State,
Purchase Details,Λεπτομέρειες αγοράς,
Depreciation Posting Date,Ημερομηνία δημοσίευσης απόσβεσης,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Απαιτείται εντολή αγοράς για αγορά τιμολογίου & δημιουργία απόδειξης,
-Purchase Receipt Required for Purchase Invoice Creation,Απαιτείται απόδειξη αγοράς για τη δημιουργία τιμολογίου αγοράς,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Από προεπιλογή, το όνομα προμηθευτή ορίζεται σύμφωνα με το όνομα προμηθευτή που έχει εισαχθεί. Αν θέλετε οι Προμηθευτές να ονομάζονται από a",
choose the 'Naming Series' option.,ορίστε την επιλογή "Naming Series".,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Διαμορφώστε την προεπιλεγμένη λίστα τιμών κατά τη δημιουργία μιας νέας συναλλαγής αγοράς. Οι τιμές των στοιχείων θα ληφθούν από αυτήν την Τιμοκατάλογος.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Είναι συστατικό φόρου εισοδήματος,
Component properties and references ,Ιδιότητες συστατικών και αναφορές,
Additional Salary ,Πρόσθετος μισθός,
-Condtion and formula,Κατάσταση και τύπος,
Unmarked days,Ημέρες χωρίς σήμανση,
Absent Days,Απόντες ημέρες,
Conditions and Formula variable and example,Συνθήκες και μεταβλητή τύπου και παράδειγμα,
Feedback By,Σχόλια από,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Τμήμα κατασκευής,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Απαιτείται παραγγελία πώλησης για δημιουργία τιμολογίου και παράδοσης σημείωσης παράδοσης,
-Delivery Note Required for Sales Invoice Creation,Απαιτείται σημείωση παράδοσης για τη δημιουργία τιμολογίου πωλήσεων,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Από προεπιλογή, το όνομα πελάτη ορίζεται σύμφωνα με το πλήρες όνομα που έχει εισαχθεί. Εάν θέλετε οι πελάτες να ονομάζονται από ένα",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Διαμορφώστε την προεπιλεγμένη λίστα τιμών κατά τη δημιουργία μιας νέας συναλλαγής πωλήσεων. Οι τιμές των αντικειμένων θα ληφθούν από αυτόν τον τιμοκατάλογο.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Εάν αυτή η επιλογή έχει διαμορφωθεί «Ναι», το ERPNext θα σας εμποδίσει να δημιουργήσετε τιμολόγιο πωλήσεων ή σημείωμα παράδοσης χωρίς να δημιουργήσετε πρώτα μια παραγγελία πώλησης. Αυτή η διαμόρφωση μπορεί να παρακαμφθεί για έναν συγκεκριμένο πελάτη ενεργοποιώντας το πλαίσιο ελέγχου "Να επιτρέπεται η δημιουργία τιμολογίου χωρίς παραγγελία πώλησης" στο κύριο πελάτη.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,Το {0} {1} προστέθηκε με επιτυχία σε όλα τα επιλεγμένα θέματα.,
Topics updated,Τα θέματα ενημερώθηκαν,
Academic Term and Program,Ακαδημαϊκός Όρος και Πρόγραμμα,
-Last Stock Transaction for item {0} was on {1}.,Η τελευταία συναλλαγή μετοχών για το στοιχείο {0} ήταν στις {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Δεν είναι δυνατή η δημοσίευση συναλλαγών μετοχών για το στοιχείο {0} πριν από αυτήν την ώρα.,
Please remove this item and try to submit again or update the posting time.,Καταργήστε αυτό το στοιχείο και προσπαθήστε να υποβάλετε ξανά ή ενημερώστε τον χρόνο δημοσίευσης.,
Failed to Authenticate the API key.,Αποτυχία ελέγχου ταυτότητας του κλειδιού API.,
Invalid Credentials,Ακυρα διαπιστευτήρια,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Ελέγξτε το αναγνωριστικό πελάτη Plaid και τις μυστικές τιμές σας,
Bank transaction creation error,Σφάλμα δημιουργίας τραπεζικής συναλλαγής,
Unit of Measurement,Μονάδα μέτρησης,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Σειρά # {}: Το ποσοστό πώλησης για το στοιχείο {} είναι χαμηλότερο από το {}. Η τιμή πώλησης πρέπει να είναι τουλάχιστον {},
Fiscal Year {0} Does Not Exist,Το οικονομικό έτος {0} δεν υπάρχει,
Row # {0}: Returned Item {1} does not exist in {2} {3},Σειρά # {0}: Το στοιχείο που επιστράφηκε {1} δεν υπάρχει στο {2} {3},
Valuation type charges can not be marked as Inclusive,Οι χρεώσεις τύπου εκτίμησης δεν μπορούν να επισημανθούν ως Συμπεριλαμβανομένων,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Ο χρόνος απόκρισης για {0} προτεραιότητα στη σειρά {1} δεν μπορεί να είναι μεγαλύτερος από τον χρόνο ανάλυσης.,
{0} is not enabled in {1},Το {0} δεν είναι ενεργοποιημένο σε {1},
Group by Material Request,Ομαδοποίηση κατά Αίτημα Υλικού,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Σειρά {0}: Για τον προμηθευτή {0}, απαιτείται διεύθυνση ηλεκτρονικού ταχυδρομείου για αποστολή email",
Email Sent to Supplier {0},Αποστολή email στον προμηθευτή {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Η πρόσβαση στο αίτημα για προσφορά από την πύλη είναι απενεργοποιημένη. Για να επιτρέψετε την πρόσβαση, ενεργοποιήστε το στις Ρυθμίσεις πύλης.",
Supplier Quotation {0} Created,Προσφορά προμηθευτή {0} Δημιουργήθηκε,
Valid till Date cannot be before Transaction Date,Ισχύει έως την ημερομηνία δεν μπορεί να είναι πριν από την ημερομηνία συναλλαγής,
+Unlink Advance Payment on Cancellation of Order,Αποσύνδεση προκαταβολής για ακύρωση παραγγελίας,
+"Simple Python Expression, Example: territory != 'All Territories'","Simple Python Expression, Παράδειγμα: wilayah! = 'Όλες οι περιοχές'",
+Sales Contributions and Incentives,Συνεισφορές και κίνητρα πωλήσεων,
+Sourced by Supplier,Προέρχεται από τον προμηθευτή,
+Total weightage assigned should be 100%.<br>It is {0},Το συνολικό βάρος που αποδίδεται πρέπει να είναι 100%.<br> Είναι {0},
+Account {0} exists in parent company {1}.,Ο λογαριασμός {0} υπάρχει στη μητρική εταιρεία {1}.,
+"To overrule this, enable '{0}' in company {1}","Για να το παρακάμψετε, ενεργοποιήστε το "{0}" στην εταιρεία {1}",
+Invalid condition expression,Μη έγκυρη έκφραση συνθήκης,
+Please Select a Company First,Επιλέξτε πρώτα μια εταιρεία,
+Please Select Both Company and Party Type First,Επιλέξτε πρώτα την εταιρεία και τον τύπο πάρτι,
+Provide the invoice portion in percent,Καταχωρίστε το τμήμα τιμολογίου σε ποσοστό,
+Give number of days according to prior selection,Δώστε τον αριθμό των ημερών σύμφωνα με την προηγούμενη επιλογή,
+Email Details,Λεπτομέρειες email,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Επιλέξτε ένα χαιρετισμό για τον παραλήπτη. Π.χ. κύριε, κυρία κ.λπ.",
+Preview Email,Προεπισκόπηση email,
+Please select a Supplier,Επιλέξτε έναν προμηθευτή,
+Supplier Lead Time (days),Χρόνος προμηθευτή (ημέρες),
+"Home, Work, etc.","Σπίτι, εργασία κ.λπ.",
+Exit Interview Held On,Έξοδος από τη συνέντευξη,
+Condition and formula,Κατάσταση και τύπος,
+Sets 'Target Warehouse' in each row of the Items table.,Ορίζει το «Target Warehouse» σε κάθε σειρά του πίνακα αντικειμένων.,
+Sets 'Source Warehouse' in each row of the Items table.,Ορίζει το "Source Warehouse" σε κάθε σειρά του πίνακα αντικειμένων.,
+POS Register,Εγγραφή POS,
+"Can not filter based on POS Profile, if grouped by POS Profile","Δεν είναι δυνατή η φιλτράρισμα με βάση το προφίλ POS, εάν ομαδοποιούνται βάσει προφίλ POS",
+"Can not filter based on Customer, if grouped by Customer","Δεν είναι δυνατή η φιλτράρισμα με βάση τον πελάτη, εάν ομαδοποιούνται ανά πελάτη",
+"Can not filter based on Cashier, if grouped by Cashier","Δεν είναι δυνατή η φιλτράρισμα βάσει Ταμείου, εάν ομαδοποιούνται κατά Ταμείο",
+Payment Method,Μέθοδος πληρωμής,
+"Can not filter based on Payment Method, if grouped by Payment Method","Δεν είναι δυνατή η φιλτράρισμα βάσει της μεθόδου πληρωμής, εάν ομαδοποιούνται βάσει της μεθόδου πληρωμής",
+Supplier Quotation Comparison,Σύγκριση προσφορών προμηθευτή,
+Price per Unit (Stock UOM),Τιμή ανά μονάδα (απόθεμα UOM),
+Group by Supplier,Ομαδοποίηση ανά προμηθευτή,
+Group by Item,Ομαδοποίηση ανά αντικείμενο,
+Remember to set {field_label}. It is required by {regulation}.,Θυμηθείτε να ορίσετε το {field_label}. Απαιτείται από τον {κανονισμό}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Η ημερομηνία εγγραφής δεν μπορεί να είναι πριν από την ημερομηνία έναρξης του ακαδημαϊκού έτους {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Η ημερομηνία εγγραφής δεν μπορεί να είναι μετά την ημερομηνία λήξης του ακαδημαϊκού όρου {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Η ημερομηνία εγγραφής δεν μπορεί να είναι πριν από την ημερομηνία έναρξης του ακαδημαϊκού όρου {0},
+Future Posting Not Allowed,Δεν επιτρέπονται μελλοντικές δημοσιεύσεις,
+"To enable Capital Work in Progress Accounting, ","Για να ενεργοποιήσετε το Capital Work in Progress Accounting,",
+you must select Capital Work in Progress Account in accounts table,Πρέπει να επιλέξετε τον πίνακα Capital Work in Progress Account στον πίνακα λογαριασμών,
+You can also set default CWIP account in Company {},Μπορείτε επίσης να ορίσετε προεπιλεγμένο λογαριασμό CWIP στην Εταιρεία {},
+The Request for Quotation can be accessed by clicking on the following button,Μπορείτε να αποκτήσετε πρόσβαση στην Αίτηση Προσφοράς κάνοντας κλικ στο παρακάτω κουμπί,
+Regards,Χαιρετισμοί,
+Please click on the following button to set your new password,Κάντε κλικ στο παρακάτω κουμπί για να ορίσετε τον νέο σας κωδικό πρόσβασης,
+Update Password,Ενημέρωση κωδικού πρόσβασης,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Σειρά # {}: Το ποσοστό πώλησης για το στοιχείο {} είναι χαμηλότερο από το {}. Η πώληση {} πρέπει να είναι τουλάχιστον {},
+You can alternatively disable selling price validation in {} to bypass this validation.,"Εναλλακτικά, μπορείτε να απενεργοποιήσετε την επικύρωση τιμής πώλησης στο {} για να παρακάμψετε αυτήν την επικύρωση.",
+Invalid Selling Price,Μη έγκυρη τιμή πώλησης,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Η διεύθυνση πρέπει να συνδεθεί με μια εταιρεία. Προσθέστε μια σειρά για την εταιρεία στον πίνακα "Σύνδεσμοι".,
+Company Not Linked,Η εταιρεία δεν είναι συνδεδεμένη,
+Import Chart of Accounts from CSV / Excel files,Εισαγωγή γραφήματος λογαριασμών από αρχεία CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',Το ολοκληρωμένο Qty δεν μπορεί να είναι μεγαλύτερο από το "Qty to Manufacture",
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Σειρά {0}: Για τον προμηθευτή {1}, απαιτείται διεύθυνση ηλεκτρονικού ταχυδρομείου για την αποστολή email",
+"If enabled, the system will post accounting entries for inventory automatically","Εάν είναι ενεργοποιημένο, το σύστημα θα δημοσιεύσει αυτόματα λογιστικές καταχωρήσεις για το απόθεμα",
+Accounts Frozen Till Date,Λογαριασμοί Παγωμένοι Μέχρι την Ημερομηνία,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Οι λογιστικές εγγραφές έχουν παγώσει μέχρι αυτήν την ημερομηνία. Κανείς δεν μπορεί να δημιουργήσει ή να τροποποιήσει καταχωρήσεις εκτός από χρήστες με τον ρόλο που καθορίζεται παρακάτω,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Επιτρέπεται ο ρόλος για τον ορισμό παγωμένων λογαριασμών και την επεξεργασία παγωμένων καταχωρήσεων,
+Address used to determine Tax Category in transactions,Διεύθυνση που χρησιμοποιείται για τον προσδιορισμό της κατηγορίας φόρου στις συναλλαγές,
+"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 ","Το ποσοστό στο οποίο επιτρέπεται να χρεώνετε περισσότερα έναντι του παραγγελθέντος ποσού. Για παράδειγμα, εάν η τιμή παραγγελίας είναι 100 $ για ένα στοιχείο και η ανοχή έχει οριστεί ως 10%, τότε επιτρέπεται η χρέωση έως 110 $",
+This role is allowed to submit transactions that exceed credit limits,Αυτός ο ρόλος επιτρέπεται να υποβάλλει συναλλαγές που υπερβαίνουν τα πιστωτικά όρια,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Εάν επιλεγεί "Μήνες", ένα σταθερό ποσό θα καταχωρηθεί ως αναβαλλόμενο έσοδο ή έξοδο για κάθε μήνα, ανεξάρτητα από τον αριθμό των ημερών σε ένα μήνα. Θα αναλογεί εάν τα αναβαλλόμενα έσοδα ή έξοδα δεν δεσμευτούν για έναν ολόκληρο μήνα",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Εάν αυτό δεν είναι επιλεγμένο, θα δημιουργηθούν άμεσες καταχωρίσεις GL για την κράτηση αναβαλλόμενων εσόδων ή εξόδων",
+Show Inclusive Tax in Print,Εμφάνιση φόρου χωρίς αποκλεισμούς σε έντυπη μορφή,
+Only select this if you have set up the Cash Flow Mapper documents,Επιλέξτε αυτό μόνο εάν έχετε ρυθμίσει τα έγγραφα του Map Flow Mapper,
+Payment Channel,Κανάλι πληρωμών,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Απαιτείται εντολή αγοράς για αγορά τιμολογίου & δημιουργία απόδειξης;,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Απαιτείται απόδειξη αγοράς για τη δημιουργία τιμολογίου αγοράς;,
+Maintain Same Rate Throughout the Purchase Cycle,Διατηρήστε την ίδια τιμή καθ 'όλη τη διάρκεια του κύκλου αγοράς,
+Allow Item To Be Added Multiple Times in a Transaction,Να επιτρέπεται στο στοιχείο να προστίθεται πολλές φορές σε μια συναλλαγή,
+Suppliers,Προμηθευτές,
+Send Emails to Suppliers,Αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου σε προμηθευτές,
+Select a Supplier,Επιλέξτε έναν προμηθευτή,
+Cannot mark attendance for future dates.,Δεν είναι δυνατή η επισήμανση παρουσίας για μελλοντικές ημερομηνίες.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Θέλετε να ενημερώσετε τη συμμετοχή;<br> Παρόν: {0}<br> Απόντες: {1},
+Mpesa Settings,Ρυθμίσεις Mesa,
+Initiator Name,Όνομα εκκινητή,
+Till Number,Μέχρι τον αριθμό,
+Sandbox,Sandbox,
+ Online PassKey,Διαδικτυακό PassKey,
+Security Credential,Διαπιστευτήρια ασφαλείας,
+Get Account Balance,Λήψη υπολοίπου λογαριασμού,
+Please set the initiator name and the security credential,Ορίστε το όνομα του εκκινητή και τα διαπιστευτήρια ασφαλείας,
+Inpatient Medication Entry,Καταχώριση φαρμάκων σε ασθενείς,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Κωδικός είδους (ναρκωτικό),
+Medication Orders,Παραγγελίες φαρμάκων,
+Get Pending Medication Orders,Λάβετε εκκρεμείς παραγγελίες φαρμάκων,
+Inpatient Medication Orders,Παραγγελίες φαρμάκων σε ασθενείς,
+Medication Warehouse,Αποθήκη φαρμάκων,
+Warehouse from where medication stock should be consumed,Αποθήκη από την οποία πρέπει να καταναλωθεί το απόθεμα φαρμάκων,
+Fetching Pending Medication Orders,Λήψη εντολών φαρμάκων σε εκκρεμότητα,
+Inpatient Medication Entry Detail,Λεπτομέρεια καταχώρησης φαρμάκων σε ασθενείς,
+Medication Details,Λεπτομέρειες φαρμάκων,
+Drug Code,Κωδικός ναρκωτικών,
+Drug Name,Όνομα φαρμάκου,
+Against Inpatient Medication Order,Ενάντια στη διαταγή φαρμάκων σε ασθενείς,
+Against Inpatient Medication Order Entry,Κατά Καταχώριση Παραγγελίας Φαρμάκων σε Νοσοκομείο,
+Inpatient Medication Order,Παραγγελία για φάρμακα σε ασθενείς,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Σύνολο παραγγελιών,
+Completed Orders,Ολοκληρωμένες παραγγελίες,
+Add Medication Orders,Προσθήκη παραγγελιών φαρμάκων,
+Adding Order Entries,Προσθήκη καταχωρίσεων παραγγελίας,
+{0} medication orders completed,Ολοκληρώθηκαν {0} παραγγελίες φαρμάκων,
+{0} medication order completed,Η παραγγελία φαρμάκων ολοκληρώθηκε,
+Inpatient Medication Order Entry,Καταχώριση παραγγελίας φαρμάκων σε ασθενείς,
+Is Order Completed,Ολοκληρώθηκε η παραγγελία,
+Employee Records to Be Created By,Αρχεία υπαλλήλων που θα δημιουργηθούν από,
+Employee records are created using the selected field,Οι εγγραφές υπαλλήλων δημιουργούνται χρησιμοποιώντας το επιλεγμένο πεδίο,
+Don't send employee birthday reminders,Μην στέλνετε υπενθυμίσεις γενεθλίων υπαλλήλων,
+Restrict Backdated Leave Applications,Περιορισμός Εφαρμογών Άδειας με Ημερομηνίες,
+Sequence ID,Αναγνωριστικό ακολουθίας,
+Sequence Id,Αναγνωριστικό ακολουθίας,
+Allow multiple material consumptions against a Work Order,Επιτρέψτε πολλές υλικές καταναλώσεις σε σχέση με μια εντολή εργασίας,
+Plan time logs outside Workstation working hours,Προγραμματίστε αρχεία καταγραφής χρόνου εκτός των ωρών εργασίας σταθμών εργασίας,
+Plan operations X days in advance,Προγραμματίστε τις εργασίες X ημέρες νωρίτερα,
+Time Between Operations (Mins),Χρόνος μεταξύ λειτουργιών (λεπτά),
+Default: 10 mins,Προεπιλογή: 10 λεπτά,
+Overproduction for Sales and Work Order,Υπερπαραγωγή για πωλήσεις και παραγγελίες εργασίας,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Ενημερώστε αυτόματα το κόστος BOM μέσω χρονοπρογραμματιστή, με βάση το τελευταίο Ποσοστό Τιμής / Τιμοκατάλογος / Ποσοστό Τελευταίας Αγοράς πρώτων υλών",
+Purchase Order already created for all Sales Order items,Η παραγγελία αγοράς έχει ήδη δημιουργηθεί για όλα τα στοιχεία της παραγγελίας,
+Select Items,Επιλέξτε Είδη,
+Against Default Supplier,Ενάντια στον προεπιλεγμένο προμηθευτή,
+Auto close Opportunity after the no. of days mentioned above,Αυτόματο κλείσιμο Ευκαιρία μετά το όχι. των ημερών που αναφέρονται παραπάνω,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Απαιτείται παραγγελία πώλησης για τη δημιουργία τιμολογίου πωλήσεων και δημιουργίας σημειώσεων παράδοσης;,
+Is Delivery Note Required for Sales Invoice Creation?,Απαιτείται σημείωση παράδοσης για τη δημιουργία τιμολογίου πωλήσεων;,
+How often should Project and Company be updated based on Sales Transactions?,Πόσο συχνά πρέπει να ενημερώνεται το Έργο και η Εταιρεία με βάση τις Συναλλαγές Πωλήσεων;,
+Allow User to Edit Price List Rate in Transactions,Επιτρέψτε στο χρήστη να επεξεργάζεται το ποσοστό τιμοκαταλόγου στις συναλλαγές,
+Allow Item to Be Added Multiple Times in a Transaction,Επιτρέψτε στο στοιχείο να προστεθεί πολλές φορές σε μια συναλλαγή,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Να επιτρέπονται πολλαπλές παραγγελίες πωλήσεων έναντι εντολής αγοράς πελάτη,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Επικυρώστε την τιμή πώλησης για το στοιχείο έναντι του ποσοστού αγοράς ή του ποσοστού αποτίμησης,
+Hide Customer's Tax ID from Sales Transactions,Απόκρυψη φορολογικού αναγνωριστικού πελάτη από συναλλαγές πωλήσεων,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Το ποσοστό στο οποίο επιτρέπεται να λαμβάνετε ή να παραδίδετε περισσότερα έναντι της παραγγελίας. Για παράδειγμα, εάν έχετε παραγγείλει 100 μονάδες και το επίδομά σας είναι 10%, τότε σας επιτρέπεται να λαμβάνετε 110 μονάδες.",
+Action If Quality Inspection Is Not Submitted,Ενέργεια εάν δεν υποβληθεί έλεγχος ποιότητας,
+Auto Insert Price List Rate If Missing,Αυτόματη εισαγωγή τιμής τιμοκαταλόγου εάν λείπει,
+Automatically Set Serial Nos Based on FIFO,Αυτόματη ρύθμιση σειριακών αριθμών βάσει του FIFO,
+Set Qty in Transactions Based on Serial No Input,Ορίστε Ποσότητα σε Συναλλαγές βάσει Σειριακής Χωρίς Εισαγωγή,
+Raise Material Request When Stock Reaches Re-order Level,Αύξηση αιτήματος υλικού όταν το απόθεμα φτάσει στο επίπεδο επαναπαραγγελίας,
+Notify by Email on Creation of Automatic Material Request,Ειδοποίηση μέσω email για τη δημιουργία αυτόματου αιτήματος υλικού,
+Allow Material Transfer from Delivery Note to Sales Invoice,Να επιτρέπεται η μεταφορά υλικού από το σημείωμα παράδοσης στο τιμολόγιο πωλήσεων,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Να επιτρέπεται η μεταφορά υλικού από την απόδειξη αγοράς στο τιμολόγιο αγοράς,
+Freeze Stocks Older Than (Days),Παγώστε τα αποθέματα παλαιότερα από (ημέρες),
+Role Allowed to Edit Frozen Stock,Επιτρέπεται ο ρόλος για επεξεργασία του Frozen Stock,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Το μη κατανεμημένο ποσό της καταχώρισης πληρωμής {0} είναι μεγαλύτερο από το μη κατανεμημένο ποσό της τραπεζικής συναλλαγής,
+Payment Received,Η πληρωμή ελήφθη,
+Attendance cannot be marked outside of Academic Year {0},Η συμμετοχή δεν μπορεί να επισημανθεί εκτός του ακαδημαϊκού έτους {0},
+Student is already enrolled via Course Enrollment {0},Ο μαθητής έχει ήδη εγγραφεί μέσω εγγραφής μαθημάτων {0},
+Attendance cannot be marked for future dates.,Η συμμετοχή δεν μπορεί να επισημανθεί για μελλοντικές ημερομηνίες.,
+Please add programs to enable admission application.,Προσθέστε προγράμματα για να ενεργοποιήσετε την αίτηση εισδοχής.,
+The following employees are currently still reporting to {0}:,Οι ακόλουθοι υπάλληλοι εξακολουθούν να αναφέρουν στο {0}:,
+Please make sure the employees above report to another Active employee.,Βεβαιωθείτε ότι οι υπάλληλοι παραπάνω αναφέρουν σε άλλο ενεργό υπάλληλο.,
+Cannot Relieve Employee,Δεν είναι δυνατή η ανακούφιση του υπαλλήλου,
+Please enter {0},Εισαγάγετε {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Επιλέξτε έναν άλλο τρόπο πληρωμής. Το Mpesa δεν υποστηρίζει συναλλαγές σε νόμισμα "{0}",
+Transaction Error,Σφάλμα συναλλαγής,
+Mpesa Express Transaction Error,Σφάλμα συναλλαγής Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Εντοπίστηκε πρόβλημα με τη διαμόρφωση Mpesa, ελέγξτε τα αρχεία καταγραφής σφαλμάτων για περισσότερες λεπτομέρειες",
+Mpesa Express Error,Σφάλμα Mpesa Express,
+Account Balance Processing Error,Σφάλμα επεξεργασίας υπολοίπου λογαριασμού,
+Please check your configuration and try again,Ελέγξτε τη διαμόρφωσή σας και δοκιμάστε ξανά,
+Mpesa Account Balance Processing Error,Σφάλμα επεξεργασίας υπολοίπου λογαριασμού Mpesa,
+Balance Details,Λεπτομέρειες υπολοίπου,
+Current Balance,Τωρινή ισσοροπία,
+Available Balance,διαθέσιμο υπόλοιπο,
+Reserved Balance,Διατηρημένο Υπόλοιπο,
+Uncleared Balance,Ακαθάριστο Υπόλοιπο,
+Payment related to {0} is not completed,Η πληρωμή που σχετίζεται με το {0} δεν έχει ολοκληρωθεί,
+Row #{}: Item Code: {} is not available under warehouse {}.,Σειρά # {}: Κωδικός είδους: {} δεν είναι διαθέσιμος στην αποθήκη {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Σειρά # {}: Η ποσότητα του αποθέματος δεν επαρκεί για τον κωδικό είδους: {} κάτω από την αποθήκη {}. Διαθέσιμη ποσότητα {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Σειρά # {}: Επιλέξτε ένα σειριακό αριθμό και παρτίδα έναντι αντικειμένου: {} ή αφαιρέστε το για να ολοκληρώσετε τη συναλλαγή.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Σειρά # {}: Δεν έχει επιλεγεί σειριακός αριθμός έναντι αντικειμένου: {}. Επιλέξτε ένα ή αφαιρέστε το για να ολοκληρώσετε τη συναλλαγή.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Σειρά # {}: Δεν επιλέχθηκε παρτίδα έναντι αντικειμένου: {}. Επιλέξτε μια παρτίδα ή αφαιρέστε την για να ολοκληρώσετε τη συναλλαγή.,
+Payment amount cannot be less than or equal to 0,Το ποσό πληρωμής δεν μπορεί να είναι μικρότερο ή ίσο με 0,
+Please enter the phone number first,Εισαγάγετε πρώτα τον αριθμό τηλεφώνου,
+Row #{}: {} {} does not exist.,Η σειρά # {}: {} {} δεν υπάρχει.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Απαιτείται σειρά # {0}: {1} για τη δημιουργία των τιμολογίων έναρξης {2},
+You had {} errors while creating opening invoices. Check {} for more details,Είχατε {} σφάλματα κατά τη δημιουργία των τιμολογίων έναρξης. Ελέγξτε {} για περισσότερες λεπτομέρειες,
+Error Occured,Παρουσιάστηκε σφάλμα,
+Opening Invoice Creation In Progress,Άνοιγμα δημιουργίας τιμολογίου σε εξέλιξη,
+Creating {} out of {} {},Δημιουργία {} από {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Σειριακός αριθμός: {0}) δεν μπορεί να καταναλωθεί, καθώς πρόκειται για πλήρωση της παραγγελίας πωλήσεων {1}.",
+Item {0} {1},Στοιχείο {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Η τελευταία συναλλαγή μετοχών για το στοιχείο {0} υπό αποθήκη {1} πραγματοποιήθηκε στις {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Οι συναλλαγές μετοχών για το στοιχείο {0} υπό αποθήκη {1} δεν μπορούν να αναρτηθούν πριν από αυτήν την ώρα.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Δεν επιτρέπεται η δημοσίευση μελλοντικών συναλλαγών μετοχών λόγω του Αμετάβλητου Καθολικού,
+A BOM with name {0} already exists for item {1}.,Υπάρχει ήδη ένα BOM με όνομα {0} για το στοιχείο {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Μετονομάσατε το στοιχείο; Επικοινωνήστε με τον διαχειριστή / τεχνική υποστήριξη,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Στη σειρά # {0}: το αναγνωριστικό ακολουθίας {1} δεν μπορεί να είναι μικρότερο από το προηγούμενο αναγνωριστικό ακολουθίας σειράς {2},
+The {0} ({1}) must be equal to {2} ({3}),Το {0} ({1}) πρέπει να είναι ίσο με {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, ολοκληρώστε τη λειτουργία {1} πριν από τη λειτουργία {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Δεν είναι δυνατή η εξασφάλιση παράδοσης με αύξοντα αριθμό καθώς προστίθεται το στοιχείο {0} με και χωρίς τη διασφάλιση παράδοσης με αριθμό σειράς,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Το στοιχείο {0} δεν έχει αριθμό σειράς. Μόνο τα σειριακά στοιχεία μπορούν να έχουν παράδοση με βάση τον αριθμό σειράς,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Δεν βρέθηκε ενεργό BOM για το στοιχείο {0}. Η παράδοση με αύξοντα αριθμό δεν μπορεί να διασφαλιστεί,
+No pending medication orders found for selected criteria,Δεν βρέθηκαν εκκρεμείς παραγγελίες φαρμάκων για επιλεγμένα κριτήρια,
+From Date cannot be after the current date.,Η ημερομηνία δεν μπορεί να είναι μετά την τρέχουσα ημερομηνία.,
+To Date cannot be after the current date.,To Date δεν μπορεί να είναι μετά την τρέχουσα ημερομηνία.,
+From Time cannot be after the current time.,Από την ώρα δεν μπορεί να είναι μετά την τρέχουσα ώρα.,
+To Time cannot be after the current time.,Το Time δεν μπορεί να είναι μετά την τρέχουσα ώρα.,
+Stock Entry {0} created and ,Η καταχώριση μετοχής {0} δημιουργήθηκε και,
+Inpatient Medication Orders updated successfully,Οι παραγγελίες φαρμάκων εντός ασθενών ενημερώθηκαν με επιτυχία,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Σειρά {0}: Δεν είναι δυνατή η δημιουργία καταχώρησης φαρμάκων για εσωτερικούς ασθενείς έναντι ακυρωμένης παραγγελίας φαρμάκων για εσωτερικούς ασθενείς {1},
+Row {0}: This Medication Order is already marked as completed,Σειρά {0}: Αυτή η παραγγελία φαρμάκων έχει ήδη επισημανθεί ως ολοκληρωμένη,
+Quantity not available for {0} in warehouse {1},Η ποσότητα δεν είναι διαθέσιμη για {0} στην αποθήκη {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Ενεργοποιήστε το Allow Negative Stock σε Stock Settings ή δημιουργήστε Stock Entry για να συνεχίσετε.,
+No Inpatient Record found against patient {0},Δεν βρέθηκε αρχείο εσωτερικών ασθενών κατά του ασθενούς {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Υπάρχει ήδη μια Εντολή Φαρμάκων Ενδονοσοκομειακών Θεμάτων {0} εναντίον Ασθενών {1}.,
+Allow In Returns,Να επιτρέπεται η επιστροφή,
+Hide Unavailable Items,Απόκρυψη μη διαθέσιμων στοιχείων,
+Apply Discount on Discounted Rate,Εφαρμόστε έκπτωση σε μειωμένη τιμή,
+Therapy Plan Template,Πρότυπο σχεδίου θεραπείας,
+Fetching Template Details,Λήψη λεπτομερειών προτύπου,
+Linked Item Details,Λεπτομέρειες συνδεδεμένου στοιχείου,
+Therapy Types,Τύποι θεραπείας,
+Therapy Plan Template Detail,Λεπτομέρεια προτύπου σχεδίου θεραπείας,
+Non Conformance,Μη συμμόρφωση,
+Process Owner,Κάτοχος διαδικασίας,
+Corrective Action,Διορθωτικά μέτρα,
+Preventive Action,Προληπτική δράση,
+Problem,Πρόβλημα,
+Responsible,Υπεύθυνος,
+Completion By,Ολοκλήρωση από,
+Process Owner Full Name,Πλήρες όνομα κατόχου διαδικασίας,
+Right Index,Δεξί ευρετήριο,
+Left Index,Αριστερός δείκτης,
+Sub Procedure,Υπο διαδικασία,
+Passed,Πέρασε,
+Print Receipt,Εκτύπωση απόδειξης,
+Edit Receipt,Επεξεργασία απόδειξης,
+Focus on search input,Εστίαση στην είσοδο αναζήτησης,
+Focus on Item Group filter,Εστίαση στο φίλτρο ομάδας στοιχείων,
+Checkout Order / Submit Order / New Order,Παραγγελία Παραγγελίας / Υποβολή Παραγγελίας / Νέα Παραγγελία,
+Add Order Discount,Προσθήκη έκπτωσης παραγγελίας,
+Item Code: {0} is not available under warehouse {1}.,Κωδικός είδους: {0} δεν είναι διαθέσιμο στην αποθήκη {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Οι σειριακοί αριθμοί δεν είναι διαθέσιμοι για το στοιχείο {0} υπό αποθήκη {1}. Δοκιμάστε να αλλάξετε την αποθήκη.,
+Fetched only {0} available serial numbers.,Λήψη μόνο {0} διαθέσιμων σειριακών αριθμών.,
+Switch Between Payment Modes,Εναλλαγή μεταξύ τρόπων πληρωμής,
+Enter {0} amount.,Εισαγάγετε το ποσό {0}.,
+You don't have enough points to redeem.,Δεν έχετε αρκετούς πόντους για εξαργύρωση.,
+You can redeem upto {0}.,Μπορείτε να εξαργυρώσετε έως και {0}.,
+Enter amount to be redeemed.,Εισαγάγετε το ποσό που θα εξαργυρωθεί.,
+You cannot redeem more than {0}.,Δεν μπορείτε να εξαργυρώσετε περισσότερα από {0}.,
+Open Form View,Άνοιγμα προβολής φόρμας,
+POS invoice {0} created succesfully,Το τιμολόγιο POS {0} δημιουργήθηκε με επιτυχία,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Η ποσότητα αποθεμάτων δεν επαρκεί για τον κωδικό είδους: {0} υπό αποθήκη {1}. Διαθέσιμη ποσότητα {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Σειριακός αριθμός: Το {0} έχει ήδη πραγματοποιηθεί συναλλαγή σε άλλο τιμολόγιο POS.,
+Balance Serial No,Υπόλοιπος αριθμός σειράς,
+Warehouse: {0} does not belong to {1},Αποθήκη: {0} δεν ανήκει στο {1},
+Please select batches for batched item {0},Επιλέξτε παρτίδες για παρτίδες {0},
+Please select quantity on row {0},Επιλέξτε ποσότητα στη σειρά {0},
+Please enter serial numbers for serialized item {0},Εισαγάγετε σειριακούς αριθμούς για σειριακό στοιχείο {0},
+Batch {0} already selected.,Η παρτίδα {0} έχει ήδη επιλεγεί.,
+Please select a warehouse to get available quantities,Επιλέξτε αποθήκη για να λάβετε διαθέσιμες ποσότητες,
+"For transfer from source, selected quantity cannot be greater than available quantity","Για μεταφορά από την πηγή, η επιλεγμένη ποσότητα δεν μπορεί να είναι μεγαλύτερη από τη διαθέσιμη ποσότητα",
+Cannot find Item with this Barcode,Δεν είναι δυνατή η εύρεση αντικειμένου με αυτόν τον γραμμικό κώδικα,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},Το {0} είναι υποχρεωτικό. Ίσως η εγγραφή συναλλάγματος δεν έχει δημιουργηθεί για {1} έως {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,Ο χρήστης {} έχει υποβάλει στοιχεία που συνδέονται με αυτό. Πρέπει να ακυρώσετε τα στοιχεία για να δημιουργήσετε επιστροφή αγοράς.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Δεν είναι δυνατή η ακύρωση αυτού του εγγράφου καθώς συνδέεται με το υποβληθέν στοιχείο {0}. Ακυρώστε το για να συνεχίσετε.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Σειρά # {}: Ο αριθμός σειράς {} έχει ήδη πραγματοποιηθεί συναλλαγή σε άλλο τιμολόγιο POS. Επιλέξτε έγκυρο αύξοντα αριθμό.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Σειρά # {}: Οι σειριακοί αριθμοί. {} Έχουν ήδη πραγματοποιηθεί συναλλαγές σε άλλο τιμολόγιο POS. Επιλέξτε έγκυρο αύξοντα αριθμό.,
+Item Unavailable,Το στοιχείο δεν είναι διαθέσιμο,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Σειρά # {}: Ο αριθμός σειράς {} δεν μπορεί να επιστραφεί επειδή δεν πραγματοποιήθηκε συναλλαγή στο αρχικό τιμολόγιο {},
+Please set default Cash or Bank account in Mode of Payment {},Ορίστε τον προεπιλεγμένο μετρητά ή τραπεζικό λογαριασμό στον τρόπο πληρωμής {},
+Please set default Cash or Bank account in Mode of Payments {},Ορίστε τον προεπιλεγμένο μετρητά ή τον τραπεζικό λογαριασμό στη λειτουργία πληρωμής {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Βεβαιωθείτε ότι ο λογαριασμός {} είναι λογαριασμός ισολογισμού. Μπορείτε να αλλάξετε τον γονικό λογαριασμό σε λογαριασμό Ισολογισμού ή να επιλέξετε διαφορετικό λογαριασμό.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Βεβαιωθείτε ότι ο λογαριασμός {} είναι λογαριασμός πληρωτέος. Αλλάξτε τον τύπο λογαριασμού σε Πληρωτέο ή επιλέξτε διαφορετικό λογαριασμό.,
+Row {}: Expense Head changed to {} ,Σειρά {}: Η κεφαλή εξόδων άλλαξε σε {},
+because account {} is not linked to warehouse {} ,επειδή ο λογαριασμός {} δεν είναι συνδεδεμένος με αποθήκη {},
+or it is not the default inventory account,ή δεν είναι ο προεπιλεγμένος λογαριασμός αποθέματος,
+Expense Head Changed,Η κεφαλή εξόδων άλλαξε,
+because expense is booked against this account in Purchase Receipt {},επειδή τα έξοδα καταγράφονται σε αυτόν τον λογαριασμό στην απόδειξη αγοράς {},
+as no Purchase Receipt is created against Item {}. ,καθώς δεν δημιουργείται απόδειξη αγοράς έναντι αντικειμένου {},
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Αυτό γίνεται για τον χειρισμό της λογιστικής για περιπτώσεις στις οποίες δημιουργείται απόδειξη αγοράς μετά το τιμολόγιο αγοράς,
+Purchase Order Required for item {},Απαιτείται παραγγελία αγοράς για το στοιχείο {},
+To submit the invoice without purchase order please set {} ,"Για να υποβάλετε το τιμολόγιο χωρίς εντολή αγοράς, ορίστε {}",
+as {} in {},όπως λέμε {},
+Mandatory Purchase Order,Υποχρεωτική εντολή αγοράς,
+Purchase Receipt Required for item {},Απαιτείται απόδειξη αγοράς για το στοιχείο {},
+To submit the invoice without purchase receipt please set {} ,"Για να υποβάλετε το τιμολόγιο χωρίς απόδειξη αγοράς, ορίστε {}",
+Mandatory Purchase Receipt,Υποχρεωτική απόδειξη αγοράς,
+POS Profile {} does not belongs to company {},Το προφίλ POS {} δεν ανήκει στην εταιρεία {},
+User {} is disabled. Please select valid user/cashier,Ο χρήστης {} είναι απενεργοποιημένος. Επιλέξτε έγκυρο χρήστη / ταμία,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Σειρά # {}: Το αρχικό τιμολόγιο {} του τιμολογίου επιστροφής {} είναι {}.,
+Original invoice should be consolidated before or along with the return invoice.,Το αρχικό τιμολόγιο πρέπει να ενοποιείται πριν ή μαζί με το τιμολόγιο επιστροφής.,
+You can add original invoice {} manually to proceed.,Μπορείτε να προσθέσετε το αρχικό τιμολόγιο {} μη αυτόματα για να συνεχίσετε.,
+Please ensure {} account is a Balance Sheet account. ,Βεβαιωθείτε ότι ο λογαριασμός {} είναι λογαριασμός ισολογισμού.,
+You can change the parent account to a Balance Sheet account or select a different account.,Μπορείτε να αλλάξετε τον γονικό λογαριασμό σε λογαριασμό Ισολογισμού ή να επιλέξετε διαφορετικό λογαριασμό.,
+Please ensure {} account is a Receivable account. ,Βεβαιωθείτε ότι ο λογαριασμός {} είναι λογαριασμός εισπρακτέος.,
+Change the account type to Receivable or select a different account.,Αλλάξτε τον τύπο λογαριασμού σε Εισπρακτέο ή επιλέξτε διαφορετικό λογαριασμό.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},Το {} δεν μπορεί να ακυρωθεί αφού εξαργυρωθούν οι πόντοι επιβράβευσης που αποκτήθηκαν. Πρώτα ακυρώστε το {} Όχι {},
+already exists,υπάρχει ήδη,
+POS Closing Entry {} against {} between selected period,POS Κλείσιμο καταχώρισης {} εναντίον {} μεταξύ της επιλεγμένης περιόδου,
+POS Invoice is {},Το τιμολόγιο POS είναι {},
+POS Profile doesn't matches {},Το προφίλ POS δεν ταιριάζει {},
+POS Invoice is not {},Το τιμολόγιο POS δεν είναι {},
+POS Invoice isn't created by user {},Το τιμολόγιο POS δεν έχει δημιουργηθεί από τον χρήστη {},
+Row #{}: {},Σειρά # {}: {},
+Invalid POS Invoices,Μη έγκυρα τιμολόγια POS,
+Please add the account to root level Company - {},Προσθέστε τον λογαριασμό στο ριζικό επίπεδο Εταιρεία - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Κατά τη δημιουργία λογαριασμού για την θυγατρική εταιρεία {0}, ο γονικός λογαριασμός {1} δεν βρέθηκε. Δημιουργήστε τον γονικό λογαριασμό στο αντίστοιχο COA",
+Account Not Found,Ο λογαριασμός δεν βρέθηκε,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Κατά τη δημιουργία λογαριασμού για την θυγατρική εταιρεία {0}, ο γονικός λογαριασμός {1} βρέθηκε ως λογαριασμός καθολικού.",
+Please convert the parent account in corresponding child company to a group account.,Μετατρέψτε τον γονικό λογαριασμό στην αντίστοιχη θυγατρική εταιρεία σε λογαριασμό ομάδας.,
+Invalid Parent Account,Μη έγκυρος γονικός λογαριασμός,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Η μετονομασία επιτρέπεται μόνο μέσω της μητρικής εταιρείας {0}, για την αποφυγή αναντιστοιχίας.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Εάν {0} {1} ποσότητες του αντικειμένου {2}, το σχήμα {3} θα εφαρμοστεί στο στοιχείο.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Εάν {0} {1} αξίζετε το στοιχείο {2}, το σχήμα {3} θα εφαρμοστεί στο στοιχείο.",
+"As the field {0} is enabled, the field {1} is mandatory.","Καθώς το πεδίο {0} είναι ενεργοποιημένο, το πεδίο {1} είναι υποχρεωτικό.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Καθώς το πεδίο {0} είναι ενεργοποιημένο, η τιμή του πεδίου {1} θα πρέπει να είναι μεγαλύτερη από 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Δεν είναι δυνατή η παράδοση του σειριακού αριθμού {0} του στοιχείου {1}, καθώς προορίζεται για την πλήρωση της παραγγελίας πωλήσεων {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Η παραγγελία πωλήσεων {0} έχει κράτηση για το αντικείμενο {1}, μπορείτε να παραδώσετε μόνο την κράτηση {1} έναντι {0}.",
+{0} Serial No {1} cannot be delivered,Δεν είναι δυνατή η παράδοση του {0} σειριακού αριθμού {1},
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Σειρά {0}: Το αντικείμενο υπεργολαβίας είναι υποχρεωτικό για την πρώτη ύλη {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Δεδομένου ότι υπάρχουν επαρκείς πρώτες ύλες, δεν απαιτείται αίτημα υλικού για αποθήκη {0}.",
+" If you still want to proceed, please enable {0}.","Εάν εξακολουθείτε να θέλετε να συνεχίσετε, ενεργοποιήστε το {0}.",
+The item referenced by {0} - {1} is already invoiced,Το στοιχείο που αναφέρεται από {0} - {1} έχει ήδη τιμολογηθεί,
+Therapy Session overlaps with {0},Η συνεδρία θεραπείας αλληλεπικαλύπτεται με {0},
+Therapy Sessions Overlapping,Συνεδρίες συνεδρίας,
+Therapy Plans,Σχέδια θεραπείας,
+"Item Code, warehouse, quantity are required on row {0}","Κωδικός είδους, αποθήκη, ποσότητα απαιτείται στη σειρά {0}",
+Get Items from Material Requests against this Supplier,Λάβετε στοιχεία από αιτήματα υλικών έναντι αυτού του προμηθευτή,
+Enable European Access,Ενεργοποίηση ευρωπαϊκής πρόσβασης,
+Creating Purchase Order ...,Δημιουργία παραγγελίας αγοράς ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Επιλέξτε έναν προμηθευτή από τους προεπιλεγμένους προμηθευτές των παρακάτω στοιχείων. Κατά την επιλογή, μια εντολή αγοράς θα πραγματοποιείται έναντι αντικειμένων που ανήκουν στον επιλεγμένο Προμηθευτή μόνο.",
+Row #{}: You must select {} serial numbers for item {}.,Σειρά # {}: Πρέπει να επιλέξετε {} σειριακούς αριθμούς για το στοιχείο {}.,
diff --git a/erpnext/translations/es.csv b/erpnext/translations/es.csv
index 08b3900..0f2259d 100644
--- a/erpnext/translations/es.csv
+++ b/erpnext/translations/es.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},El tipo de impuesto real no puede incluirse en la tarifa del artículo en la fila {0},
Add,Agregar,
Add / Edit Prices,Añadir / editar precios,
-Add All Suppliers,Añadir todos los proveedores,
Add Comment,Agregar comentario,
Add Customers,Agregar Clientes,
Add Employees,Añadir empleados,
@@ -118,7 +117,7 @@
Add Items,Añadir los artículos,
Add Leads,Añadir Prospectos,
Add Multiple Tasks,Agregar Tareas Múltiples,
-Add Row,Añadir fila,
+Add Row,Añadir Fila,
Add Sales Partners,Añadir socios de ventas,
Add Serial No,Agregar No. de serie,
Add Students,Añadir estudiantes,
@@ -422,7 +421,7 @@
Bundle items at time of sale.,Agrupe elementos al momento de la venta.,
Business Development Manager,Gerente de Desarrollo de Negocios,
Buy,Comprar,
-Buying,Comprando,
+Buying,Compras,
Buying Amount,Importe de compra,
Buying Price List,Lista de precios de compra,
Buying Rate,Tipo de Cambio de Compra,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"No se puede deducir cuando la categoría es 'de Valoración ""o"" Vaulation y Total'",
"Cannot delete Serial No {0}, as it is used in stock transactions","No se puede eliminar el No. de serie {0}, ya que esta siendo utilizado en transacciones de stock",
Cannot enroll more than {0} students for this student group.,No se puede inscribir más de {0} estudiantes para este grupo de estudiantes.,
-Cannot find Item with this barcode,No se puede encontrar el artículo con este código de barras,
Cannot find active Leave Period,No se puede encontrar el Período de permiso activo,
Cannot produce more Item {0} than Sales Order quantity {1},No se puede producir una cantidad mayor del producto {0} que lo requerido en el pedido de venta {1},
Cannot promote Employee with status Left,No se puede promocionar Empleado con estado dejado,
Cannot refer row number greater than or equal to current row number for this Charge type,No se puede referenciar a una línea mayor o igual al numero de línea actual.,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,No se puede seleccionar el tipo de cargo como 'Importe de línea anterior' o ' Total de línea anterior' para la primera linea,
-Cannot set a received RFQ to No Quote,No se puede establecer una Solicitud de Cotización (RFQ= recibida sin ninguna Cotización,
Cannot set as Lost as Sales Order is made.,"No se puede definir como pérdida, cuando la orden de venta esta hecha.",
Cannot set authorization on basis of Discount for {0},No se puede establecer la autorización sobre la base de descuento para {0},
Cannot set multiple Item Defaults for a company.,No se pueden establecer varios valores predeterminados de artículos para una empresa.,
@@ -521,7 +518,6 @@
Chargeble,Cobrable,
Charges are updated in Purchase Receipt against each item,Los cargos se actualizan en el recibo de compra por cada producto,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Los cargos se distribuirán proporcionalmente basados en la cantidad o importe, según selección",
-Chart Of Accounts,Plan de cuentas,
Chart of Cost Centers,Centros de costos,
Check all,Marcar todas,
Checkout,Pedido,
@@ -539,7 +535,7 @@
Claimed Amount,Cantidad reclamada,
Clay,Arcilla,
Clear filters,Filtros claros,
-Clear values,Valores claros,
+Clear values,Quitar valores,
Clearance Date,Fecha de liquidación,
Clearance Date not mentioned,Fecha de liquidación no definida,
Clearance Date updated,Fecha de liquidación actualizada,
@@ -581,7 +577,6 @@
Compensatory Off,Compensatorio,
Compensatory leave request days not in valid holidays,Días de solicitud de permiso compensatorio no en días feriados válidos,
Complaint,Queja,
-Completed Qty can not be greater than 'Qty to Manufacture',La cantidad completada no puede ser mayor que la cantidad a manufacturar.,
Completion Date,Fecha de finalización,
Computer,Computadora,
Condition,Condición,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Crear y gestionar resúmenes de correos; diarios, semanales y mensuales.",
Create customer quotes,Crear cotizaciones de clientes,
Create rules to restrict transactions based on values.,Crear reglas para restringir las transacciones basadas en valores.,
-Created By,Creado por,
Created {0} scorecards for {1} between: ,Creó {0} tarjetas de puntuación para {1} entre:,
Creating Company and Importing Chart of Accounts,Creación de empresa e importación de plan de cuentas,
Creating Fees,Creación de Tarifas,
@@ -734,7 +728,7 @@
Current Qty,Cant. Actual,
Current invoice {0} is missing,La factura actual {0} falta,
Custom HTML,HTML Personalizado,
-Custom?,Personalizado?,
+Custom?,¿Personalizado?,
Customer,Cliente,
Customer Addresses And Contacts,Direcciones de clientes y contactos,
Customer Contact,Contacto del Cliente,
@@ -789,7 +783,7 @@
Default BOM ({0}) must be active for this item or its template,La lista de materiales (LdM) por defecto ({0}) debe estar activa para este producto o plantilla,
Default BOM for {0} not found,BOM por defecto para {0} no encontrado,
Default BOM not found for Item {0} and Project {1},La lista de materiales predeterminada no se encontró para el Elemento {0} y el Proyecto {1},
-Default Letter Head,Encabezado predeterminado,
+Default Letter Head,Encabezado Predeterminado,
Default Tax Template,Plantilla de impuesto predeterminado,
Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.,Unidad de medida predeterminada para el artículo {0} no se puede cambiar directamente porque ya ha realizado alguna transacción (s) con otra UOM. Usted tendrá que crear un nuevo elemento a utilizar un UOM predeterminado diferente.,
Default Unit of Measure for Variant '{0}' must be same as in Template '{1}',Unidad de medida predeterminada para variante '{0}' debe ser la mismo que en la plantilla '{1}',
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,La transferencia del empleado no se puede enviar antes de la fecha de transferencia,
Employee cannot report to himself.,El empleado no puede informar a sí mismo.,
Employee relieved on {0} must be set as 'Left',"Empleado relevado en {0} debe definirse como ""izquierda""",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,El estado del empleado no se puede establecer en 'Izquierda' ya que los siguientes empleados están informando actualmente a este empleado:,
Employee {0} already submited an apllication {1} for the payroll period {2},El Empleado {0} ya envió una Aplicación {1} para el período de nómina {2},
Employee {0} has already applied for {1} between {2} and {3} : ,El empleado {0} ya ha solicitado {1} entre {2} y {3}:,
Employee {0} has no maximum benefit amount,El Empleado {0} no tiene una cantidad de beneficio máximo,
@@ -973,7 +966,7 @@
Error Log,Registro de Errores,
Error evaluating the criteria formula,Error al evaluar la fórmula de criterios,
Error in formula or condition: {0},Error Fórmula o Condición: {0},
-Error: Not a valid id?,Error: No es un ID válido?,
+Error: Not a valid id?,Error: ¿No es un ID válido?,
Estimated Cost,Costo estimado,
Evaluation,Evaluación,
"Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:","Incluso si hay varias reglas de precios con mayor prioridad, se aplican entonces siguientes prioridades internas:",
@@ -1025,7 +1018,7 @@
Fee Creation Failed,Error en la Creación de Cuotas,
Fee Creation Pending,Creación de Cuotas Pendientes,
Fee Records Created - {0},Registros de cuotas creados - {0},
-Feedback,Comentarios.,
+Feedback,Retroalimentación,
Fees,Matrícula,
Female,Femenino,
Fetch Data,Obtener datos,
@@ -1050,7 +1043,7 @@
Finished Goods,Productos terminados,
Finished Item {0} must be entered for Manufacture type entry,El producto terminado {0} debe ser introducido para el tipo de producción,
Finished product quantity <b>{0}</b> and For Quantity <b>{1}</b> cannot be different,La cantidad de productos terminados <b>{0}</b> y Por cantidad <b>{1}</b> no puede ser diferente,
-First Name,Nombre,
+First Name,Primer Nombre,
"Fiscal Regime is mandatory, kindly set the fiscal regime in the company {0}","El régimen fiscal es obligatorio, establezca amablemente el régimen fiscal en la empresa {0}",
Fiscal Year,Año fiscal,
Fiscal Year End Date should be one year after Fiscal Year Start Date,La fecha de finalización del año fiscal debe ser un año después de la fecha de inicio del año fiscal,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Para la fila {0}: ingrese cantidad planificada,
"For {0}, only credit accounts can be linked against another debit entry","Para {0}, sólo las cuentas de crédito se pueden vincular con un asiento de débito",
"For {0}, only debit accounts can be linked against another credit entry","Para {0}, sólo las cuentas de débito pueden vincular con un asiento de crédito",
-Form View,Vista de formulario,
Forum Activity,Actividad del foro,
Free item code is not selected,El código de artículo gratuito no está seleccionado,
Freight and Forwarding Charges,CARGOS DE TRANSITO Y TRANSPORTE,
@@ -1346,7 +1338,7 @@
Issued,Emitido,
Issues,Incidencias,
It is needed to fetch Item Details.,Se necesita a buscar Detalles del artículo.,
-Item,Productos,
+Item,Producto,
Item 1,Elemento 1,
Item 2,Elemento 2,
Item 3,Elemento 3,
@@ -1434,7 +1426,7 @@
Last Purchase Rate,Tasa de cambio de última compra,
Latest,Más reciente,
Latest price updated in all BOMs,Último precio actualizado en todas las Listas de Materiales,
-Lead,Dirigir,
+Lead,Iniciativa,
Lead Count,Cuenta de Iniciativa,
Lead Owner,Propietario de la iniciativa,
Lead Owner cannot be same as the Lead,Propietario de Iniciativa no puede ser igual que el de la Iniciativa,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","La licencia no puede asignarse antes de {0}, ya que el saldo de vacaciones ya se ha arrastrado en el futuro registro de asignación de vacaciones {1}.",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","La licencia no puede aplicarse o cancelarse antes de {0}, ya que el saldo de vacaciones ya se ha arrastrado en el futuro registro de asignación de vacaciones {1}.",
Leave of type {0} cannot be longer than {1},Ausencia del tipo {0} no puede tener más de {1},
-Leave the field empty to make purchase orders for all suppliers,Deje el campo vacío para hacer pedidos de compra para todos los proveedores,
Leaves,Hojas,
Leaves Allocated Successfully for {0},Vacaciones Distribuidas Satisfactoriamente para {0},
Leaves has been granted sucessfully,Hojas se ha otorgado con éxito,
@@ -1544,7 +1535,7 @@
Mark Half Day,Marcar medio día,
Mark Present,Marcar Presente,
Marketing,Márketing,
-Marketing Expenses,GASTOS DE PUBLICIDAD,
+Marketing Expenses,Gastos de Publicidad,
Marketplace,Mercado,
Marketplace Error,Error de Marketplace,
Masters,Maestros,
@@ -1601,7 +1592,7 @@
Message Sent,Mensaje enviado,
Method,Método,
Middle Income,Ingreso medio,
-Middle Name,Segundo nombre,
+Middle Name,Segundo Nombre,
Middle Name (Optional),Segundo nombre (Opcional),
Min Amt can not be greater than Max Amt,La cantidad mínima no puede ser mayor que la cantidad máxima,
Min Qty can not be greater than Max Qty,La cantidad mínima no puede ser mayor que la cantidad maxima,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,No hay artículos con la lista de materiales para la fabricación de,
No Items with Bill of Materials.,No hay artículos con lista de materiales.,
No Permission,Sin permiso,
-No Quote,Sin cotización,
No Remarks,No hay observaciones,
No Result to submit,No hay resultados para enviar,
No Salary Structure assigned for Employee {0} on given date {1},Sin estructura salarial asignada para el empleado {0} en una fecha dada {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Condiciones traslapadas entre:,
Owner,Propietario,
PAN,PAN,
-PO already created for all sales order items,PO ya creado para todos los artículos de pedido de venta,
POS,Punto de venta POS,
POS Profile,Perfil de POS,
POS Profile is required to use Point-of-Sale,Se requiere el Perfil POS para usar el Punto de Venta,
@@ -1878,7 +1867,7 @@
Part-time,Tiempo parcial,
Partially Depreciated,Despreciables Parcialmente,
Partially Received,Parcialmente recibido,
-Party,Partido,
+Party,Tercero,
Party Name,Nombre de Parte,
Party Type,Tipo de entidad,
Party Type and Party is mandatory for {0} account,Tipo de Tercero y Tercero es obligatorio para la Cuenta {0},
@@ -2033,13 +2022,12 @@
Please select Charge Type first,"Por favor, seleccione primero el tipo de cargo",
Please select Company,"Por favor, seleccione la empresa",
Please select Company and Designation,Seleccione Compañía y Designación,
-Please select Company and Party Type first,"Por favor, seleccione la compañía y el tipo de entidad",
Please select Company and Posting Date to getting entries,Seleccione Empresa y Fecha de publicación para obtener entradas,
Please select Company first,"Por favor, seleccione primero la compañía",
Please select Completion Date for Completed Asset Maintenance Log,Seleccione Fecha de Finalización para el Registro de Mantenimiento de Activos Completado,
Please select Completion Date for Completed Repair,Seleccione Fecha de Finalización para la Reparación Completa,
Please select Course,Por favor seleccione Curso,
-Please select Drug,Seleccione Droga,
+Please select Drug,Por favor seleccione fármaco,
Please select Employee,Por favor selecciona Empleado,
Please select Existing Company for creating Chart of Accounts,"Por favor, seleccione empresa ya existente para la creación del plan de cuentas",
Please select Healthcare Service,Por favor seleccione Servicio de Salud,
@@ -2130,7 +2118,7 @@
Please supply the specified items at the best possible rates,Por favor suministrar los elementos especificados en las mejores tasas posibles,
Please update your status for this training event,Actualice su estado para este evento de capacitación.,
Please wait 3 days before resending the reminder.,Espere 3 días antes de volver a enviar el recordatorio.,
-Point of Sale,Punto de venta,
+Point of Sale,Punto de Venta,
Point-of-Sale,Punto de Venta (POS),
Point-of-Sale Profile,Perfiles de punto de venta (POS),
Portal,Portal,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Línea {0}: El factor de conversión de (UdM) es obligatorio,
Row {0}: select the workstation against the operation {1},Fila {0}: seleccione la estación de trabajo contra la operación {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Fila {0}: {1} Números de serie necesarios para el elemento {2}. Ha proporcionado {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Fila {0}: {1} es necesaria para crear las facturas de apertura {2},
Row {0}: {1} must be greater than 0,Fila {0}: {1} debe ser mayor que 0,
Row {0}: {1} {2} does not match with {3},Línea {0}: {1} {2} no coincide con {3},
Row {0}:Start Date must be before End Date,Línea {0}: La fecha de inicio debe ser anterior fecha de finalización,
@@ -2566,8 +2553,8 @@
Sanctioned Amount,Monto sancionado,
Sanctioned Amount cannot be greater than Claim Amount in Row {0}.,Importe sancionado no puede ser mayor que el importe del reclamo en la línea {0}.,
Sand,Arena,
-Saturday,Sábado.,
-Saved,Guardado.,
+Saturday,Sábado,
+Saved,Guardado,
Saving {0},Guardando {0},
Scan Barcode,Escanear Código de Barras,
Schedule,Programa,
@@ -2640,16 +2627,14 @@
Selling,Ventas,
Selling Amount,Cantidad de venta,
Selling Price List,Lista de precios de venta,
-Selling Rate,Tasa de ventas,
+Selling Rate,Precio de venta,
"Selling must be checked, if Applicable For is selected as {0}","'Ventas' debe ser seleccionada, si la opción: 'Aplicable para' esta seleccionado como {0}",
Send Grant Review Email,Enviar correo electrónico de revisión de subvención,
Send Now,Enviar ahora,
Send SMS,Enviar mensaje SMS,
-Send Supplier Emails,Enviar mensajes de correo electrónico al proveedor,
Send mass SMS to your contacts,Enviar mensajes SMS masivos a sus contactos,
Sensitivity,Sensibilidad,
Sent,Enviado,
-Serial #,Serial #.,
Serial No and Batch,Número de serie y de lote,
Serial No is mandatory for Item {0},No. de serie es obligatoria para el producto {0},
Serial No {0} does not belong to Batch {1},El número de serie {0} no pertenece al lote {1},
@@ -2715,9 +2700,9 @@
Setup default values for POS Invoices,Configurar los valores predeterminados para facturas de POS,
Setup mode of POS (Online / Offline),Modo de configuración de POS (Online / Offline),
Setup your Institute in ERPNext,Configura tu instituto en ERPNext,
-Share Balance,Compartir Saldo,
+Share Balance,Balance de Acciones,
Share Ledger,Share Ledger,
-Share Management,Gestión de Compartir,
+Share Management,Administración de Acciones,
Share Transfer,Transferir Acciones,
Share Type,Tipo de acción,
Shareholder,Accionista,
@@ -2882,7 +2867,7 @@
Summary,Resumen,
Summary for this month and pending activities,Resumen para este mes y actividades pendientes,
Summary for this week and pending activities,Resumen para esta semana y actividades pendientes,
-Sunday,Domingo.,
+Sunday,Domingo,
Suplier,Proveedor,
Supplier,Proveedor,
Supplier Group,Grupo de proveedores,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Ingrese el nombre de la compañía para configurar el sistema.,
The number of shares and the share numbers are inconsistent,El número de acciones y el número de acciones son inconsistentes,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,La cuenta de puerta de enlace de pago en el plan {0} es diferente de la cuenta de puerta de enlace de pago en esta solicitud de pago,
-The request for quotation can be accessed by clicking on the following link,La solicitud de cotización se puede acceder haciendo clic en el siguiente enlace,
The selected BOMs are not for the same item,Las listas de materiales seleccionados no son para el mismo artículo,
The selected item cannot have Batch,El producto seleccionado no puede contener lotes,
The seller and the buyer cannot be the same,El vendedor y el comprador no pueden ser el mismo,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},El monto total del componente de beneficio flexible {0} no debe ser inferior al beneficio máximo {1},
Total hours: {0},Horas totales: {0},
Total leaves allocated is mandatory for Leave Type {0},Las Licencias totales asignadas son obligatorias para el Tipo de Licencia {0},
-Total weightage assigned should be 100%. It is {0},Peso total asignado debe ser de 100 %. Es {0},
Total working hours should not be greater than max working hours {0},Total de horas de trabajo no deben ser mayores que las horas de trabajo max {0},
Total {0} ({1}),Total {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Total de {0} para todos los elementos es cero, puede ser que usted debe cambiar en "Distribuir los cargos basados en '",
@@ -3316,11 +3299,10 @@
What do you need help with?,Con qué necesitas ayuda?,
What does it do?,¿A qué se dedica?,
Where manufacturing operations are carried.,Dónde se realizan las operaciones de producción,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Al crear una cuenta para la empresa secundaria {0}, no se encontró la cuenta principal {1}. Cree la cuenta principal en el COA correspondiente",
White,Blanco,
Wire Transfer,Transferencia bancaria,
WooCommerce Products,Productos WooCommerce,
-Work In Progress,Trabajo en progreso,
+Work In Progress,Trabajo en Proceso,
Work Order,Orden de trabajo,
Work Order already created for all items with BOM,Órden de Trabajo ya creada para todos los artículos con lista de materiales,
Work Order cannot be raised against a Item Template,La Órden de Trabajo no puede levantarse contra una Plantilla de Artículo,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} variantes creadas,
{0} {1} created,{0} {1} creado,
{0} {1} does not exist,{0} {1} no existe,
-{0} {1} does not exist.,{0} {1} no existe.,
{0} {1} has been modified. Please refresh.,{0} {1} ha sido modificado. Por favor actualice.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} no fue enviado por lo tanto la acción no puede estar completa,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} está asociado con {2}, pero la cuenta de grupo es {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} no existe,
{0}: {1} not found in Invoice Details table,{0}: {1} no se encontró en la tabla de detalles de factura,
{} of {},{} de {},
+Assigned To,Asignado a,
Chat,Chat,
Completed By,Completado Por,
Conditions,Condiciones,
@@ -3506,7 +3488,9 @@
Merge with existing,Combinar con existente,
Office,Oficina,
Orientation,Orientación,
+Parent,Principal,
Passive,Pasivo,
+Payment Failed,Pago Fallido,
Percent,Por ciento,
Permanent,Permanente,
Personal,Personal,
@@ -3544,7 +3528,6 @@
Company field is required,Campo de la empresa es obligatorio,
Creating Dimensions...,Creando Dimensiones ...,
Duplicate entry against the item code {0} and manufacturer {1},Entrada duplicada contra el código de artículo {0} y el fabricante {1},
-Import Chart Of Accounts from CSV / Excel files,Importar plan de cuentas de archivos CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN inválido! La entrada que ingresó no coincide con el formato GSTIN para titulares de UIN o proveedores de servicios OIDAR no residentes,
Invoice Grand Total,Factura Gran Total,
Last carbon check date cannot be a future date,La última fecha de verificación de carbono no puede ser una fecha futura,
@@ -3556,6 +3539,7 @@
Show {0},Mostrar {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caracteres especiales excepto "-", "#", ".", "/", "{" Y "}" no están permitidos en las series de nombres",
Target Details,Detalles del objetivo,
+{0} already has a Parent Procedure {1}.,{0} ya tiene un Procedimiento principal {1}.,
API,API,
Annual,Anual,
Approved,Aprobado,
@@ -3572,6 +3556,8 @@
No data to export,No hay datos para exportar,
Portrait,Retrato,
Print Heading,Imprimir Encabezado,
+Scheduler Inactive,Programador inactivo,
+Scheduler is inactive. Cannot import data.,El programador está inactivo. No se pueden importar datos.,
Show Document,Mostrar documento,
Show Traceback,Mostrar rastreo,
Video,Vídeo,
@@ -3596,7 +3582,7 @@
Accounting Period overlaps with {0},El período contable se superpone con {0},
Activity,Actividad,
Add / Manage Email Accounts.,Añadir / Administrar cuentas de correo electrónico.,
-Add Child,Agregar niño,
+Add Child,Agregar hijo,
Add Loan Security,Agregar seguridad de préstamo,
Add Multiple,Añadir Multiple,
Add Participants,Agregar Participantes,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Crear inspección de calidad para el artículo {0},
Creating Accounts...,Creando Cuentas ...,
Creating bank entries...,Creando asientos bancarios ...,
-Creating {0},Creando {0},
Credit limit is already defined for the Company {0},El límite de crédito ya está definido para la Compañía {0},
Ctrl + Enter to submit,Ctrl + Enter para enviar,
Ctrl+Enter to submit,Ctrl + Enter para enviar,
@@ -3721,14 +3706,14 @@
Designation,Puesto,
Difference Value,Valor de diferencia,
Dimension Filter,Filtro de dimensiones,
-Disabled,Discapacitado,
+Disabled,Deshabilitado,
Disbursement and Repayment,Desembolso y reembolso,
Distance cannot be greater than 4000 kms,La distancia no puede ser mayor a 4000 kms,
Do you want to submit the material request,¿Quieres enviar la solicitud de material?,
Doctype,Doctype,
Document {0} successfully uncleared,El documento {0} no se ha borrado correctamente,
Download Template,Descargar plantilla,
-Dr,Dr,
+Dr,Dr.,
Due Date,Fecha de vencimiento,
Duplicate,Duplicar,
Duplicate Project with Tasks,Proyecto duplicado con tareas,
@@ -3921,7 +3906,6 @@
Plaid public token error,Error de token público a cuadros,
Plaid transactions sync error,Error de sincronización de transacciones a cuadros,
Please check the error log for details about the import errors,Consulte el registro de errores para obtener detalles sobre los errores de importación.,
-Please click on the following link to set your new password,"Por favor, haga clic en el siguiente enlace para configurar su nueva contraseña",
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,<b>Cree la configuración de DATEV</b> para la empresa <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Cree una entrada de diario de ajuste para la cantidad {0},
Please do not create more than 500 items at a time,No cree más de 500 artículos a la vez.,
@@ -3997,6 +3981,7 @@
Release date must be in the future,La fecha de lanzamiento debe ser en el futuro,
Relieving Date must be greater than or equal to Date of Joining,La fecha de liberación debe ser mayor o igual que la fecha de incorporación,
Rename,Renombrar,
+Rename Not Allowed,Cambiar nombre no permitido,
Repayment Method is mandatory for term loans,El método de reembolso es obligatorio para préstamos a plazo,
Repayment Start Date is mandatory for term loans,La fecha de inicio de reembolso es obligatoria para préstamos a plazo,
Report Item,Reportar articulo,
@@ -4043,7 +4028,6 @@
Select All,Seleccionar todo,
Select Difference Account,Seleccionar cuenta de diferencia,
Select a Default Priority.,Seleccione una prioridad predeterminada.,
-Select a Supplier from the Default Supplier List of the items below.,Seleccione un proveedor de la lista de proveedores predeterminados de los siguientes artículos.,
Select a company,Selecciona una empresa,
Select finance book for the item {0} at row {1},Seleccione el libro de finanzas para el artículo {0} en la fila {1},
Select only one Priority as Default.,Seleccione solo una prioridad como predeterminada.,
@@ -4209,7 +4193,7 @@
Barcode,Código de barras,
Bold,Negrita,
Center,Centro,
-Clear,Claro,
+Clear,Quitar,
Comment,Comentario,
Comments,Comentarios,
DocType,DocType,
@@ -4247,7 +4231,6 @@
Actual ,Actual,
Add to cart,Añadir a la Cesta,
Budget,Presupuesto,
-Chart Of Accounts Importer,Importador de plan de cuentas,
Chart of Accounts,Catálogo de cuentas,
Customer database.,Base de datos de cliente.,
Days Since Last order,Días desde la última orden,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,la fecha final no puede ser inferior a fecha de Inicio,
For Default Supplier (Optional),Para el proveedor predeterminado (opcional),
From date cannot be greater than To date,La fecha 'Desde' no puede ser mayor que la fecha 'Hasta',
-Get items from,Obtener artículos de,
Group by,Agrupar por,
In stock,En stock,
Item name,Nombre del producto,
@@ -4322,7 +4304,7 @@
Invalid Account,Cuenta no válida,
Purchase Order Required,Orden de compra requerida,
Purchase Receipt Required,Recibo de compra requerido,
-Account Missing,Falta la cuenta,
+Account Missing,Cuenta Faltante,
Requested,Solicitado,
Partially Paid,Parcialmente pagado,
Invalid Account Currency,Moneda de la cuenta no válida,
@@ -4532,32 +4514,22 @@
Accounts Settings,Configuración de cuentas,
Settings for Accounts,Ajustes de contabilidad,
Make Accounting Entry For Every Stock Movement,Crear un asiento contable para cada movimiento de stock,
-"If enabled, the system will post accounting entries for inventory automatically.","Si está habilitado, el sistema contabiliza los asientos contables para el inventario de forma automática.",
-Accounts Frozen Upto,Cuentas congeladas hasta,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Asiento contable actualmente congelado. Nadie puede generar / modificar el asiento, excepto el rol especificado a continuación.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Rol que permite definir cuentas congeladas y editar asientos congelados,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Los usuarios con este rol pueden establecer cuentas congeladas y crear / modificar los asientos contables para las mismas,
Determine Address Tax Category From,Determinar la categoría de impuestos de la dirección de,
-Address used to determine Tax Category in transactions.,Dirección utilizada para determinar la categoría de impuestos en las transacciones.,
Over Billing Allowance (%),Sobre la asignación de facturación (%),
-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 for $110.,"Porcentaje que tiene permitido facturar más contra la cantidad solicitada. Por ejemplo: si el valor del pedido es de $ 100 para un artículo y la tolerancia se establece en 10%, se le permite facturar $ 110.",
Credit Controller,Controlador de créditos,
-Role that is allowed to submit transactions that exceed credit limits set.,Rol autorizado para validar las transacciones que excedan los límites de crédito establecidos.,
Check Supplier Invoice Number Uniqueness,Comprobar número de factura único por proveedor,
Make Payment via Journal Entry,Hace el pago vía entrada de diario,
Unlink Payment on Cancellation of Invoice,Desvinculación de Pago en la cancelación de la factura,
-Unlink Advance Payment on Cancelation of Order,Desvincular pago anticipado por cancelación de pedido,
Book Asset Depreciation Entry Automatically,Entrada de depreciación de activos de libro de forma automática,
Automatically Add Taxes and Charges from Item Tax Template,Agregar automáticamente impuestos y cargos de la plantilla de impuestos de artículos,
Automatically Fetch Payment Terms,Obtener automáticamente las condiciones de pago,
-Show Inclusive Tax In Print,Mostrar impuesto inclusivo en impresión,
Show Payment Schedule in Print,Mostrar horario de pago en Imprimir,
Currency Exchange Settings,Configuración de Cambio de Moneda,
Allow Stale Exchange Rates,Permitir Tipos de Cambio Obsoletos,
Stale Days,Días Pasados,
Report Settings,Configuración de Reportes,
Use Custom Cash Flow Format,Utilice el Formato de Flujo de Efectivo Personalizado,
-Only select if you have setup Cash Flow Mapper documents,Seleccione solo si tiene documentos de Cash Flow Mapper configurados,
Allowed To Transact With,Permitido para realizar Transacciones con,
SWIFT number,Número rápido,
Branch Code,Código de Rama,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Grupo de Clientes,
POS Field,Campo POS,
POS Item Group,POS Grupo de artículos,
-[Select],[Seleccionar],
Company Address,Dirección de la Compañía,
Update Stock,Actualizar el Inventario,
Ignore Pricing Rule,Ignorar la Regla Precios,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Ordenar proveedores por,
Default Supplier Group,Grupo de Proveedores Predeterminado,
Default Buying Price List,Lista de precios por defecto,
-Maintain same rate throughout purchase cycle,Mantener los mismos precios durante el ciclo de compras,
-Allow Item to be added multiple times in a transaction,Permitir añadir el artículo varias veces en una transacción,
Backflush Raw Materials of Subcontract Based On,Adquisición retroactiva de materia prima del subcontrato basadas en,
Material Transferred for Subcontract,Material Transferido para Subcontrato,
Over Transfer Allowance (%),Sobre asignación de transferencia (%),
@@ -5540,7 +5509,6 @@
Current Stock,Inventario Actual,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Por proveedor individual,
-Supplier Detail,Detalle del proveedor,
Link to Material Requests,Enlace a solicitudes de material,
Message for Supplier,Mensaje para los Proveedores,
Request for Quotation Item,Ítems de Solicitud de Presupuesto,
@@ -5631,7 +5599,7 @@
Received By,Recibido por,
Caller Information,Información de la llamada,
Contact Name,Nombre de contacto,
-Lead ,Dirigir,
+Lead ,Iniciativa,
Lead Name,Nombre de la iniciativa,
Ringing,Zumbido,
Missed,Perdido,
@@ -6321,7 +6289,7 @@
Normal Test Template,Plantilla de Prueba Normal,
Patient Demographics,Datos Demográficos del Paciente,
HLC-PAT-.YYYY.-,HLC-PAT-.YYYY.-,
-Middle Name (optional),Segundo nombre (opcional),
+Middle Name (optional),Segundo Nombre (Opcional),
Inpatient Status,Estado de paciente hospitalizado,
"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.","Si "Vincular cliente a paciente" está marcado en Configuración de atención médica y no se selecciona un Cliente existente, se creará un Cliente para este Paciente para registrar transacciones en el módulo Cuentas.",
Personal and Social History,Historia Personal y Social,
@@ -6481,7 +6449,6 @@
Appraisal Template,Plantilla de evaluación,
For Employee Name,Por nombre de empleado,
Goals,Objetivos,
-Calculate Total Score,Calcular puntaje total,
Total Score (Out of 5),Puntaje Total (de 5),
"Any other remarks, noteworthy effort that should go in the records.","Otras observaciones, que deben ir en los registros.",
Appraisal Goal,Meta de evaluación,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Razones de renuncia,
Leave Encashed?,Vacaciones pagadas?,
Encashment Date,Fecha de Cobro,
-Exit Interview Details,Detalles de Entrevista de Salida,
-Held On,Retenida en,
-Reason for Resignation,Motivo de la renuncia,
-Better Prospects,Mejores Prospectos,
-Health Concerns,Problemas de salud,
New Workplace,Nuevo lugar de trabajo,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Cantidad devuelta,
@@ -6656,7 +6618,7 @@
Total Experience,Experiencia total,
Default Leave Policy,Política de Licencia Predeterminada,
Default Salary Structure,Estructura de Salario Predeterminada,
-Employee Group Table,Mesa de grupo de empleados,
+Employee Group Table,Tabla de grupo de empleados,
ERPNext User ID,ERP ID de usuario siguiente,
Employee Health Insurance,Seguro de Salud para Empleados,
Health Insurance Name,Nombre del Seguro de Salud,
@@ -6740,10 +6702,7 @@
Employee Settings,Configuración de Empleado,
Retirement Age,Edad de retiro,
Enter retirement age in years,Introduzca la edad de jubilación en años,
-Employee Records to be created by,Los registros de empleados se crearán por,
-Employee record is created using selected field. ,El registro del empleado se crea utilizando el campo seleccionado.,
Stop Birthday Reminders,Detener recordatorios de cumpleaños.,
-Don't send Employee Birthday Reminders,No enviar recordatorio de cumpleaños del empleado,
Expense Approver Mandatory In Expense Claim,Aprobador de Gastos obligatorio en la Reclamación de Gastos,
Payroll Settings,Configuración de nómina,
Leave,Salir,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Aprobador de Autorización de Vacaciones es obligatorio en la Solicitud de Licencia,
Show Leaves Of All Department Members In Calendar,Mostrar hojas de todos los miembros del departamento en el calendario,
Auto Leave Encashment,Auto dejar cobro,
-Restrict Backdated Leave Application,Restringir la solicitud de licencia con fecha anterior,
Hiring Settings,Configuraciones de contratación,
Check Vacancies On Job Offer Creation,Comprobar vacantes en la creación de ofertas de trabajo,
Identification Document Type,Tipo de Documento de Identificación,
@@ -6879,10 +6837,10 @@
Number Of Employees,Número de Empleados,
Employee Details,Detalles del Empleado,
Validate Attendance,Validar la Asistencia,
-Salary Slip Based on Timesheet,Nomina basada en el Parte de Horas,
+Salary Slip Based on Timesheet,Nomina basada horas,
Select Payroll Period,Seleccione el Período de Nómina,
Deduct Tax For Unclaimed Employee Benefits,Deducir Impuestos para beneficios de Empleados no Reclamados,
-Deduct Tax For Unsubmitted Tax Exemption Proof,Deducir impuestos por prueba de exención de impuestos sin enviar,
+Deduct Tax For Unsubmitted Tax Exemption Proof,Deducir impuestos por soporte de exención de impuestos sin enviar,
Select Payment Account to make Bank Entry,Seleccionar la cuenta de pago para hacer la entrada del Banco,
Salary Slips Created,Salario Slips creado,
Salary Slips Submitted,Nómina Salarial Validada,
@@ -7134,7 +7092,7 @@
Loan Manager,Gerente de préstamos,
Loan Info,Información del Préstamo,
Rate of Interest,Tasa de interés,
-Proposed Pledges,Promesas Propuestas,
+Proposed Pledges,Prendas Propuestas,
Maximum Loan Amount,Cantidad máxima del préstamo,
Repayment Info,Información de la Devolución,
Total Payable Interest,Interés Total a Pagar,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Ajustes de Producción,
Raw Materials Consumption,Consumo de materias primas,
Allow Multiple Material Consumption,Permitir el Consumo de Material Múltiple,
-Allow multiple Material Consumption against a Work Order,Permitir el Consumo de Material Múltiple contra una Orden de Trabajo,
Backflush Raw Materials Based On,Adquisición retroactiva de materia prima basada en,
Material Transferred for Manufacture,Material Transferido para Manufacturar,
Capacity Planning,Planificación de capacidad,
Disable Capacity Planning,Desactivar planificación de capacidad,
Allow Overtime,Permitir horas extraordinarias,
-Plan time logs outside Workstation Working Hours.,Planear las horas adicionales en la estación de trabajo.,
Allow Production on Holidays,Permitir producción en días festivos,
Capacity Planning For (Days),Planificación de capacidad para (Días),
-Try planning operations for X days in advance.,Procure planear las operaciones con XX días de antelación.,
-Time Between Operations (in mins),Tiempo entre operaciones (en minutos),
-Default 10 mins,Por defecto 10 minutos,
Default Warehouses for Production,Almacenes predeterminados para producción,
Default Work In Progress Warehouse,Almacén predeterminado de trabajos en proceso,
Default Finished Goods Warehouse,Almacén predeterminado de productos terminados,
Default Scrap Warehouse,Almacén de chatarra predeterminado,
-Over Production for Sales and Work Order,Sobre producción para ventas y orden de trabajo,
Overproduction Percentage For Sales Order,Porcentaje de Sobreproducción para Orden de Venta,
Overproduction Percentage For Work Order,Porcentaje de Sobreproducción para Orden de Trabajo,
Other Settings,Otros ajustes,
Update BOM Cost Automatically,Actualizar automáticamente el coste de la lista de materiales,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Actualizar el costo de la lista de materiales automáticamente a través de las tareas programadas, basado en la última tasa de valoración / tarifa de lista de precios / última tasa de compra de materias primas.",
Material Request Plan Item,Artículo de Plan de Solicitud de Material,
Material Request Type,Tipo de Requisición,
Material Issue,Expedición de Material,
@@ -7388,7 +7339,7 @@
Available Qty at WIP Warehouse,Cantidad Disponible en Almacén WIP,
Work Order Operation,Operación de Órden de Trabajo,
Operation Description,Descripción de la operación,
-Operation completed for how many finished goods?,Se completo la operación para la cantidad de productos terminados?,
+Operation completed for how many finished goods?,¿Operación completada para cuántos productos terminados?,
Work in Progress,Trabajo en proceso,
Estimated Time and Cost,Tiempo estimado y costo,
Planned Start Time,Hora prevista de inicio,
@@ -7603,10 +7554,6 @@
Quality Goal,Objetivo de calidad,
Monitoring Frequency,Frecuencia de monitoreo,
Weekday,Día laborable,
-January-April-July-October,Enero-abril-julio-octubre,
-Revision and Revised On,Revisión y revisado en,
-Revision,Revisión,
-Revised On,Revisado en,
Objectives,Objetivos,
Quality Goal Objective,Objetivo de calidad Objetivo,
Objective,Objetivo,
@@ -7619,7 +7566,6 @@
Processes,Procesos,
Quality Procedure Process,Proceso de procedimiento de calidad,
Process Description,Descripción del proceso,
-Child Procedure,Procedimiento infantil,
Link existing Quality Procedure.,Enlace Procedimiento de calidad existente.,
Additional Information,Información Adicional,
Quality Review Objective,Objetivo de revisión de calidad,
@@ -7787,15 +7733,9 @@
Default Customer Group,Categoría de cliente predeterminada,
Default Territory,Territorio predeterminado,
Close Opportunity After Days,Cerrar Oportunidad Después Días,
-Auto close Opportunity after 15 days,Cerrar Oportunidad automáticamente luego de 15 días,
Default Quotation Validity Days,Días de Validez de Cotizaciones Predeterminados,
Sales Update Frequency,Frecuencia de Actualización de Ventas,
-How often should project and company be updated based on Sales Transactions.,¿Con qué frecuencia deben actualizarse el proyecto y la empresa en función de las transacciones de venta?,
Each Transaction,Cada Transacción,
-Allow user to edit Price List Rate in transactions,Permitir al usuario editar la lista de precios en las transacciones,
-Allow multiple Sales Orders against a Customer's Purchase Order,"Permitir varias órdenes de venta, para las ordenes de compra de los clientes",
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Validar precio de venta para el artículo contra la Tarifa de compra o tasa de valorización,
-Hide Customer's Tax Id from Sales Transactions,Ocultar ID de Impuestos del cliente según Transacciones de venta,
SMS Center,Centro SMS,
Send To,Enviar a,
All Contact,Todos los Contactos,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Fabricantes utilizados en artículos,
Limited to 12 characters,Limitado a 12 caracteres,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Establecer almacén,
-Sets 'For Warehouse' in each row of the Items table.,Establece 'Para almacén' en cada fila de la tabla Artículos.,
-Requested For,Solicitado por,
Partially Ordered,Parcialmente ordenado,
Transferred,Transferido,
% Ordered,% Ordenado,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Unidad de Medida (UdM) predeterminada para Inventario,
Sample Retention Warehouse,Almacenamiento de Muestras de Retención,
Default Valuation Method,Método predeterminado de valoración,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"El porcentaje que ud. tiene permitido para recibir o enviar mas de la cantidad ordenada. Por ejemplo: Si ha pedido 100 unidades, y su asignación es del 10%, entonces tiene permitido recibir hasta 110 unidades.",
-Action if Quality inspection is not submitted,Acción si no se presenta la inspección de calidad,
Show Barcode Field,Mostrar Campo de código de barras,
Convert Item Description to Clean HTML,Convertir la descripción del elemento a HTML Limpio,
-Auto insert Price List rate if missing,Insertar automáticamente Tasa de Lista de Precio si falta,
Allow Negative Stock,Permitir Inventario Negativo,
Automatically Set Serial Nos based on FIFO,Ajusta automáticamente los números de serie basado en FIFO,
-Set Qty in Transactions based on Serial No Input,Establezca la cantidad en transacciones basadas en la entrada del Numero de Serie,
Auto Material Request,Requisición de Materiales Automática,
-Raise Material Request when stock reaches re-order level,Generar un pedido de materiales cuando se alcance un nivel bajo el stock,
-Notify by Email on creation of automatic Material Request,Notificarme por Email cuando se genere una nueva requisición de materiales,
Inter Warehouse Transfer Settings,Configuración de transferencia entre almacenes,
-Allow Material Transfer From Delivery Note and Sales Invoice,Permitir la transferencia de material desde la nota de entrega y la factura de venta,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Permitir la transferencia de material desde el recibo de compra y la factura de compra,
Freeze Stock Entries,Congelar entradas de stock,
Stock Frozen Upto,Inventario congelado hasta,
-Freeze Stocks Older Than [Days],Congelar stock mayores a [Days],
-Role Allowed to edit frozen stock,Rol que permite editar inventario congelado,
Batch Identification,Identificación de Lote,
Use Naming Series,Usar Series de Nomenclatura,
Naming Series Prefix,Nombrar el Prefijo de la Serie,
@@ -8524,7 +8451,7 @@
Asset Depreciations and Balances,Depreciaciones de Activos y Saldos,
Available Stock for Packing Items,Inventario Disponible de Artículos de Embalaje,
Bank Clearance Summary,Resumen de Cambios Bancarios,
-Bank Remittance,Remesa bancaria,
+Bank Remittance,Giro Bancario,
Batch Item Expiry Status,Estado de Caducidad de Lote de Productos,
Batch-Wise Balance History,Historial de Saldo por Lotes,
BOM Explorer,BOM Explorer,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Tendencias de recibos de compra,
Purchase Register,Registro de compras,
Quotation Trends,Tendencias de Presupuestos,
-Quoted Item Comparison,Comparación de artículos de Cotización,
Received Items To Be Billed,Recepciones por facturar,
Qty to Order,Cantidad a Solicitar,
Requested Items To Be Transferred,Artículos solicitados para ser transferidos,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Seleccionar almacén para solicitudes de material,
Transfer Materials For Warehouse {0},Transferir materiales para almacén {0},
Production Plan Material Request Warehouse,Almacén de solicitud de material de plan de producción,
-Set From Warehouse,Establecer desde almacén,
-Source Warehouse (Material Transfer),Almacén de origen (transferencia de material),
Sets 'Source Warehouse' in each row of the items table.,Establece 'Almacén de origen' en cada fila de la tabla de artículos.,
Sets 'Target Warehouse' in each row of the items table.,Establece 'Almacén de destino' en cada fila de la tabla de artículos.,
Show Cancelled Entries,Mostrar entradas canceladas,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Servicio recibido pero no facturado,
Deferred Accounting Settings,Configuración de contabilidad diferida,
Book Deferred Entries Based On,Reservar entradas diferidas según,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Si se selecciona "Meses", la cantidad fija se contabilizará como ingreso o gasto diferido para cada mes, independientemente del número de días del mes. Se prorrateará si los ingresos o gastos diferidos no se contabilizan durante un mes completo.",
Days,Dias,
Months,Meses,
Book Deferred Entries Via Journal Entry,Reservar entradas diferidas mediante entrada de diario,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Si no se marca esta opción, se crearán entradas directas de libro mayor para registrar ingresos / gastos diferidos",
Submit Journal Entries,Enviar entradas de diario,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Si no se marca, las entradas del diario se guardarán en estado de borrador y deberán enviarse manualmente",
Enable Distributed Cost Center,Habilitar el centro de costos distribuidos,
@@ -8901,8 +8823,6 @@
Is Inter State,Es interestatal,
Purchase Details,Detalles de la compra,
Depreciation Posting Date,Fecha de contabilización de la depreciación,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Orden de compra necesaria para la creación de facturas y recibos de compra,
-Purchase Receipt Required for Purchase Invoice Creation,Recibo de compra necesario para la creación de la factura de compra,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","De forma predeterminada, el nombre del proveedor se establece según el nombre del proveedor introducido. Si desea que los proveedores sean nombrados por un",
choose the 'Naming Series' option.,elija la opción 'Serie de nombres'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Configure la lista de precios predeterminada al crear una nueva transacción de compra. Los precios de los artículos se obtendrán de esta lista de precios.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Es el componente del impuesto sobre la renta,
Component properties and references ,Propiedades y referencias de componentes,
Additional Salary ,Salario adicional,
-Condtion and formula,Condición y fórmula,
Unmarked days,Días sin marcar,
Absent Days,Días ausentes,
Conditions and Formula variable and example,Condiciones y variable de fórmula y ejemplo,
Feedback By,Comentarios de,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Sección de fabricación,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Pedido de venta necesario para la creación de facturas de venta y notas de entrega,
-Delivery Note Required for Sales Invoice Creation,Nota de entrega necesaria para la creación de facturas de venta,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","De forma predeterminada, el nombre del cliente se establece según el nombre completo introducido. Si desea que los Clientes sean nombrados por un",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Configure la lista de precios predeterminada al crear una nueva transacción de ventas. Los precios de los artículos se obtendrán de esta lista de precios.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Si esta opción está configurada como 'Sí', ERPNext le impedirá crear una factura de venta o una nota de entrega sin crear primero una orden de venta. Esta configuración se puede anular para un cliente en particular activando la casilla de verificación 'Permitir la creación de facturas de venta sin orden de venta' en el maestro de clientes.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} se agregó correctamente a todos los temas seleccionados.,
Topics updated,Temas actualizados,
Academic Term and Program,Término académico y programa,
-Last Stock Transaction for item {0} was on {1}.,La última transacción de existencias para el artículo {0} fue el {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Las transacciones de existencias para el artículo {0} no se pueden registrar antes de esta hora.,
Please remove this item and try to submit again or update the posting time.,Elimine este elemento e intente enviarlo de nuevo o actualice la hora de publicación.,
Failed to Authenticate the API key.,Error al autenticar la clave de API.,
Invalid Credentials,Credenciales no válidas,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Verifique su ID de cliente de Plaid y sus valores secretos,
Bank transaction creation error,Error de creación de transacción bancaria,
Unit of Measurement,Unidad de medida,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Fila # {}: la tasa de venta del artículo {} es menor que su {}. La tasa de venta debe ser al menos {},
Fiscal Year {0} Does Not Exist,El año fiscal {0} no existe,
Row # {0}: Returned Item {1} does not exist in {2} {3},Fila n.º {0}: el artículo devuelto {1} no existe en {2} {3},
Valuation type charges can not be marked as Inclusive,Los cargos por tipo de valoración no se pueden marcar como inclusivos,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,El tiempo de respuesta para la {0} prioridad en la fila {1} no puede ser mayor que el tiempo de resolución.,
{0} is not enabled in {1},{0} no está habilitado en {1},
Group by Material Request,Agrupar por solicitud de material,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Fila {0}: para el proveedor {0}, se requiere la dirección de correo electrónico para enviar correo electrónico",
Email Sent to Supplier {0},Correo electrónico enviado al proveedor {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","El acceso a la solicitud de cotización del portal está deshabilitado. Para permitir el acceso, habilítelo en la configuración del portal.",
Supplier Quotation {0} Created,Cotización de proveedor {0} creada,
Valid till Date cannot be before Transaction Date,La fecha válida hasta la fecha no puede ser anterior a la fecha de la transacción,
+Unlink Advance Payment on Cancellation of Order,Desvincular el pago por adelantado en la cancelación de un pedido,
+"Simple Python Expression, Example: territory != 'All Territories'","Expresión simple de Python, ejemplo: territorio! = 'Todos los territorios'",
+Sales Contributions and Incentives,Contribuciones e incentivos de ventas,
+Sourced by Supplier,Obtenido por proveedor,
+Total weightage assigned should be 100%.<br>It is {0},El peso total asignado debe ser del 100%.<br> Es {0},
+Account {0} exists in parent company {1}.,La cuenta {0} existe en la empresa matriz {1}.,
+"To overrule this, enable '{0}' in company {1}","Para anular esto, habilite "{0}" en la empresa {1}",
+Invalid condition expression,Expresión de condición no válida,
+Please Select a Company First,Primero seleccione una empresa,
+Please Select Both Company and Party Type First,Primero seleccione tanto la empresa como el tipo de partido,
+Provide the invoice portion in percent,Proporcione la parte de la factura en porcentaje,
+Give number of days according to prior selection,Dar número de días según selección previa,
+Email Details,Detalles de correo electrónico,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Seleccione un saludo para el receptor. Por ejemplo, Sr., Sra., Etc.",
+Preview Email,Vista previa del correo electrónico,
+Please select a Supplier,Seleccione un proveedor,
+Supplier Lead Time (days),Plazo de ejecución del proveedor (días),
+"Home, Work, etc.","Hogar, trabajo, etc.",
+Exit Interview Held On,Entrevista de salida retenida,
+Condition and formula,Condición y fórmula,
+Sets 'Target Warehouse' in each row of the Items table.,Establece 'Almacén de destino' en cada fila de la tabla Artículos.,
+Sets 'Source Warehouse' in each row of the Items table.,Establece 'Almacén de origen' en cada fila de la tabla Artículos.,
+POS Register,Registro POS,
+"Can not filter based on POS Profile, if grouped by POS Profile","No se puede filtrar según el perfil de POS, si está agrupado por perfil de POS",
+"Can not filter based on Customer, if grouped by Customer","No se puede filtrar según el Cliente, si está agrupado por Cliente",
+"Can not filter based on Cashier, if grouped by Cashier","No se puede filtrar según el cajero, si está agrupado por cajero",
+Payment Method,Método de pago,
+"Can not filter based on Payment Method, if grouped by Payment Method","No se puede filtrar según el método de pago, si está agrupado por método de pago",
+Supplier Quotation Comparison,Comparación de cotizaciones de proveedores,
+Price per Unit (Stock UOM),Precio por unidad (UOM de stock),
+Group by Supplier,Agrupar por proveedor,
+Group by Item,Agrupar por artículo,
+Remember to set {field_label}. It is required by {regulation}.,Recuerde configurar {field_label}. Es requerido por {regulación}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},La fecha de inscripción no puede ser anterior a la fecha de inicio del año académico {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},La fecha de inscripción no puede ser posterior a la fecha de finalización del período académico {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},La fecha de inscripción no puede ser anterior a la fecha de inicio del período académico {0},
+Future Posting Not Allowed,Publicaciones futuras no permitidas,
+"To enable Capital Work in Progress Accounting, ","Para habilitar la contabilidad del trabajo de capital en curso,",
+you must select Capital Work in Progress Account in accounts table,debe seleccionar Cuenta Capital Work in Progress en la tabla de cuentas,
+You can also set default CWIP account in Company {},También puede configurar una cuenta CWIP predeterminada en la empresa {},
+The Request for Quotation can be accessed by clicking on the following button,Se puede acceder a la Solicitud de Cotización haciendo clic en el siguiente botón,
+Regards,Saludos,
+Please click on the following button to set your new password,Haga clic en el siguiente botón para establecer su nueva contraseña,
+Update Password,Actualiza contraseña,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Fila # {}: la tasa de venta del artículo {} es menor que su {}. La venta {} debe ser al menos {},
+You can alternatively disable selling price validation in {} to bypass this validation.,"Alternativamente, puede deshabilitar la validación del precio de venta en {} para omitir esta validación.",
+Invalid Selling Price,Precio de venta no válido,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,La dirección debe estar vinculada a una empresa. Agregue una fila para Compañía en la tabla Vínculos.,
+Company Not Linked,Empresa no vinculada,
+Import Chart of Accounts from CSV / Excel files,Importar plan de cuentas desde archivos CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',La cantidad completa no puede ser mayor que la 'Cantidad para fabricar',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Fila {0}: para el proveedor {1}, se requiere la dirección de correo electrónico para enviar un correo electrónico.",
+"If enabled, the system will post accounting entries for inventory automatically","Si está habilitado, el sistema registrará entradas contables para el inventario automáticamente",
+Accounts Frozen Till Date,Cuentas congeladas hasta la fecha,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Los asientos contables están congelados hasta esta fecha. Nadie puede crear o modificar entradas excepto los usuarios con el rol especificado a continuación,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Función permitida para configurar cuentas congeladas y editar entradas congeladas,
+Address used to determine Tax Category in transactions,Dirección utilizada para determinar la categoría fiscal en las transacciones,
+"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 ","El porcentaje que se le permite facturar más contra la cantidad solicitada. Por ejemplo, si el valor del pedido es de $ 100 para un artículo y la tolerancia se establece en el 10%, entonces puede facturar hasta $ 110",
+This role is allowed to submit transactions that exceed credit limits,Este rol puede enviar transacciones que excedan los límites de crédito.,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Si se selecciona "Meses", se registrará una cantidad fija como ingreso o gasto diferido para cada mes, independientemente de la cantidad de días en un mes. Se prorrateará si los ingresos o gastos diferidos no se registran durante un mes completo.",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Si no se marca esta opción, se crearán entradas directas de libro mayor para registrar los ingresos o gastos diferidos",
+Show Inclusive Tax in Print,Mostrar impuestos incluidos en la impresión,
+Only select this if you have set up the Cash Flow Mapper documents,Solo seleccione esta opción si ha configurado los documentos de Cash Flow Mapper,
+Payment Channel,Canal de pago,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,¿Se requiere una orden de compra para la creación de facturas y recibos de compra?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,¿Se requiere un recibo de compra para la creación de una factura de compra?,
+Maintain Same Rate Throughout the Purchase Cycle,Mantenga la misma tasa durante todo el ciclo de compra,
+Allow Item To Be Added Multiple Times in a Transaction,Permitir que el artículo se agregue varias veces en una transacción,
+Suppliers,Proveedores,
+Send Emails to Suppliers,Enviar correos electrónicos a proveedores,
+Select a Supplier,Seleccione un proveedor,
+Cannot mark attendance for future dates.,No se puede marcar la asistencia para fechas futuras.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},¿Quieres actualizar la asistencia?<br> Presente: {0}<br> Ausente: {1},
+Mpesa Settings,Configuración de Mpesa,
+Initiator Name,Nombre del iniciador,
+Till Number,Hasta el número,
+Sandbox,Salvadera,
+ Online PassKey,PassKey en línea,
+Security Credential,Credencial de seguridad,
+Get Account Balance,Obtener saldo de cuenta,
+Please set the initiator name and the security credential,Establezca el nombre del iniciador y la credencial de seguridad,
+Inpatient Medication Entry,Entrada de medicación para pacientes hospitalizados,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Código de artículo (medicamento),
+Medication Orders,Órdenes de medicación,
+Get Pending Medication Orders,Obtenga pedidos de medicamentos pendientes,
+Inpatient Medication Orders,Órdenes de medicamentos para pacientes hospitalizados,
+Medication Warehouse,Almacén de medicamentos,
+Warehouse from where medication stock should be consumed,Almacén desde donde se debe consumir el stock de medicamentos,
+Fetching Pending Medication Orders,Obtención de pedidos de medicamentos pendientes,
+Inpatient Medication Entry Detail,Detalle de entrada de medicación para pacientes hospitalizados,
+Medication Details,Detalles de la medicación,
+Drug Code,Código de drogas,
+Drug Name,Nombre de la droga,
+Against Inpatient Medication Order,Contra la orden de medicación para pacientes hospitalizados,
+Against Inpatient Medication Order Entry,Contra la entrada de pedidos de medicamentos para pacientes hospitalizados,
+Inpatient Medication Order,Orden de medicación para pacientes hospitalizados,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Pedidos totales,
+Completed Orders,Pedidos completados,
+Add Medication Orders,Agregar pedidos de medicamentos,
+Adding Order Entries,Agregar entradas de pedido,
+{0} medication orders completed,{0} pedidos de medicamentos completados,
+{0} medication order completed,{0} pedido de medicamentos completado,
+Inpatient Medication Order Entry,Entrada de pedidos de medicamentos para pacientes hospitalizados,
+Is Order Completed,¿Se completó el pedido?,
+Employee Records to Be Created By,Registros de empleados que serán creados por,
+Employee records are created using the selected field,Los registros de empleados se crean utilizando el campo seleccionado,
+Don't send employee birthday reminders,No envíe recordatorios de cumpleaños a los empleados,
+Restrict Backdated Leave Applications,Restringir las solicitudes de permisos retroactivos,
+Sequence ID,ID de secuencia,
+Sequence Id,ID de secuencia,
+Allow multiple material consumptions against a Work Order,Permitir múltiples consumos de material contra una orden de trabajo,
+Plan time logs outside Workstation working hours,Planifique registros de tiempo fuera del horario laboral de la estación de trabajo,
+Plan operations X days in advance,Planifique las operaciones con X días de anticipación,
+Time Between Operations (Mins),Tiempo entre operaciones (minutos),
+Default: 10 mins,Predeterminado: 10 minutos,
+Overproduction for Sales and Work Order,Sobreproducción para ventas y órdenes de trabajo,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Actualice el costo de la lista de materiales automáticamente a través del programador, según la última tasa de valoración / tasa de lista de precios / tasa de última compra de materias primas",
+Purchase Order already created for all Sales Order items,Orden de compra ya creada para todos los artículos de orden de venta,
+Select Items,Seleccionar articulos,
+Against Default Supplier,Contra proveedor predeterminado,
+Auto close Opportunity after the no. of days mentioned above,Oportunidad de cierre automático después del no. de los días mencionados anteriormente,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,¿Se requiere una orden de venta para la creación de facturas de venta y notas de entrega?,
+Is Delivery Note Required for Sales Invoice Creation?,¿Se requiere una nota de entrega para la creación de facturas de venta?,
+How often should Project and Company be updated based on Sales Transactions?,¿Con qué frecuencia se deben actualizar el proyecto y la empresa en función de las transacciones de ventas?,
+Allow User to Edit Price List Rate in Transactions,Permitir al usuario editar la tarifa de lista de precios en las transacciones,
+Allow Item to Be Added Multiple Times in a Transaction,Permitir que el artículo se agregue varias veces en una transacción,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Permitir múltiples órdenes de venta contra la orden de compra de un cliente,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Validar el precio de venta del artículo frente a la tasa de compra o la tasa de valoración,
+Hide Customer's Tax ID from Sales Transactions,Ocultar el número de identificación fiscal del cliente de las transacciones de ventas,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","El porcentaje que se le permite recibir o entregar más en comparación con la cantidad solicitada. Por ejemplo, si ha pedido 100 unidades y su asignación es del 10%, se le permite recibir 110 unidades.",
+Action If Quality Inspection Is Not Submitted,Acción si no se envía la inspección de calidad,
+Auto Insert Price List Rate If Missing,Tarifa de lista de precios de inserción automática si falta,
+Automatically Set Serial Nos Based on FIFO,Establecer números de serie automáticamente basados en FIFO,
+Set Qty in Transactions Based on Serial No Input,Establecer la cantidad en transacciones según la entrada sin serie,
+Raise Material Request When Stock Reaches Re-order Level,Aumente la solicitud de material cuando el stock alcance el nivel de pedido,
+Notify by Email on Creation of Automatic Material Request,Notificar por correo electrónico sobre la creación de una solicitud de material automática,
+Allow Material Transfer from Delivery Note to Sales Invoice,Permitir transferencia de material de la nota de entrega a la factura de venta,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Permitir la transferencia de material desde el recibo de compra a la factura de compra,
+Freeze Stocks Older Than (Days),Congelar existencias anteriores a (días),
+Role Allowed to Edit Frozen Stock,Función permitida para editar stock congelado,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,La cantidad no asignada de Entrada de pago {0} es mayor que la cantidad no asignada de la transacción bancaria,
+Payment Received,Pago recibido,
+Attendance cannot be marked outside of Academic Year {0},La asistencia no se puede marcar fuera del año académico {0},
+Student is already enrolled via Course Enrollment {0},El estudiante ya está inscrito a través de la inscripción al curso {0},
+Attendance cannot be marked for future dates.,La asistencia no se puede marcar para fechas futuras.,
+Please add programs to enable admission application.,Agregue programas para habilitar la solicitud de admisión.,
+The following employees are currently still reporting to {0}:,Los siguientes empleados todavía están reportando a {0}:,
+Please make sure the employees above report to another Active employee.,Asegúrese de que los empleados anteriores denuncien a otro empleado activo.,
+Cannot Relieve Employee,No se puede relevar al empleado,
+Please enter {0},Ingrese {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Seleccione otro método de pago. Mpesa no admite transacciones en la moneda '{0}',
+Transaction Error,Error de transacción,
+Mpesa Express Transaction Error,Error de transacción de Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Problema detectado con la configuración de Mpesa, consulte los registros de errores para obtener más detalles",
+Mpesa Express Error,Error de Mpesa Express,
+Account Balance Processing Error,Error de procesamiento del saldo de la cuenta,
+Please check your configuration and try again,Verifique su configuración e intente nuevamente,
+Mpesa Account Balance Processing Error,Error de procesamiento del saldo de la cuenta de Mpesa,
+Balance Details,Detalles del saldo,
+Current Balance,Saldo actual,
+Available Balance,Saldo disponible,
+Reserved Balance,Saldo reservado,
+Uncleared Balance,Saldo no liquidado,
+Payment related to {0} is not completed,El pago relacionado con {0} no se completó,
+Row #{}: Item Code: {} is not available under warehouse {}.,Fila # {}: Código de artículo: {} no está disponible en el almacén {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Fila # {}: la cantidad de existencias no es suficiente para el código de artículo: {} debajo del almacén {}. Cantidad disponible {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Fila # {}: seleccione un número de serie y un lote contra el artículo: {} o elimínelo para completar la transacción.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Fila # {}: No se ha seleccionado ningún número de serie para el artículo: {}. Seleccione uno o elimínelo para completar la transacción.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Fila # {}: No se seleccionó ningún lote para el artículo: {}. Seleccione un lote o elimínelo para completar la transacción.,
+Payment amount cannot be less than or equal to 0,El monto del pago no puede ser menor o igual a 0,
+Please enter the phone number first,Primero ingrese el número de teléfono,
+Row #{}: {} {} does not exist.,Fila # {}: {} {} no existe.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Fila # {0}: {1} es obligatorio para crear las {2} facturas de apertura.,
+You had {} errors while creating opening invoices. Check {} for more details,Tuvo {} errores al crear facturas de apertura. Consulte {} para obtener más detalles,
+Error Occured,Ocurrió un error,
+Opening Invoice Creation In Progress,Creación de factura de apertura en curso,
+Creating {} out of {} {},Creando {} a partir de {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Número de serie: {0}) no se puede consumir ya que está reservado para cumplir con el pedido de venta {1}.,
+Item {0} {1},Elemento {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,La última transacción de existencias para el artículo {0} en el almacén {1} fue el {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Las transacciones de stock para el artículo {0} en el almacén {1} no se pueden contabilizar antes de esta hora.,
+Posting future stock transactions are not allowed due to Immutable Ledger,No se permite la contabilización de transacciones de stock futuras debido al Libro mayor inmutable,
+A BOM with name {0} already exists for item {1}.,Ya existe una lista de materiales con el nombre {0} para el artículo {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} ¿Cambió el nombre del elemento? Póngase en contacto con el administrador / soporte técnico,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},En la fila n.º {0}: el ID de secuencia {1} no puede ser menor que el ID de secuencia de fila anterior {2},
+The {0} ({1}) must be equal to {2} ({3}),El {0} ({1}) debe ser igual a {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, complete la operación {1} antes de la operación {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,No se puede garantizar la entrega por número de serie ya que el artículo {0} se agrega con y sin Asegurar entrega por número de serie,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,El artículo {0} no tiene un número de serie. Solo los artículos serializados pueden tener una entrega basada en el número de serie.,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,No se encontró ninguna lista de materiales activa para el artículo {0}. No se puede garantizar la entrega por número de serie,
+No pending medication orders found for selected criteria,No se encontraron pedidos de medicamentos pendientes para los criterios seleccionados,
+From Date cannot be after the current date.,Desde la fecha no puede ser posterior a la fecha actual.,
+To Date cannot be after the current date.,Hasta la fecha no puede ser posterior a la fecha actual.,
+From Time cannot be after the current time.,Desde la hora no puede ser posterior a la hora actual.,
+To Time cannot be after the current time.,Hasta la hora no puede ser posterior a la hora actual.,
+Stock Entry {0} created and ,Entrada de stock {0} creada y,
+Inpatient Medication Orders updated successfully,Los pedidos de medicamentos para pacientes hospitalizados se actualizaron correctamente,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Fila {0}: no se puede crear una entrada de medicación para pacientes hospitalizados contra una orden de medicación para pacientes hospitalizados cancelada {1},
+Row {0}: This Medication Order is already marked as completed,Fila {0}: este pedido de medicamento ya está marcado como completado,
+Quantity not available for {0} in warehouse {1},Cantidad no disponible para {0} en el almacén {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Habilite Permitir stock negativo en la configuración de stock o cree Entrada de stock para continuar.,
+No Inpatient Record found against patient {0},No se encontraron registros de pacientes hospitalizados del paciente {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Ya existe una orden de medicación para pacientes hospitalizados {0} contra el encuentro con el paciente {1}.,
+Allow In Returns,Permitir devoluciones,
+Hide Unavailable Items,Ocultar elementos no disponibles,
+Apply Discount on Discounted Rate,Aplicar descuento sobre tarifa con descuento,
+Therapy Plan Template,Plantilla de plan de terapia,
+Fetching Template Details,Obteniendo detalles de la plantilla,
+Linked Item Details,Detalles del artículo vinculado,
+Therapy Types,Tipos de terapia,
+Therapy Plan Template Detail,Detalle de la plantilla del plan de terapia,
+Non Conformance,No conformidad,
+Process Owner,Dueño del proceso,
+Corrective Action,Acción correctiva,
+Preventive Action,Acción preventiva,
+Problem,Problema,
+Responsible,Responsable,
+Completion By,Finalización por,
+Process Owner Full Name,Nombre completo del propietario del proceso,
+Right Index,Índice derecho,
+Left Index,Índice izquierdo,
+Sub Procedure,Subprocedimiento,
+Passed,Aprobado,
+Print Receipt,Imprimir el recibo,
+Edit Receipt,Editar recibo,
+Focus on search input,Centrarse en la entrada de búsqueda,
+Focus on Item Group filter,Centrarse en el filtro de grupo de artículos,
+Checkout Order / Submit Order / New Order,Realizar pedido / Enviar pedido / Nuevo pedido,
+Add Order Discount,Agregar descuento de pedido,
+Item Code: {0} is not available under warehouse {1}.,Código de artículo: {0} no está disponible en el almacén {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Los números de serie no están disponibles para el artículo {0} en almacén {1}. Intente cambiar de almacén.,
+Fetched only {0} available serial numbers.,Solo se obtuvieron {0} números de serie disponibles.,
+Switch Between Payment Modes,Cambiar entre modos de pago,
+Enter {0} amount.,Ingrese {0} monto.,
+You don't have enough points to redeem.,No tienes suficientes puntos para canjear.,
+You can redeem upto {0}.,Puede canjear hasta {0}.,
+Enter amount to be redeemed.,Ingrese el monto a canjear.,
+You cannot redeem more than {0}.,No puede canjear más de {0}.,
+Open Form View,Abrir vista de formulario,
+POS invoice {0} created succesfully,Factura de punto de venta {0} creada correctamente,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,La cantidad de existencias no es suficiente para el código de artículo: {0} en el almacén {1}. Cantidad disponible {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Número de serie: {0} ya se ha transferido a otra factura de punto de venta.,
+Balance Serial No,No de serie de la balanza,
+Warehouse: {0} does not belong to {1},Almacén: {0} no pertenece a {1},
+Please select batches for batched item {0},Seleccione lotes para el artículo por lotes {0},
+Please select quantity on row {0},Seleccione la cantidad en la fila {0},
+Please enter serial numbers for serialized item {0},Ingrese los números de serie del artículo serializado {0},
+Batch {0} already selected.,Lote {0} ya seleccionado.,
+Please select a warehouse to get available quantities,Seleccione un almacén para obtener las cantidades disponibles,
+"For transfer from source, selected quantity cannot be greater than available quantity","Para la transferencia desde la fuente, la cantidad seleccionada no puede ser mayor que la cantidad disponible",
+Cannot find Item with this Barcode,No se puede encontrar el artículo con este código de barras,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} es obligatorio. Quizás no se crea el registro de cambio de moneda para {1} a {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} ha enviado elementos vinculados a él. Debe cancelar los activos para crear una devolución de compra.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,No se puede cancelar este documento porque está vinculado con el activo enviado {0}. Cancele para continuar.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Fila # {}: el número de serie {} ya se ha transferido a otra factura de punto de venta. Seleccione un número de serie válido.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Fila # {}: Los números de serie {} ya se han transferido a otra factura de punto de venta. Seleccione un número de serie válido.,
+Item Unavailable,Artículo no disponible,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Fila # {}: No de serie {} no se puede devolver porque no se tramitó en la factura original {},
+Please set default Cash or Bank account in Mode of Payment {},Establezca una cuenta bancaria o en efectivo predeterminada en el modo de pago {},
+Please set default Cash or Bank account in Mode of Payments {},Establezca la cuenta bancaria o en efectivo predeterminada en el modo de pago {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Asegúrese de que la cuenta {} sea una cuenta de balance. Puede cambiar la cuenta principal a una cuenta de balance o seleccionar una cuenta diferente.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Asegúrese de que la {} cuenta sea una cuenta a pagar. Cambie el tipo de cuenta a Pagable o seleccione una cuenta diferente.,
+Row {}: Expense Head changed to {} ,Fila {}: la cabeza de gastos cambió a {},
+because account {} is not linked to warehouse {} ,porque la cuenta {} no está vinculada al almacén {},
+or it is not the default inventory account,o no es la cuenta de inventario predeterminada,
+Expense Head Changed,Cabeza de gastos cambiada,
+because expense is booked against this account in Purchase Receipt {},porque el gasto se registra en esta cuenta en el recibo de compra {},
+as no Purchase Receipt is created against Item {}. ,ya que no se crea ningún recibo de compra para el artículo {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Esto se hace para manejar la contabilidad de los casos en los que el recibo de compra se crea después de la factura de compra.,
+Purchase Order Required for item {},Se requiere orden de compra para el artículo {},
+To submit the invoice without purchase order please set {} ,"Para enviar la factura sin orden de compra, configure {}",
+as {} in {},como en {},
+Mandatory Purchase Order,Orden de compra obligatoria,
+Purchase Receipt Required for item {},Se requiere recibo de compra para el artículo {},
+To submit the invoice without purchase receipt please set {} ,"Para enviar la factura sin el recibo de compra, configure {}",
+Mandatory Purchase Receipt,Recibo de compra obligatorio,
+POS Profile {} does not belongs to company {},El perfil de POS {} no pertenece a la empresa {},
+User {} is disabled. Please select valid user/cashier,El usuario {} está inhabilitado. Seleccione un usuario / cajero válido,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Fila # {}: la factura original {} de la factura de devolución {} es {}.,
+Original invoice should be consolidated before or along with the return invoice.,La factura original debe consolidarse antes o junto con la factura de devolución.,
+You can add original invoice {} manually to proceed.,Puede agregar la factura original {} manualmente para continuar.,
+Please ensure {} account is a Balance Sheet account. ,Asegúrese de que la cuenta {} sea una cuenta de balance.,
+You can change the parent account to a Balance Sheet account or select a different account.,Puede cambiar la cuenta principal a una cuenta de balance o seleccionar una cuenta diferente.,
+Please ensure {} account is a Receivable account. ,Asegúrese de que la {} cuenta sea una cuenta por cobrar.,
+Change the account type to Receivable or select a different account.,Cambie el tipo de cuenta a Cobrar o seleccione una cuenta diferente.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} no se puede cancelar ya que se canjearon los puntos de fidelidad ganados. Primero cancele el {} No {},
+already exists,ya existe,
+POS Closing Entry {} against {} between selected period,Entrada de cierre de POS {} contra {} entre el período seleccionado,
+POS Invoice is {},La factura de POS es {},
+POS Profile doesn't matches {},El perfil de POS no coincide {},
+POS Invoice is not {},La factura de POS no es {},
+POS Invoice isn't created by user {},La factura de punto de venta no la crea el usuario {},
+Row #{}: {},Fila #{}: {},
+Invalid POS Invoices,Facturas POS no válidas,
+Please add the account to root level Company - {},Agregue la cuenta a la empresa de nivel raíz - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Al crear la cuenta para la empresa secundaria {0}, no se encontró la cuenta principal {1}. Cree la cuenta principal en el COA correspondiente",
+Account Not Found,Cuenta no encontrada,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Al crear una cuenta para la empresa secundaria {0}, la cuenta principal {1} se encontró como una cuenta contable.",
+Please convert the parent account in corresponding child company to a group account.,Convierta la cuenta principal de la empresa secundaria correspondiente en una cuenta de grupo.,
+Invalid Parent Account,Cuenta principal no válida,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Solo se permite cambiar el nombre a través de la empresa matriz {0}, para evitar discrepancias.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Si {0} {1} cantidades del artículo {2}, el esquema {3} se aplicará al artículo.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Si {0} {1} vale el artículo {2}, el esquema {3} se aplicará al artículo.",
+"As the field {0} is enabled, the field {1} is mandatory.","Como el campo {0} está habilitado, el campo {1} es obligatorio.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Como el campo {0} está habilitado, el valor del campo {1} debe ser superior a 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},No se puede entregar el número de serie {0} del artículo {1} ya que está reservado para cumplir con el pedido de cliente {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Pedido de venta {0} tiene reserva para el artículo {1}, solo puede entregar reservado {1} contra {0}.",
+{0} Serial No {1} cannot be delivered,No se puede entregar el {0} número de serie {1},
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Fila {0}: el artículo subcontratado es obligatorio para la materia prima {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Como hay suficientes materias primas, la Solicitud de material no es necesaria para Almacén {0}.",
+" If you still want to proceed, please enable {0}.","Si aún desea continuar, habilite {0}.",
+The item referenced by {0} - {1} is already invoiced,El artículo al que hace referencia {0} - {1} ya está facturado,
+Therapy Session overlaps with {0},La sesión de terapia se superpone con {0},
+Therapy Sessions Overlapping,Superposición de sesiones de terapia,
+Therapy Plans,Planes de terapia,
+"Item Code, warehouse, quantity are required on row {0}","El código de artículo, el almacén y la cantidad son obligatorios en la fila {0}",
+Get Items from Material Requests against this Supplier,Obtener artículos de solicitudes de material contra este proveedor,
+Enable European Access,Habilitar el acceso europeo,
+Creating Purchase Order ...,Creando orden de compra ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Seleccione un proveedor de los proveedores predeterminados de los artículos a continuación. En la selección, se realizará una orden de compra contra los artículos que pertenecen al proveedor seleccionado únicamente.",
+Row #{}: You must select {} serial numbers for item {}.,Fila # {}: debe seleccionar {} números de serie para el artículo {}.,
diff --git a/erpnext/translations/es_ar.csv b/erpnext/translations/es_ar.csv
index 9bdcba1..1fd8723 100644
--- a/erpnext/translations/es_ar.csv
+++ b/erpnext/translations/es_ar.csv
@@ -1,5 +1,4 @@
Employee {0} on Half day on {1},"Empleado {0}, media jornada el día {1}",
-Item,Producto,
Communication,Comunicacion,
Components,Componentes,
Cheque Size,Tamaño de Cheque,
diff --git a/erpnext/translations/es_co.csv b/erpnext/translations/es_co.csv
index 67621d2..bc66ae6 100644
--- a/erpnext/translations/es_co.csv
+++ b/erpnext/translations/es_co.csv
@@ -1,4 +1,4 @@
Barcode {0} is not a valid {1} code,El código de barras {0} no es un código válido {1},
Clear filters,Limpiar Filtros,
{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master,{0} no tiene agenda del profesional médico . Añádelo al médico correspondiente.,
-Disabled,Deshabilitado,
+Disabled,Inhabilitado,
diff --git a/erpnext/translations/es_gt.csv b/erpnext/translations/es_gt.csv
index 2c8dac8..29ce2b8 100644
--- a/erpnext/translations/es_gt.csv
+++ b/erpnext/translations/es_gt.csv
@@ -1,5 +1,3 @@
-Chart Of Accounts,Plan de Cuentas,
-Item,Producto,
Lead Time Days,Tiempo de ejecución en días,
Outstanding,Pendiente,
Outstanding Amount,Saldo Pendiente,
diff --git a/erpnext/translations/es_mx.csv b/erpnext/translations/es_mx.csv
index 2fb4e6f..aac1a9e 100644
--- a/erpnext/translations/es_mx.csv
+++ b/erpnext/translations/es_mx.csv
@@ -12,7 +12,6 @@
"Material Request not created, as quantity for Raw Materials already available.","La Requisición de Material no fue creada, debido a que hay suficiente materia prima disponible.",
Mode of Payments,Forma de pago,
Only Leave Applications with status 'Approved' and 'Rejected' can be submitted,"Sólo Solicitudes de Permiso con estado ""Aprobado"" y ""Rechazado"" puede ser presentado",
-PO already created for all sales order items,Ya existe una Orden de Compra para todos los artículos de la Órden de Venta,
Please enter Account for Change Amount,"Por favor, introduzca la Vuenta para el Cambio Monto",
Please set 'Gain/Loss Account on Asset Disposal' in Company {0},Por favor defina la 'Cuenta de Ganacia/Pérdida por Ventas de Activos' en la empresa {0},
Please set Company filter blank if Group By is 'Company',"Por favor, establezca el filtro de Compañía en blanco si Agrupar Por es 'Compañía'",
diff --git a/erpnext/translations/es_pe.csv b/erpnext/translations/es_pe.csv
index 2dfb04b..108782c 100644
--- a/erpnext/translations/es_pe.csv
+++ b/erpnext/translations/es_pe.csv
@@ -67,7 +67,6 @@
Cash In Hand,Efectivo Disponible,
City/Town,Ciudad/Provincia,
Commission on Sales,Comisión de Ventas,
-Completed Qty can not be greater than 'Qty to Manufacture',La cantidad completada no puede ser mayor que la cantidad a producir,
Confirmed orders from Customers.,Pedidos en firme de los clientes.,
Consumed Amount,Cantidad Consumida,
Contact Details,Datos del Contacto,
@@ -333,8 +332,6 @@
Salutation,Saludo,
Sample,Muestra,
Sanctioned Amount,importe sancionado,
-Saturday,Sábado,
-Saved,Guardado,
Schedule,Horario,
Schedule Date,Horario Fecha,
Scheduled,Programado,
@@ -347,7 +344,6 @@
Select DocType,Seleccione tipo de documento,
Select Fiscal Year...,Seleccione el año fiscal ...,
"Selling must be checked, if Applicable For is selected as {0}","Ventas debe ser seleccionado, si se selecciona Aplicable Para como {0}",
-Serial #,Serial #,
Serial No is mandatory for Item {0},No de serie es obligatoria para el elemento {0},
Serial No {0} does not belong to Delivery Note {1},Número de orden {0} no pertenece a la nota de entrega {1},
Serial No {0} does not belong to Item {1},Número de orden {0} no pertenece al elemento {1},
@@ -413,7 +409,6 @@
Successfully Reconciled,Reconciliado con éxito,
Successfully deleted all transactions related to this company!,Eliminado correctamente todas las transacciones relacionadas con esta empresa!,
Sum of points for all goals should be 100. It is {0},Suma de puntos para todas las metas debe ser 100. Es {0},
-Sunday,Domingo,
Supplier,Proveedores,
Supplier Id,Proveedor Id,
Supplier Invoice No,Factura del Proveedor No,
@@ -514,6 +509,7 @@
{0}: {1} not found in Invoice Details table,{0}: {1} no se encuentra en el detalle de la factura,
Email Settings,Configuración del correo electrónico,
Import,Importación,
+Parent,Padre,
Shop,Tienda,
Subsidiary,Filial,
There were errors while sending email. Please try again.,"Hubo errores al enviar el correo electrónico. Por favor, inténtelo de nuevo.",
@@ -555,11 +551,8 @@
Frozen,Congelado,
"If the account is frozen, entries are allowed to restricted users.","Si la cuenta está congelada , las entradas se les permite a los usuarios restringidos.",
Balance must be,Balance debe ser,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",Asiento contable congelado actualmente ; nadie puede modificar el asiento excepto el rol que se especifica a continuación .,
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Función Permitida para Establecer Cuentas Congeladas y Editar Entradas Congeladas,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Los usuarios con esta función pueden establecer cuentas congeladas y crear / modificar los asientos contables contra las cuentas congeladas,
Credit Controller,Credit Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,Función que esta autorizada a presentar las transacciones que excedan los límites de crédito establecidos .,
Contact HTML,HTML del Contacto,
Account Currency,Moneda de la Cuenta,
Invoice Date,Fecha de la factura,
@@ -728,7 +721,6 @@
"Here you can maintain height, weight, allergies, medical concerns etc","Aquí usted puede mantener la altura , el peso, alergias , problemas médicos , etc",
Educational Qualification,Capacitación Académica,
Leave Encashed?,Vacaciones Descansadas?,
-Health Concerns,Preocupaciones de salud,
School/University,Escuela / Universidad,
Under Graduate,Bajo Graduación,
Year of Passing,Año de Fallecimiento,
@@ -738,9 +730,7 @@
Holiday List Name,Lista de nombres de vacaciones,
HR Settings,Configuración de Recursos Humanos,
Employee Settings,Configuración del Empleado,
-Employee Records to be created by,Registros de empleados a ser creados por,
Stop Birthday Reminders,Detener recordatorios de cumpleaños,
-Don't send Employee Birthday Reminders,En enviar recordatorio de cumpleaños del empleado,
Select Terms and Conditions,Selecciona Términos y Condiciones,
Description of a Job Opening,Descripción de una oferta de trabajo,
New Leaves Allocated,Nuevas Vacaciones Asignadas,
@@ -799,9 +789,7 @@
Completed Qty,Cant. Completada,
Manufacturing Settings,Ajustes de Manufactura,
Allow Overtime,Permitir horas extras,
-Plan time logs outside Workstation Working Hours.,Planear bitácora de trabajo para las horas fuera de la estación.,
Allow Production on Holidays,Permitir Producción en Vacaciones,
-Try planning operations for X days in advance.,Trate de operaciones para la planificación de X días de antelación.,
Material Request Type,Tipo de Solicitud de Material,
Material Issue,Incidencia de Material,
Get Sales Orders,Recibe Órdenes de Venta,
@@ -845,7 +833,6 @@
Settings for Selling Module,Ajustes para vender Módulo,
Customer Naming By,Naming Cliente Por,
Campaign Naming By,Nombramiento de la Campaña Por,
-Allow user to edit Price List Rate in transactions,Permitir al usuario editar Precio de Lista en las transacciones,
All Sales Partner Contact,Todo Punto de Contacto de Venta,
All Sales Person,Todos Ventas de Ventas,
Messages greater than 160 characters will be split into multiple messages,Los mensajes de más de 160 caracteres se dividirá en varios mensajes,
@@ -938,7 +925,6 @@
Purchase Receipt Item,Recibo de Compra del Artículo,
Purchase Receipt Items,Artículos de Recibo de Compra,
Get Items From Purchase Receipts,Obtener los elementos desde Recibos de Compra,
-Requested For,Solicitados para,
% Ordered,% Pedido,
Terms and Conditions Content,Términos y Condiciones Contenido,
Lead Time Date,Fecha y Hora de la Iniciativa,
@@ -981,9 +967,6 @@
Stock Reconciliation Item,Articulo de Reconciliación de Inventario,
Default Stock UOM,Unidad de Medida Predeterminada para Inventario,
Auto Material Request,Solicitud de Materiales Automatica,
-Raise Material Request when stock reaches re-order level,Enviar solicitud de materiales cuando se alcance un nivel bajo el stock,
-Notify by Email on creation of automatic Material Request,Notificarme por Email cuando se genere una nueva solicitud de materiales,
-Role Allowed to edit frozen stock,Función Permitida para editar Inventario Congelado,
UOM Conversion Detail,Detalle de Conversión de Unidad de Medida,
A logical Warehouse against which stock entries are made.,Un almacén lógico por el cual se hacen las entradas de existencia.,
Warehouse Detail,Detalle de almacenes,
diff --git a/erpnext/translations/et.csv b/erpnext/translations/et.csv
index 1ae39b0..ba32187 100644
--- a/erpnext/translations/et.csv
+++ b/erpnext/translations/et.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Tegelik tüüpimaks ei kanta Punkt määr rida {0},
Add,Lisama,
Add / Edit Prices,Klienditeenindus Lisa / uuenda Hinnad,
-Add All Suppliers,Lisa kõik pakkujad,
Add Comment,Lisa kommentaar,
Add Customers,Lisa kliendid,
Add Employees,Lisa Töötajad,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Ei saa maha arvata, kui kategooria on "Hindamine" või "Vaulation ja kokku"",
"Cannot delete Serial No {0}, as it is used in stock transactions","Ei saa kustutada Serial No {0}, sest seda kasutatakse laos tehingute",
Cannot enroll more than {0} students for this student group.,Ei saa registreeruda rohkem kui {0} õpilasi tudeng rühm.,
-Cannot find Item with this barcode,Selle vöötkoodiga üksust ei leitud,
Cannot find active Leave Period,Ei leia aktiivset puhkuseperioodi,
Cannot produce more Item {0} than Sales Order quantity {1},Ei suuda toota rohkem Punkt {0} kui Sales Order koguse {1},
Cannot promote Employee with status Left,Ei saa edendada Töötajat staatusega Vasak,
Cannot refer row number greater than or equal to current row number for this Charge type,Kas ei viita rea number on suurem või võrdne praeguse rea number selle Charge tüübist,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Ei saa valida tasuta tüübiks "On eelmise rea summa" või "On eelmise rea kokku" esimese rea,
-Cannot set a received RFQ to No Quote,Saadud RFQ-d ei saa määrata tsiteerimata,
Cannot set as Lost as Sales Order is made.,"Ei saa määrata, kui on kaotatud Sales Order on tehtud.",
Cannot set authorization on basis of Discount for {0},Ei saa seada loa alusel Allahindlus {0},
Cannot set multiple Item Defaults for a company.,Ettevõte ei saa määrata mitu üksust Vaikeväärtused.,
@@ -521,7 +518,6 @@
Chargeble,Tasuline,
Charges are updated in Purchase Receipt against each item,Maksud uuendatakse ostutšekk iga punkti,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Maksud jagatakse proportsionaalselt aluseks on elemendi Kogus või summa, ühe oma valikut",
-Chart Of Accounts,Kontoplaan,
Chart of Cost Centers,Graafik kulukeskuste,
Check all,Vaata kõiki,
Checkout,Minu tellimused,
@@ -581,7 +577,6 @@
Compensatory Off,Tasandusintress Off,
Compensatory leave request days not in valid holidays,Hüvitisepuhkuse taotluste päevad pole kehtivate pühade ajal,
Complaint,Kaebus,
-Completed Qty can not be greater than 'Qty to Manufacture',Valminud Kogus ei saa olla suurem kui "Kogus et Tootmine",
Completion Date,Lõppkuupäev,
Computer,Arvuti,
Condition,Seisund,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Luua ja hallata päeva, nädala ja kuu email digests.",
Create customer quotes,Loo klientide hinnapakkumisi,
Create rules to restrict transactions based on values.,"Loo reeglite piirata tehingud, mis põhinevad väärtustel.",
-Created By,Loodud,
Created {0} scorecards for {1} between: ,Loodud {0} tulemuskaardid {1} vahel:,
Creating Company and Importing Chart of Accounts,Ettevõtte loomine ja kontoplaani importimine,
Creating Fees,Tasude loomine,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Töötaja ülekandmist ei saa esitada enne ülekande kuupäeva,
Employee cannot report to himself.,Töötaja ei saa aru ise.,
Employee relieved on {0} must be set as 'Left',Töötaja vabastati kohta {0} tuleb valida 'Vasak',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Töötaja staatust ei saa seada vasakule, kuna järgmised töötajad teatavad sellest töötajale praegu:",
Employee {0} already submited an apllication {1} for the payroll period {2},Töötaja {0} on juba esitanud apllication {1} palgaarvestusperioodi kohta {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Töötaja {0} on juba {1} jaoks taotlenud {2} ja {3} vahel:,
Employee {0} has no maximum benefit amount,Töötaja {0} ei ole maksimaalse hüvitise suurust,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Rida {0}: sisestage kavandatud kogus,
"For {0}, only credit accounts can be linked against another debit entry","Sest {0}, ainult krediitkaardi kontod võivad olla seotud teise vastu deebetkanne",
"For {0}, only debit accounts can be linked against another credit entry","Sest {0}, ainult deebetkontode võib olla seotud teise vastu kreeditlausend",
-Form View,Vormi vaade,
Forum Activity,Foorumi tegevus,
Free item code is not selected,Vaba üksuse koodi ei valitud,
Freight and Forwarding Charges,Kaubavedu ja Edasitoimetuskulude,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Jäta ei saa eraldada enne {0}, sest puhkuse tasakaal on juba carry-edastas tulevikus puhkuse jaotamise rekord {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Jäta ei saa kohaldada / tühistatud enne {0}, sest puhkuse tasakaal on juba carry-edastas tulevikus puhkuse jaotamise rekord {1}",
Leave of type {0} cannot be longer than {1},Jäta tüüpi {0} ei saa olla pikem kui {1},
-Leave the field empty to make purchase orders for all suppliers,Jätke välja kõikidele tarnijatele tellimuste täitmiseks tühi väli,
Leaves,Lehed,
Leaves Allocated Successfully for {0},Lehed Eraldatud edukalt {0},
Leaves has been granted sucessfully,Lehed on õnnestunud,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Ei objektid Materjaliandmik et Tootmine,
No Items with Bill of Materials.,Materjalide arvel pole ühtegi eset.,
No Permission,Ei Luba,
-No Quote,Tsitaat ei ole,
No Remarks,No Märkused,
No Result to submit,Ei esitata tulemust,
No Salary Structure assigned for Employee {0} on given date {1},Palkade struktuur määratud töötajatele {0} antud kuupäeval {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Kattumine olude vahel:,
Owner,Omanik,
PAN,PAN,
-PO already created for all sales order items,PO on juba loodud kõikidele müügikorralduse elementidele,
POS,POS,
POS Profile,POS profiili,
POS Profile is required to use Point-of-Sale,POS-profiil on vajalik müügipunktide kasutamiseks,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Palun valige Charge Type esimene,
Please select Company,Palun valige Company,
Please select Company and Designation,Palun vali ettevõte ja nimetus,
-Please select Company and Party Type first,Palun valige Company Pidu ja Type esimene,
Please select Company and Posting Date to getting entries,Kirjete saamiseks valige ettevõtte ja postitamise kuupäev,
Please select Company first,Palun valige Company esimene,
Please select Completion Date for Completed Asset Maintenance Log,Palun vali lõpetatud varade hoolduse logi täitmise kuupäev,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Row {0}: UOM Conversion Factor on kohustuslik,
Row {0}: select the workstation against the operation {1},Rida {0}: valige tööjaam operatsiooni vastu {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Rida {0}: {1} punkti {2} jaoks nõutavad seerianumbrid. Te olete esitanud {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Ava {2} Arvete loomiseks on vaja rea {0}: {1},
Row {0}: {1} must be greater than 0,Rida {0}: {1} peab olema suurem kui 0,
Row {0}: {1} {2} does not match with {3},Row {0} {1} {2} ei ühti {3},
Row {0}:Start Date must be before End Date,Row {0}: Start Date tuleb enne End Date,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Saatke graafikujuliste meilide saatmine,
Send Now,Saada nüüd,
Send SMS,Saada SMS,
-Send Supplier Emails,Saada Tarnija kirjad,
Send mass SMS to your contacts,Saada mass SMS oma kontaktid,
Sensitivity,Tundlikkus,
Sent,Saadetud,
-Serial #,Serial #,
Serial No and Batch,Järjekorra number ja partii,
Serial No is mandatory for Item {0},Järjekorranumber on kohustuslik Punkt {0},
Serial No {0} does not belong to Batch {1},Seerianumber {0} ei kuulu partii {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Nimi oma firma jaoks, millele te Selle süsteemi rajamisel.",
The number of shares and the share numbers are inconsistent,Aktsiate arv ja aktsiate arv on ebajärjekindlad,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Kava {0} maksejuhtseade erineb selle maksetaotluses olevast maksejõu kontolt,
-The request for quotation can be accessed by clicking on the following link,Taotluse tsitaat pääseb klõpsates järgmist linki,
The selected BOMs are not for the same item,Valitud BOMs ei ole sama objekti,
The selected item cannot have Batch,Valitud parameetrit ei ole partii,
The seller and the buyer cannot be the same,Müüja ja ostja ei saa olla sama,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Paindliku hüvitise komponendi summa {0} ei tohiks olla väiksem kui maksimaalne kasu {1},
Total hours: {0},Kursuse maht: {0},
Total leaves allocated is mandatory for Leave Type {0},Lehtede kogusumma on kohustuslik väljumiseks Tüüp {0},
-Total weightage assigned should be 100%. It is {0},Kokku weightage määratud peaks olema 100%. On {0},
Total working hours should not be greater than max working hours {0},Kokku tööaeg ei tohi olla suurem kui max tööaeg {0},
Total {0} ({1}),Kokku {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Kokku {0} kõik elemendid on null, võib olla sa peaksid muutma "Hajuta põhinevad maksud"",
@@ -3316,7 +3299,6 @@
What do you need help with?,Millega sa abi vajad?,
What does it do?,Mida ta teeb?,
Where manufacturing operations are carried.,Kus tootmistegevus viiakse.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Lapseettevõtte {0} konto loomisel emakontot {1} ei leitud. Looge vanemkonto vastavas autentsussertis,
White,Valge,
Wire Transfer,Raha telegraafiülekanne,
WooCommerce Products,WooCommerce tooted,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} variandid on loodud.,
{0} {1} created,{0} {1} loodud,
{0} {1} does not exist,{0} {1} ei eksisteeri,
-{0} {1} does not exist.,{0} {1} ei ole olemas.,
{0} {1} has been modified. Please refresh.,{0} {1} on muudetud. Palun värskenda.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} ei ole esitatud, toimingut ei saa lõpule viia",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} on seotud {2} -ga, kuid osapoole konto on {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} pole olemas,
{0}: {1} not found in Invoice Details table,{0} {1} ei leidu Arve andmed tabelis,
{} of {},{} {},
+Assigned To,Määratud,
Chat,Vestlus,
Completed By,Lõpule jõudnud,
Conditions,Tingimused,
@@ -3506,7 +3488,9 @@
Merge with existing,Ühendamine olemasoleva,
Office,Kontor,
Orientation,orientatsioon,
+Parent,Lapsevanem,
Passive,Passiivne,
+Payment Failed,makse ebaõnnestus,
Percent,Protsenti,
Permanent,püsiv,
Personal,Personal,
@@ -3544,7 +3528,6 @@
Company field is required,Ettevõtte väli on kohustuslik,
Creating Dimensions...,Mõõtmete loomine ...,
Duplicate entry against the item code {0} and manufacturer {1},Tootekoodi {0} ja tootja {1} koopia,
-Import Chart Of Accounts from CSV / Excel files,Kontograafiku importimine CSV / Exceli failidest,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Kehtetu GSTIN! Teie sisestatud sisend ei vasta UIN-i omanike või mitteresidentide OIDAR-teenuse pakkujate GSTIN-vormingule,
Invoice Grand Total,Arve suur kokku,
Last carbon check date cannot be a future date,Viimane süsiniku kontrollimise kuupäev ei saa olla tulevane kuupäev,
@@ -3556,6 +3539,7 @@
Show {0},Kuva {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Erimärgid, välja arvatud "-", "#", ".", "/", "{" Ja "}" pole sarjade nimetamisel lubatud",
Target Details,Sihtkoha üksikasjad,
+{0} already has a Parent Procedure {1}.,{0} juba on vanemamenetlus {1}.,
API,API,
Annual,Aastane,
Approved,Kinnitatud,
@@ -3572,6 +3556,8 @@
No data to export,Pole andmeid eksportimiseks,
Portrait,Portree,
Print Heading,Prindi Rubriik,
+Scheduler Inactive,Ajasti mitteaktiivne,
+Scheduler is inactive. Cannot import data.,Ajasti on passiivne. Andmeid ei saa importida.,
Show Document,Kuva dokument,
Show Traceback,Kuva jälgimisvõimalus,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Loo üksuse {0} kvaliteedikontroll,
Creating Accounts...,Kontode loomine ...,
Creating bank entries...,Pangakannete loomine ...,
-Creating {0},{0} loomine,
Credit limit is already defined for the Company {0},Krediidilimiit on ettevõttele juba määratletud {0},
Ctrl + Enter to submit,Ctrl + Enter esitamiseks,
Ctrl+Enter to submit,"Ctrl + Enter, et saata",
@@ -3921,7 +3906,6 @@
Plaid public token error,Avalik sümboolne viga,
Plaid transactions sync error,Tavalise tehingu sünkroonimisviga,
Please check the error log for details about the import errors,Importimisvigade üksikasjade kohta kontrollige vealogi,
-Please click on the following link to set your new password,Palun kliki järgmist linki seada oma uus parool,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Palun looge ettevõtte <b>{}</b> jaoks <b>DATEV-i seaded</b> .,
Please create adjustment Journal Entry for amount {0} ,Palun loo korrigeeriv ajakirja kanne summa {0} jaoks,
Please do not create more than 500 items at a time,Ärge looge rohkem kui 500 eset korraga,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Väljalaskekuupäev peab olema tulevikus,
Relieving Date must be greater than or equal to Date of Joining,Vabastamiskuupäev peab olema liitumiskuupäevast suurem või sellega võrdne,
Rename,Nimeta,
+Rename Not Allowed,Ümbernimetamine pole lubatud,
Repayment Method is mandatory for term loans,Tagasimakseviis on tähtajaliste laenude puhul kohustuslik,
Repayment Start Date is mandatory for term loans,Tagasimakse alguskuupäev on tähtajaliste laenude puhul kohustuslik,
Report Item,Aruande üksus,
@@ -4043,7 +4028,6 @@
Select All,Vali kõik,
Select Difference Account,Valige Erinevuste konto,
Select a Default Priority.,Valige vaikimisi prioriteet.,
-Select a Supplier from the Default Supplier List of the items below.,Valige allolevate üksuste vaiktarnijate loendist tarnija.,
Select a company,Valige ettevõte,
Select finance book for the item {0} at row {1},Valige real {1} kirje {0} finantseerimisraamat,
Select only one Priority as Default.,Valige vaikimisi ainult üks prioriteet.,
@@ -4247,7 +4231,6 @@
Actual ,Tegelik,
Add to cart,Lisa ostukorvi,
Budget,Eelarve,
-Chart Of Accounts Importer,Kontoplaani importija,
Chart of Accounts,Kontode kaart,
Customer database.,Kliendiandmebaas.,
Days Since Last order,Päeva eelmisest Telli,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,End Date saa olla väiksem kui alguskuupäev,
For Default Supplier (Optional),Vaikimisi tarnija (valikuline),
From date cannot be greater than To date,Siit kuupäev ei saa olla suurem kui kuupäev,
-Get items from,Võta esemed,
Group by,Group By,
In stock,Laos,
Item name,Toote nimi,
@@ -4532,32 +4514,22 @@
Accounts Settings,Kontod Seaded,
Settings for Accounts,Seaded konto,
Make Accounting Entry For Every Stock Movement,Tee Raamatupidamine kirje Iga varude liikumist,
-"If enabled, the system will post accounting entries for inventory automatically.","Kui on lubatud, siis süsteem postitada raamatupidamiskirjeteks inventuuri automaatselt.",
-Accounts Frozen Upto,Kontod Külmutatud Upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Raamatupidamise kirje külmutatud kuni see kuupäev, keegi ei saa / muuda kande arvatud rolli allpool.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Role lubatud kehtestada külmutatud kontode ja Edit Külmutatud kanded,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Kasutajad seda rolli on lubatud kehtestada külmutatud kontode ja luua / muuta raamatupidamiskirjeteks vastu külmutatud kontode,
Determine Address Tax Category From,Aadressimaksu kategooria määramine alates,
-Address used to determine Tax Category in transactions.,"Aadress, mida kasutatakse tehingute maksukategooria määramiseks.",
Over Billing Allowance (%),Üle arvelduse toetus (%),
-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 for $110.,"Protsent, millal teil on lubatud tellitud summa eest rohkem arveid arvestada. Näiteks: kui toote tellimuse väärtus on 100 dollarit ja lubatud hälbeks on seatud 10%, siis on teil lubatud arveldada 110 dollarit.",
Credit Controller,Krediidi Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,"Roll, mis on lubatud esitada tehinguid, mis ületavad laenu piirmäärade.",
Check Supplier Invoice Number Uniqueness,Vaata Tarnija Arve number Uniqueness,
Make Payment via Journal Entry,Tee makse kaudu päevikusissekanne,
Unlink Payment on Cancellation of Invoice,Lingi eemaldada Makse tühistamine Arve,
-Unlink Advance Payment on Cancelation of Order,Vabastage ettemakse link tellimuse tühistamise korral,
Book Asset Depreciation Entry Automatically,Broneeri Asset amortisatsioon Entry automaatselt,
Automatically Add Taxes and Charges from Item Tax Template,Lisage maksud ja lõivud automaatselt üksuse maksumallilt,
Automatically Fetch Payment Terms,Maksetingimuste automaatne toomine,
-Show Inclusive Tax In Print,Näita ka kaasnevat maksu printimisel,
Show Payment Schedule in Print,Kuva maksegraafik Prindis,
Currency Exchange Settings,Valuuta vahetus seaded,
Allow Stale Exchange Rates,Lubage vahetuskursi halvenemine,
Stale Days,Stale päevad,
Report Settings,Aruandeseaded,
Use Custom Cash Flow Format,Kasutage kohandatud rahavoogude vormingut,
-Only select if you have setup Cash Flow Mapper documents,"Valige ainult siis, kui olete seadistanud rahavoogude kaardistaja dokumendid",
Allowed To Transact With,Lubatud teha tehinguid,
SWIFT number,SWIFT-number,
Branch Code,Filiaali kood,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Kliendi Group,
POS Field,POS-väli,
POS Item Group,POS Artikliklasside,
-[Select],[Vali],
Company Address,ettevõtte aadress,
Update Stock,Värskenda Stock,
Ignore Pricing Rule,Ignoreeri Hinnakujundus reegel,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Tarnija nimetamine By,
Default Supplier Group,Vaikepakkumise grupp,
Default Buying Price List,Vaikimisi ostmine hinnakiri,
-Maintain same rate throughout purchase cycle,Säilitada samas tempos kogu ostutsükkel,
-Allow Item to be added multiple times in a transaction,"Luba toode, mis lisatakse mitu korda tehingu",
Backflush Raw Materials of Subcontract Based On,Allhankelepingu aluseks olevad backflush tooraineid,
Material Transferred for Subcontract,Subcontract'ile edastatud materjal,
Over Transfer Allowance (%),Ülekandetoetus (%),
@@ -5540,7 +5509,6 @@
Current Stock,Laoseis,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Üksikute tarnija,
-Supplier Detail,tarnija Detail,
Link to Material Requests,Link materjalitaotlustele,
Message for Supplier,Sõnum Tarnija,
Request for Quotation Item,Hinnapäring toode,
@@ -6481,7 +6449,6 @@
Appraisal Template,Hinnang Mall,
For Employee Name,Töötajate Nimi,
Goals,Eesmärgid,
-Calculate Total Score,Arvuta üldskoor,
Total Score (Out of 5),Üldskoor (Out of 5),
"Any other remarks, noteworthy effort that should go in the records.","Muid märkusi, tähelepanuväärne jõupingutusi, et peaks minema arvestust.",
Appraisal Goal,Hinnang Goal,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Põhjus lahkumiseks,
Leave Encashed?,Jäta realiseeritakse?,
Encashment Date,Inkassatsioon kuupäev,
-Exit Interview Details,Exit Intervjuu Üksikasjad,
-Held On,Toimunud,
-Reason for Resignation,Lahkumise põhjuseks,
-Better Prospects,Paremad väljavaated,
-Health Concerns,Terviseprobleemid,
New Workplace,New Töökoht,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Tagastatud summa,
@@ -6740,10 +6702,7 @@
Employee Settings,Töötaja Seaded,
Retirement Age,pensioniiga,
Enter retirement age in years,Sisesta pensioniiga aastat,
-Employee Records to be created by,Töötajate arvestuse loodud,
-Employee record is created using selected field. ,"Töötaja rekord on loodud, kasutades valitud valdkonnas.",
Stop Birthday Reminders,Stopp Sünnipäev meeldetuletused,
-Don't send Employee Birthday Reminders,Ärge saatke Töötaja Sünnipäev meeldetuletused,
Expense Approver Mandatory In Expense Claim,Kulude kinnitamise kohustuslik kulude hüvitamise nõue,
Payroll Settings,Palga Seaded,
Leave,Lahku,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Jäta taotleja heakskiit kohustuslikuks,
Show Leaves Of All Department Members In Calendar,Näita kõigi osakonna liikmete lehti kalendris,
Auto Leave Encashment,Automaatne lahkumise krüpteerimine,
-Restrict Backdated Leave Application,Piira tagasiulatuva puhkuserakenduse kasutamist,
Hiring Settings,Töölevõtmise seaded,
Check Vacancies On Job Offer Creation,Kontrollige tööpakkumiste loomise vabu kohti,
Identification Document Type,Identifitseerimisdokumendi tüüp,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Tootmine Seaded,
Raw Materials Consumption,Toorainete tarbimine,
Allow Multiple Material Consumption,Luba mitme materjali tarbimine,
-Allow multiple Material Consumption against a Work Order,Võimaldage mitu materjalitarbimist töökorralduse vastu,
Backflush Raw Materials Based On,Backflush tooraine põhineb,
Material Transferred for Manufacture,Materjal üleantud tootmine,
Capacity Planning,Capacity Planning,
Disable Capacity Planning,Keela võimsuse planeerimine,
Allow Overtime,Laske Ületunnitöö,
-Plan time logs outside Workstation Working Hours.,Plaani aeg kajakad väljaspool Workstation tööaega.,
Allow Production on Holidays,Laske Production Holidays,
Capacity Planning For (Days),Maht planeerimist (päevad),
-Try planning operations for X days in advance.,Proovige plaanis operatsioonide X päeva ette.,
-Time Between Operations (in mins),Aeg toimingute vahel (in minutit),
-Default 10 mins,Vaikimisi 10 minutit,
Default Warehouses for Production,Tootmise vaikelaod,
Default Work In Progress Warehouse,Vaikimisi Work In Progress Warehouse,
Default Finished Goods Warehouse,Vaikimisi valmistoodangu ladu,
Default Scrap Warehouse,Vanametalli ladu,
-Over Production for Sales and Work Order,Ületootmine müügiks ja töö tellimine,
Overproduction Percentage For Sales Order,Ületootmise protsent müügi tellimuse jaoks,
Overproduction Percentage For Work Order,Ületootmise protsent töökorraldusele,
Other Settings,Muud seaded,
Update BOM Cost Automatically,Värskenda BOM-i maksumust automaatselt,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Värskendage BOM-i automaatselt Scheduleri kaudu, tuginedes kõige värskemale hindamismäärale / hinnakirja hinnale / toorainete viimasele ostuhinnale.",
Material Request Plan Item,Materjalitaotluse kava punkt,
Material Request Type,Materjal Hankelepingu liik,
Material Issue,Materjal Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Kvaliteetne eesmärk,
Monitoring Frequency,Sageduse jälgimine,
Weekday,Nädalapäev,
-January-April-July-October,Jaanuar-aprill-juuli-oktoober,
-Revision and Revised On,Redaktsioon ja parandatud sisse,
-Revision,Redaktsioon,
-Revised On,Muudetud Sisse,
Objectives,Eesmärgid,
Quality Goal Objective,Kvaliteedieesmärk,
Objective,Objektiivne,
@@ -7619,7 +7566,6 @@
Processes,Protsessid,
Quality Procedure Process,Kvaliteediprotseduuri protsess,
Process Description,Protsessi kirjeldus,
-Child Procedure,Lapse protseduur,
Link existing Quality Procedure.,Siduge olemasolev kvaliteediprotseduur.,
Additional Information,Lisainformatsioon,
Quality Review Objective,Kvaliteedianalüüsi eesmärk,
@@ -7787,15 +7733,9 @@
Default Customer Group,Vaikimisi Kliendi Group,
Default Territory,Vaikimisi Territory,
Close Opportunity After Days,Sule Opportunity Pärast päevi,
-Auto close Opportunity after 15 days,Auto sule võimalus pärast 15 päeva,
Default Quotation Validity Days,Vaikimisi väärtpaberite kehtivuspäevad,
Sales Update Frequency,Müügi värskendamise sagedus,
-How often should project and company be updated based on Sales Transactions.,Kui tihti peaks müügitehingute põhjal uuendama projekti ja ettevõtet.,
Each Transaction,Iga tehing,
-Allow user to edit Price List Rate in transactions,Luba kasutajal muuta hinnakirja hind tehingutes,
-Allow multiple Sales Orders against a Customer's Purchase Order,Laske mitu müügitellimuste vastu Kliendi ostutellimuse,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Kinnitada müügihind kulukoht ostmise korral või Hindamine Rate,
-Hide Customer's Tax Id from Sales Transactions,Peida Kliendi Maksu Id müügitehingute,
SMS Center,SMS Center,
Send To,Saada,
All Contact,Kõik Contact,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Tootjad kasutada Esemed,
Limited to 12 characters,Üksnes 12 tähemärki,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Määra ladu,
-Sets 'For Warehouse' in each row of the Items table.,Määrab tabeli Üksused igale reale „For Warehouse”.,
-Requested For,Taotletakse,
Partially Ordered,Osaliselt tellitud,
Transferred,üle,
% Ordered,% Tellitud,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Vaikimisi Stock UOM,
Sample Retention Warehouse,Proovide säilitamise ladu,
Default Valuation Method,Vaikimisi hindamismeetod,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Osakaal teil on lubatud vastu võtta või pakkuda rohkem vastu tellitav kogus. Näiteks: Kui olete tellinud 100 ühikut. ja teie toetus on 10%, siis on lubatud saada 110 ühikut.",
-Action if Quality inspection is not submitted,"Toiming, kui kvaliteedikontrolli ei esitata",
Show Barcode Field,Näita vöötkoodi Field,
Convert Item Description to Clean HTML,Objekti kirjelduse teisendamine HTML-i puhastamiseks,
-Auto insert Price List rate if missing,"Auto sisestada Hinnakiri määra, kui puuduvad",
Allow Negative Stock,Laske Negatiivne Stock,
Automatically Set Serial Nos based on FIFO,Seatakse automaatselt Serial nr põhineb FIFO,
-Set Qty in Transactions based on Serial No Input,Määrake tehingute arv järjekorranumbriga,
Auto Material Request,Auto Material taotlus,
-Raise Material Request when stock reaches re-order level,"Tõsta materjal taotlus, kui aktsia jõuab uuesti, et tase",
-Notify by Email on creation of automatic Material Request,"Soovin e-postiga loomiseks, automaatne Material taotlus",
Inter Warehouse Transfer Settings,Inter Warehouse Transfer seaded,
-Allow Material Transfer From Delivery Note and Sales Invoice,Luba materjali üleandmine saatelehelt ja müügiarvelt,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Materjaliülekande lubamine ostutšekilt ja ostuarvest,
Freeze Stock Entries,Freeze Stock kanded,
Stock Frozen Upto,Stock Külmutatud Upto,
-Freeze Stocks Older Than [Days],Freeze Varud vanem kui [Päeva],
-Role Allowed to edit frozen stock,Role Lubatud muuta külmutatud laos,
Batch Identification,Partii identifitseerimine,
Use Naming Series,Kasutage nimeserverit,
Naming Series Prefix,Nimi seeria prefiks,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Ostutšekk Trends,
Purchase Register,Ostu Registreeri,
Quotation Trends,Tsitaat Trends,
-Quoted Item Comparison,Tsiteeritud Punkt võrdlus,
Received Items To Be Billed,Saadud objekte arve,
Qty to Order,Kogus tellida,
Requested Items To Be Transferred,Taotletud üleantavate,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Materjalitaotluste jaoks valige ladu,
Transfer Materials For Warehouse {0},Lao materjalide edastamine {0},
Production Plan Material Request Warehouse,Tootmiskava materjalitaotluse ladu,
-Set From Warehouse,Komplekt laost,
-Source Warehouse (Material Transfer),Allika ladu (materjaliülekanne),
Sets 'Source Warehouse' in each row of the items table.,Määrab üksuste tabeli igale reale 'Allika ladu'.,
Sets 'Target Warehouse' in each row of the items table.,Määrab üksuste tabeli igale reale 'Sihtlao'.,
Show Cancelled Entries,Kuva tühistatud kirjed,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Teenus saadud, kuid arveldamata",
Deferred Accounting Settings,Edasilükatud raamatupidamise seaded,
Book Deferred Entries Based On,Broneeri edasilükatud kanded selle põhjal,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Kui valitakse "Kuud", siis broneeritakse fikseeritud summa iga kuu edasilükkunud tuluna või kuluna, olenemata kuu päevade arvust. Proportsioneeritakse, kui edasilükkunud tulu või kulu ei broneerita terve kuu vältel.",
Days,Päevad,
Months,Kuud,
Book Deferred Entries Via Journal Entry,Edasilükatud kirjete broneerimine ajakirjakirje kaudu,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Kui see on märkimata, luuakse edasilükatud tulude / kulude broneerimiseks otsesed GL-kirjed",
Submit Journal Entries,Esitage päeviku kanded,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Kui see on märkimata, salvestatakse kirjed olekusse Mustand ja need tuleb esitada käsitsi",
Enable Distributed Cost Center,Luba jaotatud kulude keskus,
@@ -8901,8 +8823,6 @@
Is Inter State,On riikidevaheline,
Purchase Details,Ostu üksikasjad,
Depreciation Posting Date,Amortisatsiooni postitamise kuupäev,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Ostuarve ja kviitungi loomiseks vajalik ostutellimus,
-Purchase Receipt Required for Purchase Invoice Creation,Ostuarve loomiseks on vajalik ostutšekk,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Vaikimisi määratakse tarnija nimi sisestatud tarnija nime järgi. Kui soovite, et tarnijad nimetaks a",
choose the 'Naming Series' option.,vali variant 'Seeria nimetamine'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Uue ostutehingu loomisel konfigureerige vaikehinnakiri. Kauba hinnad saadakse sellest hinnakirjast.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Kas tulumaksu komponent,
Component properties and references ,Komponendi omadused ja viited,
Additional Salary ,Lisapalk,
-Condtion and formula,Tingimus ja valem,
Unmarked days,Märgistamata päevad,
Absent Days,Puuduvad päevad,
Conditions and Formula variable and example,Tingimused ja valemi muutuja ning näide,
Feedback By,Tagasiside autor,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Tootmise sektsioon,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Müügiarve ja saatelehe loomiseks on vajalik müügitellimus,
-Delivery Note Required for Sales Invoice Creation,Müügiarve loomiseks on vaja saatelehte,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Vaikimisi määratakse kliendinimi sisestatud täisnime järgi. Kui soovite, et klientidele annaks nime a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Uue müügitehingu loomisel konfigureerige vaikehinnakiri. Kauba hinnad saadakse sellest hinnakirjast.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Kui see suvand on konfigureeritud 'Jah', takistab ERPNext teid müügiarve või saatelehe loomist ilma, et enne müügitellimust loote. Selle konfiguratsiooni saab konkreetse kliendi jaoks tühistada, lubades kliendihalduris märkeruudu „Luba müügiarve loomine ilma müügitellimuseta”.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} lisati kõikidele valitud teemadele edukalt.,
Topics updated,Teemad on uuendatud,
Academic Term and Program,Akadeemiline termin ja programm,
-Last Stock Transaction for item {0} was on {1}.,Üksuse {0} viimane varutehing toimus {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Üksuse {0} aktsiatehinguid ei saa enne seda aega postitada.,
Please remove this item and try to submit again or update the posting time.,Eemaldage see üksus ja proovige uuesti esitada või värskendage postitamise aega.,
Failed to Authenticate the API key.,API võtme autentimine ebaõnnestus.,
Invalid Credentials,Kehtetu mandaat,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Kontrollige oma Plaid-kliendi ID-d ja salajasi väärtusi,
Bank transaction creation error,Pangatehingute loomise viga,
Unit of Measurement,Mõõtühik,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Rida nr {}: üksuse {} müügimäär on madalam kui selle {}. Müügimäär peaks olema vähemalt {},
Fiscal Year {0} Does Not Exist,Eelarveaasta {0} puudub,
Row # {0}: Returned Item {1} does not exist in {2} {3},Rida nr {0}: tagastatud üksust {1} pole piirkonnas {2} {3},
Valuation type charges can not be marked as Inclusive,Hindamistüübi tasusid ei saa märkida kaasavateks,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,{0} Rea {1} prioriteedi reageerimisaeg ei tohi olla pikem kui eraldusvõime aeg.,
{0} is not enabled in {1},{0} pole piirkonnas {1} lubatud,
Group by Material Request,Rühmitage materjalitaotluse järgi,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Rida {0}: tarnija {0} jaoks on e-posti saatmiseks vaja e-posti aadressi,
Email Sent to Supplier {0},Tarnijale saadetud e-post {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",Juurdepääs portaali hinnapakkumistele on keelatud. Juurdepääsu lubamiseks lubage see portaali seadetes.,
Supplier Quotation {0} Created,Tarnija pakkumine {0} loodud,
Valid till Date cannot be before Transaction Date,Kehtiv kuupäev ei saa olla enne tehingu kuupäeva,
+Unlink Advance Payment on Cancellation of Order,Tühistage ettemakse tellimuse tühistamisel,
+"Simple Python Expression, Example: territory != 'All Territories'","Lihtne Pythoni väljend, näide: territoorium! = 'Kõik territooriumid'",
+Sales Contributions and Incentives,Müügimaksed ja stiimulid,
+Sourced by Supplier,Hankinud tarnija,
+Total weightage assigned should be 100%.<br>It is {0},Määratud kogukaal peaks olema 100%.<br> See on {0},
+Account {0} exists in parent company {1}.,Konto {0} on emaettevõttes {1}.,
+"To overrule this, enable '{0}' in company {1}",Selle tühistamiseks lubage ettevõttes „{0}” {1},
+Invalid condition expression,Vale tingimuse avaldis,
+Please Select a Company First,Valige kõigepealt ettevõte,
+Please Select Both Company and Party Type First,Palun valige kõigepealt nii ettevõtte kui ka peo tüüp,
+Provide the invoice portion in percent,Esitage arve osa protsentides,
+Give number of days according to prior selection,Esitage päevade arv vastavalt eelnevale valikule,
+Email Details,E-posti üksikasjad,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Valige vastuvõtjale tervitus. Nt härra, proua jne.",
+Preview Email,E-posti eelvaade,
+Please select a Supplier,Valige tarnija,
+Supplier Lead Time (days),Tarnija tarneaeg (päevades),
+"Home, Work, etc.","Kodu, töökoht jne.",
+Exit Interview Held On,Väljumisintervjuu on pooleli,
+Condition and formula,Seisund ja valem,
+Sets 'Target Warehouse' in each row of the Items table.,Määrab tabeli Üksused igale reale 'Sihtlao'.,
+Sets 'Source Warehouse' in each row of the Items table.,Määrab tabeli Üksused igale reale 'Allika ladu'.,
+POS Register,POSide register,
+"Can not filter based on POS Profile, if grouped by POS Profile",POS-profiili järgi ei saa filtreerida POS-profiili järgi,
+"Can not filter based on Customer, if grouped by Customer","Kliendi järgi ei saa filtreerida, kui see on rühmitatud kliendi järgi",
+"Can not filter based on Cashier, if grouped by Cashier",Kasseri järgi ei saa filtreerida kassapõhiselt,
+Payment Method,Makseviis,
+"Can not filter based on Payment Method, if grouped by Payment Method","Makseviisi järgi ei saa filtreerida, kui see on rühmitatud makseviisi järgi",
+Supplier Quotation Comparison,Tarnijate pakkumiste võrdlus,
+Price per Unit (Stock UOM),Ühiku hind (varu UOM),
+Group by Supplier,Rühmitage tarnija järgi,
+Group by Item,Rühmitage üksuste kaupa,
+Remember to set {field_label}. It is required by {regulation}.,Ärge unustage määrata {field_label}. Seda nõuab {määrus}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Registreerumise kuupäev ei tohi olla varasem kui õppeaasta alguskuupäev {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Registreerumise kuupäev ei tohi olla akadeemilise tähtaja lõppkuupäevast {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Registreerumise kuupäev ei tohi olla varasem kui akadeemilise termini alguskuupäev {0},
+Future Posting Not Allowed,Tulevane postitamine pole lubatud,
+"To enable Capital Work in Progress Accounting, ",Kapitalitöö jätkamise raamatupidamise lubamiseks,
+you must select Capital Work in Progress Account in accounts table,kontode tabelis peate valima Töötlemata konto,
+You can also set default CWIP account in Company {},CWIP-i vaikekonto saate määrata ka ettevõttes {},
+The Request for Quotation can be accessed by clicking on the following button,Hinnapakkumisele pääsete juurde klõpsates järgmist nuppu,
+Regards,Tervitades,
+Please click on the following button to set your new password,Uue parooli määramiseks klõpsake järgmisel nupul,
+Update Password,Parooli värskendamine,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Rida nr {}: üksuse {} müügimäär on madalam kui selle {}. Müük {} peaks olema vähemalt {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Selle valideerimise vältimiseks võite müügihindade valideerimise keelata asukohas {}.,
+Invalid Selling Price,Vale müügihind,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Aadress tuleb ettevõttega linkida. Lisage tabelisse Lingid ettevõtte rida.,
+Company Not Linked,Ettevõte pole lingitud,
+Import Chart of Accounts from CSV / Excel files,Kontoplaani import CSV / Exceli failidest,
+Completed Qty cannot be greater than 'Qty to Manufacture',Täidetud kogus ei tohi olla suurem kui „tootmise kogus”,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Rida {0}: tarnija {1} jaoks on meili saatmiseks vaja e-posti aadressi,
+"If enabled, the system will post accounting entries for inventory automatically","Kui see on lubatud, postitab süsteem varude arvestuskanded automaatselt",
+Accounts Frozen Till Date,Kontod külmutatud kuni kuupäevani,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"Raamatupidamiskirjed on selle kuupäevani külmutatud. Keegi ei saa kirjeid luua ega muuta, välja arvatud allpool määratletud rolliga kasutajad",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Külmutatud kontode määramiseks ja külmutatud kirjete muutmiseks on lubatud roll,
+Address used to determine Tax Category in transactions,"Aadress, mida kasutatakse tehingute maksukategooria määramiseks",
+"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 ","Protsent, mille kohta saate tellitud summa eest rohkem arveid esitada. Näiteks kui üksuse tellimuse väärtus on 100 dollarit ja tolerantsiks on seatud 10%, on teil lubatud arveldada kuni 110 dollarit",
+This role is allowed to submit transactions that exceed credit limits,"Sellel rollil on lubatud esitada tehinguid, mis ületavad krediidilimiite",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Kui valitakse "Kuud", broneeritakse fikseeritud summa iga kuu edasilükkunud tuluna või kuluna, olenemata kuu päevade arvust. See proportsioneeritakse, kui edasilükkunud tulu või kulu ei broneerita terve kuu vältel",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Kui see on märkimata, luuakse edasilükkunud tulude või kulude kirjendamiseks otsesed GL-kirjed",
+Show Inclusive Tax in Print,Kuva kaasav maks printimises,
+Only select this if you have set up the Cash Flow Mapper documents,"Valige see ainult siis, kui olete seadistanud Cash Flow Mapperi dokumendid",
+Payment Channel,Maksekanal,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Kas ostuarve ja kviitungi loomiseks on vaja ostutellimust?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Kas ostuarve koostamiseks on vajalik ostutšekk?,
+Maintain Same Rate Throughout the Purchase Cycle,Säilitage kogu ostutsükli jooksul sama määr,
+Allow Item To Be Added Multiple Times in a Transaction,Lubage üksust tehingus mitu korda lisada,
+Suppliers,Tarnijad,
+Send Emails to Suppliers,Saada e-kirjad tarnijatele,
+Select a Supplier,Valige tarnija,
+Cannot mark attendance for future dates.,Edasiste kuupäevade külastamist ei saa märkida.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Kas soovite värskendada külastatavust?<br> Kohal: {0}<br> Puudub: {1},
+Mpesa Settings,Mpesa seaded,
+Initiator Name,Algataja nimi,
+Till Number,Kuni numbrini,
+Sandbox,Liivakast,
+ Online PassKey,Veebipõhine PassKey,
+Security Credential,Turvalisuse mandaat,
+Get Account Balance,Hankige konto saldo,
+Please set the initiator name and the security credential,Palun määrake algataja nimi ja turvakandaat,
+Inpatient Medication Entry,Statsionaarsete ravimite sissekanne,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Kauba kood (ravim),
+Medication Orders,Ravimitellimused,
+Get Pending Medication Orders,Hankige ootel olevad ravimitellimused,
+Inpatient Medication Orders,Statsionaarsed ravimitellimused,
+Medication Warehouse,Ravimite ladu,
+Warehouse from where medication stock should be consumed,"Ladu, kust tuleks ravimivarusid tarbida",
+Fetching Pending Medication Orders,Ootel olevate ravimitellimuste toomine,
+Inpatient Medication Entry Detail,Statsionaarsete ravimite sisenemise üksikasjad,
+Medication Details,Ravimite üksikasjad,
+Drug Code,Ravimikood,
+Drug Name,Ravimi nimi,
+Against Inpatient Medication Order,Statsionaarsete ravimite tellimuse vastu,
+Against Inpatient Medication Order Entry,Statsionaarsete ravimitellimuste sissekande vastu,
+Inpatient Medication Order,Statsionaarsete ravimite tellimine,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Tellimusi kokku,
+Completed Orders,Täidetud tellimused,
+Add Medication Orders,Lisage ravimitellimused,
+Adding Order Entries,Tellimiskannete lisamine,
+{0} medication orders completed,{0} ravimitellimust täidetud,
+{0} medication order completed,{0} ravimitellimus täidetud,
+Inpatient Medication Order Entry,Statsionaarsete ravimite tellimuse kanne,
+Is Order Completed,Kas tellimus on täidetud,
+Employee Records to Be Created By,"Töötajate registrid, mille loovad",
+Employee records are created using the selected field,Töötajate kirjed luuakse valitud välja abil,
+Don't send employee birthday reminders,Ärge saatke töötajate sünnipäeva meeldetuletusi,
+Restrict Backdated Leave Applications,Piirata aegunud lahkumisrakendusi,
+Sequence ID,Järjestuse ID,
+Sequence Id,Järjestuse ID,
+Allow multiple material consumptions against a Work Order,Töökorralduse vastu lubage mitu materjali tarbimist,
+Plan time logs outside Workstation working hours,Planeerige ajagraafikud väljaspool tööjaama tööaega,
+Plan operations X days in advance,Planeerige operatsioone X päeva ette,
+Time Between Operations (Mins),Operatsioonide vaheline aeg (min),
+Default: 10 mins,Vaikimisi: 10 minutit,
+Overproduction for Sales and Work Order,Müügi ja töökorra ületootmine,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",Värskendage BOM-i maksumust ajakava abil automaatselt tooraine uusima hindamismäära / hinnakirja määra / viimase ostumäära alusel,
+Purchase Order already created for all Sales Order items,Kõigi müügitellimuse üksuste jaoks on juba loodud ostutellimus,
+Select Items,Valige üksused,
+Against Default Supplier,Vaikimisi tarnija vastu,
+Auto close Opportunity after the no. of days mentioned above,Automaatne sulgemisvõimalus pärast nr. ülalnimetatud päevadest,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Kas müügiarve ja saatelehe loomiseks on vaja müügitellimust?,
+Is Delivery Note Required for Sales Invoice Creation?,Kas müügiarve koostamiseks on vaja saatelehte?,
+How often should Project and Company be updated based on Sales Transactions?,Kui tihti tuleks projekti ja ettevõtet müügitehingute põhjal värskendada?,
+Allow User to Edit Price List Rate in Transactions,Luba kasutajal muuta tehingute hinnakirja määra,
+Allow Item to Be Added Multiple Times in a Transaction,Luba üksust mitu korda tehingus lisada,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Luba mitu müügitellimust kliendi ostutellimuse vastu,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Kinnitage kauba müügihind võrreldes ostumäära või hindamismääraga,
+Hide Customer's Tax ID from Sales Transactions,Peida kliendi maksu-ID müügitehingute alt,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Protsent, mida lubatakse tellitud koguse vastu rohkem kätte saada või tarnida. Näiteks kui olete tellinud 100 ühikut ja teie toetus on 10%, on lubatud saada 110 ühikut.",
+Action If Quality Inspection Is Not Submitted,"Toiming, kui kvaliteedikontrolli ei esitata",
+Auto Insert Price List Rate If Missing,"Automaatselt lisage hinnakirja määr, kui see puudub",
+Automatically Set Serial Nos Based on FIFO,Määra automaatselt seerianumbrid FIFO põhjal,
+Set Qty in Transactions Based on Serial No Input,Määra tehingute arv sisese sisendi põhjal,
+Raise Material Request When Stock Reaches Re-order Level,"Tõsta materjalitaotlust, kui laos on järeltellimise tase",
+Notify by Email on Creation of Automatic Material Request,Automaatse materjalitaotluse loomise kohta teavitage meili teel,
+Allow Material Transfer from Delivery Note to Sales Invoice,Luba materjali üleandmine saatelehelt müügiarvele,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Luba materjaliülekanne ostukviitungilt ostuarvele,
+Freeze Stocks Older Than (Days),Vanemate kui päevade varude külmutamine,
+Role Allowed to Edit Frozen Stock,Roll on lubatud külmutatud varu muutmiseks,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Maksekande {0} jaotamata summa on suurem kui pangatehingu jaotamata summa,
+Payment Received,Makse laekunud,
+Attendance cannot be marked outside of Academic Year {0},Osalemist ei saa märkida väljaspool õppeaastat {0},
+Student is already enrolled via Course Enrollment {0},Õpilane on juba registreerunud kursuse registreerimise kaudu {0},
+Attendance cannot be marked for future dates.,Tulevaste kuupäevade puhul ei saa osalemist märkida.,
+Please add programs to enable admission application.,Lisage sisseastumisavalduse lubamiseks programmid.,
+The following employees are currently still reporting to {0}:,Järgmised töötajad annavad praegu ettevõttele {0} endiselt aru:,
+Please make sure the employees above report to another Active employee.,"Veenduge, et ülaltoodud töötajad teataksid teisele aktiivsele töötajale.",
+Cannot Relieve Employee,Töötajat ei saa leevendada,
+Please enter {0},Sisestage {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Valige mõni muu makseviis. Mpesa ei toeta tehinguid valuutas „{0}”,
+Transaction Error,Tehingu viga,
+Mpesa Express Transaction Error,Mpesa Expressi tehingu viga,
+"Issue detected with Mpesa configuration, check the error logs for more details","Mpesa konfiguratsioonis tuvastati probleem, lisateabe saamiseks kontrollige tõrke logisid",
+Mpesa Express Error,Mpesa Expressi viga,
+Account Balance Processing Error,Konto saldo töötlemise viga,
+Please check your configuration and try again,Kontrollige oma konfiguratsiooni ja proovige uuesti,
+Mpesa Account Balance Processing Error,Mpesa konto saldo töötlemise viga,
+Balance Details,Saldo üksikasjad,
+Current Balance,Kontojääk,
+Available Balance,Vaba jääk,
+Reserved Balance,Reserveeritud saldo,
+Uncleared Balance,Tühjendamata saldo,
+Payment related to {0} is not completed,Kontoga {0} seotud makse pole lõpule viidud,
+Row #{}: Item Code: {} is not available under warehouse {}.,Rida nr {}: üksuse kood: {} pole laos saadaval {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Rida nr {}: laokogusest ei piisa tootekoodi jaoks: {} lao all {}. Saadaval kogus {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Rida nr {}: tehingu lõpuleviimiseks valige seerianumber ja partii üksuse vastu: {} või eemaldage see.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Rida nr {}: üksuse seerianumbrit pole valitud: {}. Tehingu lõpuleviimiseks valige üks või eemaldage see.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Rida nr {}: üksuse vastu pole valitud ühtegi partiid: {}. Tehingu lõpuleviimiseks valige pakk või eemaldage see.,
+Payment amount cannot be less than or equal to 0,Maksesumma ei tohi olla väiksem kui 0 või sellega võrdne,
+Please enter the phone number first,Esmalt sisestage telefoninumber,
+Row #{}: {} {} does not exist.,Rida nr {}: {} {} pole olemas.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Rida nr {0}: arvete avamine {2} on vajalik {1},
+You had {} errors while creating opening invoices. Check {} for more details,Avaarve loomisel tekkis {} viga. Lisateavet leiate aadressilt {},
+Error Occured,Ilmnes viga,
+Opening Invoice Creation In Progress,Arve loomise avamine on pooleli,
+Creating {} out of {} {},Loomine {} / {} {} -st,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Seerianumber: {0}) ei saa tarbida, kuna see on ette nähtud müügitellimuse täitmiseks {1}.",
+Item {0} {1},Üksus {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Üksuse {0} lao {1} viimane varutehing toimus {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Varude {0} lao {1} laotehinguid ei saa enne seda aega postitada.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Tulevaste aktsiatehingute postitamine pole lubatud muutumatu pearaamatu tõttu,
+A BOM with name {0} already exists for item {1}.,Nimega {0} BOM on juba üksusel {1} olemas.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Kas nimetasite üksuse ümber? Võtke ühendust administraatori / tehnilise toega,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Reas nr {0}: jada ID {1} ei tohi olla väiksem kui eelmine rea jada ID {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) peab olema võrdne väärtusega {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, lõpetage toiming {1} enne toimingut {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Ei saa tagada kohaletoimetamist seerianumbriga, kuna üksus {0} on lisatud koos ja ilma tagamiseta seerianumbriga.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Üksusel {0} ei ole seerianumbrit. Seerianumbri alusel saab tarnida ainult seriliseeritud üksusi,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Üksuse {0} aktiivset BOM-i ei leitud. Edastamist seerianumbriga ei saa tagada,
+No pending medication orders found for selected criteria,Valitud kriteeriumide järgi ei leitud ootel ravimeid,
+From Date cannot be after the current date.,Kuupäev ei saa olla praegusest kuupäevast hilisem.,
+To Date cannot be after the current date.,Kuupäev ei saa olla praegusest kuupäevast hilisem.,
+From Time cannot be after the current time.,Alates ajast ei saa olla praeguse aja järel.,
+To Time cannot be after the current time.,Kellaaeg ei saa olla pärast praegust kellaaega.,
+Stock Entry {0} created and ,Varude kanne {0} on loodud ja,
+Inpatient Medication Orders updated successfully,Statsionaarsete ravimitellimuste uuendamine õnnestus,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Rida {0}: statsionaarset ravimikirjet ei saa tühistatud statsionaarse ravimitellimuse alusel luua {1},
+Row {0}: This Medication Order is already marked as completed,Rida {0}: see ravimitellimus on juba täidetuks märgitud,
+Quantity not available for {0} in warehouse {1},Kogus {0} laos {1} pole saadaval,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Jätkamiseks lubage aktsiaseadetes Luba negatiivne varu või looge varude sisestus.,
+No Inpatient Record found against patient {0},Patsiendi {0} kohta ei leitud statsionaarset dokumenti,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Statsionaarsete ravimite tellimus {0} patsiendi kohtumise vastu {1} on juba olemas.,
+Allow In Returns,Luba vastutasuks,
+Hide Unavailable Items,Peida kättesaamatud üksused,
+Apply Discount on Discounted Rate,Rakenda soodushinnale allahindlust,
+Therapy Plan Template,Teraapiakava mall,
+Fetching Template Details,Malli üksikasjade toomine,
+Linked Item Details,Lingitud üksuse üksikasjad,
+Therapy Types,Ravi tüübid,
+Therapy Plan Template Detail,Teraapiakava malli üksikasjad,
+Non Conformance,Mittevastavus,
+Process Owner,Protsessi omanik,
+Corrective Action,Parandusmeetmeid,
+Preventive Action,Ennetav tegevus,
+Problem,Probleem,
+Responsible,Vastutav,
+Completion By,Valmimine poolt,
+Process Owner Full Name,Protsessi omaniku täielik nimi,
+Right Index,Parem indeks,
+Left Index,Vasak indeks,
+Sub Procedure,Alammenetlus,
+Passed,Läbitud,
+Print Receipt,Prindi kviitung,
+Edit Receipt,Redigeeri kviitungit,
+Focus on search input,Keskenduge otsingusisendile,
+Focus on Item Group filter,Keskenduge üksuserühma filtrile,
+Checkout Order / Submit Order / New Order,Kassa tellimus / esitage tellimus / uus tellimus,
+Add Order Discount,Lisa tellimuse allahindlus,
+Item Code: {0} is not available under warehouse {1}.,Tootekood: {0} pole laos {1} saadaval.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Seerianumbrid pole saadaval kauba {0} laos {1} all. Proovige ladu vahetada.,
+Fetched only {0} available serial numbers.,Tõmmati ainult {0} saadaolevat seerianumbrit.,
+Switch Between Payment Modes,Makseviiside vahel vahetamine,
+Enter {0} amount.,Sisestage summa {0}.,
+You don't have enough points to redeem.,Teil pole lunastamiseks piisavalt punkte.,
+You can redeem upto {0}.,Saate lunastada kuni {0}.,
+Enter amount to be redeemed.,Sisestage lunastatav summa.,
+You cannot redeem more than {0}.,Te ei saa lunastada rohkem kui {0}.,
+Open Form View,Avage vormivaade,
+POS invoice {0} created succesfully,POS-arve {0} loodi edukalt,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Laokogusest ei piisa tootekoodi jaoks: {0} lao all {1}. Saadaval kogus {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Seerianumber: {0} on juba üle kantud teise POS-arvega.,
+Balance Serial No,Tasakaalu seerianumber,
+Warehouse: {0} does not belong to {1},Ladu: {0} ei kuulu domeenile {1},
+Please select batches for batched item {0},Valige partii pakendatud üksuse jaoks {0},
+Please select quantity on row {0},Valige real {0} kogus,
+Please enter serial numbers for serialized item {0},Sisestage jadatud üksuse {0} seerianumbrid,
+Batch {0} already selected.,Pakett {0} on juba valitud.,
+Please select a warehouse to get available quantities,Saadavate koguste saamiseks valige ladu,
+"For transfer from source, selected quantity cannot be greater than available quantity",Allikast ülekandmiseks ei tohi valitud kogus olla suurem kui saadaolev kogus,
+Cannot find Item with this Barcode,Selle vöötkoodiga üksust ei leia,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} on kohustuslik. Võib-olla pole valuutavahetuse kirjet loodud {1} - {2} jaoks,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} on esitanud sellega seotud varad. Ostu tagastamise loomiseks peate vara tühistama.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Seda dokumenti ei saa tühistada, kuna see on seotud esitatud varaga {0}. Jätkamiseks tühistage see.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Rida nr {}: seerianumber {} on juba üle kantud teise POS-arvega. Valige kehtiv seerianumber.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Rida nr {}: seerianumbrid {} on juba üle kantud teise POS-arvega. Valige kehtiv seerianumber.,
+Item Unavailable,Üksus pole saadaval,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Rida nr {}: seerianumbrit {} ei saa tagastada, kuna seda ei tehtud algses arves {}",
+Please set default Cash or Bank account in Mode of Payment {},Valige makseviisiks vaikesularaha või pangakonto {},
+Please set default Cash or Bank account in Mode of Payments {},Valige makserežiimis vaikesularaha või pangakonto {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Veenduge, et konto {} oleks bilansikonto. Saate muuta vanemkonto bilansikontoks või valida teise konto.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Veenduge, et konto {} oleks tasuline. Muutke konto tüüp tasutavaks või valige mõni muu konto.",
+Row {}: Expense Head changed to {} ,Rida {}: kulu pealkirjaks muudeti {,
+because account {} is not linked to warehouse {} ,kuna konto {} pole lingiga seotud {},
+or it is not the default inventory account,või see pole vaikekonto konto,
+Expense Head Changed,Kulu pea vahetatud,
+because expense is booked against this account in Purchase Receipt {},kuna kulu broneeritakse selle konto arvel ostutšekis {},
+as no Purchase Receipt is created against Item {}. ,kuna üksuse {} vastu ei looda ostutšekki.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Seda tehakse raamatupidamise juhtumite jaoks, kui ostuarve järel luuakse ostutšekk",
+Purchase Order Required for item {},Üksuse {} jaoks on vajalik ostutellimus,
+To submit the invoice without purchase order please set {} ,Arve esitamiseks ilma ostutellimuseta määrake {},
+as {} in {},nagu {},
+Mandatory Purchase Order,Kohustuslik ostutellimus,
+Purchase Receipt Required for item {},Üksuse {} jaoks on nõutav ostutšekk,
+To submit the invoice without purchase receipt please set {} ,Arve esitamiseks ilma ostutšekita määrake {},
+Mandatory Purchase Receipt,Kohustuslik ostutšekk,
+POS Profile {} does not belongs to company {},POS-profiil {} ei kuulu ettevõttele {},
+User {} is disabled. Please select valid user/cashier,Kasutaja {} on keelatud. Valige kehtiv kasutaja / kassapidaja,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Rida nr {}: tagastatava arve {} originaalarve {} on {}.,
+Original invoice should be consolidated before or along with the return invoice.,Algne arve tuleks koondada enne tagastusarvet või koos sellega.,
+You can add original invoice {} manually to proceed.,Jätkamiseks saate algse arve {} käsitsi lisada.,
+Please ensure {} account is a Balance Sheet account. ,"Veenduge, et konto {} oleks bilansikonto.",
+You can change the parent account to a Balance Sheet account or select a different account.,Saate muuta vanemkonto bilansikontoks või valida teise konto.,
+Please ensure {} account is a Receivable account. ,"Veenduge, et konto {} oleks saadaolev konto.",
+Change the account type to Receivable or select a different account.,Muutke konto tüüp olekuks Saada või valige mõni teine konto.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"{} ei saa tühistada, kuna teenitud lojaalsuspunktid on lunastatud. Kõigepealt tühistage {} Ei {}",
+already exists,juba eksisteerib,
+POS Closing Entry {} against {} between selected period,POSi sulgemiskanne {} vastu {} valitud perioodi vahel,
+POS Invoice is {},POS-arve on {},
+POS Profile doesn't matches {},POS-profiil ei ühti {},
+POS Invoice is not {},POS-arve pole {},
+POS Invoice isn't created by user {},POS-arvet ei loonud kasutaja {},
+Row #{}: {},Rida nr {}: {},
+Invalid POS Invoices,Vale POS-arve,
+Please add the account to root level Company - {},Lisage konto juurtaseme ettevõttele - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Lapseettevõttele {0} konto loomisel ei leitud vanemkontot {1}. Looge vanemakonto vastavas COA-s,
+Account Not Found,Kontot ei leitud,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",Lapseettevõttele {0} konto loomisel leiti vanemkonto {1} pearaamatu kontona.,
+Please convert the parent account in corresponding child company to a group account.,Teisendage vastava alaettevõtte vanemkonto grupikontoks.,
+Invalid Parent Account,Vale vanemakonto,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",Selle erinevuse vältimiseks on selle ümbernimetamine lubatud ainult emaettevõtte {0} kaudu.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",{0} {1} üksuse koguste {2} kasutamisel rakendatakse üksusele skeemi {3}.,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Kui {0} {1} väärt üksust {2}, rakendatakse üksusele skeemi {3}.",
+"As the field {0} is enabled, the field {1} is mandatory.","Kuna väli {0} on lubatud, on väli {1} kohustuslik.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Kuna väli {0} on lubatud, peaks välja {1} väärtus olema suurem kui 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Üksuse {0} seerianumbrit {1} ei saa edastada, kuna see on reserveeritud müügitellimuse täitmiseks {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Müügitellimusel {0} on üksuse {1} reservatsioon, saate reserveeritud {1} kohale toimetada ainult vastu {0}.",
+{0} Serial No {1} cannot be delivered,{0} Seerianumbrit {1} ei saa edastada,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Rida {0}: allhankeüksus on tooraine jaoks kohustuslik {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Kuna toorainet on piisavalt, pole Ladu {0} vaja materjalitaotlust.",
+" If you still want to proceed, please enable {0}.","Kui soovite siiski jätkata, lubage {0}.",
+The item referenced by {0} - {1} is already invoiced,"Üksus, millele viitab {0} - {1}, on juba arvega",
+Therapy Session overlaps with {0},Teraapiaseanss kattub rakendusega {0},
+Therapy Sessions Overlapping,Teraapiaseansid kattuvad,
+Therapy Plans,Teraapiakavad,
+"Item Code, warehouse, quantity are required on row {0}","Real {0} on nõutav kaubakood, ladu ja kogus",
+Get Items from Material Requests against this Supplier,Hankige esemeid selle tarnija vastu esitatud materjalitaotlustest,
+Enable European Access,Luba Euroopa juurdepääs,
+Creating Purchase Order ...,Ostutellimuse loomine ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",Valige allpool olevate üksuste vaiketarnijatest tarnija. Valiku alusel tehakse ostutellimus ainult valitud tarnijale kuuluvate kaupade kohta.,
+Row #{}: You must select {} serial numbers for item {}.,Rida nr {}: peate valima {} üksuse seerianumbrid {}.,
diff --git a/erpnext/translations/fa.csv b/erpnext/translations/fa.csv
index 7c05d34..4a7c979 100644
--- a/erpnext/translations/fa.csv
+++ b/erpnext/translations/fa.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},مالیات واقعی نوع می تواند در میزان مورد در ردیف شامل نمی شود {0},
Add,افزودن,
Add / Edit Prices,افزودن / ویرایش قیمت ها,
-Add All Suppliers,اضافه کردن همه تامین کنندگان,
Add Comment,اضافه کردن نظر,
Add Customers,اضافه کردن مشتریان,
Add Employees,اضافه کردن کارمندان,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',نمی توانید کسر وقتی دسته است برای ارزش گذاری "یا" Vaulation و مجموع:,
"Cannot delete Serial No {0}, as it is used in stock transactions",نمی توانید حذف سریال نه {0}، آن را به عنوان در معاملات سهام مورد استفاده,
Cannot enroll more than {0} students for this student group.,نمی توانید بیش از {0} دانش آموزان برای این گروه از دانشجویان ثبت نام.,
-Cannot find Item with this barcode,با این بارکد نمی توان مورد را یافت,
Cannot find active Leave Period,می توانید دوره فعال خروج را پیدا نکنید,
Cannot produce more Item {0} than Sales Order quantity {1},می تواند مورد دیگر {0} از مقدار سفارش فروش تولید نمی {1},
Cannot promote Employee with status Left,کارمند با وضعیت چپ را نمیتوان ارتقا داد,
Cannot refer row number greater than or equal to current row number for this Charge type,می توانید تعداد ردیف بزرگتر یا مساوی به تعداد سطر فعلی برای این نوع شارژ مراجعه نمی,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,می توانید نوع اتهام به عنوان 'در مقدار قبلی Row را انتخاب کنید و یا' در ردیف قبلی مجموع برای سطر اول,
-Cannot set a received RFQ to No Quote,نمی توان RFQ دریافتی را بدون نقل قول تنظیم کرد,
Cannot set as Lost as Sales Order is made.,می توانید مجموعه ای نه به عنوان از دست داده تا سفارش فروش ساخته شده است.,
Cannot set authorization on basis of Discount for {0},آیا می توانم مجوز بر اساس تخفیف برای تنظیم نشده {0},
Cannot set multiple Item Defaults for a company.,می توانید چندین مورد پیش فرض برای یک شرکت تنظیم کنید.,
@@ -521,7 +518,6 @@
Chargeble,شارژ,
Charges are updated in Purchase Receipt against each item,اتهامات در رسید خرید بر علیه هر یک از آیتم به روز شده,
"Charges will be distributed proportionately based on item qty or amount, as per your selection",اتهامات خواهد شد توزیع متناسب در تعداد آیتم یا مقدار بر اساس، به عنوان در هر انتخاب شما,
-Chart Of Accounts,ساختار حسابها,
Chart of Cost Centers,نمودار مراکز هزینه,
Check all,بررسی همه,
Checkout,وارسی,
@@ -581,7 +577,6 @@
Compensatory Off,جبرانی فعال,
Compensatory leave request days not in valid holidays,درخواست روز بازپرداخت جبران خسارت در تعطیلات معتبر,
Complaint,شکایت,
-Completed Qty can not be greater than 'Qty to Manufacture',تکمیل تعداد نمی تواند بیشتر از 'تعداد برای تولید',
Completion Date,تاریخ تکمیل,
Computer,کامپیوتر,
Condition,شرط,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.",ایجاد و مدیریت روزانه، هفتگی و ماهانه هضم ایمیل.,
Create customer quotes,درست به نقل از مشتری,
Create rules to restrict transactions based on values.,ایجاد قوانین برای محدود کردن معاملات بر اساس ارزش.,
-Created By,خلق شده توسط,
Created {0} scorecards for {1} between: ,{0} کارت امتیازی برای {1} ایجاد شده بین:,
Creating Company and Importing Chart of Accounts,ایجاد شرکت و وارد کردن نمودار حساب,
Creating Fees,ایجاد هزینه ها,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,انتقال کارفرما نمی تواند قبل از تاریخ انتقال ارسال شود,
Employee cannot report to himself.,کارمند نمی تواند به خود گزارش دهید.,
Employee relieved on {0} must be set as 'Left',کارمند رها در {0} باید تنظیم شود به عنوان چپ,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,وضعیت کارمندان را نمی توان "چپ" قرار داد زیرا کارمندان زیر در حال حاضر به این کارمند گزارش می دهند:,
Employee {0} already submited an apllication {1} for the payroll period {2},کارمند {0} قبلا یک آپلود {1} را برای مدت زمان پرداخت {2},
Employee {0} has already applied for {1} between {2} and {3} : ,کارکنان {0} قبلا برای {1} بین {2} و {3} درخواست شده است:,
Employee {0} has no maximum benefit amount,کارمند {0} مقدار حداکثر سود ندارد,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,برای ردیف {0}: تعداد برنامه ریزی شده را وارد کنید,
"For {0}, only credit accounts can be linked against another debit entry",برای {0}، تنها حساب های اعتباری می تواند در مقابل ورود بدهی دیگر مرتبط,
"For {0}, only debit accounts can be linked against another credit entry",برای {0}، تنها حساب های بانکی را می توان در برابر ورود اعتباری دیگر مرتبط,
-Form View,فرم مشاهده,
Forum Activity,فعالیت انجمن,
Free item code is not selected,کد مورد رایگان انتخاب نشده است,
Freight and Forwarding Charges,حمل و نقل و حمل و نقل اتهامات,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",می توانید قبل از ترک نمی اختصاص داده شود {0}، به عنوان تعادل مرخصی در حال حاضر شده حمل فرستاده در آینده رکورد تخصیص مرخصی {1},
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",ترک نمی تواند اعمال شود / قبل از {0} لغو، به عنوان تعادل مرخصی در حال حاضر شده حمل فرستاده در آینده رکورد تخصیص مرخصی {1},
Leave of type {0} cannot be longer than {1},مرخصی از نوع {0} نمی تواند بیش از {1},
-Leave the field empty to make purchase orders for all suppliers,زمینه را خالی بگذارید تا سفارشات خرید را برای همه تأمین کنندگان انجام دهید,
Leaves,برگها,
Leaves Allocated Successfully for {0},برگ با موفقیت برای اختصاص {0},
Leaves has been granted sucessfully,برگ ها به موفقیت آموخته شده اند,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,هیچ موردی با بیل از مواد برای تولید,
No Items with Bill of Materials.,هیچ موردی با قبض مواد وجود ندارد.,
No Permission,بدون اجازه,
-No Quote,بدون نقل قول,
No Remarks,بدون شرح,
No Result to submit,هیچ نتیجهای برای ارسال وجود ندارد,
No Salary Structure assigned for Employee {0} on given date {1},بدون ساختار حقوق و دستمزد برای کارمندان {0} در تاریخ داده شده {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,شرایط با هم تداخل دارند بین:,
Owner,مالک,
PAN,ماهی تابه,
-PO already created for all sales order items,PO برای تمام اقلام سفارش فروش ایجاد شده است,
POS,POS,
POS Profile,نمایش POS,
POS Profile is required to use Point-of-Sale,مشخصات POS برای استفاده از Point-of-Sale مورد نیاز است,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,لطفا ابتدا شارژ نوع را انتخاب کنید,
Please select Company,لطفا انتخاب کنید شرکت,
Please select Company and Designation,لطفا شرکت و تعیین را انتخاب کنید,
-Please select Company and Party Type first,لطفا ابتدا شرکت و حزب نوع را انتخاب کنید,
Please select Company and Posting Date to getting entries,لطفا شرکت و تاریخ ارسال را برای گرفتن نوشته انتخاب کنید,
Please select Company first,لطفا ابتدا شرکت را انتخاب کنید,
Please select Completion Date for Completed Asset Maintenance Log,لطفا تاریخ تکمیل را برای ورود به سیستم نگهداری دارایی تکمیل کنید,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,ردیف {0}: UOM عامل تبدیل الزامی است,
Row {0}: select the workstation against the operation {1},ردیف {0}: ایستگاه کاری را در برابر عملیات انتخاب کنید {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,ردیف {0}: {1} شماره سریال مورد برای {2} مورد نیاز است. شما {3} را ارائه کرده اید.,
-Row {0}: {1} is required to create the Opening {2} Invoices,ردیف {0}: {1} لازم است برای ایجاد بازخوانی {2} صورتحساب,
Row {0}: {1} must be greater than 0,ردیف {0}: {1} باید از 0 باشد,
Row {0}: {1} {2} does not match with {3},ردیف {0}: {1} {2} با مطابقت ندارد {3},
Row {0}:Start Date must be before End Date,ردیف {0}: تاریخ شروع باید قبل از پایان تاریخ است,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,ارسال ایمیل به گرانت,
Send Now,در حال حاضر ارسال,
Send SMS,ارسال اس ام اس,
-Send Supplier Emails,ارسال ایمیل کننده,
Send mass SMS to your contacts,ارسال اس ام اس انبوه به مخاطبین خود,
Sensitivity,حساسیت,
Sent,فرستاده,
-Serial #,سریال #,
Serial No and Batch,سریال نه و دسته ای,
Serial No is mandatory for Item {0},سریال بدون برای مورد الزامی است {0},
Serial No {0} does not belong to Batch {1},شماره سریال {0} به دسته {1} تعلق ندارد,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,نام شرکت خود را که برای آن شما راه اندازی این سیستم.,
The number of shares and the share numbers are inconsistent,تعداد سهام و شماره سهم ناسازگار است,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,حساب دروازه پرداخت در برنامه {0} متفاوت از حساب دروازه پرداخت در این درخواست پرداخت است,
-The request for quotation can be accessed by clicking on the following link,درخواست برای نقل قول می توان با کلیک بر روی لینک زیر قابل دسترسی,
The selected BOMs are not for the same item,BOM ها انتخاب شده برای آیتم یکسان نیست,
The selected item cannot have Batch,آیتم انتخاب شده می تواند دسته ای ندارد,
The seller and the buyer cannot be the same,فروشنده و خریدار نمیتوانند یکسان باشند,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},مقدار کامپوننت منعطف انعطاف پذیر {0} نباید کمتر از مزایای حداکثر باشد {1},
Total hours: {0},کل ساعت: {0},
Total leaves allocated is mandatory for Leave Type {0},مجموع برگ ها اختصاص داده شده برای نوع ترک {0} اجباری است,
-Total weightage assigned should be 100%. It is {0},بین وزنها مجموع اختصاص داده باید 100٪ باشد. این {0},
Total working hours should not be greater than max working hours {0},کل ساعات کار نباید از ساعات کار حداکثر است بیشتر {0},
Total {0} ({1}),مجموع {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'",مجموع {0} برای همه موارد صفر است، ممکن است شما باید 'اتهامات بر اساس توزیع را تغییر,
@@ -3316,7 +3299,6 @@
What do you need help with?,به چه نیاز دارید کمک کنیم؟,
What does it do?,چه کاری انجام میدهد؟,
Where manufacturing operations are carried.,که در آن عملیات ساخت در حال انجام شده است.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",هنگام ایجاد حساب کاربری برای شرکت کودک {0} ، حساب والدین {1} یافت نشد. لطفاً حساب والدین را در COA مربوطه ایجاد کنید,
White,سفید,
Wire Transfer,انتقال سیم,
WooCommerce Products,محصولات WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} انواع ایجاد شده است.,
{0} {1} created,{0} {1} ایجاد شد,
{0} {1} does not exist,{0} {1} وجود ندارد,
-{0} {1} does not exist.,{0} {1} وجود ندارد,
{0} {1} has been modified. Please refresh.,{0} {1} اصلاح شده است. لطفا بازخوانی کنید.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} ارائه نشده است پس از عمل نمی تواند تکمیل شود,
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1} با {2} مرتبط است، اما حساب حزبی {3},
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} وجود ندارد,
{0}: {1} not found in Invoice Details table,{0}: {1} در فاکتور جزییات جدول یافت نشد,
{} of {},{} از {},
+Assigned To,اختصاص یافته به,
Chat,گپ زدن,
Completed By,تکمیل شده توسط,
Conditions,شرایط,
@@ -3506,7 +3488,9 @@
Merge with existing,ادغام با موجود,
Office,دفتر,
Orientation,گرایش,
+Parent,والدین,
Passive,غیر فعال,
+Payment Failed,پرداخت ناموفق,
Percent,در صد,
Permanent,دائمي,
Personal,شخصی,
@@ -3544,7 +3528,6 @@
Company field is required,زمینه شرکت مورد نیاز است,
Creating Dimensions...,ایجاد ابعاد ...,
Duplicate entry against the item code {0} and manufacturer {1},ورودی کپی شده در برابر کد مورد {0} و سازنده {1},
-Import Chart Of Accounts from CSV / Excel files,وارد کردن نمودار حساب از پرونده های CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN نامعتبر است! ورودی که وارد کردید با قالب GSTIN برای دارندگان UIN یا ارائه دهندگان خدمات OIDAR غیر مقیم مطابقت ندارد,
Invoice Grand Total,تعداد کل فاکتور,
Last carbon check date cannot be a future date,تاریخ آخرین بررسی کربن نمی تواند یک تاریخ آینده باشد,
@@ -3556,6 +3539,7 @@
Show {0},نمایش {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",کاراکترهای خاص به جز "-" ، "#" ، "." ، "/" ، "{" و "}" در سریال نامگذاری مجاز نیستند,
Target Details,جزئیات هدف,
+{0} already has a Parent Procedure {1}.,{0} در حال حاضر یک روش والدین {1} دارد.,
API,API,
Annual,سالیانه,
Approved,تایید,
@@ -3572,6 +3556,8 @@
No data to export,داده ای برای صادرات وجود ندارد,
Portrait,پرتره,
Print Heading,چاپ سرنویس,
+Scheduler Inactive,زمانبند غیرفعال,
+Scheduler is inactive. Cannot import data.,زمانبند غیرفعال است. وارد کردن داده امکان پذیر نیست.,
Show Document,نمایش سند,
Show Traceback,نمایش ردگیری,
Video,فیلم,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},ایجاد کیفیت بازرسی برای مورد {0},
Creating Accounts...,ایجاد حساب ...,
Creating bank entries...,در حال ایجاد ورودی های بانکی ...,
-Creating {0},ایجاد {0},
Credit limit is already defined for the Company {0},حد اعتبار در حال حاضر برای 0 {شرکت تعریف شده است,
Ctrl + Enter to submit,Ctrl + را وارد کنید تا ارسال شود,
Ctrl+Enter to submit,Ctrl + برای ارسال وارد شوید,
@@ -3921,7 +3906,6 @@
Plaid public token error,خطای نشانه عمومی,
Plaid transactions sync error,خطای همگام سازی معاملات کار شده,
Please check the error log for details about the import errors,لطفاً جزئیات مربوط به خطاهای واردات را وارد کنید,
-Please click on the following link to set your new password,لطفا بر روی لینک زیر کلیک کنید برای تنظیم کلمه عبور جدید خود را,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,لطفا ایجاد <b>DATEV تنظیمات</b> برای شرکت <b>{}.</b>,
Please create adjustment Journal Entry for amount {0} ,لطفاً مبلغ ورود مجله تنظیم را برای مبلغ {0} ایجاد کنید,
Please do not create more than 500 items at a time,لطفاً بیش از 500 مورد را همزمان ایجاد نکنید,
@@ -3997,6 +3981,7 @@
Release date must be in the future,تاریخ انتشار باید در آینده باشد,
Relieving Date must be greater than or equal to Date of Joining,Relieve Date باید بیشتر یا مساوی تاریخ عضویت باشد,
Rename,تغییر نام,
+Rename Not Allowed,تغییر نام مجاز نیست,
Repayment Method is mandatory for term loans,روش بازپرداخت برای وام های کوتاه مدت الزامی است,
Repayment Start Date is mandatory for term loans,تاریخ شروع بازپرداخت برای وام های کوتاه مدت الزامی است,
Report Item,گزارش مورد,
@@ -4043,7 +4028,6 @@
Select All,انتخاب همه,
Select Difference Account,حساب کاربری تفاوت را انتخاب کنید,
Select a Default Priority.,اولویت پیش فرض را انتخاب کنید.,
-Select a Supplier from the Default Supplier List of the items below.,تأمین کننده را از لیست پیش فرض تهیه کننده موارد زیر انتخاب کنید.,
Select a company,شرکتی را انتخاب کنید,
Select finance book for the item {0} at row {1},کتاب مالی را برای کالا {0} در ردیف {1 Select انتخاب کنید,
Select only one Priority as Default.,فقط یک اولویت را به عنوان پیش فرض انتخاب کنید.,
@@ -4247,7 +4231,6 @@
Actual ,واقعی,
Add to cart,اضافه کردن به سبد,
Budget,بودجه,
-Chart Of Accounts Importer,وارد کننده نمودار,
Chart of Accounts,نمودار حساب,
Customer database.,پایگاه داده مشتری.,
Days Since Last order,روز پس از آخرین سفارش,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,تاریخ پایان نمی تواند کمتر از تاریخ شروع,
For Default Supplier (Optional),برای تامین کننده پیش فرض (اختیاری),
From date cannot be greater than To date,از تاریخ نمی تواند بیشتر از تاریخ باشد,
-Get items from,گرفتن اقلام از,
Group by,گروه توسط,
In stock,در انبار,
Item name,نام آیتم,
@@ -4532,32 +4514,22 @@
Accounts Settings,تنظیمات حسابها,
Settings for Accounts,تنظیمات برای حساب,
Make Accounting Entry For Every Stock Movement,را حسابداری برای ورود به جنبش هر سهام,
-"If enabled, the system will post accounting entries for inventory automatically.",اگر فعال باشد، سیستم مطالب حسابداری برای موجودی ارسال به صورت خودکار.,
-Accounts Frozen Upto,حساب منجمد تا حد,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",ثبت حسابداری تا این تاریخ منجمد، هیچ کس نمی تواند انجام / اصلاح ورود به جز نقش های مشخص شده زیر.,
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,نقش مجاز به تنظیم حساب های یخ زده و منجمد ویرایش مطالب,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,کاربران با این نقش ها اجازه تنظیم حساب های یخ زده و ایجاد / تغییر نوشته های حسابداری در برابر حساب منجمد,
Determine Address Tax Category From,طبقه بندی مالیات آدرس را تعیین کنید,
-Address used to determine Tax Category in transactions.,آدرس مورد استفاده برای تعیین رده مالیاتی در معاملات.,
Over Billing Allowance (%),بیش از کمک هزینه صورتحساب (٪),
-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 for $110.,درصدی از شما مجاز به پرداخت مبلغ بیشتری درمقابل مبلغ سفارش شده هستید. به عنوان مثال: اگر مقدار سفارش برای یک مورد 100 دلار باشد و تحمل 10٪ تعیین شده باشد ، به شما اجازه می دهد برای 110 دلار صورتحساب بدهید.,
Credit Controller,کنترل اعتبار,
-Role that is allowed to submit transactions that exceed credit limits set.,نقش است که مجاز به ارائه معاملات است که بیش از محدودیت های اعتباری تعیین شده است.,
Check Supplier Invoice Number Uniqueness,بررسی تولید کننده فاکتور شماره منحصر به فرد,
Make Payment via Journal Entry,پرداخت از طریق ورود مجله,
Unlink Payment on Cancellation of Invoice,قطع ارتباط پرداخت در لغو فاکتور,
-Unlink Advance Payment on Cancelation of Order,پیوند پیش پرداخت را با لغو سفارش لغو پیوند دهید,
Book Asset Depreciation Entry Automatically,کتاب دارایی ورودی استهلاک به صورت خودکار,
Automatically Add Taxes and Charges from Item Tax Template,به طور خودکار مالیات و عوارض را از الگوی مالیات مورد اضافه کنید,
Automatically Fetch Payment Terms,شرایط پرداخت به صورت خودکار را اخذ کنید,
-Show Inclusive Tax In Print,نشان دادن مالیات فراگیر در چاپ,
Show Payment Schedule in Print,نمایش برنامه پرداخت در چاپ,
Currency Exchange Settings,تنظیمات ارز Exchange,
Allow Stale Exchange Rates,نرخ ارز ثابت,
Stale Days,روزهای سخت,
Report Settings,گزارش تنظیمات,
Use Custom Cash Flow Format,از فرم سفارشی جریان جریان استفاده کنید,
-Only select if you have setup Cash Flow Mapper documents,فقط اگر شما اسناد Flow Mapper را تنظیم کرده اید، انتخاب کنید,
Allowed To Transact With,مجاز به انجام معاملات,
SWIFT number,شماره SWIFT,
Branch Code,کد شعبه,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS و ضوابط گروه,
POS Field,زمینه POS,
POS Item Group,POS مورد گروه,
-[Select],[انتخاب],
Company Address,آدرس شرکت,
Update Stock,به روز رسانی سهام,
Ignore Pricing Rule,نادیده گرفتن قانون قیمت گذاری,
@@ -5495,8 +5466,6 @@
Supplier Naming By,تامین کننده نامگذاری توسط,
Default Supplier Group,گروه پیشفرض شرکت,
Default Buying Price List,به طور پیش فرض لیست قیمت خرید,
-Maintain same rate throughout purchase cycle,حفظ همان نرخ در سراسر چرخه خرید,
-Allow Item to be added multiple times in a transaction,اجازه می دهد مورد به چند بار در یک معامله اضافه شود,
Backflush Raw Materials of Subcontract Based On,مواد اولیه فرآورده های فرعی مبتنی بر قرارداد,
Material Transferred for Subcontract,ماده انتقال قرارداد قرارداد,
Over Transfer Allowance (%),بیش از کمک هزینه انتقال (٪),
@@ -5540,7 +5509,6 @@
Current Stock,سهام کنونی,
PUR-RFQ-.YYYY.-,PUR-RFQ- .YYYY.-,
For individual supplier,عرضه کننده منحصر به فرد,
-Supplier Detail,جزئیات کننده,
Link to Material Requests,پیوند به درخواستهای مواد,
Message for Supplier,پیام برای عرضه,
Request for Quotation Item,درخواست برای مورد دیگر,
@@ -6481,7 +6449,6 @@
Appraisal Template,ارزیابی الگو,
For Employee Name,نام کارمند,
Goals,اهداف,
-Calculate Total Score,محاسبه مجموع امتیاز,
Total Score (Out of 5),نمره کل (از 5),
"Any other remarks, noteworthy effort that should go in the records.",هر گونه اظهارات دیگر، تلاش قابل توجه است که باید در پرونده بروید.,
Appraisal Goal,ارزیابی هدف,
@@ -6599,11 +6566,6 @@
Reason for Leaving,دلیلی برای ترک,
Leave Encashed?,ترک نقد شدنی؟,
Encashment Date,Encashment عضویت,
-Exit Interview Details,جزییات خروج مصاحبه,
-Held On,برگزار,
-Reason for Resignation,دلیل استعفای,
-Better Prospects,چشم انداز بهتر,
-Health Concerns,نگرانی های بهداشتی,
New Workplace,جدید محل کار,
HR-EAD-.YYYY.-,HR-EAD- .YYYY.-,
Returned Amount,مقدار برگشت داده شد,
@@ -6740,10 +6702,7 @@
Employee Settings,تنظیمات کارمند,
Retirement Age,سن بازنشستگی,
Enter retirement age in years,سن بازنشستگی را وارد کنید در سال های,
-Employee Records to be created by,سوابق کارمند به ایجاد شود,
-Employee record is created using selected field. ,رکورد کارمند با استفاده از درست انتخاب شده ایجاد می شود.,
Stop Birthday Reminders,توقف تولد یادآوری,
-Don't send Employee Birthday Reminders,آیا کارمند تولد یادآوری ارسال کنید,
Expense Approver Mandatory In Expense Claim,تأیید کننده هزینه مورد نیاز در هزینه ادعا,
Payroll Settings,تنظیمات حقوق و دستمزد,
Leave,ترک کردن,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,خروج از تأیید کننده در مورد درخواست اجباری,
Show Leaves Of All Department Members In Calendar,نمایش برگ همه اعضای گروه در تقویم,
Auto Leave Encashment,خودکار ترک کردن رمزگذاری,
-Restrict Backdated Leave Application,برنامه مرخصی عقب مانده را محدود کنید,
Hiring Settings,تنظیمات استخدام,
Check Vacancies On Job Offer Creation,فرصتهای شغلی در ایجاد پیشنهاد شغلی را بررسی کنید,
Identification Document Type,نوع سند شناسایی,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,تنظیمات ساخت,
Raw Materials Consumption,مصرف مواد اولیه,
Allow Multiple Material Consumption,اجازه مصرف مواد چندگانه,
-Allow multiple Material Consumption against a Work Order,اجازه مصرف چند ماده در برابر سفارش کار,
Backflush Raw Materials Based On,Backflush مواد اولیه بر اساس,
Material Transferred for Manufacture,مواد منتقل شده برای ساخت,
Capacity Planning,برنامه ریزی ظرفیت,
Disable Capacity Planning,برنامه ریزی ظرفیت را غیرفعال کنید,
Allow Overtime,اجازه اضافه کاری,
-Plan time logs outside Workstation Working Hours.,برنامه ریزی سیاهههای مربوط به زمان در خارج از ساعات کاری ایستگاه کاری.,
Allow Production on Holidays,اجازه تولید در تعطیلات,
Capacity Planning For (Days),برنامه ریزی ظرفیت برای (روز),
-Try planning operations for X days in advance.,سعی کنید برنامه ریزی عملیات به مدت چند روز X در پیش است.,
-Time Between Operations (in mins),زمان بین عملیات (در دقیقه),
-Default 10 mins,پیش فرض 10 دقیقه,
Default Warehouses for Production,انبارهای پیش فرض برای تولید,
Default Work In Progress Warehouse,پیش فرض کار در انبار پیشرفت,
Default Finished Goods Warehouse,به طور پیش فرض به پایان رسید کالا انبار,
Default Scrap Warehouse,انبار ضایعات پیش فرض,
-Over Production for Sales and Work Order,بیش از تولید برای فروش و سفارش کار,
Overproduction Percentage For Sales Order,درصد تولید بیش از حد برای سفارش فروش,
Overproduction Percentage For Work Order,درصد تولید بیش از حد برای سفارش کار,
Other Settings,سایر تنظیمات,
Update BOM Cost Automatically,به روز رسانی BOM هزینه به صورت خودکار,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",به روز رسانی BOM هزینه به طور خودکار از طریق زمانبند، بر اساس آخرین ارزش نرخ نرخ / نرخ قیمت / آخرین نرخ خرید مواد خام.,
Material Request Plan Item,مورد درخواست طرح مواد,
Material Request Type,مواد نوع درخواست,
Material Issue,شماره مواد,
@@ -7603,10 +7554,6 @@
Quality Goal,هدف کیفیت,
Monitoring Frequency,فرکانس نظارت,
Weekday,روز هفته,
-January-April-July-October,ژانویه-آوریل-جولای-اکتبر,
-Revision and Revised On,بازبینی و اصلاح شده در,
-Revision,تجدید نظر,
-Revised On,اصلاح شده در,
Objectives,اهداف,
Quality Goal Objective,هدف کیفیت هدف,
Objective,هدف، واقعگرایانه,
@@ -7619,7 +7566,6 @@
Processes,مراحل,
Quality Procedure Process,فرایند روش کیفیت,
Process Description,شرح فرایند,
-Child Procedure,رویه کودک,
Link existing Quality Procedure.,رویه کیفیت موجود را پیوند دهید.,
Additional Information,اطلاعات اضافی,
Quality Review Objective,هدف مرور کیفیت,
@@ -7787,15 +7733,9 @@
Default Customer Group,گروه مشتری پیش فرض,
Default Territory,منطقه پیش فرض,
Close Opportunity After Days,نزدیک فرصت پس از چند روز,
-Auto close Opportunity after 15 days,خودرو فرصت نزدیک پس از 15 روز,
Default Quotation Validity Days,روز معتبر نقل قول,
Sales Update Frequency,فرکانس به روز رسانی فروش,
-How often should project and company be updated based on Sales Transactions.,چگونه باید پروژه و شرکت را براساس معاملات تجاری به روز کرد.,
Each Transaction,هر تراکنش,
-Allow user to edit Price List Rate in transactions,کاربر مجاز به ویرایش لیست قیمت نرخ در معاملات,
-Allow multiple Sales Orders against a Customer's Purchase Order,اجازه چندین سفارشات فروش در برابر خرید سفارش مشتری,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,اعتبار قیمت فروش برای مورد در برابر نرخ خرید و یا رای دادن به ارزش گذاری,
-Hide Customer's Tax Id from Sales Transactions,مخفی کردن شناسه مالیاتی مشتری از معاملات فروش,
SMS Center,مرکز SMS,
Send To,فرستادن به,
All Contact,همه تماس,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,تولید کنندگان مورد استفاده در موارد,
Limited to 12 characters,محدود به 12 کاراکتر,
MAT-MR-.YYYY.-,MAT-MR- .YYYY.-,
-Set Warehouse,انبار را تنظیم کنید,
-Sets 'For Warehouse' in each row of the Items table.,مجموعه "برای انبار" را در هر ردیف از جدول موارد قرار می دهد.,
-Requested For,درخواست برای,
Partially Ordered,تا حدی سفارش داده شده است,
Transferred,منتقل شده,
% Ordered,مرتب٪,
@@ -8407,24 +8344,14 @@
Default Stock UOM,به طور پیش فرض بورس UOM,
Sample Retention Warehouse,نمونه نگهداری انبار,
Default Valuation Method,روش های ارزش گذاری پیش فرض,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,درصد شما مجاز به دریافت و یا ارائه بیش برابر مقدار سفارش داد. به عنوان مثال: اگر شما 100 واحد دستور داده اند. و کمک هزینه خود را 10٪ و سپس شما مجاز به دریافت 110 واحد است.,
-Action if Quality inspection is not submitted,اگر بازرسی کیفیت ارائه نشود ، اقدام کنید,
Show Barcode Field,نمایش بارکد درست,
Convert Item Description to Clean HTML,Convert Item Description برای پاک کردن HTML,
-Auto insert Price List rate if missing,درج خودرو نرخ لیست قیمت اگر از دست رفته,
Allow Negative Stock,اجازه می دهد بورس منفی,
Automatically Set Serial Nos based on FIFO,تنظیم به صورت خودکار سریال بر اساس شماره FIFO,
-Set Qty in Transactions based on Serial No Input,مقدار در معاملات را بر اساس سریال بدون ورودی تنظیم کنید,
Auto Material Request,درخواست مواد خودکار,
-Raise Material Request when stock reaches re-order level,افزایش درخواست مواد زمانی که سهام سطح دوباره سفارش می رسد,
-Notify by Email on creation of automatic Material Request,با رایانامه آگاه کن در ایجاد درخواست مواد اتوماتیک,
Inter Warehouse Transfer Settings,تنظیمات انتقال انبار بین,
-Allow Material Transfer From Delivery Note and Sales Invoice,انتقال مواد از برگ تحویل و فاکتور فروش را مجاز کنید,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,انتقال مواد از قبض خرید و فاکتور خرید را مجاز کنید,
Freeze Stock Entries,یخ مطالب سهام,
Stock Frozen Upto,سهام منجمد تا حد,
-Freeze Stocks Older Than [Days],سهام یخ قدیمی تر از [روز],
-Role Allowed to edit frozen stock,نقش مجاز به ویرایش سهام منجمد,
Batch Identification,شناسایی دسته ای,
Use Naming Series,استفاده از نامگذاری سری,
Naming Series Prefix,پیشوند سری نامگذاری,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,روند رسید خرید,
Purchase Register,خرید ثبت نام,
Quotation Trends,روند نقل قول,
-Quoted Item Comparison,مورد نقل مقایسه,
Received Items To Be Billed,دریافت گزینه هایی که صورتحساب,
Qty to Order,تعداد سفارش,
Requested Items To Be Transferred,آیتم ها درخواست می شود منتقل,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,انبار را برای درخواست های مواد انتخاب کنید,
Transfer Materials For Warehouse {0},انتقال مواد برای انبار {0},
Production Plan Material Request Warehouse,طرح تولید انبار درخواست مواد,
-Set From Warehouse,تنظیم از انبار,
-Source Warehouse (Material Transfer),انبار منبع (انتقال مواد),
Sets 'Source Warehouse' in each row of the items table.,"انبار منبع" را در هر ردیف از جدول موارد تنظیم می کند.,
Sets 'Target Warehouse' in each row of the items table.,"Target Warehouse" را در هر ردیف از جدول موارد تنظیم می کند.,
Show Cancelled Entries,نمایش مطالب لغو شده,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,خدمات دریافت شده اما قبض نشده است,
Deferred Accounting Settings,تنظیمات حسابداری معوق,
Book Deferred Entries Based On,مطالب به تعویق افتادن کتاب بر اساس,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",اگر "ماه" انتخاب شود ، بدون توجه به روزهای ماه ، مبلغ ثابت به عنوان درآمد یا هزینه معوق برای هر ماه ثبت می شود. اگر درآمد یا هزینه تأخیر برای یک ماه کامل رزرو نشود ، محاسبه خواهد شد.,
Days,روزها,
Months,ماه ها,
Book Deferred Entries Via Journal Entry,ثبت مطالب به تعویق افتاده از طریق مجله,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,اگر این مورد علامت زده نشود ، مستقیماً ورودی های GL برای رزرو درآمد / هزینه معوق ایجاد می شود,
Submit Journal Entries,ارسال مطالب ژورنالی,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,اگر این مورد علامت زده نشود ، ورودی های ژورنال در حالت پیش نویس ذخیره می شوند و باید به صورت دستی ارسال شوند,
Enable Distributed Cost Center,مرکز هزینه های توزیع شده را فعال کنید,
@@ -8901,8 +8823,6 @@
Is Inter State,آیا ایالت اینتر است,
Purchase Details,جزئیات خرید,
Depreciation Posting Date,تاریخ ارسال استهلاک,
-Purchase Order Required for Purchase Invoice & Receipt Creation,سفارش خرید مورد نیاز برای فاکتور خرید و ایجاد رسید,
-Purchase Receipt Required for Purchase Invoice Creation,رسید خرید برای ایجاد فاکتور خرید مورد نیاز است,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",به طور پیش فرض ، نام تأمین کننده بر اساس نام تأمین کننده وارد شده تنظیم می شود. اگر می خواهید تامین کنندگان توسط a نامگذاری شوند,
choose the 'Naming Series' option.,گزینه "Naming Series" را انتخاب کنید.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,هنگام ایجاد یک معامله خرید جدید ، لیست قیمت پیش فرض را پیکربندی کنید. قیمت اقلام از این لیست قیمت دریافت می شود.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,آیا م Taxلفه مالیات بر درآمد است,
Component properties and references ,خصوصیات و منابع ملفه,
Additional Salary ,حقوق اضافی,
-Condtion and formula,شرط و فرمول,
Unmarked days,روزهای بدون علامت,
Absent Days,روزهای غایب,
Conditions and Formula variable and example,شرایط و متغیر فرمول و مثال,
Feedback By,بازخورد توسط,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG -. آره. -. MM. -. DD - -,
Manufacturing Section,بخش ساخت,
-Sales Order Required for Sales Invoice & Delivery Note Creation,سفارش فروش مورد نیاز برای ایجاد فاکتور فروش و ایجاد نامه تحویل,
-Delivery Note Required for Sales Invoice Creation,یادداشت تحویل برای ایجاد فاکتور فروش مورد نیاز است,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",به طور پیش فرض ، نام مشتری بر اساس نام کامل وارد شده تنظیم می شود. اگر می خواهید مشتریان توسط الف نامگذاری شوند,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,هنگام ایجاد یک معامله جدید فروش ، لیست قیمت پیش فرض را پیکربندی کنید. قیمت اقلام از این لیست قیمت دریافت می شود.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",اگر این گزینه "بله" پیکربندی شده باشد ، ERPNext از ایجاد فاکتور فروش یا یادداشت تحویل بدون ایجاد ابتدا سفارش فروش جلوگیری می کند. با فعال کردن کادر تأیید «ایجاد فاکتور فروش بدون سفارش فروش» ، این پیکربندی را می توان برای مشتری خاصی لغو کرد.,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} با موفقیت به همه عناوین انتخاب شده اضافه شد.,
Topics updated,مباحث به روز شد,
Academic Term and Program,ترم و برنامه دانشگاهی,
-Last Stock Transaction for item {0} was on {1}.,آخرین معامله سهام برای مورد {0} در تاریخ {1} انجام شد.,
-Stock Transactions for Item {0} cannot be posted before this time.,معاملات سهام برای مورد {0} نمی تواند قبل از این زمان ارسال شود.,
Please remove this item and try to submit again or update the posting time.,لطفاً این مورد را بردارید و سعی کنید دوباره ارسال کنید یا زمان ارسال را به روز کنید.,
Failed to Authenticate the API key.,تأیید اعتبار کلید API انجام نشد.,
Invalid Credentials,گواهی نامه نامعتبر,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,لطفاً شناسه مشتری Plaid و مقادیر محرمانه خود را بررسی کنید,
Bank transaction creation error,خطای ایجاد تراکنش بانکی,
Unit of Measurement,واحد اندازه گیری,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},ردیف شماره {}: نرخ فروش مورد {} کمتر از {} آن است. نرخ فروش باید حداقل باشد {},
Fiscal Year {0} Does Not Exist,سال مالی {0} وجود ندارد,
Row # {0}: Returned Item {1} does not exist in {2} {3},ردیف شماره {0}: مورد برگشت داده شده {1} در {2} {3} وجود ندارد,
Valuation type charges can not be marked as Inclusive,هزینه های نوع ارزیابی را نمی توان به عنوان فراگیر علامت گذاری کرد,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,زمان پاسخ برای {0} اولویت در ردیف {1} نمی تواند بیشتر از زمان وضوح باشد.,
{0} is not enabled in {1},{0} در {1} فعال نیست,
Group by Material Request,گروه بندی براساس درخواست مواد,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",ردیف {0}: برای تأمین کننده {0} ، آدرس ایمیل برای ارسال ایمیل لازم است,
Email Sent to Supplier {0},ایمیل به تأمین کننده ارسال شد {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",دسترسی به درخواست قیمت از پورتال غیرفعال است. برای اجازه دسترسی ، آن را در تنظیمات پورتال فعال کنید.,
Supplier Quotation {0} Created,قیمت عرضه کننده {0} ایجاد شد,
Valid till Date cannot be before Transaction Date,معتبر تا تاریخ نمی تواند قبل از تاریخ معامله باشد,
+Unlink Advance Payment on Cancellation of Order,پیش پرداخت لغو سفارش را لغو پیوند کنید,
+"Simple Python Expression, Example: territory != 'All Territories'",بیان ساده پایتون ، مثال: Territory! = 'All Territories',
+Sales Contributions and Incentives,مشارکت ها و مشوق های فروش,
+Sourced by Supplier,منبع تأمین کننده,
+Total weightage assigned should be 100%.<br>It is {0},وزن کل اختصاص داده شده باید 100٪ باشد.<br> این {0} است,
+Account {0} exists in parent company {1}.,حساب {0} در شرکت مادر وجود دارد {1}.,
+"To overrule this, enable '{0}' in company {1}",برای کنار گذاشتن این مورد ، "{0}" را در شرکت {1} فعال کنید,
+Invalid condition expression,بیان شرط نامعتبر است,
+Please Select a Company First,لطفاً ابتدا یک شرکت را انتخاب کنید,
+Please Select Both Company and Party Type First,لطفا ابتدا هر دو نوع شرکت و مهمانی را انتخاب کنید,
+Provide the invoice portion in percent,قسمت فاکتور را به درصد ارائه دهید,
+Give number of days according to prior selection,با توجه به انتخاب قبلی ، تعداد روزها را بدهید,
+Email Details,جزئیات ایمیل,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.",یک تبریک برای گیرنده انتخاب کنید. مثلاً آقا ، خانم و غیره,
+Preview Email,پیش نمایش ایمیل,
+Please select a Supplier,لطفاً یک تامین کننده انتخاب کنید,
+Supplier Lead Time (days),زمان سرب تامین کننده (روزها),
+"Home, Work, etc.",خانه ، محل کار و غیره,
+Exit Interview Held On,مصاحبه خارج شد,
+Condition and formula,شرایط و فرمول,
+Sets 'Target Warehouse' in each row of the Items table.,"Target Warehouse" را در هر ردیف از جدول آیتم ها تنظیم می کند.,
+Sets 'Source Warehouse' in each row of the Items table.,"منبع انبار" را در هر ردیف از جدول آیتم ها تنظیم می کند.,
+POS Register,ثبت نام POS,
+"Can not filter based on POS Profile, if grouped by POS Profile",اگر براساس نمایه POS دسته بندی شود ، نمی توان براساس نمایه POS فیلتر کرد,
+"Can not filter based on Customer, if grouped by Customer",اگر براساس مشتری گروه بندی شده باشد ، نمی توان براساس مشتری فیلتر کرد,
+"Can not filter based on Cashier, if grouped by Cashier",اگر براساس صندوقدار دسته بندی شود نمی توان براساس صندوقدار فیلتر کرد,
+Payment Method,روش پرداخت,
+"Can not filter based on Payment Method, if grouped by Payment Method",اگر براساس روش پرداخت دسته بندی شود ، نمی توان براساس روش پرداخت فیلتر کرد,
+Supplier Quotation Comparison,مقایسه قیمت فروشنده,
+Price per Unit (Stock UOM),قیمت هر واحد (سهام UOM),
+Group by Supplier,گروه بندی توسط تأمین کننده,
+Group by Item,گروه بندی بر اساس مورد,
+Remember to set {field_label}. It is required by {regulation}.,فراموش نکنید که {field_label} را تنظیم کنید. این توسط {مقررات} لازم است.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},تاریخ ثبت نام نمی تواند قبل از تاریخ شروع سال تحصیلی باشد {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},تاریخ ثبت نام نمی تواند بعد از تاریخ پایان ترم تحصیلی باشد {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},تاریخ ثبت نام نمی تواند قبل از تاریخ شروع ترم تحصیلی باشد {0},
+Future Posting Not Allowed,ارسال آینده مجاز نیست,
+"To enable Capital Work in Progress Accounting, ",برای فعال کردن سرمایه کار در حسابداری در حال پیشرفت ،,
+you must select Capital Work in Progress Account in accounts table,شما باید جدول Capital Work in Progress را در جدول حساب ها انتخاب کنید,
+You can also set default CWIP account in Company {},همچنین می توانید حساب پیش فرض CWIP را در شرکت تنظیم کنید {},
+The Request for Quotation can be accessed by clicking on the following button,با کلیک بر روی دکمه زیر می توان به درخواست برای قیمت گذاری دسترسی پیدا کرد,
+Regards,با احترام,
+Please click on the following button to set your new password,لطفاً برای تنظیم رمز ورود جدید خود بر روی دکمه زیر کلیک کنید,
+Update Password,رمز عبور را به روز کنید,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},ردیف شماره {}: نرخ فروش مورد {} کمتر از {} آن است. فروش {} باید حداقل باشد {},
+You can alternatively disable selling price validation in {} to bypass this validation.,برای دور زدن این اعتبار سنجی ، می توانید اعتبار فروش قیمت را در {} غیرفعال کنید.,
+Invalid Selling Price,قیمت فروش نامعتبر است,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,آدرس باید به یک شرکت پیوند داده شود. لطفاً یک ردیف برای شرکت در جدول پیوندها اضافه کنید.,
+Company Not Linked,شرکت پیوندی ندارد,
+Import Chart of Accounts from CSV / Excel files,نمودار حساب ها را از پرونده های CSV / Excel وارد کنید,
+Completed Qty cannot be greater than 'Qty to Manufacture',تعداد تکمیل شده نمی تواند بزرگتر از "تعداد تولید" باشد,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",ردیف {0}: برای تامین کننده {1} ، برای ارسال نامه الکترونیکی آدرس ایمیل لازم است,
+"If enabled, the system will post accounting entries for inventory automatically",در صورت فعال بودن ، سیستم ورودی های حسابداری موجودی را به طور خودکار ارسال می کند,
+Accounts Frozen Till Date,حساب ها تا تاریخ منجمد,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,ورودی های حسابداری تا این تاریخ مسدود می شوند. به جز کاربران با نقشی که در زیر مشخص شده است ، هیچ کس نمی تواند ورودی ها را ایجاد یا اصلاح کند,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,نقش برای تنظیم حسابهای منجمد و ویرایش مطالب منجمد مجاز است,
+Address used to determine Tax Category in transactions,آدرس مورد استفاده برای تعیین گروه مالیات در معاملات,
+"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 ",درصدی که مجاز به قبض بیشتر در برابر مبلغ سفارش شده هستید. به عنوان مثال ، اگر مقدار سفارش 100 دلار برای کالایی 100 دلار باشد و میزان تحمل 10 درصد تعیین شود ، در این صورت مجاز به صدور صورت حساب تا 110 دلار هستید.,
+This role is allowed to submit transactions that exceed credit limits,این نقش برای ارائه معاملات بیش از حد اعتباری مجاز است,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",در صورت انتخاب "ماه" ، صرف نظر از تعداد روزهای ماه ، مبلغ ثابتی به عنوان درآمد یا هزینه معوق برای هر ماه ثبت می شود. اگر درآمد یا هزینه تأخیر برای یک ماه کامل رزرو نشود ، محاسبه خواهد شد,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",اگر این مورد علامت زده نشود ، ورودی های مستقیم GL برای رزرو درآمد یا هزینه تأخیر ایجاد می شود,
+Show Inclusive Tax in Print,مالیات فراگیر را در چاپ نشان دهید,
+Only select this if you have set up the Cash Flow Mapper documents,تنها در صورت تنظیم اسناد Cash Flow Mapper ، این مورد را انتخاب کنید,
+Payment Channel,کانال پرداخت,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,آیا سفارش خرید برای فاکتور خرید و ایجاد رسید لازم است؟,
+Is Purchase Receipt Required for Purchase Invoice Creation?,آیا برای ایجاد فاکتور خرید ، رسید خرید لازم است؟,
+Maintain Same Rate Throughout the Purchase Cycle,در تمام دوره خرید همان نرخ را حفظ کنید,
+Allow Item To Be Added Multiple Times in a Transaction,اجازه دهید مورد مورد نظر در معامله چندین بار اضافه شود,
+Suppliers,تأمین کنندگان,
+Send Emails to Suppliers,ارسال ایمیل به تأمین کنندگان,
+Select a Supplier,یک تأمین کننده انتخاب کنید,
+Cannot mark attendance for future dates.,حضور در تاریخ های آینده را نمی توان مشخص کرد.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},آیا می خواهید حضور و غیاب را به روز کنید؟<br> حال: {0}<br> غایب: {1},
+Mpesa Settings,تنظیمات Mpesa,
+Initiator Name,نام آغازگر,
+Till Number,تا شماره,
+Sandbox,جعبه شنی,
+ Online PassKey,PassKey آنلاین,
+Security Credential,مدارک امنیتی,
+Get Account Balance,موجودی حساب را دریافت کنید,
+Please set the initiator name and the security credential,لطفاً نام آغازگر و اعتبارنامه را تنظیم کنید,
+Inpatient Medication Entry,ورودی داروی سرپایی,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),کد کالا (دارو),
+Medication Orders,سفارشات دارو,
+Get Pending Medication Orders,سفارشات معلق دارو را دریافت کنید,
+Inpatient Medication Orders,سفارشات دارویی بستری,
+Medication Warehouse,انبار دارو,
+Warehouse from where medication stock should be consumed,انباری که باید از آنجا مواد مخدر مصرف شود,
+Fetching Pending Medication Orders,واکشی دستورات دارویی در انتظار,
+Inpatient Medication Entry Detail,جزئیات ورودی داروهای سرپایی,
+Medication Details,جزئیات دارو,
+Drug Code,کد دارو,
+Drug Name,نام دارو,
+Against Inpatient Medication Order,در برابر دستور داروهای بستری,
+Against Inpatient Medication Order Entry,در برابر ورود دارو به درمان سرپایی,
+Inpatient Medication Order,سفارش داروی سرپایی,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,تعداد کل سفارشات,
+Completed Orders,سفارشات انجام شده,
+Add Medication Orders,سفارشات دارو را اضافه کنید,
+Adding Order Entries,افزودن ورودی های سفارش,
+{0} medication orders completed,{0} سفارش دارو انجام شد,
+{0} medication order completed,{0} سفارش دارو تکمیل شد,
+Inpatient Medication Order Entry,ورودی سفارش دارو برای بیماران سرپایی,
+Is Order Completed,سفارش تکمیل شده است,
+Employee Records to Be Created By,سوابق کارمندان توسط ایجاد شود,
+Employee records are created using the selected field,سوابق کارمندان با استفاده از قسمت انتخاب شده ایجاد می شوند,
+Don't send employee birthday reminders,یادآوری تولد کارمندان را ارسال نکنید,
+Restrict Backdated Leave Applications,برنامه های مرخصی با تاریخ گذشته را محدود کنید,
+Sequence ID,شناسه توالی,
+Sequence Id,شناسه توالی,
+Allow multiple material consumptions against a Work Order,چندین مصرف مواد را در برابر دستور کار مجاز بگذارید,
+Plan time logs outside Workstation working hours,ثبت گزارش از زمان ثبت نام در خارج از ساعت کاری ایستگاه کاری,
+Plan operations X days in advance,برنامه ریزی عملیات X روز قبل,
+Time Between Operations (Mins),زمان بین عملیات (مین ها),
+Default: 10 mins,پیش فرض: 10 دقیقه,
+Overproduction for Sales and Work Order,تولید بیش از حد برای فروش و سفارش کار,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",بر اساس آخرین نرخ ارزیابی / نرخ لیست قیمت / آخرین نرخ خرید مواد اولیه ، هزینه BOM را به طور خودکار از طریق زمانبند به روز کنید.,
+Purchase Order already created for all Sales Order items,سفارش خرید که قبلاً برای همه موارد سفارش فروش ایجاد شده است,
+Select Items,موارد را انتخاب کنید,
+Against Default Supplier,در برابر تأمین کننده پیش فرض,
+Auto close Opportunity after the no. of days mentioned above,بعد از شماره ، فرصت را ببندید روزهایی که در بالا ذکر شد,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,آیا برای ایجاد فاکتور فروش و یادداشت تحویل سفارش فروش لازم است؟,
+Is Delivery Note Required for Sales Invoice Creation?,آیا برای ایجاد فاکتور فروش ، برگه تحویل لازم است؟,
+How often should Project and Company be updated based on Sales Transactions?,چند بار باید پروژه و شرکت براساس معاملات فروش به روز شود؟,
+Allow User to Edit Price List Rate in Transactions,به کاربر اجازه دهید نرخ معاملات لیست را در معاملات ویرایش کند,
+Allow Item to Be Added Multiple Times in a Transaction,اجازه دهید چندین مورد در یک معامله مورد اضافه شود,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,سفارشات متعدد فروش در برابر سفارش خرید مشتری را مجاز کنید,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,قیمت فروش کالا را در برابر نرخ خرید یا نرخ ارزیابی تأیید کنید,
+Hide Customer's Tax ID from Sales Transactions,شناسه مالیاتی مشتری را از معاملات فروش پنهان کنید,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.",درصدی که مجاز به دریافت یا تحویل بیشتر در برابر مقدار سفارش شده هستید. به عنوان مثال ، اگر 100 واحد سفارش داده اید و کمک هزینه شما 10٪ است ، در این صورت مجاز به دریافت 110 واحد هستید.,
+Action If Quality Inspection Is Not Submitted,در صورت عدم ارسال بازرسی کیفیت اقدام کنید,
+Auto Insert Price List Rate If Missing,در صورت عدم وجود ، نرخ لیست قیمت خودکار را وارد کنید,
+Automatically Set Serial Nos Based on FIFO,شماره های سریال را به صورت خودکار بر اساس FIFO تنظیم کنید,
+Set Qty in Transactions Based on Serial No Input,تعداد معاملات را براساس ورودی بدون سریال تنظیم کنید,
+Raise Material Request When Stock Reaches Re-order Level,هنگامی که سهام به سطح سفارش مجدد رسید ، درخواست مواد را افزایش دهید,
+Notify by Email on Creation of Automatic Material Request,در مورد ایجاد درخواست خودکار مواد از طریق ایمیل اطلاع دهید,
+Allow Material Transfer from Delivery Note to Sales Invoice,اجازه انتقال مواد از برگ تحویل به فاکتور فروش را بدهید,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,انتقال مواد از رسید خرید به فاکتور خرید را مجاز کنید,
+Freeze Stocks Older Than (Days),مسدود کردن سهام قدیمی تر از (روزها),
+Role Allowed to Edit Frozen Stock,نقش مجاز برای ویرایش سهام منجمد,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,مبلغ تخصیص نیافته پرداخت پرداخت {0} بیشتر از مبلغ اختصاص نیافته تراکنش بانکی است,
+Payment Received,پرداخت دریافت شد,
+Attendance cannot be marked outside of Academic Year {0},حضور در خارج از سال تحصیلی {0} مشخص نمی شود,
+Student is already enrolled via Course Enrollment {0},دانشجو از قبل از طریق ثبت نام دوره {0} ثبت نام کرده است,
+Attendance cannot be marked for future dates.,حضور در تاریخ های آینده مشخص نیست.,
+Please add programs to enable admission application.,لطفاً برنامه ها را برای فعال کردن برنامه پذیرش اضافه کنید.,
+The following employees are currently still reporting to {0}:,کارمندان زیر در حال حاضر همچنان به {0} گزارش می دهند:,
+Please make sure the employees above report to another Active employee.,لطفاً اطمینان حاصل کنید که کارمندان فوق به یکی دیگر از کارمندان فعال گزارش می دهند.,
+Cannot Relieve Employee,نمی توان کارمند را تسکین داد,
+Please enter {0},لطفاً {0} را وارد کنید,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',لطفاً روش پرداخت دیگری را انتخاب کنید. Mpesa از معاملات با ارز "{0}" پشتیبانی نمی کند,
+Transaction Error,خطای معامله,
+Mpesa Express Transaction Error,خطای تراکنش اکسپرس Mpesa,
+"Issue detected with Mpesa configuration, check the error logs for more details",مشکلی با پیکربندی Mpesa شناسایی شد ، برای جزئیات بیشتر گزارش خطاها را بررسی کنید,
+Mpesa Express Error,خطای اکسپرس Mpesa,
+Account Balance Processing Error,خطای پردازش موجودی حساب,
+Please check your configuration and try again,لطفا پیکربندی خود را بررسی کنید و دوباره امتحان کنید,
+Mpesa Account Balance Processing Error,خطای پردازش موجودی حساب Mpesa,
+Balance Details,جزئیات موجودی,
+Current Balance,موجودی فعلی,
+Available Balance,موجودی موجود,
+Reserved Balance,موجودی رزرو شده,
+Uncleared Balance,تراز نامشخص,
+Payment related to {0} is not completed,پرداخت مربوط به {0} تکمیل نشده است,
+Row #{}: Item Code: {} is not available under warehouse {}.,ردیف # {}: کد مورد: {} در انبار موجود نیست {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,ردیف # {}: مقدار سهام برای کد مورد کافی نیست: {} زیر انبار {}. مقدار موجود {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,ردیف شماره {}: لطفاً شماره سریال و دسته ای از موارد را انتخاب کنید: {} یا آن را حذف کنید تا معامله کامل شود.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,ردیف # {}: شماره سریال در برابر مورد انتخاب نشده است: {}. لطفاً برای تکمیل معامله یکی را انتخاب کنید یا آن را حذف کنید.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,ردیف # {}: هیچ دسته ای در برابر مورد انتخاب نشده است: {}. لطفاً برای تکمیل معامله دسته ای را انتخاب کنید یا آن را حذف کنید.,
+Payment amount cannot be less than or equal to 0,مقدار پرداخت نمی تواند کمتر از یا برابر با 0 باشد,
+Please enter the phone number first,لطفاً ابتدا شماره تلفن را وارد کنید,
+Row #{}: {} {} does not exist.,ردیف شماره {}: {} {} وجود ندارد.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,ردیف شماره {0}: برای ایجاد افتتاحیه {2} فاکتورها {1} لازم است,
+You had {} errors while creating opening invoices. Check {} for more details,هنگام ایجاد فاکتورهای افتتاحیه {} خطا داشتید. برای جزئیات بیشتر {} را بررسی کنید,
+Error Occured,خطایی روی داد,
+Opening Invoice Creation In Progress,افتتاح ایجاد فاکتور در حال انجام است,
+Creating {} out of {} {},ایجاد {} از {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(شماره سریال: {0}) نمی تواند مصرف شود زیرا ذخیره سفارش سفارش برای فروش کامل است {1}.,
+Item {0} {1},مورد {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,آخرین معامله سهام برای مورد {0} زیر انبار {1} در تاریخ {2} انجام شد.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,معاملات سهام برای مورد {0} زیر انبار {1} نمی تواند قبل از این زمان ارسال شود.,
+Posting future stock transactions are not allowed due to Immutable Ledger,ارسال معاملات سهام در آینده به دلیل دفتر تغییر ناپذیر مجاز نیست,
+A BOM with name {0} already exists for item {1}.,BOM با نام {0} از قبل برای مورد {1} وجود دارد.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} آیا نام را تغییر دادید؟ لطفا با پشتیبانی / مدیر فنی تماس بگیرید,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},در ردیف شماره {0}: شناسه توالی {1} نمی تواند کمتر از شناسه توالی ردیف قبلی باشد {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) باید برابر با {2} ({3}) باشد,
+"{0}, complete the operation {1} before the operation {2}.",{0} ، قبل از انجام عملیات {1} را کامل کنید {2}.,
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,نمی توان اطمینان داشت که شماره سریال با شماره سریال 0 0 با و بدون اطمینان از تحویل شماره سریال اضافه شده است.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,مورد {0} شماره سریال ندارد. فقط موارد سریال سازی شده می توانند براساس شماره سریال تحویل داده شوند,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,هیچ BOM فعال برای مورد {0} یافت نشد. تحویل توسط شماره سریال قابل اطمینان نیست,
+No pending medication orders found for selected criteria,برای معیارهای انتخاب شده هیچ سفارش دارویی معلق یافت نشد,
+From Date cannot be after the current date.,از تاریخ نمی تواند بعد از تاریخ فعلی باشد.,
+To Date cannot be after the current date.,To Date نمی تواند بعد از تاریخ فعلی باشد.,
+From Time cannot be after the current time.,از زمان نمی تواند بعد از زمان فعلی باشد.,
+To Time cannot be after the current time.,To Time نمی تواند بعد از زمان فعلی باشد.,
+Stock Entry {0} created and ,ورودی سهام {0} ایجاد شد و,
+Inpatient Medication Orders updated successfully,سفارشات دارویی بستری با موفقیت به روز شد,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},ردیف {0}: نمی توان ورودی داروی بیماران بستری را در برابر دستور داروهای بستری در بیمارستان لغو کرد {1},
+Row {0}: This Medication Order is already marked as completed,ردیف {0}: این سفارش دارو قبلاً به عنوان تکمیل شده علامت گذاری شده است,
+Quantity not available for {0} in warehouse {1},مقدار برای {0} در انبار {1} در دسترس نیست,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,لطفاً اجازه دهید سهام منفی را در تنظیمات سهام فعال کنید یا ورود سهام را برای ادامه ایجاد کنید.,
+No Inpatient Record found against patient {0},هیچ سابقه بستری در مورد بیمار یافت نشد {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,یک دستور دارویی در بیماران بستری {0} علیه ملاقات با بیمار {1} از قبل موجود است.,
+Allow In Returns,در بازگشت مجاز است,
+Hide Unavailable Items,موارد موجود را پنهان کنید,
+Apply Discount on Discounted Rate,تخفیف را با نرخ تخفیف اعمال کنید,
+Therapy Plan Template,الگوی طرح درمانی,
+Fetching Template Details,واکشی جزئیات الگو,
+Linked Item Details,جزئیات مورد پیوند داده شده,
+Therapy Types,انواع درمان,
+Therapy Plan Template Detail,جزئیات الگوی طرح درمانی,
+Non Conformance,عدم انطباق,
+Process Owner,صاحب فرآیند,
+Corrective Action,اقدام اصلاحی,
+Preventive Action,اقدام پیشگیرانه,
+Problem,مسئله,
+Responsible,مسئول,
+Completion By,تکمیل توسط,
+Process Owner Full Name,نام کامل مالک فرآیند,
+Right Index,نمایه درست,
+Left Index,شاخص چپ,
+Sub Procedure,روش فرعی,
+Passed,گذشت,
+Print Receipt,رسید چاپ,
+Edit Receipt,رسید را ویرایش کنید,
+Focus on search input,بر ورودی جستجو تمرکز کنید,
+Focus on Item Group filter,روی فیلتر گروه مورد تمرکز کنید,
+Checkout Order / Submit Order / New Order,سفارش پرداخت / ارسال سفارش / سفارش جدید,
+Add Order Discount,تخفیف سفارش را اضافه کنید,
+Item Code: {0} is not available under warehouse {1}.,کد مورد: {0} در انبار موجود نیست {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,شماره های سریال برای مورد {0} زیر انبار {1} در دسترس نیست. لطفاً انبار را تغییر دهید.,
+Fetched only {0} available serial numbers.,فقط {0} شماره سریال موجود دریافت شد.,
+Switch Between Payment Modes,جابجایی بین حالت های پرداخت,
+Enter {0} amount.,{0} مقدار را وارد کنید.,
+You don't have enough points to redeem.,شما امتیاز کافی برای استفاده ندارید.,
+You can redeem upto {0}.,می توانید تا {0} استفاده کنید.,
+Enter amount to be redeemed.,مبلغی را که باید استفاده شود وارد کنید.,
+You cannot redeem more than {0}.,نمی توانید بیش از {0} استفاده کنید.,
+Open Form View,نمای فرم را باز کنید,
+POS invoice {0} created succesfully,فاکتور POS {0} با موفقیت ایجاد شد,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,مقدار سهام برای کد مورد کافی نیست: {0} زیر انبار {1}. مقدار موجود {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,شماره سریال: {0} قبلاً به فاکتور POS دیگری معامله شده است.,
+Balance Serial No,شماره سریال موجودی,
+Warehouse: {0} does not belong to {1},انبار: {0} متعلق به {1} نیست,
+Please select batches for batched item {0},لطفاً دسته ها را برای مورد دسته ای انتخاب کنید {0},
+Please select quantity on row {0},لطفاً مقدار را در ردیف {0} انتخاب کنید,
+Please enter serial numbers for serialized item {0},لطفا شماره سریال را برای مورد سریال وارد کنید {0},
+Batch {0} already selected.,دسته ای {0} از قبل انتخاب شده است.,
+Please select a warehouse to get available quantities,لطفاً یک انبار را برای دریافت مقادیر موجود انتخاب کنید,
+"For transfer from source, selected quantity cannot be greater than available quantity",برای انتقال از منبع ، مقدار انتخاب شده نمی تواند بیشتر از مقدار موجود باشد,
+Cannot find Item with this Barcode,با این بارکد نمی توانید مورد را پیدا کنید,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} اجباری است. شاید سابقه تبدیل ارز برای {1} تا {2} ایجاد نشده باشد,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} دارایی های مرتبط با آن را ارسال کرده است. برای ایجاد بازده خرید ، باید دارایی ها را لغو کنید.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,نمی توان این سند را لغو کرد زیرا با دارایی ارسالی {0} مرتبط است. لطفاً برای ادامه آن را لغو کنید.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,ردیف شماره {}: شماره سریال {} قبلاً به فاکتور POS دیگری انتقال داده شده است. لطفا شماره سریال معتبر را انتخاب کنید.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,ردیف # {}: شماره سریال. {} قبلاً به یک فاکتور POS دیگر تبدیل شده است. لطفا شماره سریال معتبر را انتخاب کنید.,
+Item Unavailable,مورد موجود نیست,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},ردیف # {}: شماره سریال {} قابل بازگشت نیست زیرا در فاکتور اصلی معامله نشده است {},
+Please set default Cash or Bank account in Mode of Payment {},لطفاً پول نقد یا حساب بانکی پیش فرض را در روش پرداخت تنظیم کنید {},
+Please set default Cash or Bank account in Mode of Payments {},لطفاً پول نقد یا حساب بانکی پیش فرض را در حالت پرداخت تنظیم کنید {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,لطفاً اطمینان حاصل کنید که {} حساب یک حساب ترازنامه است. می توانید حساب والد را به یک حساب ترازنامه تغییر دهید یا یک حساب دیگر انتخاب کنید.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,لطفاً اطمینان حاصل کنید که حساب {} یک حساب قابل پرداخت است. نوع حساب را به Payable تغییر دهید یا حساب دیگری را انتخاب کنید.,
+Row {}: Expense Head changed to {} ,ردیف {}: سر هزینه به {} تغییر یافت,
+because account {} is not linked to warehouse {} ,زیرا حساب {} به انبار پیوند ندارد {},
+or it is not the default inventory account,یا حساب موجودی پیش فرض نیست,
+Expense Head Changed,سر هزینه تغییر کرد,
+because expense is booked against this account in Purchase Receipt {},زیرا هزینه در قبض خرید در مقابل این حساب رزرو شده است {},
+as no Purchase Receipt is created against Item {}. ,چون هیچ رسید خریدی در برابر مورد {} ایجاد نمی شود.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,این کار برای رسیدگی به حسابداری در مواردی است که پس از فاکتور خرید ، رسید خرید ایجاد می شود,
+Purchase Order Required for item {},سفارش خرید برای مورد مورد نیاز است {},
+To submit the invoice without purchase order please set {} ,برای ارسال فاکتور بدون سفارش خرید لطفاً {},
+as {} in {},به عنوان {} در {},
+Mandatory Purchase Order,سفارش خرید اجباری,
+Purchase Receipt Required for item {},رسید خرید برای مورد نیاز است {},
+To submit the invoice without purchase receipt please set {} ,برای ارسال فاکتور بدون رسید خرید لطفاً تنظیم کنید {},
+Mandatory Purchase Receipt,رسید خرید اجباری,
+POS Profile {} does not belongs to company {},نمایه POS {} متعلق به شرکت نیست {},
+User {} is disabled. Please select valid user/cashier,کاربر {} غیرفعال است. لطفاً کاربر / صندوقدار معتبر را انتخاب کنید,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,ردیف # {}: فاکتور اصلی {} فاکتور برگشت {} {} است.,
+Original invoice should be consolidated before or along with the return invoice.,فاکتور اصلی باید قبل یا همراه با فاکتور برگشت ادغام شود.,
+You can add original invoice {} manually to proceed.,برای ادامه کار می توانید فاکتور اصلی را {} به صورت دستی اضافه کنید.,
+Please ensure {} account is a Balance Sheet account. ,لطفاً اطمینان حاصل کنید که {} حساب یک حساب ترازنامه است.,
+You can change the parent account to a Balance Sheet account or select a different account.,می توانید حساب والد را به یک حساب ترازنامه تغییر دهید یا یک حساب دیگر انتخاب کنید.,
+Please ensure {} account is a Receivable account. ,لطفاً مطمئن شوید که {} حساب یک حساب قابل دریافت است.,
+Change the account type to Receivable or select a different account.,نوع حساب را به قابل دریافت تغییر دهید یا حساب دیگری را انتخاب کنید.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},از زمان استفاده از امتیازات وفاداری کسب شده ، {} قابل لغو نیست. ابتدا {} نه {} را لغو کنید,
+already exists,درحال حاضر وجود دارد,
+POS Closing Entry {} against {} between selected period,ورودی بسته شدن POS بین دوره انتخاب شده {} در برابر {},
+POS Invoice is {},فاکتور POS {} است,
+POS Profile doesn't matches {},نمایه POS مطابقت ندارد {},
+POS Invoice is not {},فاکتور POS {} نیست,
+POS Invoice isn't created by user {},فاکتور POS توسط کاربر ایجاد نشده است {},
+Row #{}: {},ردیف شماره {}: {},
+Invalid POS Invoices,فاکتورهای POS نامعتبر است,
+Please add the account to root level Company - {},لطفاً حساب را به سطح root شرکت اضافه کنید - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",هنگام ایجاد حساب برای شرکت کودک {0} ، حساب والد {1} پیدا نشد. لطفاً حساب والدین را در COA مربوطه ایجاد کنید,
+Account Not Found,حساب یافت نشد,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",هنگام ایجاد حساب برای شرکت کودک {0} ، حساب والد {1} به عنوان یک حساب دفتر پیدا شد.,
+Please convert the parent account in corresponding child company to a group account.,لطفاً حساب والدین را در شرکت مربوط به فرزند به یک حساب گروهی تبدیل کنید.,
+Invalid Parent Account,حساب والد نامعتبر است,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",تغییر نام آن فقط از طریق شرکت مادر {0} مجاز است تا از عدم تطابق جلوگیری شود.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",اگر {0} {1} مقادیر مورد {2} داشته باشید ، طرح {3} روی مورد اعمال می شود.,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",اگر {0} {1} مورد موردی را داشته باشید {2} ، طرح {3} روی مورد اعمال می شود.,
+"As the field {0} is enabled, the field {1} is mandatory.",همانطور که قسمت {0} فعال است ، قسمت {1} اجباری است.,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",همانطور که قسمت {0} فعال است ، مقدار فیلد {1} باید بیش از 1 باشد.,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},نمی توان شماره سریال {0} مورد {1} را تحویل داد زیرا برای تکمیل سفارش فروش {2} محفوظ است,
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",سفارش فروش {0} برای مورد رزرو دارد {1} ، شما فقط می توانید رزرو شده {1} را در مقابل {0} تحویل دهید.,
+{0} Serial No {1} cannot be delivered,{0} شماره سریال {1} تحویل داده نمی شود,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},ردیف {0}: مورد پیمانکاری فرعی برای ماده اولیه اجباری است {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",از آنجا که مواد اولیه کافی وجود دارد ، درخواست مواد برای انبار {0} لازم نیست.,
+" If you still want to proceed, please enable {0}.",اگر هنوز می خواهید ادامه دهید ، لطفاً {0} را فعال کنید.,
+The item referenced by {0} - {1} is already invoiced,مورد ارجاع شده توسط {0} - {1} قبلاً فاکتور شده است,
+Therapy Session overlaps with {0},جلسه درمانی با {0} همپوشانی دارد,
+Therapy Sessions Overlapping,جلسات درمانی با هم تداخل دارند,
+Therapy Plans,برنامه های درمانی,
+"Item Code, warehouse, quantity are required on row {0}",کد مورد ، انبار ، مقدار در ردیف {0} لازم است,
+Get Items from Material Requests against this Supplier,مواردی را از درخواستهای ماده در برابر این تأمین کننده دریافت کنید,
+Enable European Access,دسترسی اروپا را فعال کنید,
+Creating Purchase Order ...,در حال ایجاد سفارش خرید ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",از تامین کنندگان پیش فرض موارد زیر یک تأمین کننده انتخاب کنید. هنگام انتخاب ، سفارش خرید فقط در مورد کالاهای متعلق به تنها تامین کننده انتخاب شده انجام می شود.,
+Row #{}: You must select {} serial numbers for item {}.,ردیف شماره {}: شما باید {} شماره سریال را برای مورد {} انتخاب کنید.,
diff --git a/erpnext/translations/fi.csv b/erpnext/translations/fi.csv
index 8912848..29eb567 100644
--- a/erpnext/translations/fi.csv
+++ b/erpnext/translations/fi.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},todellista veroa ei voi sisällyttää tuotteen tasoon rivillä {0},
Add,Lisää,
Add / Edit Prices,Lisää / muokkaa hintoja,
-Add All Suppliers,Lisää kaikki toimittajat,
Add Comment,Lisää kommentti,
Add Customers,Lisää Asiakkaat,
Add Employees,Lisää Työntekijät,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Ei voi vähentää, kun kategoria on "arvostus" tai "Vaulation ja Total"",
"Cannot delete Serial No {0}, as it is used in stock transactions","Sarjanumeroa {0} ei voida poistaa, koska sitä on käytetty varastotapahtumissa",
Cannot enroll more than {0} students for this student group.,Ei voi ilmoittautua enintään {0} opiskelijat tälle opiskelijaryhmälle.,
-Cannot find Item with this barcode,Tuotetta ei löydy tällä viivakoodilla,
Cannot find active Leave Period,Ei ole aktiivista lomaaikaa,
Cannot produce more Item {0} than Sales Order quantity {1},ei voi valmistaa suurempaa määrää tuotteita {0} kuin myyntitilauksen määrä {1},
Cannot promote Employee with status Left,Et voi edistää Työntekijän asemaa vasemmalla,
Cannot refer row number greater than or equal to current row number for this Charge type,"rivi ei voi viitata nykyistä suurempaan tai nykyisen rivin numeroon, vaihda maksun tyyppiä",
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"ei voi valita maksun tyyppiä, kuten 'edellisen rivin arvomäärä' tai 'edellinen rivi yhteensä' ensimmäiseksi riviksi",
-Cannot set a received RFQ to No Quote,Vastaanotettua pyyntöä ei voi määrittää Ei lainkaan,
Cannot set as Lost as Sales Order is made.,ei voi asettaa hävityksi sillä myyntitilaus on tehty,
Cannot set authorization on basis of Discount for {0},oikeutusta ei voi asettaa alennuksen perusteella {0},
Cannot set multiple Item Defaults for a company.,Yrityksesi ei voi asettaa useampia oletuksia asetuksille.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,maksut on päivitetty ostokuitilla kondistettuna jokaiseen tuotteeseen,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","maksut jaetaan suhteellisesti tuotteiden yksikkömäärän tai arvomäärän mukaan, määrityksen perusteella",
-Chart Of Accounts,Tilikartta,
Chart of Cost Centers,Kustannuspaikkakaavio,
Check all,Tarkista kaikki,
Checkout,Tarkista,
@@ -581,7 +577,6 @@
Compensatory Off,korvaava on pois,
Compensatory leave request days not in valid holidays,Korvausvapautuspäivät eivät ole voimassaoloaikoina,
Complaint,Valitus,
-Completed Qty can not be greater than 'Qty to Manufacture',"valmiit yksikkömäärä ei voi olla suurempi kuin ""tuotannon määrä""",
Completion Date,katselmus päivä,
Computer,Tietokone,
Condition,ehto,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","tee ja hallitse (päivä-, viikko- ja kuukausi) sähköpostitiedotteita",
Create customer quotes,Luoda asiakkaalle lainausmerkit,
Create rules to restrict transactions based on values.,tee tapahtumien arvoon perustuvia rajoitussääntöjä,
-Created By,tekijä,
Created {0} scorecards for {1} between: ,Luotu {0} tuloskartan {1} välillä:,
Creating Company and Importing Chart of Accounts,Yrityksen luominen ja tilikartan tuominen,
Creating Fees,Maksujen luominen,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Työntekijöiden siirtoa ei voida lähettää ennen siirron ajankohtaa,
Employee cannot report to himself.,työntekijä ei voi raportoida itselleen,
Employee relieved on {0} must be set as 'Left',"työntekijä vapautettu {0} tulee asettaa ""vasemmalla""",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Työntekijän tilaa ei voida asettaa Vasemmalle, koska seuraavat työntekijät raportoivat tällä työntekijällä:",
Employee {0} already submited an apllication {1} for the payroll period {2},Työntekijä {0} on jo lähettänyt apllication {1} palkanlaskennan kaudelle {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Työntekijä {0} on jo hakenut {1} välillä {2} ja {3}:,
Employee {0} has no maximum benefit amount,Työntekijä {0} ei ole enimmäishyvää,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Rivi {0}: Syötä suunniteltu määrä,
"For {0}, only credit accounts can be linked against another debit entry","{0}, vain kredit tili voidaan kohdistaa debet kirjaukseen",
"For {0}, only debit accounts can be linked against another credit entry","{0}, vain debet tili voidaan kohdistaa kredit kirjaukseen",
-Form View,Lomakenäkymä,
Forum Activity,Foorumin toiminta,
Free item code is not selected,Ilmaista tuotekoodia ei ole valittu,
Freight and Forwarding Charges,rahdin ja huolinnan maksut,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Vapaita ei voida käyttää ennen {0}, koska käytettävissä olevat vapaat on jo siirretty eteenpäin jaksolle {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Vapaita ei voida käyttää / peruuttaa ennen {0}, koska käytettävissä olevat vapaat on jo siirretty eteenpäin jaksolle {1}",
Leave of type {0} cannot be longer than {1},{0} -tyyppinen vapaa ei voi olla pidempi kuin {1},
-Leave the field empty to make purchase orders for all suppliers,Jätä kenttä tyhjäksi tehdäksesi tilauksia kaikille toimittajille,
Leaves,lehdet,
Leaves Allocated Successfully for {0},Vapaat kohdennettu {0}:lle,
Leaves has been granted sucessfully,Lehdet on myönnetty onnistuneesti,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Kohteita ei Bill materiaalien valmistus,
No Items with Bill of Materials.,"Ei esineitä, joilla on lasku materiaaleja.",
No Permission,Ei oikeuksia,
-No Quote,Ei lainkaan,
No Remarks,Ei huomautuksia,
No Result to submit,Ei tulosta,
No Salary Structure assigned for Employee {0} on given date {1},Työntekijälle {0} annettuun palkkarakenteeseen ei annettu päivämäärää {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Päällekkäiset olosuhteisiin välillä:,
Owner,Omistaja,
PAN,PANOROIDA,
-PO already created for all sales order items,PO on jo luotu kaikille myyntitilauksille,
POS,POS,
POS Profile,POS Profile,
POS Profile is required to use Point-of-Sale,POS-profiilia tarvitaan myyntipisteen käyttämiseen,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Valitse ensin veloitus tyyppi,
Please select Company,Ole hyvä ja valitse Company,
Please select Company and Designation,Valitse Yritys ja nimike,
-Please select Company and Party Type first,Valitse ensin yritys ja osapuoli tyyppi,
Please select Company and Posting Date to getting entries,Valitse Yritykset ja kirjauspäivämäärä saadaksesi merkinnät,
Please select Company first,Ole hyvä ja valitse Company ensin,
Please select Completion Date for Completed Asset Maintenance Log,Valitse Valmistuneen omaisuudenhoitorekisterin päättymispäivä,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Rivi {0}: UOM Muuntokerroin on pakollinen,
Row {0}: select the workstation against the operation {1},Rivi {0}: valitse työasema operaatiota vastaan {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Rivi {0}: {1} Sarjanumerot kohdasta {2}. Olet antanut {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Rivi {0}: {1} vaaditaan avaavan {2} laskujen luomiseen,
Row {0}: {1} must be greater than 0,Rivi {0}: {1} on oltava suurempi kuin 0,
Row {0}: {1} {2} does not match with {3},rivi {0}: {1} {2} ei täsmää {3} kanssa,
Row {0}:Start Date must be before End Date,Rivi {0}: Aloitus on ennen Päättymispäivä,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Lähetä rahastoarvio sähköposti,
Send Now,Lähetä nyt,
Send SMS,Lähetä tekstiviesti,
-Send Supplier Emails,Lähetä toimittaja Sähköpostit,
Send mass SMS to your contacts,Lähetä massatekstiviesti yhteystiedoillesi,
Sensitivity,Herkkyys,
Sent,Lähetetty,
-Serial #,Sarja #,
Serial No and Batch,Sarjanumero ja erä,
Serial No is mandatory for Item {0},Sarjanumero vaaditaan tuotteelle {0},
Serial No {0} does not belong to Batch {1},Sarjanumero {0} ei kuulu erään {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Yrityksen nimi, jolle olet luomassa tätä järjestelmää",
The number of shares and the share numbers are inconsistent,Osakkeiden lukumäärä ja osakemäärä ovat epäjohdonmukaisia,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Maksuyhdyskäytävätietojärjestelmä {0} poikkeaa maksupyyntötilistä tässä maksupyynnössä,
-The request for quotation can be accessed by clicking on the following link,Tarjouspyyntöön pääsee klikkaamalla seuraavaa linkkiä,
The selected BOMs are not for the same item,Valitut osaluettelot eivät koske samaa nimikettä,
The selected item cannot have Batch,Valittu tuote ei voi olla erä,
The seller and the buyer cannot be the same,Myyjä ja ostaja eivät voi olla samat,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Joustavan etuuskomponentin {0} kokonaismäärä ei saa olla pienempi kuin enimmäisetujen {1},
Total hours: {0},Yhteensä tuntia: {0},
Total leaves allocated is mandatory for Leave Type {0},Jako myönnetty määrä yhteensä on {0},
-Total weightage assigned should be 100%. It is {0},Nimetyn painoarvon tulee yhteensä olla 100%. Nyt se on {0},
Total working hours should not be greater than max working hours {0},Yhteensä työaika ei saisi olla suurempi kuin max työaika {0},
Total {0} ({1}),Yhteensä {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Yhteensä {0} kaikki kohteet on nolla, voi olla sinun pitäisi muuttaa "välit perustuvat maksujen '",
@@ -3316,7 +3299,6 @@
What do you need help with?,Minkä kanssa tarvitset apua?,
What does it do?,Mitä tämä tekee?,
Where manufacturing operations are carried.,Missä valmistus tapahtuu,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Luodessaan tiliä lastenyritykselle {0}, emotiltiä {1} ei löytynyt. Luo vanhemman tili vastaavaan todistukseen",
White,Valkoinen,
Wire Transfer,Sähköinen tilisiirto,
WooCommerce Products,WooCommerce-tuotteet,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} muunnoksia luotu.,
{0} {1} created,{0} {1} luotu,
{0} {1} does not exist,{0} {1} ei ole olemassa,
-{0} {1} does not exist.,{0} {1} ei ole olemassa.,
{0} {1} has been modified. Please refresh.,{0} {1} on muuttunut. Lataa uudelleen.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} ei ole vahvistettu, joten toimintoa ei voida suorittaa loppuun",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} liittyy {2}, mutta Party-tili on {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} ei löydy,
{0}: {1} not found in Invoice Details table,{0}: {1} ei löydy laskun lisätiedot taulukosta,
{} of {},{} / {},
+Assigned To,nimetty,
Chat,Pikaviestintä,
Completed By,Täydentänyt,
Conditions,olosuhteet,
@@ -3506,7 +3488,9 @@
Merge with existing,Yhdistä nykyiseen,
Office,Toimisto,
Orientation,Suuntautuminen,
+Parent,Vanhempi,
Passive,Passiivinen,
+Payment Failed,Maksu epäonnistui,
Percent,prosentti,
Permanent,Pysyvä,
Personal,Henkilökohtainen,
@@ -3544,7 +3528,6 @@
Company field is required,Yrityksen kenttä on pakollinen,
Creating Dimensions...,Luodaan ulottuvuuksia ...,
Duplicate entry against the item code {0} and manufacturer {1},Kopio merkinnästä tuotekoodiin {0} ja valmistajaan {1},
-Import Chart Of Accounts from CSV / Excel files,Tuo tilikartta CSV / Excel-tiedostoista,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Virheellinen GSTIN! Antamasi syöte ei vastaa UIN-haltijoiden tai muualla kuin OIDAR-palveluntarjoajien GSTIN-muotoa,
Invoice Grand Total,Laskun kokonaissumma,
Last carbon check date cannot be a future date,Viimeinen hiilitarkastuspäivämäärä ei voi olla tulevaisuuden päivämäärä,
@@ -3556,6 +3539,7 @@
Show {0},Näytä {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Erikoismerkit paitsi "-", "#", ".", "/", "{" Ja "}" eivät ole sallittuja nimeämissarjoissa",
Target Details,Kohteen yksityiskohdat,
+{0} already has a Parent Procedure {1}.,{0}: llä on jo vanhempainmenettely {1}.,
API,API,
Annual,Vuotuinen,
Approved,hyväksytty,
@@ -3572,6 +3556,8 @@
No data to export,Ei vietäviä tietoja,
Portrait,Muotokuva,
Print Heading,Tulosteen otsikko,
+Scheduler Inactive,Aikataulu ei aktiivinen,
+Scheduler is inactive. Cannot import data.,Aikataulu ei ole aktiivinen. Tietoja ei voi tuoda.,
Show Document,Näytä asiakirja,
Show Traceback,Näytä jäljitys,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Luo tuotteen {0} laatutarkastus,
Creating Accounts...,Luodaan tilejä ...,
Creating bank entries...,Luodaan pankkitietoja ...,
-Creating {0},{0},
Credit limit is already defined for the Company {0},Luottoraja on jo määritelty yritykselle {0},
Ctrl + Enter to submit,Ctrl + Enter lähettääksesi,
Ctrl+Enter to submit,Lähetä Ctrl + Enter,
@@ -3921,7 +3906,6 @@
Plaid public token error,Tavallinen julkinen tunnusvirhe,
Plaid transactions sync error,Ruudullinen tapahtumien synkronointivirhe,
Please check the error log for details about the import errors,Tarkista tuontivirheistä virheloki,
-Please click on the following link to set your new password,Klikkaa seuraavaa linkkiä asettaa uuden salasanan,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Luo <b>DATEV-asetukset</b> yritykselle <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Luo oikaisu päiväkirjakirjaukseen summalle {0},
Please do not create more than 500 items at a time,Älä luo enempää kuin 500 tuotetta kerrallaan,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Julkaisupäivän on oltava tulevaisuudessa,
Relieving Date must be greater than or equal to Date of Joining,Päivityspäivämäärän on oltava suurempi tai yhtä suuri kuin Liittymispäivä,
Rename,Nimeä uudelleen,
+Rename Not Allowed,Nimeä uudelleen ei sallita,
Repayment Method is mandatory for term loans,Takaisinmaksutapa on pakollinen lainoille,
Repayment Start Date is mandatory for term loans,Takaisinmaksun alkamispäivä on pakollinen lainoille,
Report Item,Raportoi esine,
@@ -4043,7 +4028,6 @@
Select All,Valitse kaikki,
Select Difference Account,Valitse Ero-tili,
Select a Default Priority.,Valitse oletusprioriteetti.,
-Select a Supplier from the Default Supplier List of the items below.,Valitse toimittaja alla olevista kohteista oletustoimittajaluettelosta.,
Select a company,Valitse yritys,
Select finance book for the item {0} at row {1},Valitse kohteelle {0} rivillä {1} rahoituskirja,
Select only one Priority as Default.,Valitse vain yksi prioriteetti oletukseksi.,
@@ -4247,7 +4231,6 @@
Actual ,kiinteä määrä,
Add to cart,Lisää koriin,
Budget,budjetti,
-Chart Of Accounts Importer,Tilikartta tuoja,
Chart of Accounts,Tilikartta,
Customer database.,Asiakastietokanta.,
Days Since Last order,päivää edellisestä tilauksesta,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,päättymispäivä ei voi olla ennen aloituspäivää,
For Default Supplier (Optional),Oletuksena toimittaja (valinnainen),
From date cannot be greater than To date,Alkaen päivä ei voi olla suurempi kuin päättymispäivä,
-Get items from,Hae nimikkeet,
Group by,ryhmän,
In stock,Varastossa,
Item name,Nimikkeen nimi,
@@ -4532,32 +4514,22 @@
Accounts Settings,tilien asetukset,
Settings for Accounts,Tilien asetukset,
Make Accounting Entry For Every Stock Movement,tee kirjanpidon kirjaus kaikille varastotapahtumille,
-"If enabled, the system will post accounting entries for inventory automatically.","Mikäli käytössä, järjestelmä tekee varastokirjanpidon tilikirjaukset automaattisesti.",
-Accounts Frozen Upto,tilit jäädytetty toistaiseksi / asti,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","kirjanpidon kirjaus on toistaiseksi jäädytetty, vain alla mainitussa roolissa voi tällä hetkellä kirjata / muokata tiliä",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,rooli voi jäädyttää- sekä muokata jäädytettyjä kirjauksia,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,"Roolin omaavat käyttäjät voivat jäädyttää tilejä, sekä luoda ja muokata kirjanpidon kirjauksia jäädytettyillä tileillä",
Determine Address Tax Category From,Määritä osoiteveroluokka alkaen,
-Address used to determine Tax Category in transactions.,"Osoite, jota käytetään veroluokan määrittämiseen liiketoimissa.",
Over Billing Allowance (%),Yli laskutuskorvaus (%),
-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 for $110.,"Prosenttiosuus, jolla saa laskuttaa enemmän tilattua summaa vastaan. Esimerkiksi: Jos tilauksen arvo on 100 dollaria tuotteelle ja toleranssiksi on asetettu 10%, sinulla on oikeus laskuttaa 110 dollaria.",
Credit Controller,kredit valvoja,
-Role that is allowed to submit transactions that exceed credit limits set.,roolilla jolla voi lähettää tapamtumia pääsee luottoraja asetuksiin,
Check Supplier Invoice Number Uniqueness,tarkista toimittajan laskunumeron yksilöllisyys,
Make Payment via Journal Entry,Tee Maksu Päiväkirjakirjaus,
Unlink Payment on Cancellation of Invoice,Linkityksen Maksu mitätöinti Lasku,
-Unlink Advance Payment on Cancelation of Order,Irrota ennakkomaksu tilauksen peruuttamisen yhteydessä,
Book Asset Depreciation Entry Automatically,Kirja Asset Poistot Entry Automaattisesti,
Automatically Add Taxes and Charges from Item Tax Template,Lisää verot ja maksut automaattisesti tuoteveromallista,
Automatically Fetch Payment Terms,Hae maksuehdot automaattisesti,
-Show Inclusive Tax In Print,Näytä Inclusive Tax In Print,
Show Payment Schedule in Print,Näytä maksuaikataulu Tulosta,
Currency Exchange Settings,Valuutanvaihtoasetukset,
Allow Stale Exchange Rates,Salli vanhentuneet kurssit,
Stale Days,Stale Days,
Report Settings,Raporttiasetukset,
Use Custom Cash Flow Format,Käytä Custom Cash Flow -muotoa,
-Only select if you have setup Cash Flow Mapper documents,"Valitse vain, jos sinulla on asetettu Cash Flow Mapper -asiakirjoja",
Allowed To Transact With,Sallitut liiketoimet,
SWIFT number,SWIFT-numero,
Branch Code,Sivukonttorin koodi,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Asiakas Group,
POS Field,POS-kenttä,
POS Item Group,POS Kohta Group,
-[Select],[valitse],
Company Address,yritys osoite,
Update Stock,Päivitä varasto,
Ignore Pricing Rule,ohita hinnoittelu sääntö,
@@ -5495,8 +5466,6 @@
Supplier Naming By,toimittajan nimennyt,
Default Supplier Group,Oletuksena toimittajaryhmä,
Default Buying Price List,Ostohinnasto (oletus),
-Maintain same rate throughout purchase cycle,ylläpidä samaa tasoa läpi ostosyklin,
-Allow Item to be added multiple times in a transaction,Salli Kohta lisätään useita kertoja liiketoimi,
Backflush Raw Materials of Subcontract Based On,Alihankintaan perustuvat raaka-aineet,
Material Transferred for Subcontract,Alihankintaan siirretty materiaali,
Over Transfer Allowance (%),Ylisiirto-oikeus (%),
@@ -5540,7 +5509,6 @@
Current Stock,nykyinen varasto,
PUR-RFQ-.YYYY.-,PUR-Tarjouspyyntö-.YYYY.-,
For individual supplier,Yksittäisten toimittaja,
-Supplier Detail,Toimittaja Detail,
Link to Material Requests,Linkki materiaalipyyntöihin,
Message for Supplier,Viesti toimittaja,
Request for Quotation Item,tarjouspyynnön tuote,
@@ -6481,7 +6449,6 @@
Appraisal Template,Arvioinnin mallipohjat,
For Employee Name,Työntekijän nimeen,
Goals,tavoitteet,
-Calculate Total Score,Laske yhteispisteet,
Total Score (Out of 5),osumat (5:stä) yhteensä,
"Any other remarks, noteworthy effort that should go in the records.","muut huomiot, huomioitavat asiat tulee laittaa tähän tietueeseen",
Appraisal Goal,arvioinnin tavoite,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Poistumisen syy,
Leave Encashed?,vapaa kuitattu rahana?,
Encashment Date,perintä päivä,
-Exit Interview Details,poistu haastattelun lisätiedoista,
-Held On,järjesteltiin,
-Reason for Resignation,Eroamisen syy,
-Better Prospects,Parempi Näkymät,
-Health Concerns,"terveys, huolenaiheet",
New Workplace,Uusi Työpaikka,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Palautettu määrä,
@@ -6740,10 +6702,7 @@
Employee Settings,työntekijän asetukset,
Retirement Age,Eläkeikä,
Enter retirement age in years,Anna eläkeikä vuosina,
-Employee Records to be created by,työntekijä tietue on tehtävä,
-Employee record is created using selected field. ,työntekijä tietue luodaan käyttämällä valittua kenttää,
Stop Birthday Reminders,lopeta syntymäpäivämuistutukset,
-Don't send Employee Birthday Reminders,älä lähetä työntekijälle syntymäpäivämuistutuksia,
Expense Approver Mandatory In Expense Claim,Kulujen hyväksyntä pakollisena kulukorvauksessa,
Payroll Settings,Palkanlaskennan asetukset,
Leave,Poistu,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Jätä hyväksyntä pakolliseksi jätä sovellus,
Show Leaves Of All Department Members In Calendar,Näytä lehdet kaikista osaston jäsenistä kalenterista,
Auto Leave Encashment,Automaattinen poistuminen,
-Restrict Backdated Leave Application,Rajoita takaisin päivättyä jättöhakemusta,
Hiring Settings,Palkkausasetukset,
Check Vacancies On Job Offer Creation,Tarkista avoimien työpaikkojen luomisen tarjoukset,
Identification Document Type,Tunnistustyypin tyyppi,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,valmistuksen asetukset,
Raw Materials Consumption,Raaka-aineiden kulutus,
Allow Multiple Material Consumption,Salli moninkertainen materiaalikulutus,
-Allow multiple Material Consumption against a Work Order,Salli moninkertainen materiaalikulutus työtilaa vastaan,
Backflush Raw Materials Based On,Backflush Raaka-aineet Perustuvat,
Material Transferred for Manufacture,Tuotantoon siirretyt materiaalit,
Capacity Planning,kapasiteetin suunnittelu,
Disable Capacity Planning,Poista kapasiteettisuunnittelu käytöstä,
Allow Overtime,Salli Ylityöt,
-Plan time logs outside Workstation Working Hours.,Suunnittele aikaa lokit ulkopuolella Workstation työaikalain.,
Allow Production on Holidays,salli tuotanto lomapäivinä,
Capacity Planning For (Days),kapasiteetin suunnittelu (päiville),
-Try planning operations for X days in advance.,kokeile suunnitella toimia X päivää etukäteen,
-Time Between Operations (in mins),Toimintojen välinen aika (minuuteissa),
-Default 10 mins,oletus 10 min,
Default Warehouses for Production,Tuotannon oletusvarastot,
Default Work In Progress Warehouse,Oletus KET-varasto,
Default Finished Goods Warehouse,Valmiiden tavaroiden oletusvarasto,
Default Scrap Warehouse,Romun oletusvarasto,
-Over Production for Sales and Work Order,Ylituotanto myyntiä varten ja tilaus,
Overproduction Percentage For Sales Order,Ylituotanto prosentteina myyntitilauksesta,
Overproduction Percentage For Work Order,Ylituotanto prosentteina työjärjestykselle,
Other Settings,Muut asetukset,
Update BOM Cost Automatically,Päivitä BOM-hinta automaattisesti,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Päivitys BOM maksaa automaattisesti Scheduler-ohjelman avulla, joka perustuu viimeisimpään arvostusnopeuteen / hinnastonopeuteen / raaka-aineiden viimeiseen ostohintaan.",
Material Request Plan Item,Materiaalihakemuksen suunnitelma,
Material Request Type,Hankintapyynnön tyyppi,
Material Issue,materiaali aihe,
@@ -7603,10 +7554,6 @@
Quality Goal,Laadullinen tavoite,
Monitoring Frequency,Monitorointitaajuus,
Weekday,arkipäivä,
-January-April-July-October,Tammi-huhtikuu-heinäkuun ja lokakuun,
-Revision and Revised On,Tarkistettu ja muutettu päälle,
-Revision,tarkistus,
-Revised On,Tarkistettu päälle,
Objectives,tavoitteet,
Quality Goal Objective,Laadukas tavoite,
Objective,Tavoite,
@@ -7619,7 +7566,6 @@
Processes,Prosessit,
Quality Procedure Process,Laatumenettelyprosessi,
Process Description,Prosessin kuvaus,
-Child Procedure,Lapsen menettely,
Link existing Quality Procedure.,Yhdistä olemassa oleva laatumenettely.,
Additional Information,lisäinformaatio,
Quality Review Objective,Laadun arvioinnin tavoite,
@@ -7787,15 +7733,9 @@
Default Customer Group,Oletusasiakasryhmä,
Default Territory,oletus alue,
Close Opportunity After Days,Close tilaisuuden päivää,
-Auto close Opportunity after 15 days,Auto lähellä Mahdollisuus 15 päivän jälkeen,
Default Quotation Validity Days,Oletushakemusten voimassaoloajat,
Sales Update Frequency,Myyntipäivitystaajuus,
-How often should project and company be updated based on Sales Transactions.,Kuinka usein projektin ja yrityksen tulee päivittää myyntitapahtumien perusteella.,
Each Transaction,Jokainen liiketoimi,
-Allow user to edit Price List Rate in transactions,salli käyttäjän muokata hinnaston tasoa tapahtumissa,
-Allow multiple Sales Orders against a Customer's Purchase Order,Salli useat Myyntitilaukset vastaan Asiakkaan Ostotilauksen,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Validoi myyntihinta Tuote vastaan Purchase Rate tai arvostus Hinta,
-Hide Customer's Tax Id from Sales Transactions,Piilota Asiakkaan Tax Id myyntitapahtumia,
SMS Center,Tekstiviesti keskus,
Send To,Lähetä kenelle,
All Contact,kaikki yhteystiedot,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Valmistajat käytetään Items,
Limited to 12 characters,Rajattu 12 merkkiin,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Aseta Warehouse,
-Sets 'For Warehouse' in each row of the Items table.,Asettaa 'Varastolle' Kohteet-taulukon jokaiselle riville.,
-Requested For,Pyydetty kohteelle,
Partially Ordered,Osittain tilattu,
Transferred,siirretty,
% Ordered,% järjestetty,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Oletusvarastoyksikkö,
Sample Retention Warehouse,Näytteen säilytysvarasto,
Default Valuation Method,oletus arvomenetelmä,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Vastaanoton tai toimituksen prosenttiosuus on liian suuri suhteessa tilausmäärään, esim: mikäli 100 yksikköä on tilattu sallittu ylitys on 10% niin sallittu määrä on 110 yksikköä",
-Action if Quality inspection is not submitted,"Toimenpide, jos laadun tarkastusta ei toimiteta",
Show Barcode Field,Näytä Viivakoodi-kenttä,
Convert Item Description to Clean HTML,Muuta kohteen kuvaus Puhdista HTML,
-Auto insert Price List rate if missing,"Lisää automaattisesti hinnastoon, jos puuttuu",
Allow Negative Stock,salli negatiivinen varastoarvo,
Automatically Set Serial Nos based on FIFO,Automaattisesti Serial nro perustuu FIFO,
-Set Qty in Transactions based on Serial No Input,"Aseta määrä operaatioihin, jotka perustuvat sarjamuotoiseen tuloon",
Auto Material Request,Automaattinen hankintapyyntö,
-Raise Material Request when stock reaches re-order level,Luo hankintapyyntö kun saldo on alle tilauspisteen,
-Notify by Email on creation of automatic Material Request,Ilmoita automaattisen hankintapyynnön luomisesta sähköpostitse,
Inter Warehouse Transfer Settings,Inter Warehouse Transfer -asetukset,
-Allow Material Transfer From Delivery Note and Sales Invoice,Salli materiaalinsiirto lähetysluettelosta ja myyntilaskusta,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Salli materiaalinsiirto ostokuitista ja ostolaskusta,
Freeze Stock Entries,jäädytä varaston kirjaukset,
Stock Frozen Upto,varasto jäädytetty asti,
-Freeze Stocks Older Than [Days],jäädytä yli [päivää] vanhat varastot,
-Role Allowed to edit frozen stock,rooli saa muokata jäädytettyä varastoa,
Batch Identification,Erätunnistus,
Use Naming Series,Käytä nimipalvelusarjaa,
Naming Series Prefix,Nimeä sarjan etuliite,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Saapumisten kehitys,
Purchase Register,Osto Rekisteröidy,
Quotation Trends,Tarjousten kehitys,
-Quoted Item Comparison,Noteeratut Kohta Vertailu,
Received Items To Be Billed,Saivat kohteet laskuttamat,
Qty to Order,Tilattava yksikkömäärä,
Requested Items To Be Transferred,siirrettävät pyydetyt tuotteet,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Valitse varasto materiaalipyyntöjä varten,
Transfer Materials For Warehouse {0},Siirrä materiaaleja varastoon {0},
Production Plan Material Request Warehouse,Tuotantosuunnitelman materiaalipyyntövarasto,
-Set From Warehouse,Aseta varastosta,
-Source Warehouse (Material Transfer),Lähdevarasto (materiaalinsiirto),
Sets 'Source Warehouse' in each row of the items table.,Asettaa 'Lähdevarasto' kullekin tuotetaulukon riville.,
Sets 'Target Warehouse' in each row of the items table.,Asettaa kohdevaraston kullekin tuotetaulukon riville.,
Show Cancelled Entries,Näytä peruutetut merkinnät,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Palvelu vastaanotettu, mutta sitä ei laskuteta",
Deferred Accounting Settings,Laskennalliset kirjanpitoasetukset,
Book Deferred Entries Based On,Kirjaa lykätyt merkinnät,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Jos "Kuukaudet" on valittu, kiinteä summa kirjataan laskennalliseksi tuloksi tai kuluksi kustakin kuukaudesta riippumatta kuukauden päivien määrästä. Se suhteutetaan, jos laskennallisia tuloja tai kuluja ei ole kirjattu koko kuukaudeksi.",
Days,Päivää,
Months,Kuukaudet,
Book Deferred Entries Via Journal Entry,Varaa lykätyt merkinnät päiväkirjakirjauksen kautta,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Jos tämä ei ole valittuna, GL-kirjaukset luodaan laskennallisten tulojen / kulujen kirjaamiseen",
Submit Journal Entries,Lähetä päiväkirjamerkinnät,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Jos tämä ei ole valittuna, päiväkirjamerkinnät tallennetaan luonnostilaan ja ne on lähetettävä manuaalisesti",
Enable Distributed Cost Center,Ota hajautettu kustannuskeskus käyttöön,
@@ -8901,8 +8823,6 @@
Is Inter State,Onko valtioiden välinen,
Purchase Details,Ostotiedot,
Depreciation Posting Date,Poistojen kirjauspäivä,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Ostolaskun ja kuitin luomiseen vaaditaan ostotilaus,
-Purchase Receipt Required for Purchase Invoice Creation,Ostolaskun luomiseen vaaditaan ostokuitti,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",Oletusarvon mukaan toimittajan nimi asetetaan syötetyn toimittajan nimen mukaan. Jos haluat toimittajien nimeävän a,
choose the 'Naming Series' option.,valitse 'Naming Series' -vaihtoehto.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,"Määritä oletushinnasto, kun luot uutta ostotapahtumaa. Tuotteiden hinnat haetaan tästä hinnastosta.",
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Onko tuloverokomponentti,
Component properties and references ,Komponenttien ominaisuudet ja viitteet,
Additional Salary ,Lisäpalkka,
-Condtion and formula,Ehto ja kaava,
Unmarked days,Merkitsemättömät päivät,
Absent Days,Poissa olevat päivät,
Conditions and Formula variable and example,Ehdot ja kaavan muuttuja ja esimerkki,
Feedback By,Palaute,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Valmistusosa,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Myyntilaskun ja lähetysluettelon luomiseen vaaditaan myyntitilaus,
-Delivery Note Required for Sales Invoice Creation,Toimituslasku vaaditaan myyntilaskun luomiseen,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",Asiakkaan nimi asetetaan oletusarvoisesti syötetyn koko nimen mukaan. Jos haluat asiakkaiden nimeävän a,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,"Määritä oletushinta, kun luot uutta myyntitapahtumaa. Tuotteiden hinnat haetaan tästä hinnastosta.",
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Jos tämä vaihtoehto on määritetty Kyllä, ERPNext estää sinua luomasta myyntilaskua tai lähetysilmoitusta luomatta ensin myyntitilausta. Tämä kokoonpano voidaan ohittaa tietylle asiakkaalle ottamalla Salli myyntilaskun luominen ilman myyntitilausta -valintaruutu asiakaspäällikössä.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} on lisätty kaikkiin valittuihin aiheisiin.,
Topics updated,Aiheet päivitettiin,
Academic Term and Program,Akateeminen termi ja ohjelma,
-Last Stock Transaction for item {0} was on {1}.,Tuotteen {0} viimeinen varastotapahtuma oli {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Tuotteen {0} varastotapahtumia ei voi lähettää ennen tätä aikaa.,
Please remove this item and try to submit again or update the posting time.,Poista tämä kohde ja yritä lähettää uudelleen tai päivittää lähetysaika.,
Failed to Authenticate the API key.,API-avaimen todentaminen epäonnistui.,
Invalid Credentials,Virheelliset kirjautumistiedot,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Tarkista Plaid-asiakastunnuksesi ja salaiset arvosi,
Bank transaction creation error,Pankkitapahtumien luomisvirhe,
Unit of Measurement,Mittayksikkö,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Rivi # {}: Tuotteen {} myyntihinta on matalampi kuin sen {}. Myyntikoron tulee olla vähintään {},
Fiscal Year {0} Does Not Exist,Tilikausi {0} ei ole olemassa,
Row # {0}: Returned Item {1} does not exist in {2} {3},Rivi # {0}: Palautettua kohdetta {1} ei ole kohteessa {2} {3},
Valuation type charges can not be marked as Inclusive,Arvostustyyppisiä maksuja ei voida merkitä sisältäviksi,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Vasteaika {0} rivillä {1} olevalle prioriteetille ei voi olla suurempi kuin tarkkuusaika.,
{0} is not enabled in {1},{0} ei ole käytössä maassa {1},
Group by Material Request,Ryhmittele materiaalipyynnön mukaan,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Rivi {0}: Toimittajan {0} sähköpostiosoite vaaditaan sähköpostin lähettämiseen,
Email Sent to Supplier {0},Sähköposti lähetetty toimittajalle {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Pääsy tarjouspyyntöön portaalista on poistettu käytöstä. Jos haluat sallia pääsyn, ota se käyttöön portaalin asetuksissa.",
Supplier Quotation {0} Created,Toimittajan tarjous {0} luotu,
Valid till Date cannot be before Transaction Date,Voimassa oleva päivämäärä ei voi olla ennen tapahtuman päivämäärää,
+Unlink Advance Payment on Cancellation of Order,Poista ennakkomaksu tilauksen peruuttamisen yhteydessä,
+"Simple Python Expression, Example: territory != 'All Territories'","Yksinkertainen Python-lauseke, Esimerkki: alue! = 'Kaikki alueet'",
+Sales Contributions and Incentives,Myynnin osuus ja kannustimet,
+Sourced by Supplier,Toimittaja,
+Total weightage assigned should be 100%.<br>It is {0},Kohdistetun kokonaispainon tulisi olla 100%.<br> Se on {0},
+Account {0} exists in parent company {1}.,Tili {0} on emoyhtiössä {1}.,
+"To overrule this, enable '{0}' in company {1}",Voit kumota tämän ottamalla yrityksen {0} käyttöön yrityksessä {1},
+Invalid condition expression,Virheellinen ehtolauseke,
+Please Select a Company First,Valitse ensin yritys,
+Please Select Both Company and Party Type First,Valitse ensin sekä yritys- että juhlatyyppi,
+Provide the invoice portion in percent,Anna laskutusosuus prosentteina,
+Give number of days according to prior selection,Ilmoita päivien määrä etukäteen tehdyn valinnan mukaan,
+Email Details,Sähköpostin tiedot,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Valitse tervehdys vastaanottimelle. Esim. Herra, rouva jne.",
+Preview Email,Esikatsele sähköpostia,
+Please select a Supplier,Valitse toimittaja,
+Supplier Lead Time (days),Toimittajan toimitusaika (päivää),
+"Home, Work, etc.","Koti, työ jne.",
+Exit Interview Held On,Lopeta haastattelu,
+Condition and formula,Kunto ja kaava,
+Sets 'Target Warehouse' in each row of the Items table.,Asettaa Kohdevarasto Kohde-taulukon jokaiselle riville.,
+Sets 'Source Warehouse' in each row of the Items table.,Asettaa Lähdevarasto Kohteet-taulukon jokaiselle riville.,
+POS Register,POS-rekisteri,
+"Can not filter based on POS Profile, if grouped by POS Profile","Ei voida suodattaa POS-profiilin perusteella, jos se on ryhmitelty POS-profiilin mukaan",
+"Can not filter based on Customer, if grouped by Customer","Ei voi suodattaa asiakkaan perusteella, jos asiakas on ryhmitelty",
+"Can not filter based on Cashier, if grouped by Cashier","Ei voi suodattaa kassan perusteella, jos se on ryhmitelty kassan mukaan",
+Payment Method,Maksutapa,
+"Can not filter based on Payment Method, if grouped by Payment Method","Ei voi suodattaa maksutavan perusteella, jos se on ryhmitelty maksutavan mukaan",
+Supplier Quotation Comparison,Toimittajien tarjousten vertailu,
+Price per Unit (Stock UOM),Yksikköhinta (varastossa UOM),
+Group by Supplier,Ryhmittele toimittajan mukaan,
+Group by Item,Ryhmittele kohteiden mukaan,
+Remember to set {field_label}. It is required by {regulation}.,Muista asettaa {field_label}. Sitä vaaditaan {asetuksessa}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Ilmoittautumispäivä ei voi olla aikaisempi kuin lukuvuoden aloituspäivä {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Ilmoittautumispäivä ei voi olla lukukauden päättymispäivän jälkeen {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Ilmoittautumispäivä ei voi olla aikaisempi kuin lukukauden aloituspäivä {0},
+Future Posting Not Allowed,Tulevaa julkaisua ei sallita,
+"To enable Capital Work in Progress Accounting, ","Jotta pääomatyö käynnissä olevaan kirjanpitoon voidaan ottaa käyttöön,",
+you must select Capital Work in Progress Account in accounts table,sinun on valittava pääomatyö käynnissä -tili tilitaulukosta,
+You can also set default CWIP account in Company {},Voit myös asettaa CWIP-oletustilin yrityksessä {},
+The Request for Quotation can be accessed by clicking on the following button,Tarjouspyyntöön pääsee napsauttamalla seuraavaa painiketta,
+Regards,Terveiset,
+Please click on the following button to set your new password,Napsauta seuraavaa painiketta asettaaksesi uuden salasanasi,
+Update Password,Päivitä salasana,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Rivi # {}: Tuotteen {} myyntihinta on matalampi kuin sen {}. Myynnin {} tulisi olla vähintään {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Voit vaihtoehtoisesti poistaa myyntihinnan vahvistuksen käytöstä {} ohittaaksesi tämän vahvistuksen.,
+Invalid Selling Price,Virheellinen myyntihinta,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Osoite on linkitettävä yritykseen. Lisää linkki-taulukkoon Yritys-rivi.,
+Company Not Linked,Yritystä ei ole linkitetty,
+Import Chart of Accounts from CSV / Excel files,Tuo tilikartta CSV / Excel-tiedostoista,
+Completed Qty cannot be greater than 'Qty to Manufacture',Toteutettu määrä ei voi olla suurempi kuin "Valmistuksen määrä",
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Rivi {0}: Toimittajalle {1} sähköpostiosoite vaaditaan sähköpostin lähettämiseen,
+"If enabled, the system will post accounting entries for inventory automatically","Jos tämä on käytössä, järjestelmä kirjaa varastomerkinnät automaattisesti",
+Accounts Frozen Till Date,Tilit jäädytetty asti,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"Kirjanpitomerkinnät on jäädytetty tähän päivään saakka. Kukaan ei voi luoda tai muokata merkintöjä paitsi käyttäjät, joilla on alla määritelty rooli",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Rooli sallitaan asettaa jäädytetyt tilit ja muokata jäädytettyjä viestejä,
+Address used to determine Tax Category in transactions,"Osoite, jota käytetään veroluokan määrittämiseen tapahtumissa",
+"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 ","Prosenttiosuus, jonka saat laskuttaa enemmän tilattua summaa vastaan. Esimerkiksi, jos tilauksen arvo on 100 dollaria tuotteelle ja toleranssiksi on asetettu 10%, voit laskuttaa enintään 110 dollaria",
+This role is allowed to submit transactions that exceed credit limits,"Tämä rooli saa lähettää tapahtumia, jotka ylittävät luottorajat",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Jos "Kuukaudet" on valittu, kiinteä summa kirjataan laskennalliseksi tuloksi tai kuluksi kustakin kuukaudesta riippumatta kuukauden päivien määrästä. Se suhteutetaan, jos laskennallisia tuloja tai kuluja ei ole kirjattu koko kuukaudeksi",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Jos tätä ei ole valittu, luvatut suorat kirjaukset luodaan laskennallisten tulojen tai kulujen kirjaamiseksi",
+Show Inclusive Tax in Print,Näytä kattava vero painettuna,
+Only select this if you have set up the Cash Flow Mapper documents,"Valitse tämä vain, jos olet määrittänyt Cash Flow Mapper -asiakirjat",
+Payment Channel,Maksukanava,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Tarvitaanko ostotilaus ostolaskun ja kuitin luomiseen?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Onko ostolasku vaadittava ostolaskun luomiseen?,
+Maintain Same Rate Throughout the Purchase Cycle,Säilytä sama hinta koko ostojakson ajan,
+Allow Item To Be Added Multiple Times in a Transaction,Salli kohteen lisääminen useita kertoja tapahtumassa,
+Suppliers,Toimittajat,
+Send Emails to Suppliers,Lähetä sähköpostit toimittajille,
+Select a Supplier,Valitse toimittaja,
+Cannot mark attendance for future dates.,Läsnäoloa ei voi merkitä tuleville päivämäärille.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Haluatko päivittää läsnäoloa?<br> Läsnä: {0}<br> Poissa: {1},
+Mpesa Settings,Mpesa-asetukset,
+Initiator Name,Aloittelijan nimi,
+Till Number,Till numero,
+Sandbox,Hiekkalaatikko,
+ Online PassKey,Online PassKey,
+Security Credential,Suojaustiedot,
+Get Account Balance,Hanki tilin saldo,
+Please set the initiator name and the security credential,Määritä aloittajan nimi ja suojaustunnus,
+Inpatient Medication Entry,Sairaalan lääkehoito,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Tuotekoodi (huume),
+Medication Orders,Lääkitys tilaukset,
+Get Pending Medication Orders,Hanki vireillä olevat lääketilaukset,
+Inpatient Medication Orders,Sairaalan lääkemääräykset,
+Medication Warehouse,Lääkevarasto,
+Warehouse from where medication stock should be consumed,"Varasto, josta lääkevarasto tulisi kuluttaa",
+Fetching Pending Medication Orders,Haetaan odottavia lääketilauksia,
+Inpatient Medication Entry Detail,Sairaalan lääkehoidon alkutiedot,
+Medication Details,Lääkityksen yksityiskohdat,
+Drug Code,Lääkekoodi,
+Drug Name,Lääkkeen nimi,
+Against Inpatient Medication Order,Sairaalan lääkemääräystä vastaan,
+Against Inpatient Medication Order Entry,Sairaanhoitolääkkeiden tilausta vastaan,
+Inpatient Medication Order,Sairaalan lääkemääräys,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Tilaukset yhteensä,
+Completed Orders,Valmiit tilaukset,
+Add Medication Orders,Lisää lääketilauksia,
+Adding Order Entries,Tilaustietojen lisääminen,
+{0} medication orders completed,{0} lääketilausta tehty,
+{0} medication order completed,{0} lääkitysmääräys valmis,
+Inpatient Medication Order Entry,Sairaalan lääkemääräys,
+Is Order Completed,Onko tilaus valmis,
+Employee Records to Be Created By,Työntekijätietueiden luoma,
+Employee records are created using the selected field,Työntekijätietueet luodaan käyttämällä valittua kenttää,
+Don't send employee birthday reminders,Älä lähetä työntekijän muistutuksia syntymäpäivästä,
+Restrict Backdated Leave Applications,Rajoita vanhentuneita lomahakemuksia,
+Sequence ID,Sekvenssitunnus,
+Sequence Id,Sekvenssitunnus,
+Allow multiple material consumptions against a Work Order,Salli useita materiaalikulutuksia työmääräykseen,
+Plan time logs outside Workstation working hours,Suunnittele aikalokit työaseman työajan ulkopuolella,
+Plan operations X days in advance,Suunnittele toiminta X päivää etukäteen,
+Time Between Operations (Mins),Operaatioiden välinen aika (minuutit),
+Default: 10 mins,Oletus: 10 min,
+Overproduction for Sales and Work Order,Myynnin ja työtilausten ylituotanto,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",Päivitä BOM-kustannukset automaattisesti ajastimen kautta viimeisimpien raaka-aineiden arvostusnopeuden / hinnaston / viimeisen oston perusteella,
+Purchase Order already created for all Sales Order items,Kaikille myyntitilaustuotteille on jo luotu ostotilaus,
+Select Items,Valitse Kohteet,
+Against Default Supplier,Oletustoimittajaa vastaan,
+Auto close Opportunity after the no. of days mentioned above,Automaattinen sulkemismahdollisuus ei-numeron jälkeen edellä mainituista päivistä,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Tarvitaanko myyntitilaus myyntilaskun ja lähetysluettelon luomiseen?,
+Is Delivery Note Required for Sales Invoice Creation?,Tarvitaanko lähetyslasku myyntilaskun luomiseen?,
+How often should Project and Company be updated based on Sales Transactions?,Kuinka usein projekti ja yritys tulisi päivittää myyntitapahtumien perusteella?,
+Allow User to Edit Price List Rate in Transactions,Salli käyttäjän muokata hintaluetteloa tapahtumissa,
+Allow Item to Be Added Multiple Times in a Transaction,Salli kohteen lisääminen useita kertoja tapahtumassa,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Salli useita myyntitilauksia asiakkaan ostotilausta vastaan,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Vahvista tuotteen myyntihinta osto- tai arvostusastetta vastaan,
+Hide Customer's Tax ID from Sales Transactions,Piilota asiakkaan verotunnus myyntitapahtumista,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Prosenttiosuus, jonka saat vastaanottaa tai toimittaa enemmän tilattuun määrään nähden. Esimerkiksi, jos olet tilannut 100 yksikköä ja korvauksesi on 10%, voit saada 110 yksikköä.",
+Action If Quality Inspection Is Not Submitted,"Toimi, jos laatutarkastusta ei toimiteta",
+Auto Insert Price List Rate If Missing,"Lisää hinnaston hinta automaattisesti, jos se puuttuu",
+Automatically Set Serial Nos Based on FIFO,Aseta sarjanumerot automaattisesti FIFO: n perusteella,
+Set Qty in Transactions Based on Serial No Input,Määritä tapahtumien määrä sarjakohtaisen syötteen perusteella,
+Raise Material Request When Stock Reaches Re-order Level,"Nosta materiaalipyyntö, kun varasto saavuttaa tilaustason",
+Notify by Email on Creation of Automatic Material Request,Ilmoita sähköpostitse automaattisen materiaalipyynnön luomisesta,
+Allow Material Transfer from Delivery Note to Sales Invoice,Salli materiaalien siirto lähetysilmoituksesta myyntilaskuun,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Salli materiaalinsiirto ostokuitista ostolaskuun,
+Freeze Stocks Older Than (Days),Jäädytä varastot vanhempia kuin (päivät),
+Role Allowed to Edit Frozen Stock,Rooli saa muokata jäädytettyä varastoa,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Maksutapahtuman kohdentamaton summa {0} on suurempi kuin pankkitapahtuman kohdentamaton summa,
+Payment Received,Maksu vastaanotettu,
+Attendance cannot be marked outside of Academic Year {0},Läsnäoloa ei voida merkitä lukuvuoden ulkopuolella {0},
+Student is already enrolled via Course Enrollment {0},Opiskelija on jo ilmoittautunut kurssin ilmoittautumisen kautta {0},
+Attendance cannot be marked for future dates.,Läsnäoloa ei voida merkitä tuleville päiville.,
+Please add programs to enable admission application.,"Lisää ohjelmat, jotta pääsy hakemukseen.",
+The following employees are currently still reporting to {0}:,Seuraavat työntekijät raportoivat edelleen {0}:,
+Please make sure the employees above report to another Active employee.,"Varmista, että yllä olevat työntekijät raportoivat toiselle aktiiviselle työntekijälle.",
+Cannot Relieve Employee,Työntekijää ei voi vapauttaa,
+Please enter {0},Kirjoita {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Valitse toinen maksutapa. Mpesa ei tue tapahtumia valuutalla {0},
+Transaction Error,Tapahtumavirhe,
+Mpesa Express Transaction Error,Mpesa Express -tapahtumavirhe,
+"Issue detected with Mpesa configuration, check the error logs for more details","Mpesa-määrityksessä havaittu ongelma, tarkista virhelokit",
+Mpesa Express Error,Mpesa Express -virhe,
+Account Balance Processing Error,Tilin saldon käsittelyvirhe,
+Please check your configuration and try again,Tarkista kokoonpanosi ja yritä uudelleen,
+Mpesa Account Balance Processing Error,Mpesa-tilin saldon käsittelyvirhe,
+Balance Details,Saldotiedot,
+Current Balance,Nykyinen tasapaino,
+Available Balance,Käytettävissä oleva saldo,
+Reserved Balance,Varattu saldo,
+Uncleared Balance,Tyhjentämätön saldo,
+Payment related to {0} is not completed,Kohteeseen {0} liittyvä maksu ei ole suoritettu,
+Row #{}: Item Code: {} is not available under warehouse {}.,Rivi # {}: Tuotekoodi: {} ei ole käytettävissä varastossa {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Rivi # {}: varastomäärä ei riitä tuotekoodille: {} varaston alla {}. Saatavilla oleva määrä {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Rivi # {}: Valitse sarjanumero ja erä kohteelle: {} tai poista se suorittaaksesi tapahtuman.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Rivi # {}: Kohdasta {} ei ole valittu sarjanumeroa. Valitse yksi tai poista se suorittaaksesi tapahtuman loppuun.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Rivi # {}: Kohdetta {} ei ole valittu. Valitse erä tai poista se suorittaaksesi tapahtuman loppuun.,
+Payment amount cannot be less than or equal to 0,Maksun summa ei voi olla pienempi tai yhtä suuri kuin 0,
+Please enter the phone number first,Anna ensin puhelinnumero,
+Row #{}: {} {} does not exist.,Rivi # {}: {} {} ei ole olemassa.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Rivi # {0}: {1} vaaditaan avaavien {2} laskujen luomiseen,
+You had {} errors while creating opening invoices. Check {} for more details,Sinulla oli {} virhettä avatessasi laskuja. Katso lisätietoja osoitteesta {},
+Error Occured,Tapahtui virhe,
+Opening Invoice Creation In Progress,Laskun luominen käynnissä,
+Creating {} out of {} {},Luodaan {} / {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Sarjanumero: {0}) ei voida käyttää, koska se on varattu myyntitilauksen täyttämiseen {1}.",
+Item {0} {1},Tuote {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Tuotteen {0} varasto {1} viimeinen varastotapahtuma oli {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Tuotteen {0} varasto {1} varastotapahtumia ei voi lähettää ennen tätä aikaa.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Tulevien osakekauppojen kirjaaminen ei ole sallittua Immutable Ledgerin vuoksi,
+A BOM with name {0} already exists for item {1}.,"Tuotteelle {1} on jo olemassa BOM, jonka nimi on {0}.",
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Nimesitkö kohteen uudelleen? Ota yhteyttä järjestelmänvalvojaan / tekniseen tukeen,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Rivillä # {0}: sekvenssitunnus {1} ei voi olla pienempi kuin edellinen rivisekvenssitunnus {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) on oltava yhtä suuri kuin {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, suorita toiminto {1} ennen operaatiota {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Toimitusta sarjanumerolla ei voida varmistaa, koska tuote {0} lisätään ja ilman varmistaa sarjanumero.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Kohteella {0} ei ole sarjanumeroa. Vain serilisoidut tuotteet voivat toimittaa sarjanumeron perusteella,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Kohteelle {0} ei löytynyt aktiivista BOM: ia Toimitusta Sarjanumerolla ei voida varmistaa,
+No pending medication orders found for selected criteria,Valituille kriteereille ei löytynyt odottavia lääketilauksia,
+From Date cannot be after the current date.,Aloituspäivä ei voi olla nykyisen päivämäärän jälkeen.,
+To Date cannot be after the current date.,Päivämäärä ei voi olla nykyisen päivämäärän jälkeen.,
+From Time cannot be after the current time.,From Time ei voi olla nykyisen ajan jälkeen.,
+To Time cannot be after the current time.,Aika ei voi olla nykyisen ajan jälkeen.,
+Stock Entry {0} created and ,Varastomerkintä {0} luotu ja,
+Inpatient Medication Orders updated successfully,Sairaanhoitolääketilausten päivitys onnistui,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Rivi {0}: Sairaalan lääkehoitoa ei voi luoda peruutettua sairaalalääketilausta vastaan {1},
+Row {0}: This Medication Order is already marked as completed,Rivi {0}: Tämä lääkitysmääräys on jo merkitty valmiiksi,
+Quantity not available for {0} in warehouse {1},Määrä ei ole käytettävissä kohteelle {0} varastossa {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Ota Salli negatiivinen varastossa -osake käyttöön tai luo varastotiedot jatkaaksesi.,
+No Inpatient Record found against patient {0},Potilasta {0} vastaan ei löytynyt sairaalatietoja,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Sairaalan lääkemääräys {0} potilastapaamista vastaan {1} on jo olemassa.,
+Allow In Returns,Salli vastineeksi,
+Hide Unavailable Items,Piilota käytettävissä olevat kohteet,
+Apply Discount on Discounted Rate,Käytä alennusta alennettuun hintaan,
+Therapy Plan Template,Hoitosuunnitelman malli,
+Fetching Template Details,Haetaan mallin yksityiskohtia,
+Linked Item Details,Linkitetyn tuotteen tiedot,
+Therapy Types,Hoitotyypit,
+Therapy Plan Template Detail,Hoitosuunnitelman malli,
+Non Conformance,Vaatimustenvastaisuus,
+Process Owner,Prosessin omistaja,
+Corrective Action,Korjaava toimenpide,
+Preventive Action,Ennaltaehkäisevä toiminta,
+Problem,Ongelma,
+Responsible,Vastuullinen,
+Completion By,Valmistuminen,
+Process Owner Full Name,Prosessin omistajan koko nimi,
+Right Index,Oikea hakemisto,
+Left Index,Vasen hakemisto,
+Sub Procedure,Alimenettely,
+Passed,Hyväksytty,
+Print Receipt,Tulosta kuitti,
+Edit Receipt,Muokkaa kuittiä,
+Focus on search input,Keskity hakusyöttöön,
+Focus on Item Group filter,Keskity tuoteryhmän suodattimeen,
+Checkout Order / Submit Order / New Order,Kassatilaus / Lähetä tilaus / Uusi tilaus,
+Add Order Discount,Lisää tilausalennus,
+Item Code: {0} is not available under warehouse {1}.,Tuotekoodi: {0} ei ole käytettävissä varastossa {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Sarjanumerot eivät ole käytettävissä tuotteelle {0} varaston alla {1}. Yritä vaihtaa varastoa.,
+Fetched only {0} available serial numbers.,Haettu vain {0} käytettävissä olevaa sarjanumeroa.,
+Switch Between Payment Modes,Vaihda maksutapojen välillä,
+Enter {0} amount.,Anna summa {0}.,
+You don't have enough points to redeem.,Sinulla ei ole tarpeeksi pisteitä lunastettavaksi.,
+You can redeem upto {0}.,Voit lunastaa jopa {0}.,
+Enter amount to be redeemed.,Syötä lunastettava summa.,
+You cannot redeem more than {0}.,Et voi lunastaa enempää kuin {0}.,
+Open Form View,Avaa lomakkeenäkymä,
+POS invoice {0} created succesfully,POS-lasku {0} luotu onnistuneesti,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Varastomäärä ei riitä tuotekoodiin: {0} varaston alla {1}. Saatavilla oleva määrä {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Sarjanumero: {0} on jo tehty toiseen POS-laskuun.,
+Balance Serial No,Saldo Sarjanumero,
+Warehouse: {0} does not belong to {1},Varasto: {0} ei kuulu {1},
+Please select batches for batched item {0},Valitse erät eräkohtaiselle tuotteelle {0},
+Please select quantity on row {0},Valitse määrä riviltä {0},
+Please enter serial numbers for serialized item {0},Anna sarjanumero sarjanumerolle {0},
+Batch {0} already selected.,Erä {0} on jo valittu.,
+Please select a warehouse to get available quantities,Valitse varasto saadaksesi käytettävissä olevat määrät,
+"For transfer from source, selected quantity cannot be greater than available quantity",Lähteestä siirtoa varten valittu määrä ei voi olla suurempi kuin käytettävissä oleva määrä,
+Cannot find Item with this Barcode,Tuotetta ei löydy tällä viivakoodilla,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} on pakollinen. Ehkä valuutanvaihtotietuetta ei ole luotu käyttäjille {1} - {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} on lähettänyt siihen linkitetyn sisällön. Sinun on peruttava varat, jotta voit luoda ostotuoton.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Tätä asiakirjaa ei voi peruuttaa, koska se on linkitetty lähetettyyn sisältöön {0}. Peruuta se jatkaaksesi.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Rivi # {}: Sarjanumero {} on jo tehty toiseen POS-laskuun. Valitse voimassa oleva sarjanumero.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Rivi # {}: Sarjanumerot {} on jo tehty toiseen POS-laskuun. Valitse voimassa oleva sarjanumero.,
+Item Unavailable,Kohde ei ole käytettävissä,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Rivi # {}: Sarjanumeroa {} ei voi palauttaa, koska sitä ei käsitelty alkuperäisessä laskussa {}",
+Please set default Cash or Bank account in Mode of Payment {},Määritä oletusarvoinen käteis- tai pankkitili Maksutilassa {},
+Please set default Cash or Bank account in Mode of Payments {},Aseta oletusarvoinen käteis- tai pankkitili Maksutilassa {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Varmista, että {} -tili on tase-tili. Voit vaihtaa päätilin tase-tiliksi tai valita toisen tilin.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Varmista, että {} -tili on maksettava tili. Muuta tilityypiksi Maksettava tai valitse toinen tili.",
+Row {}: Expense Head changed to {} ,Rivi {}: Kulupää vaihdettu arvoksi {},
+because account {} is not linked to warehouse {} ,koska tiliä {} ei ole linkitetty varastoon {},
+or it is not the default inventory account,tai se ei ole oletusvarastotili,
+Expense Head Changed,Kulupää vaihdettu,
+because expense is booked against this account in Purchase Receipt {},koska kulu kirjataan tätä tiliä vastaan ostokuittiin {},
+as no Purchase Receipt is created against Item {}. ,koska tuotteelle {} ei luoda ostokuittiä.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Tämä tehdään kirjanpidon hoitamiseksi tapauksissa, joissa ostokuitti luodaan ostolaskun jälkeen",
+Purchase Order Required for item {},Tuotteen {} ostotilaus vaaditaan,
+To submit the invoice without purchase order please set {} ,"Jos haluat lähettää laskun ilman ostotilausta, aseta {}",
+as {} in {},kuten {} kohteessa {},
+Mandatory Purchase Order,Pakollinen ostotilaus,
+Purchase Receipt Required for item {},Tuotteelle vaaditaan ostokuitti,
+To submit the invoice without purchase receipt please set {} ,"Jos haluat lähettää laskun ilman ostokuittiä, aseta {}",
+Mandatory Purchase Receipt,Pakollinen ostokuitti,
+POS Profile {} does not belongs to company {},POS-profiili {} ei kuulu yritykseen {},
+User {} is disabled. Please select valid user/cashier,Käyttäjä {} on poistettu käytöstä. Valitse kelvollinen käyttäjä / kassanhaltija,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Rivi # {}: palautuslaskun {} alkuperäinen lasku {} on {}.,
+Original invoice should be consolidated before or along with the return invoice.,Alkuperäinen lasku tulee yhdistää ennen palautuslaskua tai sen mukana.,
+You can add original invoice {} manually to proceed.,Voit lisätä alkuperäisen laskun {} manuaalisesti jatkaaksesi.,
+Please ensure {} account is a Balance Sheet account. ,"Varmista, että {} -tili on tase-tili.",
+You can change the parent account to a Balance Sheet account or select a different account.,Voit vaihtaa päätilin tase-tiliksi tai valita toisen tilin.,
+Please ensure {} account is a Receivable account. ,"Varmista, että {} -tili on Saamisetili.",
+Change the account type to Receivable or select a different account.,Muuta tilityypiksi Saamiset tai valitse toinen tili.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"{} ei voi peruuttaa, koska ansaitut kanta-asiakaspisteet on lunastettu. Peruuta ensin {} Ei {}",
+already exists,on jo olemassa,
+POS Closing Entry {} against {} between selected period,POS-loppumerkintä {} vastaan {} valitun jakson välillä,
+POS Invoice is {},POS-lasku on {},
+POS Profile doesn't matches {},POS-profiili ei vastaa {},
+POS Invoice is not {},POS-lasku ei ole {},
+POS Invoice isn't created by user {},POS-laskua ei ole luonut käyttäjä {},
+Row #{}: {},Rivi # {}: {},
+Invalid POS Invoices,Virheelliset POS-laskut,
+Please add the account to root level Company - {},Lisää tili juuritason yritykselle - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Kun luot yritystiliä lapsiyritykselle {0}, emotiliä {1} ei löydy. Luo vanhemman tili vastaavassa aitoustodistuksessa",
+Account Not Found,Tiliä ei löydy,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Kun luot yritystiliä {0}, emotili {1} löydettiin kirjanpitotiliksi.",
+Please convert the parent account in corresponding child company to a group account.,Muunna vastaavan alayrityksen emotili ryhmätiliksi.,
+Invalid Parent Account,Virheellinen vanhempien tili,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Sen uudelleennimeäminen on sallittua vain emoyrityksen {0} kautta, jotta vältetään ristiriidat.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Jos {0} {1} tuotemääriä {2} käytetään, malliin {3} sovelletaan tuotetta.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Jos {0} {1} arvoinen kohde {2}, malliin {3} sovelletaan tuotetta.",
+"As the field {0} is enabled, the field {1} is mandatory.","Koska kenttä {0} on käytössä, kenttä {1} on pakollinen.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Koska kenttä {0} on käytössä, kentän {1} arvon tulisi olla suurempi kuin 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Tuotteen {0} sarjanumeroa {1} ei voida toimittaa, koska se on varattu täyden myyntitilauksen {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Myyntitilauksessa {0} on varaus tuotteelle {1}, voit toimittaa varattuja {1} vain vastaan {0}.",
+{0} Serial No {1} cannot be delivered,{0} Sarjanumeroa {1} ei voida toimittaa,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Rivi {0}: Alihankintatuote on pakollinen raaka-aineelle {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Koska raaka-aineita on riittävästi, Materiaalipyyntöä ei vaadita Varasto {0} -palvelussa.",
+" If you still want to proceed, please enable {0}.","Jos haluat edelleen jatkaa, ota {0} käyttöön.",
+The item referenced by {0} - {1} is already invoiced,"Kohde, johon {0} - {1} viittaa, on jo laskutettu",
+Therapy Session overlaps with {0},Hoitoistunto on päällekkäinen kohteen {0} kanssa,
+Therapy Sessions Overlapping,Hoitoistunnot ovat päällekkäisiä,
+Therapy Plans,Hoitosuunnitelmat,
+"Item Code, warehouse, quantity are required on row {0}","Tuotekoodi, varasto, määrä vaaditaan rivillä {0}",
+Get Items from Material Requests against this Supplier,Hanki tuotteita tältä toimittajalta saaduista materiaalipyynnöistä,
+Enable European Access,Ota käyttöön eurooppalainen käyttöoikeus,
+Creating Purchase Order ...,Luodaan ostotilausta ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",Valitse toimittaja alla olevien tuotteiden oletustoimittajista. Valinnan yhteydessä ostotilaus tehdään vain valitulle toimittajalle kuuluvista tuotteista.,
+Row #{}: You must select {} serial numbers for item {}.,Rivi # {}: Sinun on valittava {} tuotteen sarjanumerot {}.,
diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv
index dd72c2e..3cdae45 100644
--- a/erpnext/translations/fr.csv
+++ b/erpnext/translations/fr.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Le type de taxe réel ne peut pas être inclus dans le prix de l'Article à la ligne {0},
Add,Ajouter,
Add / Edit Prices,Ajouter / Modifier Prix,
-Add All Suppliers,Ajouter tous les fournisseurs,
Add Comment,Ajouter un Commentaire,
Add Customers,Ajouter des clients,
Add Employees,Ajouter des employés,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Vous ne pouvez pas déduire lorsqu'une catégorie est pour 'Évaluation' ou 'Évaluation et Total',
"Cannot delete Serial No {0}, as it is used in stock transactions","Impossible de supprimer les N° de série {0}, s'ils sont dans les mouvements de stock",
Cannot enroll more than {0} students for this student group.,Inscription de plus de {0} étudiants impossible pour ce groupe d'étudiants.,
-Cannot find Item with this barcode,Impossible de trouver l'article avec ce code à barres,
Cannot find active Leave Period,Impossible de trouver une période de congés active,
Cannot produce more Item {0} than Sales Order quantity {1},Impossible de produire plus d'Article {0} que la quantité {1} du Bon de Commande,
Cannot promote Employee with status Left,"Impossible de promouvoir un employé avec le statut ""Parti""",
Cannot refer row number greater than or equal to current row number for this Charge type,Impossible de se référer au numéro de la ligne supérieure ou égale au numéro de la ligne courante pour ce type de Charge,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Impossible de sélectionner le type de charge comme étant «Le Montant de la Ligne Précédente» ou «Montant Total de la Ligne Précédente» pour la première ligne,
-Cannot set a received RFQ to No Quote,Impossible de lier une Réponse à Appel d'Offres reçue à Aucun Devis,
Cannot set as Lost as Sales Order is made.,Impossible de définir comme perdu alors qu'un Bon de Commande a été créé.,
Cannot set authorization on basis of Discount for {0},Impossible de définir l'autorisation sur la base des Prix Réduits pour {0},
Cannot set multiple Item Defaults for a company.,Impossible de définir plusieurs valeurs par défaut pour une entreprise.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Les frais sont mis à jour dans le Reçu d'Achat pour chaque article,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Les frais seront distribués proportionnellement à la qté ou au montant de l'article, selon votre sélection",
-Chart Of Accounts,Plan comptable,
Chart of Cost Centers,Tableau des centres de coûts,
Check all,Cochez tout,
Checkout,Règlement,
@@ -581,14 +577,13 @@
Compensatory Off,Congé Compensatoire,
Compensatory leave request days not in valid holidays,Les jours de la demande de congé compensatoire ne sont pas dans des vacances valides,
Complaint,Plainte,
-Completed Qty can not be greater than 'Qty to Manufacture',"Qté Terminée ne peut pas être supérieure à ""Quantité de Production""",
Completion Date,Date d'Achèvement,
Computer,Ordinateur,
Condition,Conditions,
Configure,Configurer,
Configure {0},Configurer {0},
Confirmed orders from Customers.,Commandes confirmées des clients.,
-Connect Amazon with ERPNext,Connectez Amazon avec ERPNext,
+Connect Amazon with ERPNext,Connecter Amazon avec ERPNext,
Connect Shopify with ERPNext,Connectez Shopify avec ERPNext,
Connect to Quickbooks,Se connecter à Quickbooks,
Connected to QuickBooks,Connecté à QuickBooks,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Créer et gérer des résumés d'E-mail quotidiens, hebdomadaires et mensuels .",
Create customer quotes,Créer les devis client,
Create rules to restrict transactions based on values.,Créer des règles pour restreindre les transactions basées sur les valeurs .,
-Created By,Établi par,
Created {0} scorecards for {1} between: ,{0} fiches d'évaluations créées pour {1} entre:,
Creating Company and Importing Chart of Accounts,Création d'une société et importation d'un plan comptable,
Creating Fees,Création d'Honoraires,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Le transfert ne peut pas être soumis avant la date de transfert,
Employee cannot report to himself.,L'employé ne peut pas rendre de compte à lui-même.,
Employee relieved on {0} must be set as 'Left',Employé dégagé de {0} doit être défini comme 'Gauche',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,Le statut d'employé ne peut pas être défini sur 'Gauche' car les employés suivants sont actuellement rattachés à cet employé:,
Employee {0} already submited an apllication {1} for the payroll period {2},L'employé {0} a déjà envoyé une demande {1} pour la période de calcul de paie {2},
Employee {0} has already applied for {1} between {2} and {3} : ,L'employé {0} a déjà postulé pour {1} entre {2} et {3}:,
Employee {0} has no maximum benefit amount,L'employé {0} n'a pas de montant maximal d'avantages sociaux,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Pour la ligne {0}: entrez la quantité planifiée,
"For {0}, only credit accounts can be linked against another debit entry","Pour {0}, seuls les comptes de crédit peuvent être liés avec une autre écriture de débit",
"For {0}, only debit accounts can be linked against another credit entry","Pour {0}, seuls les comptes de débit peuvent être liés avec une autre écriture de crédit",
-Form View,Vue de Formulaire,
Forum Activity,Activité du forum,
Free item code is not selected,Le code d'article gratuit n'est pas sélectionné,
Freight and Forwarding Charges,Frais de Fret et d'Expédition,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Congé ne peut être alloué avant le {0}, car le solde de congés a déjà été reporté dans la feuille d'allocation de congés futurs {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Congé ne peut être demandé / annulé avant le {0}, car le solde de congés a déjà été reporté dans la feuille d'allocation de congés futurs {1}",
Leave of type {0} cannot be longer than {1},Les Congés de type {0} ne peuvent pas être plus long que {1},
-Leave the field empty to make purchase orders for all suppliers,Laissez le champ vide pour passer des commandes pour tous les fournisseurs,
Leaves,Feuilles,
Leaves Allocated Successfully for {0},Congés Attribués avec Succès pour {0},
Leaves has been granted sucessfully,Des feuilles ont été accordées avec succès,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Aucun Article avec une Liste de Matériel à Produire,
No Items with Bill of Materials.,Aucun article avec nomenclature.,
No Permission,Aucune autorisation,
-No Quote,Aucun Devis,
No Remarks,Aucune Remarque,
No Result to submit,Aucun résultat à soumettre,
No Salary Structure assigned for Employee {0} on given date {1},Aucune structure de salaire attribuée à l'employé {0} à la date donnée {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Conditions qui coincident touvées entre :,
Owner,Responsable,
PAN,Numéro de compte permanent (PAN),
-PO already created for all sales order items,PO déjà créé pour tous les postes de commande client,
POS,PDV,
POS Profile,Profil PDV,
POS Profile is required to use Point-of-Sale,Un profil PDV est requis pour utiliser le point de vente,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Veuillez d’abord sélectionner le Type de Facturation,
Please select Company,Veuillez sélectionner une Société,
Please select Company and Designation,Veuillez sélectionner la société et la désignation,
-Please select Company and Party Type first,Veuillez d’abord sélectionner une Société et le Type de Tiers,
Please select Company and Posting Date to getting entries,Veuillez sélectionner la société et la date de comptabilisation pour obtenir les écritures,
Please select Company first,Veuillez d’abord sélectionner une Société,
Please select Completion Date for Completed Asset Maintenance Log,Veuillez sélectionner la date d'achèvement pour le journal de maintenance des actifs terminé,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Ligne {0} : Facteur de Conversion LDM est obligatoire,
Row {0}: select the workstation against the operation {1},Ligne {0}: sélectionnez le poste de travail en fonction de l'opération {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Ligne {0}: {1} Numéros de série requis pour l'article {2}. Vous en avez fourni {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,La ligne {0}: {1} est requise pour créer les factures d'ouverture {2},
Row {0}: {1} must be greater than 0,Ligne {0}: {1} doit être supérieure à 0,
Row {0}: {1} {2} does not match with {3},Ligne {0} : {1} {2} ne correspond pas à {3},
Row {0}:Start Date must be before End Date,Ligne {0} : La Date de Début doit être avant la Date de Fin,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Envoyer un email d'examen de la demande de subvention,
Send Now,Envoyer Maintenant,
Send SMS,Envoyer un SMS,
-Send Supplier Emails,Envoyer des Emails au Fournisseur,
Send mass SMS to your contacts,Envoyer un SMS en masse à vos contacts,
Sensitivity,Sensibilité,
Sent,Envoyé,
-Serial #,Série #,
Serial No and Batch,N° de Série et lot,
Serial No is mandatory for Item {0},N° de Série est obligatoire pour l'Article {0},
Serial No {0} does not belong to Batch {1},Le numéro de série {0} n'appartient pas au lot {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Le nom de l'entreprise pour laquelle vous configurez ce système.,
The number of shares and the share numbers are inconsistent,Le nombre d'actions dans les transactions est incohérent avec le nombre total d'actions,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Le compte passerelle de paiement dans le plan {0} est différent du compte passerelle de paiement dans cette requête de paiement.,
-The request for quotation can be accessed by clicking on the following link,La demande de devis peut être consultée en cliquant sur le lien suivant,
The selected BOMs are not for the same item,Les LDMs sélectionnées ne sont pas pour le même article,
The selected item cannot have Batch,L’article sélectionné ne peut pas avoir de Lot,
The seller and the buyer cannot be the same,Le vendeur et l'acheteur ne peuvent pas être les mêmes,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Le montant total de la composante de prestation flexible {0} ne doit pas être inférieur au nombre maximal de prestations {1},
Total hours: {0},Nombre total d'heures : {0},
Total leaves allocated is mandatory for Leave Type {0},Le nombre total de congés alloués est obligatoire pour le type de congé {0},
-Total weightage assigned should be 100%. It is {0},Le total des pondérations attribuées devrait être de 100 %. Il est {0},
Total working hours should not be greater than max working hours {0},Le nombre total d'heures travaillées ne doit pas être supérieur à la durée maximale du travail {0},
Total {0} ({1}),Total {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Le Total {0} pour tous les articles est nul, peut-être devriez-vous modifier ‘Distribuez les Frais sur la Base de’",
@@ -3316,7 +3299,6 @@
What do you need help with?,Avec quoi avez vous besoin d'aide ?,
What does it do?,Qu'est-ce que ça fait ?,
Where manufacturing operations are carried.,Là où les opérations de production sont réalisées.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Lors de la création du compte pour la société enfant {0}, le compte parent {1} est introuvable. Veuillez créer le compte parent dans le COA correspondant.",
White,blanc,
Wire Transfer,Virement,
WooCommerce Products,Produits WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} variantes créées.,
{0} {1} created,{0} {1} créé,
{0} {1} does not exist,{0} {1} n'existe pas,
-{0} {1} does not exist.,{0} {1} n'existe pas,
{0} {1} has been modified. Please refresh.,{0} {1} a été modifié. Veuillez actualiser.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} n'a pas été soumis, donc l'action ne peut pas être complétée",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} est associé à {2}, mais le compte tiers est {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0} : {1} n’existe pas,
{0}: {1} not found in Invoice Details table,{0} : {1} introuvable dans la table de Détails de la Facture,
{} of {},{} de {},
+Assigned To,Assigné À,
Chat,Chat,
Completed By,Effectué par,
Conditions,Conditions,
@@ -3506,7 +3488,9 @@
Merge with existing,Fusionner avec existant,
Office,Bureau,
Orientation,Orientation,
+Parent,Parent,
Passive,Passif,
+Payment Failed,Le Paiement a Échoué,
Percent,Pourcent,
Permanent,Permanent,
Personal,Personnel,
@@ -3544,7 +3528,6 @@
Company field is required,Le champ de l'entreprise est obligatoire,
Creating Dimensions...,Créer des dimensions ...,
Duplicate entry against the item code {0} and manufacturer {1},Dupliquer la saisie par rapport au code article {0} et au fabricant {1},
-Import Chart Of Accounts from CSV / Excel files,Importer un graphique des comptes à partir de fichiers CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN invalide! L'entrée que vous avez entrée ne correspond pas au format GSTIN pour les titulaires d'un UIN ou les fournisseurs de services OIDAR non résidents,
Invoice Grand Total,Total général de la facture,
Last carbon check date cannot be a future date,La date du dernier bilan carbone ne peut pas être une date future,
@@ -3556,6 +3539,7 @@
Show {0},Montrer {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caractères spéciaux sauf "-", "#", ".", "/", "{" Et "}" non autorisés dans les séries de nommage",
Target Details,Détails de la cible,
+{0} already has a Parent Procedure {1}.,{0} a déjà une procédure parent {1}.,
API,API,
Annual,Annuel,
Approved,Approuvé,
@@ -3572,6 +3556,8 @@
No data to export,Aucune donnée à exporter,
Portrait,Portrait,
Print Heading,Imprimer Titre,
+Scheduler Inactive,Planificateur inactif,
+Scheduler is inactive. Cannot import data.,Le planificateur est inactif. Impossible d'importer des données.,
Show Document,Afficher le document,
Show Traceback,Afficher le traçage,
Video,Vidéo,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Créer un contrôle qualité pour l'article {0},
Creating Accounts...,Création de comptes ...,
Creating bank entries...,Création d'entrées bancaires ...,
-Creating {0},Création de {0},
Credit limit is already defined for the Company {0},La limite de crédit est déjà définie pour la société {0}.,
Ctrl + Enter to submit,Ctrl + Entrée pour soumettre,
Ctrl+Enter to submit,Ctrl + Entrée pour soumettre,
@@ -3921,7 +3906,6 @@
Plaid public token error,Erreur de jeton public Plaid,
Plaid transactions sync error,Erreur de synchronisation des transactions plaid,
Please check the error log for details about the import errors,Veuillez consulter le journal des erreurs pour plus de détails sur les erreurs d'importation.,
-Please click on the following link to set your new password,Veuillez cliquer sur le lien suivant pour définir votre nouveau mot de passe,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Veuillez créer les <b>paramètres DATEV</b> pour l'entreprise <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Veuillez créer une écriture de journal d'ajustement pour le montant {0},
Please do not create more than 500 items at a time,Ne créez pas plus de 500 objets à la fois.,
@@ -3997,6 +3981,7 @@
Release date must be in the future,La date de sortie doit être dans le futur,
Relieving Date must be greater than or equal to Date of Joining,La date de libération doit être supérieure ou égale à la date d'adhésion,
Rename,Renommer,
+Rename Not Allowed,Renommer non autorisé,
Repayment Method is mandatory for term loans,La méthode de remboursement est obligatoire pour les prêts à terme,
Repayment Start Date is mandatory for term loans,La date de début de remboursement est obligatoire pour les prêts à terme,
Report Item,Élément de rapport,
@@ -4043,7 +4028,6 @@
Select All,Sélectionner Tout,
Select Difference Account,Sélectionnez compte différentiel,
Select a Default Priority.,Sélectionnez une priorité par défaut.,
-Select a Supplier from the Default Supplier List of the items below.,Sélectionnez un fournisseur dans la liste des fournisseurs par défaut des éléments ci-dessous.,
Select a company,Sélectionnez une entreprise,
Select finance book for the item {0} at row {1},Sélectionnez le livre de financement pour l'élément {0} à la ligne {1}.,
Select only one Priority as Default.,Sélectionnez une seule priorité par défaut.,
@@ -4247,7 +4231,6 @@
Actual ,Réel,
Add to cart,Ajouter au Panier,
Budget,Budget,
-Chart Of Accounts Importer,Importateur de plan comptable,
Chart of Accounts,Plan comptable,
Customer database.,Base de données clients.,
Days Since Last order,Jours depuis la dernière commande,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,La date de Fin ne peut pas être antérieure à la Date de Début,
For Default Supplier (Optional),Pour le fournisseur par défaut (facultatif),
From date cannot be greater than To date,La Date Initiale ne peut pas être postérieure à la Date Finale,
-Get items from,Obtenir les articles de,
Group by,Grouper Par,
In stock,En stock,
Item name,Nom de l'article,
@@ -4532,32 +4514,22 @@
Accounts Settings,Paramètres des Comptes,
Settings for Accounts,Paramètres des Comptes,
Make Accounting Entry For Every Stock Movement,Faites une Écriture Comptable Pour Chaque Mouvement du Stock,
-"If enabled, the system will post accounting entries for inventory automatically.","Si activé, le système publiera automatiquement les écritures comptables pour l'inventaire.",
-Accounts Frozen Upto,Comptes Gelés Jusqu'au,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Les écritures comptables sont gelées jusqu'à cette date, personne ne peut ajouter / modifier les entrées sauf les rôles spécifiés ci-dessous.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Rôle Autorisé à Geler des Comptes & à Éditer des Écritures Gelées,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Les utilisateurs ayant ce rôle sont autorisés à définir les comptes gelés et à créer / modifier des écritures comptables sur des comptes gelés,
Determine Address Tax Category From,Déterminer la catégorie de taxe d'adresse à partir de,
-Address used to determine Tax Category in transactions.,Adresse utilisée pour déterminer la catégorie de taxe dans les transactions.,
Over Billing Allowance (%),Frais de facturation excédentaires (%),
-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 for $110.,"Pourcentage vous êtes autorisé à facturer plus par rapport au montant commandé. Par exemple: Si la valeur de la commande est de 100 USD pour un article et que la tolérance est définie sur 10%, vous êtes autorisé à facturer 110 USD.",
Credit Controller,Controlleur du Crédit,
-Role that is allowed to submit transactions that exceed credit limits set.,Rôle qui est autorisé à soumettre des transactions qui dépassent les limites de crédit fixées.,
Check Supplier Invoice Number Uniqueness,Vérifiez l'Unicité du Numéro de Facture du Fournisseur,
Make Payment via Journal Entry,Effectuer un Paiement par une Écriture de Journal,
Unlink Payment on Cancellation of Invoice,Délier Paiement à l'Annulation de la Facture,
-Unlink Advance Payment on Cancelation of Order,Dissocier le paiement anticipé lors de l'annulation d'une commande,
Book Asset Depreciation Entry Automatically,Comptabiliser les Entrées de Dépréciation d'Actifs Automatiquement,
Automatically Add Taxes and Charges from Item Tax Template,Ajouter automatiquement des taxes et des frais à partir du modèle de taxe à la pièce,
Automatically Fetch Payment Terms,Récupérer automatiquement les conditions de paiement,
-Show Inclusive Tax In Print,Afficher la taxe inclusive en impression,
Show Payment Schedule in Print,Afficher le calendrier de paiement dans Imprimer,
Currency Exchange Settings,Paramètres d'échange de devises,
Allow Stale Exchange Rates,Autoriser les Taux de Change Existants,
Stale Days,Journées Passées,
Report Settings,Paramètres de rapport,
Use Custom Cash Flow Format,Utiliser le format de flux de trésorerie personnalisé,
-Only select if you have setup Cash Flow Mapper documents,Ne sélectionner que si vous avez configuré des documents de mapping de trésorerie,
Allowed To Transact With,Autorisé à faire affaire avec,
SWIFT number,Numéro rapide,
Branch Code,Code de la branche,
@@ -4940,7 +4912,6 @@
POS Customer Group,Groupe Clients PDV,
POS Field,Champ POS,
POS Item Group,Groupe d'Articles PDV,
-[Select],[Choisir],
Company Address,Adresse de la Société,
Update Stock,Mettre à Jour le Stock,
Ignore Pricing Rule,Ignorez Règle de Prix,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Nomenclature de Fournisseur Par,
Default Supplier Group,Groupe de fournisseurs par défaut,
Default Buying Price List,Liste des Prix d'Achat par Défaut,
-Maintain same rate throughout purchase cycle,Maintenir le même taux durant le cycle d'achat,
-Allow Item to be added multiple times in a transaction,Autoriser un article à être ajouté plusieurs fois dans une transaction,
Backflush Raw Materials of Subcontract Based On,Sortir rétroactivement les matières premières d'un contrat de sous-traitance sur la base de,
Material Transferred for Subcontract,Matériel transféré pour sous-traitance,
Over Transfer Allowance (%),Sur indemnité de transfert (%),
@@ -5540,7 +5509,6 @@
Current Stock,Stock Actuel,
PUR-RFQ-.YYYY.-,PUR-RFQ-.AAAA.-,
For individual supplier,Pour un fournisseur individuel,
-Supplier Detail,Détails du Fournisseur,
Link to Material Requests,Lien vers les demandes de matériel,
Message for Supplier,Message pour le Fournisseur,
Request for Quotation Item,Article de l'Appel d'Offre,
@@ -6481,7 +6449,6 @@
Appraisal Template,Modèle d'évaluation,
For Employee Name,Nom de l'Employé,
Goals,Objectifs,
-Calculate Total Score,Calculer le Résultat Total,
Total Score (Out of 5),Score Total (sur 5),
"Any other remarks, noteworthy effort that should go in the records.","Toute autre remarque, effort remarquable qui devrait aller dans les dossiers.",
Appraisal Goal,Objectif d'Estimation,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Raison du Départ,
Leave Encashed?,Laisser Encaissé ?,
Encashment Date,Date de l'Encaissement,
-Exit Interview Details,Entretient de Départ,
-Held On,Tenu le,
-Reason for Resignation,Raison de la Démission,
-Better Prospects,Meilleures Perspectives,
-Health Concerns,Problèmes de Santé,
New Workplace,Nouveau Lieu de Travail,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Montant retourné,
@@ -6740,10 +6702,7 @@
Employee Settings,Paramètres des Employés,
Retirement Age,Âge de la Retraite,
Enter retirement age in years,Entrez l'âge de la retraite en années,
-Employee Records to be created by,Dossiers de l'Employés ont été créées par,
-Employee record is created using selected field. ,Le dossier de l'employé est créé en utilisant le champ sélectionné.,
Stop Birthday Reminders,Arrêter les Rappels d'Anniversaire,
-Don't send Employee Birthday Reminders,Ne pas envoyer de rappel pour le Jour d'Anniversaire des Employés,
Expense Approver Mandatory In Expense Claim,Approbateur obligatoire pour les notes de frais,
Payroll Settings,Paramètres de Paie,
Leave,Partir,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Approbateur de congés obligatoire dans une demande de congé,
Show Leaves Of All Department Members In Calendar,Afficher les congés de tous les membres du département dans le calendrier,
Auto Leave Encashment,Auto Leave Encashment,
-Restrict Backdated Leave Application,Restreindre la demande de congé antidaté,
Hiring Settings,Paramètres d'embauche,
Check Vacancies On Job Offer Creation,Vérifier les offres d'emploi lors de la création d'une offre d'emploi,
Identification Document Type,Type de document d'identification,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Paramètres de Production,
Raw Materials Consumption,Consommation de matières premières,
Allow Multiple Material Consumption,Autoriser la consommation de plusieurs matériaux,
-Allow multiple Material Consumption against a Work Order,Autoriser la consommation de plusieurs articles par rapport à un ordre de travail,
Backflush Raw Materials Based On,Enregistrer les Matières Premières sur la Base de,
Material Transferred for Manufacture,Matériel Transféré pour la Production,
Capacity Planning,Planification de Capacité,
Disable Capacity Planning,Désactiver la planification des capacités,
Allow Overtime,Autoriser les Heures Supplémentaires,
-Plan time logs outside Workstation Working Hours.,Autoriser les feuilles de temps en dehors des heures de travail de la station de travail.,
Allow Production on Holidays,Autoriser la Fabrication pendant les Vacances,
Capacity Planning For (Days),Planification de Capacité Pendant (Jours),
-Try planning operations for X days in advance.,Essayez de planifer des opérations X jours à l'avance.,
-Time Between Operations (in mins),Temps entre les opérations (en min),
-Default 10 mins,10 minutes Par Défaut,
Default Warehouses for Production,Entrepôts par défaut pour la production,
Default Work In Progress Warehouse,Entrepôt de Travail en Cours par Défaut,
Default Finished Goods Warehouse,Entrepôt de Produits Finis par Défaut,
Default Scrap Warehouse,Entrepôt de rebut par défaut,
-Over Production for Sales and Work Order,Sur-production pour les ventes et les bons de travail,
Overproduction Percentage For Sales Order,Pourcentage de surproduction pour les commandes client,
Overproduction Percentage For Work Order,Pourcentage de surproduction pour les ordres de travail,
Other Settings,Autres Paramètres,
Update BOM Cost Automatically,Mettre à jour automatiquement le coût de la LDM,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Mettre à jour le coût de la LDM automatiquement via le Planificateur, en fonction du dernier taux de valorisation / tarif de la liste de prix / dernier prix d'achat des matières premières.",
Material Request Plan Item,Article du plan de demande de matériel,
Material Request Type,Type de Demande de Matériel,
Material Issue,Sortie de Matériel,
@@ -7603,10 +7554,6 @@
Quality Goal,Objectif de qualité,
Monitoring Frequency,Fréquence de surveillance,
Weekday,Jour de la semaine,
-January-April-July-October,Janvier-avril-juillet-octobre,
-Revision and Revised On,Révision et révisé le,
-Revision,Révision,
-Revised On,Révisé le,
Objectives,Objectifs,
Quality Goal Objective,Objectif de qualité Objectif,
Objective,Objectif,
@@ -7619,7 +7566,6 @@
Processes,Les processus,
Quality Procedure Process,Processus de procédure de qualité,
Process Description,Description du processus,
-Child Procedure,Procédure enfant,
Link existing Quality Procedure.,Lier la procédure qualité existante.,
Additional Information,Information additionnelle,
Quality Review Objective,Objectif de revue de qualité,
@@ -7787,15 +7733,9 @@
Default Customer Group,Groupe de Clients par Défaut,
Default Territory,Région par Défaut,
Close Opportunity After Days,Fermer Opportunité Après Jours,
-Auto close Opportunity after 15 days,Fermer automatiquement les Opportunités après 15 jours,
Default Quotation Validity Days,Jours de validité par défaut pour les devis,
Sales Update Frequency,Fréquence de mise à jour des ventes,
-How often should project and company be updated based on Sales Transactions.,À quelle fréquence le projet et la société doivent-ils être mis à jour sur la base des transactions de vente?,
Each Transaction,A chaque transaction,
-Allow user to edit Price List Rate in transactions,Autoriser l'utilisateur l'édition de la Liste des Prix lors des transactions,
-Allow multiple Sales Orders against a Customer's Purchase Order,Autoriser plusieurs Commandes Clients pour un Bon de Commande d'un Client,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Valider le Prix de Vente de l'Article avec le Prix d'Achat ou le Taux de Valorisation,
-Hide Customer's Tax Id from Sales Transactions,Cacher le N° de TVA du Client des Transactions de Vente,
SMS Center,Centre des SMS,
Send To,Envoyer À,
All Contact,Tout Contact,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Fabricants utilisés dans les Articles,
Limited to 12 characters,Limité à 12 caractères,
MAT-MR-.YYYY.-,MAT-MR-YYYY.-,
-Set Warehouse,Définir l'entrepôt,
-Sets 'For Warehouse' in each row of the Items table.,Définit «Pour l'entrepôt» dans chaque ligne de la table Articles.,
-Requested For,Demandé Pour,
Partially Ordered,Partiellement commandé,
Transferred,Transféré,
% Ordered,% Commandé,
@@ -8407,24 +8344,14 @@
Default Stock UOM,UDM par Défaut des Articles,
Sample Retention Warehouse,Entrepôt de stockage des échantillons,
Default Valuation Method,Méthode de Valorisation par Défaut,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Pourcentage que vous êtes autorisé à recevoir ou à livrer en plus de la quantité commandée. Par exemple : Si vous avez commandé 100 unités et que votre allocation est de 10% alors que vous êtes autorisé à recevoir 110 unités.,
-Action if Quality inspection is not submitted,Action si l'inspection qualité n'est pas soumise,
Show Barcode Field,Afficher Champ Code Barre,
Convert Item Description to Clean HTML,Convertir la description de l'élément pour nettoyer le code HTML,
-Auto insert Price List rate if missing,Insertion automatique du taux de la Liste de Prix si manquante,
Allow Negative Stock,Autoriser un Stock Négatif,
Automatically Set Serial Nos based on FIFO,Régler Automatiquement les Nos de Série basés sur FIFO,
-Set Qty in Transactions based on Serial No Input,Définir la quantité dans les transactions en fonction des données du numéro de série,
Auto Material Request,Demande de Matériel Automatique,
-Raise Material Request when stock reaches re-order level,Créer une demande de matériel lorsque le stock atteint le niveau de réapprovisionnement,
-Notify by Email on creation of automatic Material Request,Notifier par Email lors de la création automatique de la Demande de Matériel,
Inter Warehouse Transfer Settings,Paramètres de transfert entre entrepôts,
-Allow Material Transfer From Delivery Note and Sales Invoice,Autoriser le transfert d'articles à partir du bon de livraison et de la facture de vente,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Autoriser le transfert de matériel à partir du reçu d'achat et de la facture d'achat,
Freeze Stock Entries,Geler les Entrées de Stocks,
Stock Frozen Upto,Stock Gelé Jusqu'au,
-Freeze Stocks Older Than [Days],Geler les Articles plus Anciens que [Jours],
-Role Allowed to edit frozen stock,Rôle Autorisé à modifier un stock gelé,
Batch Identification,Identification par lots,
Use Naming Series,Utiliser la série de noms,
Naming Series Prefix,Préfix du nom de série,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Tendances des Reçus d'Achats,
Purchase Register,Registre des Achats,
Quotation Trends,Tendances des Devis,
-Quoted Item Comparison,Comparaison d'Article Soumis,
Received Items To Be Billed,Articles Reçus à Facturer,
Qty to Order,Quantité à Commander,
Requested Items To Be Transferred,Articles Demandés à Transférer,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Sélectionnez l'entrepôt pour les demandes de matériel,
Transfer Materials For Warehouse {0},Transférer des matériaux pour l'entrepôt {0},
Production Plan Material Request Warehouse,Entrepôt de demande de matériel du plan de production,
-Set From Warehouse,Définir de l'entrepôt,
-Source Warehouse (Material Transfer),Entrepôt d'origine (transfert de matériel),
Sets 'Source Warehouse' in each row of the items table.,Définit «Entrepôt source» dans chaque ligne de la table des éléments.,
Sets 'Target Warehouse' in each row of the items table.,Définit «Entrepôt cible» dans chaque ligne de la table des articles.,
Show Cancelled Entries,Afficher les entrées annulées,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Service reçu mais non facturé,
Deferred Accounting Settings,Paramètres de comptabilité différée,
Book Deferred Entries Based On,Enregistrer les entrées différées en fonction de,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Si «Mois» est sélectionné, un montant fixe sera comptabilisé en tant que revenus ou dépenses différés pour chaque mois, quel que soit le nombre de jours dans un mois. Sera calculé au prorata si les revenus ou dépenses différés ne sont pas comptabilisés pour un mois entier.",
Days,Journées,
Months,Mois,
Book Deferred Entries Via Journal Entry,Enregistrer les écritures différées via l'écriture au journal,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Si cette case n'est pas cochée, des entrées GL directes seront créées pour enregistrer les revenus / dépenses différés",
Submit Journal Entries,Soumettre les entrées de journal,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Si cette case n'est pas cochée, les entrées de journal seront enregistrées dans un état Brouillon et devront être soumises manuellement",
Enable Distributed Cost Center,Activer le centre de coûts distribués,
@@ -8901,8 +8823,6 @@
Is Inter State,Est Inter State,
Purchase Details,Détails d'achat,
Depreciation Posting Date,Date comptable de l'amortissement,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Bon de commande requis pour la création de factures et de reçus d'achat,
-Purchase Receipt Required for Purchase Invoice Creation,Reçu d'achat requis pour la création de la facture d'achat,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Par défaut, le nom du fournisseur est défini selon le nom du fournisseur saisi. Si vous souhaitez que les fournisseurs soient nommés par un",
choose the 'Naming Series' option.,choisissez l'option 'Naming Series'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Configurez la liste de prix par défaut lors de la création d'une nouvelle transaction d'achat. Les prix des articles seront extraits de cette liste de prix.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Est un élément de l'impôt sur le revenu,
Component properties and references ,Propriétés et références des composants,
Additional Salary ,Salaire supplémentaire,
-Condtion and formula,Condition et formule,
Unmarked days,Jours non marqués,
Absent Days,Jours d'absence,
Conditions and Formula variable and example,Conditions et variable de formule et exemple,
Feedback By,Commentaires de,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. JJ.-,
Manufacturing Section,Section de fabrication,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Commande client requise pour la création d'une facture client et d'un bon de livraison,
-Delivery Note Required for Sales Invoice Creation,Bon de livraison requis pour la création de la facture de vente,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Par défaut, le nom du client est défini selon le nom complet entré. Si vous souhaitez que les clients soient nommés par un",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Configurez la liste de prix par défaut lors de la création d'une nouvelle transaction de vente. Les prix des articles seront extraits de cette liste de prix.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Si cette option est configurée sur «Oui», ERPNext vous empêchera de créer une facture client ou un bon de livraison sans créer d'abord une commande client. Cette configuration peut être remplacée pour un client particulier en activant la case à cocher «Autoriser la création de facture client sans commande client» dans la fiche Client.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} a bien été ajouté à tous les sujets sélectionnés.,
Topics updated,Sujets mis à jour,
Academic Term and Program,Terme académique et programme,
-Last Stock Transaction for item {0} was on {1}.,La dernière transaction sur stock pour l'article {0} a eu lieu le {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Les transactions sur stock pour l'article {0} ne peuvent pas être validées avant cette heure.,
Please remove this item and try to submit again or update the posting time.,Veuillez supprimer cet élément et réessayer de le soumettre ou mettre à jour l'heure de publication.,
Failed to Authenticate the API key.,Échec de l'authentification de la clé API.,
Invalid Credentials,Les informations d'identification invalides,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Veuillez vérifier votre identifiant client Plaid et vos valeurs secrètes,
Bank transaction creation error,Erreur de création de transaction bancaire,
Unit of Measurement,Unité de mesure,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Ligne n ° {}: le taux de vente de l'article {} est inférieur à son {}. Le taux de vente doit être d'au moins {},
Fiscal Year {0} Does Not Exist,L'exercice budgétaire {0} n'existe pas,
Row # {0}: Returned Item {1} does not exist in {2} {3},Ligne n ° {0}: l'élément renvoyé {1} n'existe pas dans {2} {3},
Valuation type charges can not be marked as Inclusive,Les frais de type d'évaluation ne peuvent pas être marqués comme inclusifs,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Le temps de réponse pour la {0} priorité dans la ligne {1} ne peut pas être supérieur au temps de résolution.,
{0} is not enabled in {1},{0} n'est pas activé dans {1},
Group by Material Request,Regrouper par demande de matériel,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Ligne {0}: pour le fournisseur {0}, l'adresse e-mail est requise pour envoyer un e-mail",
Email Sent to Supplier {0},E-mail envoyé au fournisseur {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","L'accès à la demande de devis du portail est désactivé. Pour autoriser l'accès, activez-le dans les paramètres du portail.",
Supplier Quotation {0} Created,Devis fournisseur {0} créé,
Valid till Date cannot be before Transaction Date,La date de validité ne peut pas être antérieure à la date de transaction,
+Unlink Advance Payment on Cancellation of Order,Dissocier le paiement anticipé lors de l'annulation de la commande,
+"Simple Python Expression, Example: territory != 'All Territories'","Expression Python simple, exemple: territoire! = 'Tous les territoires'",
+Sales Contributions and Incentives,Contributions et incitations aux ventes,
+Sourced by Supplier,Fourni par le fournisseur,
+Total weightage assigned should be 100%.<br>It is {0},Le poids total attribué doit être de 100%.<br> C'est {0},
+Account {0} exists in parent company {1}.,Le compte {0} existe dans la société mère {1}.,
+"To overrule this, enable '{0}' in company {1}","Pour contourner ce problème, activez «{0}» dans l'entreprise {1}",
+Invalid condition expression,Expression de condition non valide,
+Please Select a Company First,Veuillez d'abord sélectionner une entreprise,
+Please Select Both Company and Party Type First,Veuillez d'abord sélectionner à la fois la société et le type de partie,
+Provide the invoice portion in percent,Fournissez la partie de la facture en pourcentage,
+Give number of days according to prior selection,Donnez le nombre de jours selon la sélection préalable,
+Email Details,Détails de l'e-mail,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Sélectionnez un message d'accueil pour le destinataire. Par exemple, M., Mme, etc.",
+Preview Email,Aperçu de l'e-mail,
+Please select a Supplier,Veuillez sélectionner un fournisseur,
+Supplier Lead Time (days),Délai fournisseur (jours),
+"Home, Work, etc.","Domicile, travail, etc.",
+Exit Interview Held On,Entretien de sortie tenu le,
+Condition and formula,Condition et formule,
+Sets 'Target Warehouse' in each row of the Items table.,Définit «Entrepôt cible» dans chaque ligne de la table Articles.,
+Sets 'Source Warehouse' in each row of the Items table.,Définit «Entrepôt source» dans chaque ligne de la table Articles.,
+POS Register,Registre POS,
+"Can not filter based on POS Profile, if grouped by POS Profile","Impossible de filtrer en fonction du profil de point de vente, s'il est regroupé par profil de point de vente",
+"Can not filter based on Customer, if grouped by Customer","Impossible de filtrer en fonction du client, s'il est regroupé par client",
+"Can not filter based on Cashier, if grouped by Cashier","Impossible de filtrer en fonction du caissier, s'il est regroupé par caissier",
+Payment Method,Mode de paiement,
+"Can not filter based on Payment Method, if grouped by Payment Method","Impossible de filtrer en fonction du mode de paiement, s'il est regroupé par mode de paiement",
+Supplier Quotation Comparison,Comparaison des devis fournisseurs,
+Price per Unit (Stock UOM),Prix unitaire (Stock UdM),
+Group by Supplier,Regrouper par fournisseur,
+Group by Item,Grouper par article,
+Remember to set {field_label}. It is required by {regulation}.,N'oubliez pas de définir {field_label}. Il est requis par {règlement}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},La date d'inscription ne peut pas être antérieure à la date de début de l'année universitaire {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},La date d'inscription ne peut pas être postérieure à la date de fin du trimestre universitaire {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},La date d'inscription ne peut pas être antérieure à la date de début de la session universitaire {0},
+Future Posting Not Allowed,Publication future non autorisée,
+"To enable Capital Work in Progress Accounting, ","Pour activer la comptabilité des immobilisations en cours,",
+you must select Capital Work in Progress Account in accounts table,vous devez sélectionner le compte des travaux d'immobilisations en cours dans le tableau des comptes,
+You can also set default CWIP account in Company {},Vous pouvez également définir le compte CWIP par défaut dans Entreprise {},
+The Request for Quotation can be accessed by clicking on the following button,La demande de devis est accessible en cliquant sur le bouton suivant,
+Regards,Cordialement,
+Please click on the following button to set your new password,Veuillez cliquer sur le bouton suivant pour définir votre nouveau mot de passe,
+Update Password,Mettre à jour le mot de passe,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Ligne n ° {}: le taux de vente de l'article {} est inférieur à son {}. La vente {} doit être au moins {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Vous pouvez également désactiver la validation du prix de vente dans {} pour contourner cette validation.,
+Invalid Selling Price,Prix de vente invalide,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,L'adresse doit être liée à une entreprise. Veuillez ajouter une ligne pour Entreprise dans le tableau Liens.,
+Company Not Linked,Entreprise non liée,
+Import Chart of Accounts from CSV / Excel files,Importer un plan comptable à partir de fichiers CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',La quantité terminée ne peut pas être supérieure à la `` quantité à fabriquer '',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Ligne {0}: pour le fournisseur {1}, l'adresse e-mail est obligatoire pour envoyer un e-mail",
+"If enabled, the system will post accounting entries for inventory automatically","Si activé, le système enregistrera automatiquement les écritures comptables pour l'inventaire",
+Accounts Frozen Till Date,Comptes gelés jusqu'à la date,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Les écritures comptables sont gelées jusqu'à cette date. Personne ne peut créer ou modifier des entrées sauf les utilisateurs avec le rôle spécifié ci-dessous,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Rôle autorisé à définir des comptes gelés et à modifier les entrées gelées,
+Address used to determine Tax Category in transactions,Adresse utilisée pour déterminer la catégorie de taxe dans les transactions,
+"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 ","Le pourcentage que vous êtes autorisé à facturer davantage par rapport au montant commandé. Par exemple, si la valeur de la commande est de 100 USD pour un article et que la tolérance est définie sur 10%, vous êtes autorisé à facturer jusqu'à 110 USD.",
+This role is allowed to submit transactions that exceed credit limits,Ce rôle est autorisé à soumettre des transactions qui dépassent les limites de crédit,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Si «Mois» est sélectionné, un montant fixe sera comptabilisé en tant que revenus ou dépenses différés pour chaque mois, quel que soit le nombre de jours dans un mois. Il sera calculé au prorata si les revenus ou les dépenses différés ne sont pas comptabilisés pour un mois entier",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Si cette case n'est pas cochée, des entrées GL directes seront créées pour enregistrer les revenus ou les dépenses différés",
+Show Inclusive Tax in Print,Afficher la taxe incluse en version imprimée,
+Only select this if you have set up the Cash Flow Mapper documents,Sélectionnez ceci uniquement si vous avez configuré les documents Cash Flow Mapper,
+Payment Channel,Canal de paiement,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Un bon de commande est-il requis pour la création de factures d'achat et de reçus?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Un reçu d'achat est-il requis pour la création d'une facture d'achat?,
+Maintain Same Rate Throughout the Purchase Cycle,Maintenir le même taux tout au long du cycle d'achat,
+Allow Item To Be Added Multiple Times in a Transaction,Autoriser l'ajout d'un article plusieurs fois dans une transaction,
+Suppliers,Fournisseurs,
+Send Emails to Suppliers,Envoyer des e-mails aux fournisseurs,
+Select a Supplier,Sélectionnez un fournisseur,
+Cannot mark attendance for future dates.,Impossible de marquer la participation pour les dates futures.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Voulez-vous mettre à jour la participation?<br> Présent: {0}<br> Absent: {1},
+Mpesa Settings,Paramètres Mpesa,
+Initiator Name,Nom de l'initiateur,
+Till Number,Numéro de caisse,
+Sandbox,bac à sable,
+ Online PassKey,PassKey en ligne,
+Security Credential,Identifiant de sécurité,
+Get Account Balance,Obtenir le solde du compte,
+Please set the initiator name and the security credential,Veuillez définir le nom de l'initiateur et les informations d'identification de sécurité,
+Inpatient Medication Entry,Entrée de médicaments pour patients hospitalisés,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Code de l'article (médicament),
+Medication Orders,Ordonnances de médicaments,
+Get Pending Medication Orders,Obtenir des commandes de médicaments en attente,
+Inpatient Medication Orders,Ordonnances de médicaments pour patients hospitalisés,
+Medication Warehouse,Entrepôt de médicaments,
+Warehouse from where medication stock should be consumed,Entrepôt à partir duquel le stock de médicaments doit être consommé,
+Fetching Pending Medication Orders,Récupération des commandes de médicaments en attente,
+Inpatient Medication Entry Detail,Détail de l'entrée des médicaments pour patients hospitalisés,
+Medication Details,Détails du médicament,
+Drug Code,Code de la drogue,
+Drug Name,Nom du médicament,
+Against Inpatient Medication Order,Contre la prescription de médicaments pour patients hospitalisés,
+Against Inpatient Medication Order Entry,Contre la saisie des commandes de médicaments en milieu hospitalier,
+Inpatient Medication Order,Ordonnance de médicaments pour patients hospitalisés,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Total des commandes,
+Completed Orders,Commandes terminées,
+Add Medication Orders,Ajouter des commandes de médicaments,
+Adding Order Entries,Ajouter des entrées de commande,
+{0} medication orders completed,{0} commandes de médicaments terminées,
+{0} medication order completed,{0} commande de médicaments terminée,
+Inpatient Medication Order Entry,Saisie des commandes de médicaments pour patients hospitalisés,
+Is Order Completed,La commande est-elle terminée,
+Employee Records to Be Created By,Dossiers d'employés à créer par,
+Employee records are created using the selected field,Les enregistrements d'employés sont créés à l'aide du champ sélectionné,
+Don't send employee birthday reminders,N'envoyez pas de rappels d'anniversaire aux employés,
+Restrict Backdated Leave Applications,Restreindre les demandes de congé antidatées,
+Sequence ID,ID de séquence,
+Sequence Id,Id de séquence,
+Allow multiple material consumptions against a Work Order,Autoriser plusieurs consommations de matériaux par rapport à un ordre de travail,
+Plan time logs outside Workstation working hours,Planifier les journaux de temps en dehors des heures de travail du poste de travail,
+Plan operations X days in advance,Planifier les opérations X jours à l'avance,
+Time Between Operations (Mins),Temps entre les opérations (minutes),
+Default: 10 mins,Par défaut: 10 minutes,
+Overproduction for Sales and Work Order,Surproduction pour les ventes et les bons de travail,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Mettre à jour automatiquement le coût de la nomenclature via le planificateur, en fonction du dernier taux de valorisation / tarif tarifaire / dernier taux d'achat de matières premières",
+Purchase Order already created for all Sales Order items,Bon de commande déjà créé pour tous les articles de commande client,
+Select Items,Sélectionner des éléments,
+Against Default Supplier,Contre le fournisseur par défaut,
+Auto close Opportunity after the no. of days mentioned above,Opportunité de fermeture automatique après le non. de jours mentionnés ci-dessus,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Une commande client est-elle requise pour la création de factures clients et de bons de livraison?,
+Is Delivery Note Required for Sales Invoice Creation?,Un bon de livraison est-il nécessaire pour la création de factures de vente?,
+How often should Project and Company be updated based on Sales Transactions?,À quelle fréquence le projet et l'entreprise doivent-ils être mis à jour en fonction des transactions de vente?,
+Allow User to Edit Price List Rate in Transactions,Autoriser l'utilisateur à modifier le tarif tarifaire dans les transactions,
+Allow Item to Be Added Multiple Times in a Transaction,Autoriser l'ajout d'un article plusieurs fois dans une transaction,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Autoriser plusieurs commandes client par rapport à la commande d'achat d'un client,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Valider le prix de vente de l'article par rapport au taux d'achat ou au taux de valorisation,
+Hide Customer's Tax ID from Sales Transactions,Masquer le numéro d'identification fiscale du client dans les transactions de vente,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Le pourcentage que vous êtes autorisé à recevoir ou à livrer plus par rapport à la quantité commandée. Par exemple, si vous avez commandé 100 unités et que votre allocation est de 10%, vous êtes autorisé à recevoir 110 unités.",
+Action If Quality Inspection Is Not Submitted,Action si l'inspection de la qualité n'est pas soumise,
+Auto Insert Price List Rate If Missing,Taux de liste de prix d'insertion automatique s'il est manquant,
+Automatically Set Serial Nos Based on FIFO,Définir automatiquement les numéros de série en fonction de FIFO,
+Set Qty in Transactions Based on Serial No Input,Définir la quantité dans les transactions en fonction du numéro de série,
+Raise Material Request When Stock Reaches Re-order Level,Augmenter la demande d'article lorsque le stock atteint le niveau de commande,
+Notify by Email on Creation of Automatic Material Request,Notifier par e-mail lors de la création d'une demande de matériel automatique,
+Allow Material Transfer from Delivery Note to Sales Invoice,Autoriser le transfert d'articles du bon de livraison à la facture de vente,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Autoriser le transfert de matériel du reçu d'achat à la facture d'achat,
+Freeze Stocks Older Than (Days),Gel des stocks de plus de (jours),
+Role Allowed to Edit Frozen Stock,Rôle autorisé à modifier le stock gelé,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Le montant non alloué de l'écriture de paiement {0} est supérieur au montant non alloué de l'opération bancaire,
+Payment Received,Paiement reçu,
+Attendance cannot be marked outside of Academic Year {0},La participation ne peut pas être marquée en dehors de l'année académique {0},
+Student is already enrolled via Course Enrollment {0},L'élève est déjà inscrit via l'inscription au cours {0},
+Attendance cannot be marked for future dates.,La participation ne peut pas être marquée pour les dates futures.,
+Please add programs to enable admission application.,Veuillez ajouter des programmes pour permettre la demande d'admission.,
+The following employees are currently still reporting to {0}:,Les employés suivants relèvent toujours de {0}:,
+Please make sure the employees above report to another Active employee.,Veuillez vous assurer que les employés ci-dessus font rapport à un autre employé actif.,
+Cannot Relieve Employee,Ne peut pas soulager l'employé,
+Please enter {0},Veuillez saisir {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Veuillez sélectionner un autre mode de paiement. Mpesa ne prend pas en charge les transactions dans la devise "{0}",
+Transaction Error,Erreur de transaction,
+Mpesa Express Transaction Error,Erreur de transaction Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Problème détecté avec la configuration de Mpesa, consultez les journaux d'erreurs pour plus de détails",
+Mpesa Express Error,Erreur Mpesa Express,
+Account Balance Processing Error,Erreur de traitement du solde du compte,
+Please check your configuration and try again,Veuillez vérifier votre configuration et réessayer,
+Mpesa Account Balance Processing Error,Erreur de traitement du solde du compte Mpesa,
+Balance Details,Détails du solde,
+Current Balance,Solde actuel,
+Available Balance,Solde disponible,
+Reserved Balance,Solde réservé,
+Uncleared Balance,Solde non compensé,
+Payment related to {0} is not completed,Le paiement lié à {0} n'est pas terminé,
+Row #{}: Item Code: {} is not available under warehouse {}.,Ligne n ° {}: code article: {} n'est pas disponible dans l'entrepôt {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Ligne n ° {}: quantité en stock insuffisante pour le code article: {} sous l'entrepôt {}. Quantité disponible {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Ligne n ° {}: veuillez sélectionner un numéro de série et un lot pour l'article: {} ou supprimez-le pour terminer la transaction.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Ligne n ° {}: aucun numéro de série sélectionné pour l'article: {}. Veuillez en sélectionner un ou le supprimer pour terminer la transaction.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Ligne n ° {}: aucun lot sélectionné pour l'élément: {}. Veuillez sélectionner un lot ou le supprimer pour terminer la transaction.,
+Payment amount cannot be less than or equal to 0,Le montant du paiement ne peut pas être inférieur ou égal à 0,
+Please enter the phone number first,Veuillez d'abord saisir le numéro de téléphone,
+Row #{}: {} {} does not exist.,Ligne n ° {}: {} {} n'existe pas.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Ligne n ° {0}: {1} est requise pour créer les {2} factures d'ouverture,
+You had {} errors while creating opening invoices. Check {} for more details,Vous avez rencontré {} erreurs lors de la création des factures d'ouverture. Consultez {} pour plus de détails,
+Error Occured,Erreur est survenue,
+Opening Invoice Creation In Progress,Ouverture de la création de facture en cours,
+Creating {} out of {} {},Création de {} sur {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Numéro de série: {0}) ne peut pas être utilisé car il est réservé pour remplir la commande client {1}.,
+Item {0} {1},Élément {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,La dernière transaction de stock pour l'article {0} dans l'entrepôt {1} a eu lieu le {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Les transactions de stock pour l'article {0} dans l'entrepôt {1} ne peuvent pas être validées avant cette heure.,
+Posting future stock transactions are not allowed due to Immutable Ledger,La comptabilisation des futures transactions de stock n'est pas autorisée en raison du grand livre immuable,
+A BOM with name {0} already exists for item {1}.,Une nomenclature portant le nom {0} existe déjà pour l'article {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Avez-vous renommé l'élément? Veuillez contacter l'administrateur / le support technique,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},À la ligne n ° {0}: l'ID de séquence {1} ne peut pas être inférieur à l'ID de séquence de ligne précédent {2},
+The {0} ({1}) must be equal to {2} ({3}),Le {0} ({1}) doit être égal à {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, terminez l'opération {1} avant l'opération {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Impossible de garantir la livraison par numéro de série car l'article {0} est ajouté avec et sans Assurer la livraison par numéro de série,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,L'article {0} n'a pas de numéro de série. Seuls les articles sérialisés peuvent être livrés en fonction du numéro de série,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Aucune nomenclature active trouvée pour l'article {0}. La livraison par numéro de série ne peut pas être assurée,
+No pending medication orders found for selected criteria,Aucune commande de médicaments en attente trouvée pour les critères sélectionnés,
+From Date cannot be after the current date.,La date de début ne peut pas être postérieure à la date actuelle.,
+To Date cannot be after the current date.,La date ne peut pas être postérieure à la date actuelle.,
+From Time cannot be after the current time.,L'heure de départ ne peut pas être postérieure à l'heure actuelle.,
+To Time cannot be after the current time.,L'heure ne peut pas être postérieure à l'heure actuelle.,
+Stock Entry {0} created and ,Entrée de stock {0} créée et,
+Inpatient Medication Orders updated successfully,Les commandes de médicaments pour patients hospitalisés ont été mises à jour avec succès,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Ligne {0}: Impossible de créer une entrée de médicaments pour patients hospitalisés contre une commande de médicaments pour patients hospitalisés annulée {1},
+Row {0}: This Medication Order is already marked as completed,Ligne {0}: cette ordonnance de médicaments est déjà marquée comme terminée,
+Quantity not available for {0} in warehouse {1},Quantité non disponible pour {0} dans l'entrepôt {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Veuillez activer Autoriser le stock négatif dans les paramètres de stock ou créer une entrée de stock pour continuer.,
+No Inpatient Record found against patient {0},Aucun dossier d'hospitalisation trouvé pour le patient {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Une ordonnance de médicament pour patients hospitalisés {0} contre rencontre avec un patient {1} existe déjà.,
+Allow In Returns,Autoriser les retours,
+Hide Unavailable Items,Masquer les éléments non disponibles,
+Apply Discount on Discounted Rate,Appliquer une remise sur un tarif réduit,
+Therapy Plan Template,Modèle de plan de thérapie,
+Fetching Template Details,Récupération des détails du modèle,
+Linked Item Details,Détails de l'élément lié,
+Therapy Types,Types de thérapie,
+Therapy Plan Template Detail,Détail du modèle de plan de thérapie,
+Non Conformance,Non-conformité,
+Process Owner,Propriétaire du processus,
+Corrective Action,Action corrective,
+Preventive Action,Action préventive,
+Problem,Problème,
+Responsible,Responsable,
+Completion By,Achèvement par,
+Process Owner Full Name,Nom complet du propriétaire du processus,
+Right Index,Index droit,
+Left Index,Index gauche,
+Sub Procedure,Sous-procédure,
+Passed,Passé,
+Print Receipt,Imprimer le reçu,
+Edit Receipt,Modifier le reçu,
+Focus on search input,Focus sur l'entrée de recherche,
+Focus on Item Group filter,Focus sur le filtre de groupe d'articles,
+Checkout Order / Submit Order / New Order,Commander la commande / Soumettre la commande / Nouvelle commande,
+Add Order Discount,Ajouter une remise de commande,
+Item Code: {0} is not available under warehouse {1}.,Code d'article: {0} n'est pas disponible dans l'entrepôt {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Numéros de série non disponibles pour l'article {0} sous l'entrepôt {1}. Veuillez essayer de changer d’entrepôt.,
+Fetched only {0} available serial numbers.,Récupéré uniquement {0} numéros de série disponibles.,
+Switch Between Payment Modes,Basculer entre les modes de paiement,
+Enter {0} amount.,Saisissez le montant de {0}.,
+You don't have enough points to redeem.,Vous n'avez pas assez de points à échanger.,
+You can redeem upto {0}.,Vous pouvez utiliser jusqu'à {0}.,
+Enter amount to be redeemed.,Entrez le montant à utiliser.,
+You cannot redeem more than {0}.,Vous ne pouvez pas utiliser plus de {0}.,
+Open Form View,Ouvrir la vue formulaire,
+POS invoice {0} created succesfully,Facture PDV {0} créée avec succès,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Quantité en stock insuffisante pour le code article: {0} sous l'entrepôt {1}. Quantité disponible {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Numéro de série: {0} a déjà été traité sur une autre facture PDV.,
+Balance Serial No,Numéro de série de la balance,
+Warehouse: {0} does not belong to {1},Entrepôt: {0} n'appartient pas à {1},
+Please select batches for batched item {0},Veuillez sélectionner des lots pour l'article en lots {0},
+Please select quantity on row {0},Veuillez sélectionner la quantité sur la ligne {0},
+Please enter serial numbers for serialized item {0},Veuillez saisir les numéros de série de l'article sérialisé {0},
+Batch {0} already selected.,Lot {0} déjà sélectionné.,
+Please select a warehouse to get available quantities,Veuillez sélectionner un entrepôt pour obtenir les quantités disponibles,
+"For transfer from source, selected quantity cannot be greater than available quantity","Pour le transfert depuis la source, la quantité sélectionnée ne peut pas être supérieure à la quantité disponible",
+Cannot find Item with this Barcode,Impossible de trouver l'article avec ce code-barres,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} est obligatoire. L'enregistrement de change de devises n'est peut-être pas créé pour le {1} au {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} a soumis des éléments qui lui sont associés. Vous devez annuler les actifs pour créer un retour d'achat.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Impossible d'annuler ce document car il est associé à l'élément soumis {0}. Veuillez l'annuler pour continuer.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ligne n ° {}: le numéro de série {} a déjà été transposé sur une autre facture PDV. Veuillez sélectionner un numéro de série valide.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ligne n ° {}: les numéros de série {} ont déjà été traités sur une autre facture PDV. Veuillez sélectionner un numéro de série valide.,
+Item Unavailable,Article non disponible,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Ligne n ° {}: le numéro de série {} ne peut pas être renvoyé car il n'a pas été traité dans la facture d'origine {},
+Please set default Cash or Bank account in Mode of Payment {},Veuillez définir le compte de trésorerie ou bancaire par défaut dans le mode de paiement {},
+Please set default Cash or Bank account in Mode of Payments {},Veuillez définir le compte par défaut en espèces ou en banque dans Mode de paiement {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Veuillez vous assurer que {} compte est un compte de bilan. Vous pouvez changer le compte parent en compte de bilan ou sélectionner un autre compte.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Veuillez vous assurer que {} compte est un compte Payable. Modifiez le type de compte sur Payable ou sélectionnez un autre compte.,
+Row {}: Expense Head changed to {} ,Ligne {}: le paramètre Expense Head a été remplacé par {},
+because account {} is not linked to warehouse {} ,car le compte {} n'est pas associé à l'entrepôt {},
+or it is not the default inventory account,ou ce n'est pas le compte d'inventaire par défaut,
+Expense Head Changed,Tête de dépense modifiée,
+because expense is booked against this account in Purchase Receipt {},car les dépenses sont imputées à ce compte dans le reçu d'achat {},
+as no Purchase Receipt is created against Item {}. ,car aucun reçu d'achat n'est créé pour l'article {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Ceci est fait pour gérer la comptabilité des cas où le reçu d'achat est créé après la facture d'achat,
+Purchase Order Required for item {},Bon de commande requis pour l'article {},
+To submit the invoice without purchase order please set {} ,"Pour soumettre la facture sans bon de commande, veuillez définir {}",
+as {} in {},un péché {},
+Mandatory Purchase Order,Bon de commande obligatoire,
+Purchase Receipt Required for item {},Reçu d'achat requis pour l'article {},
+To submit the invoice without purchase receipt please set {} ,"Pour soumettre la facture sans reçu d'achat, veuillez définir {}",
+Mandatory Purchase Receipt,Reçu d'achat obligatoire,
+POS Profile {} does not belongs to company {},Le profil PDV {} n'appartient pas à l'entreprise {},
+User {} is disabled. Please select valid user/cashier,L'utilisateur {} est désactivé. Veuillez sélectionner un utilisateur / caissier valide,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Ligne n ° {}: la facture originale {} de la facture de retour {} est {}.,
+Original invoice should be consolidated before or along with the return invoice.,La facture originale doit être consolidée avant ou avec la facture de retour.,
+You can add original invoice {} manually to proceed.,Vous pouvez ajouter la facture originale {} manuellement pour continuer.,
+Please ensure {} account is a Balance Sheet account. ,Veuillez vous assurer que {} compte est un compte de bilan.,
+You can change the parent account to a Balance Sheet account or select a different account.,Vous pouvez changer le compte parent en compte de bilan ou sélectionner un autre compte.,
+Please ensure {} account is a Receivable account. ,Veuillez vous assurer que {} compte est un compte recevable.,
+Change the account type to Receivable or select a different account.,Changez le type de compte en recevable ou sélectionnez un autre compte.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} ne peut pas être annulé car les points de fidélité gagnés ont été utilisés. Annulez d'abord le {} Non {},
+already exists,existe déjà,
+POS Closing Entry {} against {} between selected period,Entrée de clôture du PDV {} contre {} entre la période sélectionnée,
+POS Invoice is {},La facture PDV est {},
+POS Profile doesn't matches {},Le profil de point de vente ne correspond pas à {},
+POS Invoice is not {},La facture PDV n'est pas {},
+POS Invoice isn't created by user {},La facture PDV n'est pas créée par l'utilisateur {},
+Row #{}: {},Rangée #{}: {},
+Invalid POS Invoices,Factures PDV non valides,
+Please add the account to root level Company - {},Veuillez ajouter le compte à la société au niveau racine - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Lors de la création du compte pour l'entreprise enfant {0}, le compte parent {1} est introuvable. Veuillez créer le compte parent dans le COA correspondant",
+Account Not Found,Compte non trouvé,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Lors de la création du compte pour l'entreprise enfant {0}, le compte parent {1} a été trouvé en tant que compte du grand livre.",
+Please convert the parent account in corresponding child company to a group account.,Veuillez convertir le compte parent de l'entreprise enfant correspondante en compte de groupe.,
+Invalid Parent Account,Compte parent non valide,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Le renommer n'est autorisé que via la société mère {0}, pour éviter les incompatibilités.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Si vous {0} {1} quantités de l'article {2}, le schéma {3} sera appliqué à l'article.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Si vous {0} {1} valez un article {2}, le schéma {3} sera appliqué à l'article.",
+"As the field {0} is enabled, the field {1} is mandatory.","Comme le champ {0} est activé, le champ {1} est obligatoire.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Lorsque le champ {0} est activé, la valeur du champ {1} doit être supérieure à 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Impossible de livrer le numéro de série {0} de l'article {1} car il est réservé pour remplir la commande client {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","La commande client {0} a une réservation pour l'article {1}, vous ne pouvez livrer que réservée {1} contre {0}.",
+{0} Serial No {1} cannot be delivered,Le {0} numéro de série {1} ne peut pas être livré,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Ligne {0}: l'article sous-traité est obligatoire pour la matière première {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Comme il y a suffisamment de matières premières, la demande de matériel n'est pas requise pour l'entrepôt {0}.",
+" If you still want to proceed, please enable {0}.","Si vous souhaitez continuer, veuillez activer {0}.",
+The item referenced by {0} - {1} is already invoiced,L'article référencé par {0} - {1} est déjà facturé,
+Therapy Session overlaps with {0},La session de thérapie chevauche {0},
+Therapy Sessions Overlapping,Chevauchement des séances de thérapie,
+Therapy Plans,Plans de thérapie,
+"Item Code, warehouse, quantity are required on row {0}","Le code article, l'entrepôt et la quantité sont obligatoires sur la ligne {0}",
+Get Items from Material Requests against this Supplier,Obtenir des articles à partir de demandes d'articles auprès de ce fournisseur,
+Enable European Access,Activer l'accès européen,
+Creating Purchase Order ...,Création d'une commande d'achat ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Sélectionnez un fournisseur parmi les fournisseurs par défaut des articles ci-dessous. Lors de la sélection, un bon de commande sera effectué contre des articles appartenant uniquement au fournisseur sélectionné.",
+Row #{}: You must select {} serial numbers for item {}.,Ligne n ° {}: vous devez sélectionner {} numéros de série pour l'article {}.,
diff --git a/erpnext/translations/fr_ca.csv b/erpnext/translations/fr_ca.csv
index 3c4e05e..8a618b3 100644
--- a/erpnext/translations/fr_ca.csv
+++ b/erpnext/translations/fr_ca.csv
@@ -10,4 +10,3 @@
{0} {1}: Supplier is required against Payable account {2},{0} {1}: Fournisseur est requis envers un compte à payer {2},
Difference (Dr - Cr),Différence (Dt - Ct ),
Price List Rate (Company Currency),Taux de la Liste de Prix (Devise de la Compagnie),
-Auto insert Price List rate if missing,Insertion automatique du taux à la Liste de Prix si manquant,
diff --git a/erpnext/translations/gu.csv b/erpnext/translations/gu.csv
index 452935a..5c2b520 100644
--- a/erpnext/translations/gu.csv
+++ b/erpnext/translations/gu.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},વાસ્તવિક પ્રકાર કર પંક્તિ માં આઇટમ રેટ સમાવેશ કરવામાં નથી કરી શકો છો {0},
Add,ઉમેરો,
Add / Edit Prices,/ સંપાદિત કરો ભાવમાં ઉમેરો,
-Add All Suppliers,બધા સપ્લાયર્સ ઉમેરો,
Add Comment,ટિપ્પણી ઉમેરો,
Add Customers,ગ્રાહકો ઉમેરો,
Add Employees,કર્મચારીઓની ઉમેરો,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',કપાત કરી શકો છો જ્યારે શ્રેણી 'વેલ્યુએશન' અથવા 'Vaulation અને કુલ' માટે છે,
"Cannot delete Serial No {0}, as it is used in stock transactions","કાઢી શકતા નથી સીરીયલ કોઈ {0}, તે સ્ટોક વ્યવહારો તરીકે ઉપયોગ થાય છે",
Cannot enroll more than {0} students for this student group.,{0} આ વિદ્યાર્થી જૂથ માટે વિદ્યાર્થીઓ કરતાં વધુ નોંધણી કરી શકતા નથી.,
-Cannot find Item with this barcode,આ બારકોડથી આઇટમ શોધી શકાતી નથી,
Cannot find active Leave Period,સક્રિય રજા અવધિ શોધી શકાતો નથી,
Cannot produce more Item {0} than Sales Order quantity {1},સેલ્સ ક્રમ સાથે જથ્થો કરતાં વધુ આઇટમ {0} પેદા કરી શકતા નથી {1},
Cannot promote Employee with status Left,કર્મચારીને દરજ્જા સાથે બઢતી ન આપી શકે,
Cannot refer row number greater than or equal to current row number for this Charge type,આ ચાર્જ પ્રકાર માટે વર્તમાન પંક્તિ નંબર એક કરતાં વધારે અથવા સમાન પંક્તિ નંબર નો સંદર્ભ લો નથી કરી શકો છો,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,પ્રથમ પંક્તિ માટે 'અગાઉના પંક્તિ કુલ પર' 'અગાઉના પંક્તિ રકમ પર' તરીકે ચાર્જ પ્રકાર પસંદ કરો અથવા નથી કરી શકો છો,
-Cannot set a received RFQ to No Quote,કોઈ ક્વોટ માટે પ્રાપ્ત કરેલ આરએફક્યુને સેટ કરી શકતા નથી,
Cannot set as Lost as Sales Order is made.,વેચાણ ઓર્ડર કરવામાં આવે છે ગુમાવી સેટ કરી શકાતો નથી.,
Cannot set authorization on basis of Discount for {0},માટે ડિસ્કાઉન્ટ આધારે અધિકૃતિ સેટ કરી શકાતો નથી {0},
Cannot set multiple Item Defaults for a company.,કોઈ કંપની માટે બહુવિધ આઇટમ ડિફોલ્ટ્સ સેટ કરી શકતા નથી.,
@@ -521,7 +518,6 @@
Chargeble,ચાર્જબલ,
Charges are updated in Purchase Receipt against each item,સમાયોજિત દરેક વસ્તુ સામે ખરીદી રસીદ અપડેટ કરવામાં આવે છે,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","સમાયોજિત પ્રમાણમાં તમારી પસંદગી મુજબ, વસ્તુ Qty અથવા રકમ પર આધારિત વિતરણ કરવામાં આવશે",
-Chart Of Accounts,એકાઉન્ટ્સ ઓફ ચાર્ટ,
Chart of Cost Centers,કિંમત કેન્દ્રો ચાર્ટ,
Check all,બધા તપાસો,
Checkout,ચેકઆઉટ,
@@ -581,7 +577,6 @@
Compensatory Off,વળતર બંધ,
Compensatory leave request days not in valid holidays,માન્ય રજાઓના દિવસોમાં વળતરની રજાની વિનંતીઓ,
Complaint,ફરિયાદ,
-Completed Qty can not be greater than 'Qty to Manufacture',કરતાં 'Qty ઉત્પાદન' પૂર્ણ Qty વધારે ન હોઈ શકે,
Completion Date,પૂર્ણાહુતિ તારીખ્,
Computer,કમ્પ્યુટર,
Condition,કન્ડિશન,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","બનાવો અને દૈનિક, સાપ્તાહિક અને માસિક ઇમેઇલ પચાવી મેનેજ કરો.",
Create customer quotes,ગ્રાહક અવતરણ બનાવો,
Create rules to restrict transactions based on values.,મૂલ્યો પર આધારિત વ્યવહારો પ્રતિબંધિત કરવા માટે નિયમો બનાવો.,
-Created By,દ્વારા બનાવવામાં,
Created {0} scorecards for {1} between: ,{1} માટે {0} સ્કોરકાર્ડ્સ વચ્ચે બનાવ્યાં:,
Creating Company and Importing Chart of Accounts,કંપની બનાવવી અને એકાઉન્ટ્સનો આયાત કરવો,
Creating Fees,ફી બનાવવી,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,ટ્રાન્સફર તારીખ પહેલાં કર્મચારીનું ટ્રાન્સફર સબમિટ કરી શકાતું નથી,
Employee cannot report to himself.,કર્મચારીનું પોતાની જાતને જાણ કરી શકો છો.,
Employee relieved on {0} must be set as 'Left',{0} સુયોજિત થયેલ હોવું જ જોઈએ પર રાહત કર્મચારી 'ડાબી' તરીકે,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,કર્મચારીની સ્થિતિ 'ડાબે' પર સેટ કરી શકાતી નથી કારણ કે નીચેના કર્મચારીઓ હાલમાં આ કર્મચારીને રિપોર્ટ કરે છે:,
Employee {0} already submited an apllication {1} for the payroll period {2},કર્મચારી {0} પહેલેથી પગારપત્રક સમયગાળા {2} માટે એક એપ્લિકેશન {1} સબમિટ કરે છે,
Employee {0} has already applied for {1} between {2} and {3} : ,{2} અને {3} વચ્ચે {1} માટે કર્મચારી {0} પહેલેથી જ લાગુ છે:,
Employee {0} has no maximum benefit amount,કર્મચારી {0} પાસે મહત્તમ સહાયક રકમ નથી,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,{0} પંક્તિ માટે: નિયુક્ત કરેલું કક્ષ દાખલ કરો,
"For {0}, only credit accounts can be linked against another debit entry","{0}, માત્ર ક્રેડિટ ખાતાઓ અન્ય ડેબિટ પ્રવેશ સામે લિંક કરી શકો છો",
"For {0}, only debit accounts can be linked against another credit entry","{0}, માત્ર ડેબિટ એકાઉન્ટ્સ બીજા ક્રેડિટ પ્રવેશ સામે લિંક કરી શકો છો",
-Form View,ફોર્મ જુઓ,
Forum Activity,ફોરમ પ્રવૃત્તિ,
Free item code is not selected,મફત આઇટમ કોડ પસંદ થયેલ નથી,
Freight and Forwarding Charges,નૂર અને ફોરવર્ડિંગ સમાયોજિત,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","પહેલાં ફાળવવામાં કરી શકાતી નથી મૂકો {0}, રજા બેલેન્સ પહેલેથી કેરી આગળ ભવિષ્યમાં રજા ફાળવણી રેકોર્ડ કરવામાં આવી છે {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","રજા બેલેન્સ પહેલેથી કેરી આગળ ભવિષ્યમાં રજા ફાળવણી રેકોર્ડ કરવામાં આવી છે, પહેલાં {0} રદ / લાગુ કરી શકાય નહીં છોડો {1}",
Leave of type {0} cannot be longer than {1},પ્રકાર રજા {0} કરતાં લાંબા સમય સુધી ન હોઈ શકે {1},
-Leave the field empty to make purchase orders for all suppliers,બધા સપ્લાયર્સ માટે ખરીદી ઓર્ડર કરવા માટે ક્ષેત્ર ખાલી છોડો,
Leaves,પાંદડા,
Leaves Allocated Successfully for {0},માટે સફળતાપૂર્વક સોંપાયેલ પાંદડાઓ {0},
Leaves has been granted sucessfully,પાંદડા સફળતાપૂર્વક આપવામાં આવી છે,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,માલ બિલ સાથે કોઈ વસ્તુઓ ઉત્પાદન,
No Items with Bill of Materials.,બીલ Materialફ મટિરિયલ્સવાળી કોઈ આઇટમ્સ નથી.,
No Permission,પરવાનગી નથી,
-No Quote,કોઈ ક્વોટ નથી,
No Remarks,કોઈ ટિપ્પણી,
No Result to submit,સબમિટ કરવાના કોઈ પરિણામો નથી,
No Salary Structure assigned for Employee {0} on given date {1},આપેલ તારીખ {1} પર કર્મચારી {0} માટે કોઈ પગાર માળખું નથી.,
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,વચ્ચે ઑવરલેપ શરતો:,
Owner,માલિક,
PAN,PAN,
-PO already created for all sales order items,PO બધા વેચાણની ઓર્ડર વસ્તુઓ માટે બનાવેલ છે,
POS,POS,
POS Profile,POS પ્રોફાઇલ,
POS Profile is required to use Point-of-Sale,પીઓસ પ્રોફાઇલને પોઈન્ટ ઓફ સેલનો ઉપયોગ કરવો જરૂરી છે,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,પ્રથમ ચાર્જ પ્રકાર પસંદ કરો,
Please select Company,કંપની પસંદ કરો,
Please select Company and Designation,કંપની અને હોદ્દો પસંદ કરો,
-Please select Company and Party Type first,પ્રથમ કંપની અને પાર્ટી પ્રકાર પસંદ કરો,
Please select Company and Posting Date to getting entries,પ્રવેશ મેળવવા માટેની કંપની અને પોસ્ટિંગ તારીખ પસંદ કરો,
Please select Company first,પ્રથમ કંપની પસંદ કરો,
Please select Completion Date for Completed Asset Maintenance Log,પૂર્ણ સંપત્તિ જાળવણી પ્રવેશ માટે સમાપ્તિ તારીખ પસંદ કરો,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,રો {0}: UOM રૂપાંતર ફેક્ટર ફરજિયાત છે,
Row {0}: select the workstation against the operation {1},રો {0}: ઓપરેશન સામે વર્કસ્ટેશન પસંદ કરો {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,પંક્તિ {0}: {1} વસ્તુ {2} માટે આવશ્યક ક્રમાંક ક્રમાંક. તમે {3} પ્રદાન કરેલ છે,
-Row {0}: {1} is required to create the Opening {2} Invoices,પંક્તિ {0}: {1} ઓપનિંગ {2} ઇનવોઇસ બનાવવા માટે આવશ્યક છે,
Row {0}: {1} must be greater than 0,પંક્તિ {0}: {1} 0 કરતાં મોટી હોવી જોઈએ,
Row {0}: {1} {2} does not match with {3},રો {0}: {1} {2} સાથે મેળ ખાતું નથી {3},
Row {0}:Start Date must be before End Date,રો {0}: પ્રારંભ તારીખ સમાપ્તિ તારીખ પહેલાં જ હોવી જોઈએ,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,ગ્રાન્ટ સમીક્ષા ઇમેઇલ મોકલો,
Send Now,હવે મોકલો,
Send SMS,એસએમએસ મોકલો,
-Send Supplier Emails,પુરવઠોકર્તા ઇમેઇલ્સ મોકલો,
Send mass SMS to your contacts,સામૂહિક એસએમએસ તમારા સંપર્કો મોકલો,
Sensitivity,સંવેદનશીલતા,
Sent,મોકલ્યું,
-Serial #,સીરીયલ #,
Serial No and Batch,સીરીયલ કોઈ અને બેચ,
Serial No is mandatory for Item {0},સીરીયલ કોઈ વસ્તુ માટે ફરજિયાત છે {0},
Serial No {0} does not belong to Batch {1},સીરિયલ કોઈ {0} બેચની નથી {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,તમારી કંપનીના નામ કે જેના માટે તમે આ સિસ્ટમ સુયોજિત કરી રહ્યા હોય.,
The number of shares and the share numbers are inconsistent,શેર્સની સંખ્યા અને શેરની સંખ્યા અસંગત છે,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,પ્લાન {0} માં ચુકવણી ગેટવે એકાઉન્ટ ચુકવણીની વિનંતીમાં ચુકવણી ગેટવે એકાઉન્ટથી અલગ છે,
-The request for quotation can be accessed by clicking on the following link,અવતરણ માટે વિનંતી નીચેની લિંક પર ક્લિક કરીને વાપરી શકાય છે,
The selected BOMs are not for the same item,પસંદ BOMs જ વસ્તુ માટે નથી,
The selected item cannot have Batch,પસંદ કરેલ વસ્તુ બેચ હોઈ શકે નહિં,
The seller and the buyer cannot be the same,વેચનાર અને ખરીદનાર તે જ ન હોઈ શકે,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},કુલ ફ્લેક્સિબલ લાભ ઘટક રકમ {0} મહત્તમ લાભ કરતાં ઓછી હોવી જોઈએ નહીં {1},
Total hours: {0},કુલ સમય: {0},
Total leaves allocated is mandatory for Leave Type {0},રવાના પ્રકાર {0} માટે ફાળવેલ કુલ પાંદડા ફરજિયાત છે,
-Total weightage assigned should be 100%. It is {0},100% પ્રયત્ન કરીશું સોંપાયેલ કુલ વેઇટેજ. તે {0},
Total working hours should not be greater than max working hours {0},કુલ કામના કલાકો મેક્સ કામના કલાકો કરતાં વધારે ન હોવી જોઈએ {0},
Total {0} ({1}),કુલ {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","કુલ {0} બધી વસ્તુઓ માટે શૂન્ય છે, તો તમે 'પર આધારિત ચાર્જિસ વિતરિત' બદલવા જોઈએ કરી શકે",
@@ -3316,7 +3299,6 @@
What do you need help with?,શું તમે સાથે મદદ જરૂર છે?,
What does it do?,તે શું કરે છે?,
Where manufacturing operations are carried.,ઉત્પાદન કામગીરી જ્યાં ધરવામાં આવે છે.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","બાળ કંપની {0} માટે એકાઉન્ટ બનાવતી વખતે, પિતૃ એકાઉન્ટ {1} મળ્યું નથી. કૃપા કરીને સંબંધિત COA માં પેરેંટ એકાઉન્ટ બનાવો",
White,વ્હાઇટ,
Wire Transfer,વાયર ટ્રાન્સફર,
WooCommerce Products,WooCommerce ઉત્પાદનો,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} ચલો બનાવ્યાં છે,
{0} {1} created,{0} {1} બનાવવામાં,
{0} {1} does not exist,{0} {1} અસ્તિત્વમાં નથી,
-{0} {1} does not exist.,{0} {1} અસ્તિત્વમાં નથી.,
{0} {1} has been modified. Please refresh.,{0} {1} સુધારાઈ ગયેલ છે. તાજું કરો.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} સબમિટ કરવામાં આવી નથી જેથી ક્રિયા પૂર્ણ કરી શકાતી નથી,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} {2} સાથે સંકળાયેલ છે, પરંતુ પાર્ટી એકાઉન્ટ {3} છે",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} નથી અસ્તિત્વમાં,
{0}: {1} not found in Invoice Details table,{0}: {1} ભરતિયું વિગતો ટેબલ મળી નથી,
{} of {},{{ના {,
+Assigned To,સોંપેલ,
Chat,ચેટ,
Completed By,દ્વારા પૂર્ણ,
Conditions,શરતો,
@@ -3506,7 +3488,9 @@
Merge with existing,વર્તમાન સાથે મર્જ,
Office,ઓફિસ,
Orientation,ઓરિએન્ટેશન,
+Parent,પિતૃ,
Passive,નિષ્ક્રીય,
+Payment Failed,ચુકવણી કરવામાં નિષ્ફળ,
Percent,ટકા,
Permanent,કાયમી,
Personal,વ્યક્તિગત,
@@ -3544,7 +3528,6 @@
Company field is required,કંપની ક્ષેત્ર આવશ્યક છે,
Creating Dimensions...,પરિમાણો બનાવી રહ્યાં છે ...,
Duplicate entry against the item code {0} and manufacturer {1},આઇટમ કોડ {0} અને ઉત્પાદક {1} વિરુદ્ધ ડુપ્લિકેટ એન્ટ્રી,
-Import Chart Of Accounts from CSV / Excel files,સીએસવી / એક્સેલ ફાઇલોથી એકાઉન્ટ્સનો ચાર્ટ આયાત કરો,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,અમાન્ય જીએસટીઆઈએન! તમે દાખલ કરેલ ઇનપુટ યુઆઈએન ધારકો અથવા બિન-નિવાસી OIDAR સેવા પ્રદાતાઓ માટેના GSTIN ફોર્મેટ સાથે મેળ ખાતું નથી,
Invoice Grand Total,ભરતિયું ગ્રાન્ડ કુલ,
Last carbon check date cannot be a future date,છેલ્લી કાર્બન ચેક તારીખ ભવિષ્યની તારીખ હોઈ શકતી નથી,
@@ -3556,6 +3539,7 @@
Show {0},બતાવો {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" અને "}" સિવાયના વિશેષ અક્ષરો નામકરણ શ્રેણીમાં મંજૂરી નથી",
Target Details,લક્ષ્યાંક વિગતો,
+{0} already has a Parent Procedure {1}.,{0} પાસે પહેલેથી જ પિતૃ કાર્યવાહી છે {1}.,
API,API,
Annual,વાર્ષિક,
Approved,મંજૂર,
@@ -3572,6 +3556,8 @@
No data to export,નિકાસ કરવા માટે કોઈ ડેટા નથી,
Portrait,પોટ્રેટ,
Print Heading,પ્રિંટ મથાળું,
+Scheduler Inactive,સુનિશ્ચિત નિષ્ક્રિય,
+Scheduler is inactive. Cannot import data.,શેડ્યૂલર નિષ્ક્રિય છે. ડેટા આયાત કરી શકાતો નથી.,
Show Document,દસ્તાવેજ બતાવો,
Show Traceback,ટ્રેસબેક બતાવો,
Video,વિડિઓ,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},આઇટમ Quality 0 Quality માટે ગુણવત્તા નિરીક્ષણ બનાવો.,
Creating Accounts...,એકાઉન્ટ્સ બનાવી રહ્યાં છે ...,
Creating bank entries...,બેંક પ્રવેશો બનાવી રહ્યાં છે ...,
-Creating {0},{0} બનાવી રહ્યા છે,
Credit limit is already defined for the Company {0},ક્રેડિટ મર્યાદા પહેલાથી જ કંપની defined 0 for માટે નિર્ધારિત છે,
Ctrl + Enter to submit,સબમિટ કરવા માટે Ctrl + Enter,
Ctrl+Enter to submit,સબમિટ કરવા માટે Ctrl + Enter,
@@ -3921,7 +3906,6 @@
Plaid public token error,પ્લેડ સાર્વજનિક ટોકન ભૂલ,
Plaid transactions sync error,પ્લેઇડ ટ્રાન્ઝેક્શન સમન્વયન ભૂલ,
Please check the error log for details about the import errors,કૃપા કરીને આયાત ભૂલો વિશેની વિગતો માટે ભૂલ લોગને તપાસો,
-Please click on the following link to set your new password,તમારો નવો પાસવર્ડ સુયોજિત કરવા માટે નીચેની લિંક પર ક્લિક કરો,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,કૃપા કરીને કંપની <b>{</b> <b>for</b> માટે <b>DATEV સેટિંગ્સ</b> બનાવો.,
Please create adjustment Journal Entry for amount {0} ,કૃપા કરી રકમ for 0 for માટે એડજસ્ટમેન્ટ જર્નલ એન્ટ્રી બનાવો,
Please do not create more than 500 items at a time,કૃપા કરીને એક સમયે 500 થી વધુ વસ્તુઓ બનાવશો નહીં,
@@ -3997,6 +3981,7 @@
Release date must be in the future,પ્રકાશન તારીખ ભવિષ્યમાં હોવી આવશ્યક છે,
Relieving Date must be greater than or equal to Date of Joining,રાહત આપવાની તારીખ જોડાવાની તારીખથી મોટી અથવા તેના જેટલી હોવી જોઈએ,
Rename,નામ બદલો,
+Rename Not Allowed,નામ બદલી મંજૂરી નથી,
Repayment Method is mandatory for term loans,ટર્મ લોન માટે ચુકવણીની પદ્ધતિ ફરજિયાત છે,
Repayment Start Date is mandatory for term loans,ટર્મ લોન માટે ચુકવણીની શરૂઆત તારીખ ફરજિયાત છે,
Report Item,રિપોર્ટ આઇટમ,
@@ -4043,7 +4028,6 @@
Select All,બધા પસંદ કરો,
Select Difference Account,ડિફરન્સ એકાઉન્ટ પસંદ કરો,
Select a Default Priority.,ડિફોલ્ટ પ્રાધાન્યતા પસંદ કરો.,
-Select a Supplier from the Default Supplier List of the items below.,નીચેની આઇટમ્સની ડિફોલ્ટ સપ્લાયર સૂચિમાંથી સપ્લાયર પસંદ કરો.,
Select a company,કોઈ કંપની પસંદ કરો,
Select finance book for the item {0} at row {1},પંક્તિ {1} પર આઇટમ {0} માટે ફાઇનાન્સ બુક પસંદ કરો,
Select only one Priority as Default.,ડિફaultલ્ટ તરીકે ફક્ત એક પ્રાધાન્યતા પસંદ કરો.,
@@ -4247,7 +4231,6 @@
Actual ,વાસ્તવિક,
Add to cart,સૂચી માં સામેલ કરો,
Budget,બજેટ,
-Chart Of Accounts Importer,એકાઉન્ટ્સ આયાતકારનો ચાર્ટ,
Chart of Accounts,હિસાબનો ચાર્ટ,
Customer database.,ગ્રાહક ડેટાબેઝ.,
Days Since Last order,છેલ્લે ઓર્ડર સુધીનાં દિવસો,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,સમાપ્તિ તારીખ પ્રારંભ તારીખ કરતાં ઓછી હોઈ શકતી નથી,
For Default Supplier (Optional),ડિફોલ્ટ સપ્લાયર માટે (વૈકલ્પિક),
From date cannot be greater than To date,તારીખથી તારીખ કરતાં વધુ હોઈ શકતી નથી,
-Get items from,વસ્તુઓ મેળવો,
Group by,ગ્રુપ દ્વારા,
In stock,ઉપલબ્ધ છે,
Item name,વસ્તુ નામ,
@@ -4532,32 +4514,22 @@
Accounts Settings,સેટિંગ્સ એકાઉન્ટ્સ,
Settings for Accounts,એકાઉન્ટ્સ માટે સુયોજનો,
Make Accounting Entry For Every Stock Movement,દરેક સ્ટોક ચળવળ માટે એકાઉન્ટિંગ પ્રવેશ કરો,
-"If enabled, the system will post accounting entries for inventory automatically.","જો સક્રિય હોય તો, સિસ્ટમ આપોઆપ યાદી માટે એકાઉન્ટિંગ પ્રવેશો પોસ્ટ થશે.",
-Accounts Frozen Upto,ફ્રોઝન સુધી એકાઉન્ટ્સ,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","આ તારીખ સુધી સ્થિર હિસાબી પ્રવેશ, કોઈએ / કરવા નીચે સ્પષ્ટ ભૂમિકા સિવાય પ્રવેશ સુધારી શકો છો.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,ભૂમિકા ફ્રોઝન એકાઉન્ટ્સ & સંપાદિત કરો ફ્રોઝન પ્રવેશો સેટ કરવાની મંજૂરી,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,આ ભૂમિકા સાથેના વપરાશકર્તાઓ સ્થિર એકાઉન્ટ્સ સામે હિસાબી પ્રવેશો સ્થિર એકાઉન્ટ્સ સેટ અને બનાવવા / સુધારવા માટે માન્ય છે,
Determine Address Tax Category From,થી સરનામાં કર કેટેગરી નક્કી કરો,
-Address used to determine Tax Category in transactions.,વ્યવહારમાં કર શ્રેણી નક્કી કરવા માટે વપરાયેલ સરનામું.,
Over Billing Allowance (%),ઓવર બિલિંગ એલાઉન્સ (%),
-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 for $110.,"ઓર્ડર કરેલી રકમની સરખામણીએ તમને વધુ બિલ આપવાની મંજૂરી છે. ઉદાહરણ તરીકે: જો કોઈ આઇટમ માટે orderર્ડર મૂલ્ય is 100 છે અને સહિષ્ણુતા 10% તરીકે સેટ કરેલી છે, તો તમને $ 110 માટે બિલ આપવાની મંજૂરી છે.",
Credit Controller,ક્રેડિટ કંટ્રોલર,
-Role that is allowed to submit transactions that exceed credit limits set.,સેટ ક્રેડિટ મર્યાદા કરતાં વધી કે વ્યવહારો સબમિટ કરવા માટે માન્ય છે તે ભૂમિકા.,
Check Supplier Invoice Number Uniqueness,ચેક પુરવઠોકર્તા ભરતિયું નંબર વિશિષ્ટતા,
Make Payment via Journal Entry,જર્નલ પ્રવેશ મારફતે ચુકવણી બનાવો,
Unlink Payment on Cancellation of Invoice,ભરતિયું રદ પર ચુકવણી નાપસંદ,
-Unlink Advance Payment on Cancelation of Order,હુકમ રદ પર અનલિંક એડવાન્સ ચુકવણી,
Book Asset Depreciation Entry Automatically,બુક એસેટ ઘસારો એન્ટ્રી આપમેળે,
Automatically Add Taxes and Charges from Item Tax Template,આઇટમ ટેક્સ Templateાંચોથી આપમેળે કર અને ચાર્જ ઉમેરો,
Automatically Fetch Payment Terms,આપમેળે ચુકવણીની શરતો મેળવો,
-Show Inclusive Tax In Print,પ્રિન્ટમાં વ્યાપક ટેક્સ દર્શાવો,
Show Payment Schedule in Print,પ્રિન્ટમાં પેમેન્ટ શેડ્યૂલ દર્શાવો,
Currency Exchange Settings,ચલણ વિનિમય સેટિંગ્સ,
Allow Stale Exchange Rates,સ્ટેલ એક્સચેન્જ દરોને મંજૂરી આપો,
Stale Days,સ્ટેલ ડેઝ,
Report Settings,રિપોર્ટ સેટિંગ્સ,
Use Custom Cash Flow Format,કસ્ટમ કેશ ફ્લો ફોર્મેટનો ઉપયોગ કરો,
-Only select if you have setup Cash Flow Mapper documents,માત્ર જો તમે સેટઅપ કેશ ફ્લો મેપર દસ્તાવેજો છે તે પસંદ કરો,
Allowed To Transact With,સાથે વ્યવહાર કરવા માટે મંજૂર,
SWIFT number,સ્વીફ્ટ નંબર,
Branch Code,શાખા સંકેત,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS ગ્રાહક જૂથ,
POS Field,પોસ ક્ષેત્ર,
POS Item Group,POS વસ્તુ ગ્રુપ,
-[Select],[પસંદ કરો],
Company Address,કંપનીનું સરનામું,
Update Stock,સુધારા સ્ટોક,
Ignore Pricing Rule,પ્રાઇસીંગ નિયમ અવગણો,
@@ -5495,8 +5466,6 @@
Supplier Naming By,દ્વારા પુરવઠોકર્તા નામકરણ,
Default Supplier Group,ડિફોલ્ટ સપ્લાયર ગ્રુપ,
Default Buying Price List,ડિફૉલ્ટ ખરીદી ભાવ યાદી,
-Maintain same rate throughout purchase cycle,ખરીદી ચક્ર દરમ્યાન જ દર જાળવી,
-Allow Item to be added multiple times in a transaction,વસ્તુ વ્યવહાર ઘણી વખત ઉમેરી શકાય માટે પરવાનગી આપે છે,
Backflush Raw Materials of Subcontract Based On,બેકકોલશ કાચો માલ ઓફ સબકોન્ટ્રોક પર આધારીત,
Material Transferred for Subcontract,ઉપકોન્ટ્રેક્ટ માટે વપરાયેલી સામગ્રી,
Over Transfer Allowance (%),ઓવર ટ્રાન્સફર એલાઉન્સ (%),
@@ -5540,7 +5509,6 @@
Current Stock,વર્તમાન સ્ટોક,
PUR-RFQ-.YYYY.-,PUR-RFQ- .YYYY.-,
For individual supplier,વ્યક્તિગત સપ્લાયર માટે,
-Supplier Detail,પુરવઠોકર્તા વિગતવાર,
Link to Material Requests,સામગ્રી વિનંતીઓ માટે લિંક,
Message for Supplier,પુરવઠોકર્તા માટે સંદેશ,
Request for Quotation Item,અવતરણ વસ્તુ માટે વિનંતી,
@@ -6481,7 +6449,6 @@
Appraisal Template,મૂલ્યાંકન ઢાંચો,
For Employee Name,કર્મચારીનું નામ માટે,
Goals,લક્ષ્યાંક,
-Calculate Total Score,કુલ સ્કોર ગણતરી,
Total Score (Out of 5),(5) કુલ સ્કોર,
"Any other remarks, noteworthy effort that should go in the records.","કોઈપણ અન્ય ટીકા, રેકોર્ડ જવા જોઈએ કે નોંધપાત્ર પ્રયાસ.",
Appraisal Goal,મૂલ્યાંકન ગોલ,
@@ -6599,11 +6566,6 @@
Reason for Leaving,છોડીને માટે કારણ,
Leave Encashed?,વટાવી છોડી?,
Encashment Date,એન્કેશમેન્ટ તારીખ,
-Exit Interview Details,બહાર નીકળો મુલાકાત વિગતો,
-Held On,આયોજન પર,
-Reason for Resignation,રાજીનામાની કારણ,
-Better Prospects,સારી સંભાવના,
-Health Concerns,આરોગ્ય ચિંતા,
New Workplace,ન્યૂ નોકરીના સ્થળે,
HR-EAD-.YYYY.-,એચઆર-ઇએડી-. યેવાયવાય.-,
Returned Amount,પરત રકમ,
@@ -6740,10 +6702,7 @@
Employee Settings,કર્મચારીનું સેટિંગ્સ,
Retirement Age,નિવૃત્તિ વય,
Enter retirement age in years,વર્ષમાં નિવૃત્તિ વય દાખલ,
-Employee Records to be created by,કર્મચારીનું રેકોર્ડ્સ દ્વારા બનાવી શકાય,
-Employee record is created using selected field. ,કર્મચારીનું રેકોર્ડ પસંદ ક્ષેત્ર ઉપયોગ કરીને બનાવવામાં આવે છે.,
Stop Birthday Reminders,સ્ટોપ જન્મદિવસ રિમાઇન્ડર્સ,
-Don't send Employee Birthday Reminders,કર્મચારીનું જન્મદિવસ રિમાઇન્ડર્સ મોકલશો નહીં,
Expense Approver Mandatory In Expense Claim,ખર્ચ દાવા માં ખર્ચાળ ફરજિયાત ખર્ચ,
Payroll Settings,પગારપત્રક સેટિંગ્સ,
Leave,રજા,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,અરજી છોડો માં મંજૂર છોડી દો,
Show Leaves Of All Department Members In Calendar,કૅલેન્ડરમાં બધા ડિપાર્ટમેન્ટના સભ્યોની પાંદડીઓ બતાવો,
Auto Leave Encashment,Autoટો લીવ એન્કેશમેન્ટ,
-Restrict Backdated Leave Application,બેકડેટેડ રજા એપ્લિકેશનને પ્રતિબંધિત કરો,
Hiring Settings,હાયરિંગ સેટિંગ્સ,
Check Vacancies On Job Offer Creation,જોબ erફર સર્જન પર ખાલી જગ્યાઓ તપાસો,
Identification Document Type,ઓળખ દસ્તાવેજ પ્રકાર,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,ઉત્પાદન સેટિંગ્સ,
Raw Materials Consumption,કાચો માલનો વપરાશ,
Allow Multiple Material Consumption,મલ્ટીપલ મટિરિયલ કન્ઝ્પ્શનને મંજૂરી,
-Allow multiple Material Consumption against a Work Order,વર્ક ઓર્ડર સામે બહુવિધ વપરાયેલી સામગ્રીને મંજૂરી આપો,
Backflush Raw Materials Based On,Backflush કાચો માલ પર આધારિત,
Material Transferred for Manufacture,સામગ્રી ઉત્પાદન માટે તબદીલ,
Capacity Planning,ક્ષમતા આયોજન,
Disable Capacity Planning,ક્ષમતા આયોજન નિષ્ક્રિય કરો,
Allow Overtime,અતિકાલિક માટે પરવાનગી આપે છે,
-Plan time logs outside Workstation Working Hours.,વર્કસ્ટેશન કામ કલાકો બહાર સમય લોગ યોજના બનાવો.,
Allow Production on Holidays,રજાઓ પર ઉત્પાદન માટે પરવાનગી આપે છે,
Capacity Planning For (Days),(દિવસ) માટે ક્ષમતા આયોજન,
-Try planning operations for X days in advance.,અગાઉથી X દિવસ માટે કામગીરી આયોજન કરવાનો પ્રયાસ કરો.,
-Time Between Operations (in mins),(મિનિટ) ઓપરેશન્સ વચ્ચે સમય,
-Default 10 mins,10 મિનિટ મૂળભૂત,
Default Warehouses for Production,ઉત્પાદન માટે ડિફોલ્ટ વેરહાઉસ,
Default Work In Progress Warehouse,પ્રગતિ વેરહાઉસ માં મૂળભૂત કામ,
Default Finished Goods Warehouse,મૂળભૂત ફિનિશ્ડ ગૂડ્સ વેરહાઉસ,
Default Scrap Warehouse,ડિફaultલ્ટ સ્ક્રેપ વેરહાઉસ,
-Over Production for Sales and Work Order,ઓવર પ્રોડક્શન ફોર સેલ્સ અને વર્ક ઓર્ડર,
Overproduction Percentage For Sales Order,સેલ્સ ઓર્ડર માટે વધુ ઉત્પાદનની ટકાવારી,
Overproduction Percentage For Work Order,વર્ક ઓર્ડર માટે વધુ ઉત્પાદનની ટકાવારી,
Other Settings,અન્ય સેટિંગ્સ,
Update BOM Cost Automatically,આપમેળે BOM કિંમત અપડેટ કરો,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","તાજેતરની મૂલ્યાંકન દર / ભાવ યાદી દર / કાચા માલની છેલ્લી ખરીદી દરના આધારે, શેડ્યૂલર દ્વારા આપમેળે બીઓએમની કિંમતને અપડેટ કરો.",
Material Request Plan Item,સામગ્રી વિનંતી યોજના આઇટમ,
Material Request Type,સામગ્રી વિનંતી પ્રકાર,
Material Issue,મહત્વનો મુદ્દો,
@@ -7603,10 +7554,6 @@
Quality Goal,ગુણવત્તા ધ્યેય,
Monitoring Frequency,મોનિટરિંગ આવર્તન,
Weekday,અઠવાડિયાનો દિવસ,
-January-April-July-October,જાન્યુઆરી-એપ્રિલ-જુલાઈ-Octoberક્ટોબર,
-Revision and Revised On,સુધારો અને સુધારેલ,
-Revision,પુનરાવર્તન,
-Revised On,રિવાઇઝ્ડ ઓન,
Objectives,ઉદ્દેશો,
Quality Goal Objective,ગુણવત્તા ધ્યેય ઉદ્દેશ,
Objective,ઉદ્દેશ્ય,
@@ -7619,7 +7566,6 @@
Processes,પ્રક્રિયાઓ,
Quality Procedure Process,ગુણવત્તા પ્રક્રિયા પ્રક્રિયા,
Process Description,પ્રક્રિયા વર્ણન,
-Child Procedure,બાળ પ્રક્રિયા,
Link existing Quality Procedure.,હાલની ગુણવત્તા પ્રક્રિયાને લિંક કરો.,
Additional Information,વધારાની માહિતી,
Quality Review Objective,ગુણવત્તા સમીક્ષા ઉદ્દેશ્ય,
@@ -7787,15 +7733,9 @@
Default Customer Group,મૂળભૂત ગ્રાહક જૂથ,
Default Territory,મૂળભૂત પ્રદેશ,
Close Opportunity After Days,બંધ તકો દિવસો પછી,
-Auto close Opportunity after 15 days,15 દિવસ પછી ઓટો બંધ તકો,
Default Quotation Validity Days,ડિફોલ્ટ ક્વોટેશન વેલિડિટી ડેઝ,
Sales Update Frequency,વેચાણ અપડેટ આવર્તન,
-How often should project and company be updated based on Sales Transactions.,સેલ્સ વ્યવહારો પર આધારિત કેટલી વાર પ્રોજેક્ટ અને કંપનીને અપડેટ કરવું જોઈએ.,
Each Transaction,દરેક ટ્રાન્ઝેક્શન,
-Allow user to edit Price List Rate in transactions,વપરાશકર્તા વ્યવહારો ભાવ યાદી દર ફેરફાર કરવા માટે પરવાનગી આપે છે,
-Allow multiple Sales Orders against a Customer's Purchase Order,એક ગ્રાહક ખરીદી ઓર્ડર સામે બહુવિધ વેચાણ ઓર્ડર માટે પરવાનગી આપે છે,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,માન્ય વેચાણ કિંમત ખરીદી દર અથવા મૂલ્યાંકન દર સામે વસ્તુ,
-Hide Customer's Tax Id from Sales Transactions,સેલ્સ વહેવારો ગ્રાહકનો ટેક્સ ID છુપાવો,
SMS Center,એસએમએસ કેન્દ્ર,
Send To,ને મોકલવું,
All Contact,તમામ સંપર્ક,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,વસ્તુઓ વપરાય ઉત્પાદકો,
Limited to 12 characters,12 અક્ષરો સુધી મર્યાદિત,
MAT-MR-.YYYY.-,એમએટી- એમઆર-યુ.વાયવાયવાય.-,
-Set Warehouse,વેરહાઉસ સેટ કરો,
-Sets 'For Warehouse' in each row of the Items table.,આઇટમ કોષ્ટકની દરેક પંક્તિમાં 'વેરહાઉસ માટે' સેટ કરો.,
-Requested For,વિનંતી,
Partially Ordered,આંશિક રીતે આદેશ આપ્યો,
Transferred,પર સ્થાનાંતરિત કરવામાં આવી,
% Ordered,% આદેશ આપ્યો,
@@ -8407,24 +8344,14 @@
Default Stock UOM,મૂળભૂત સ્ટોક UOM,
Sample Retention Warehouse,નમૂના રીટેન્શન વેરહાઉસ,
Default Valuation Method,મૂળભૂત મૂલ્યાંકન પદ્ધતિ,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,ટકાવારી તમે પ્રાપ્ત અથવા આદેશ આપ્યો જથ્થો સામે વધુ પહોંચાડવા માટે માન્ય છે. ઉદાહરણ તરીકે: તમે 100 એકમો આદેશ આપ્યો હોય તો. અને તમારા ભથ્થું પછી તમે 110 એકમો મેળવવા માટે માન્ય છે 10% છે.,
-Action if Quality inspection is not submitted,જો ગુણવત્તા નિરીક્ષણ સબમિટ ન કરાયું હોય તો કાર્યવાહી કરો,
Show Barcode Field,બતાવો બારકોડ ક્ષેત્ર,
Convert Item Description to Clean HTML,સંકેત શુધ્ધ HTML માટે આઇટમ વર્ણન કન્વર્ટ કરો,
-Auto insert Price List rate if missing,ઓટો સામેલ ભાવ યાદી દર ગુમ તો,
Allow Negative Stock,નકારાત્મક સ્ટોક પરવાનગી આપે છે,
Automatically Set Serial Nos based on FIFO,આપમેળે FIFO પર આધારિત અમે સીરીયલ સેટ,
-Set Qty in Transactions based on Serial No Input,સીરીઅલ ઇનપુટ પર આધારિત વ્યવહારોમાં જથ્થો સેટ કરો,
Auto Material Request,ઓટો સામગ્રી વિનંતી,
-Raise Material Request when stock reaches re-order level,સ્ટોક ફરીથી ક્રમમાં સ્તર સુધી પહોંચે છે ત્યારે સામગ્રી વિનંતી વધારો,
-Notify by Email on creation of automatic Material Request,આપોઆપ સામગ્રી વિનંતી બનાવટ પર ઇમેઇલ દ્વારા સૂચિત,
Inter Warehouse Transfer Settings,ઇન્ટર વેરહાઉસ ટ્રાન્સફર સેટિંગ્સ,
-Allow Material Transfer From Delivery Note and Sales Invoice,ડિલિવરી નોટ અને સેલ્સ ઇન્વોઇસથી મટિરીયલ ટ્રાન્સફરને મંજૂરી આપો,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,ખરીદી રસીદ અને ખરીદી ઇન્વoiceઇસથી સામગ્રીના સ્થાનાંતરણને મંજૂરી આપો,
Freeze Stock Entries,ફ્રીઝ સ્ટોક પ્રવેશો,
Stock Frozen Upto,સ્ટોક ફ્રોઝન સુધી,
-Freeze Stocks Older Than [Days],ફ્રીઝ સ્ટોક્સ કરતાં જૂની [ટ્રેડીંગ],
-Role Allowed to edit frozen stock,ભૂમિકા સ્થિર સ્ટોક ફેરફાર કરવા માટે પરવાનગી,
Batch Identification,બેચની ઓળખ,
Use Naming Series,નેમિંગ સિરીઝનો ઉપયોગ કરો,
Naming Series Prefix,નામકરણ શ્રેણી ઉપસર્ગ,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,ખરીદી રસીદ પ્રવાહો,
Purchase Register,ખરીદી રજીસ્ટર,
Quotation Trends,અવતરણ પ્રવાહો,
-Quoted Item Comparison,નોંધાયેલા વસ્તુ સરખામણી,
Received Items To Be Billed,પ્રાપ્ત વસ્તુઓ બિલ કરવા,
Qty to Order,ઓર્ડર Qty,
Requested Items To Be Transferred,વિનંતી વસ્તુઓ ટ્રાન્સફર કરી,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,સામગ્રી વિનંતીઓ માટે વેરહાઉસ પસંદ કરો,
Transfer Materials For Warehouse {0},વેરહાઉસ Material 0 For માટે સામગ્રી સ્થાનાંતરિત કરો,
Production Plan Material Request Warehouse,ઉત્પાદન યોજના સામગ્રી વિનંતી વેરહાઉસ,
-Set From Warehouse,વેરહાઉસમાંથી સેટ કરો,
-Source Warehouse (Material Transfer),સોર્સ વેરહાઉસ (મટીરિયલ ટ્રાન્સફર),
Sets 'Source Warehouse' in each row of the items table.,આઇટમ્સ કોષ્ટકની દરેક પંક્તિમાં 'સોર્સ વેરહાઉસ' સેટ કરો.,
Sets 'Target Warehouse' in each row of the items table.,આઇટમ્સના ટેબલની દરેક પંક્તિમાં 'લક્ષ્ય વેરહાઉસ' સેટ કરો.,
Show Cancelled Entries,રદ કરેલ પ્રવેશો બતાવો,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,સેવા પ્રાપ્ત થઈ પરંતુ બિલ નથી કરાયું,
Deferred Accounting Settings,સ્થગિત એકાઉન્ટિંગ સેટિંગ્સ,
Book Deferred Entries Based On,પુસ્તક સ્થગિત પ્રવેશો આધારે,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","જો "મહિનાઓ" પસંદ કરવામાં આવે છે, તો પછી મહિનામાં દિવસોની સંખ્યાને ધ્યાનમાં લીધા વિના, દર મહિને સ્થગિત રકમ સ્થગિત આવક અથવા ખર્ચ તરીકે બુક કરવામાં આવશે. જો વિલંબિત આવક અથવા ખર્ચ આખા મહિના માટે બુક કરાયો ન હોય તો તેની કાર્યવાહી કરવામાં આવશે.",
Days,દિવસ,
Months,મહિનાઓ,
Book Deferred Entries Via Journal Entry,જર્નલ એન્ટ્રી દ્વારા પુસ્તક સ્થગિત એન્ટ્રીઓ,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,જો આને ચકાસાયેલ ન હોય તો ડિફરર્ડ મહેસૂલ / ખર્ચ બુક કરવા માટે ડાયરેક્ટ જી.એલ. એન્ટ્રીઝ બનાવવામાં આવશે,
Submit Journal Entries,જર્નલ એન્ટ્રી સબમિટ કરો,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,જો આને ચકાસાયેલ ન હોય તો જર્નલ પ્રવેશો ડ્રાફ્ટ સ્થિતિમાં સાચવવામાં આવશે અને જાતે જ સબમિટ કરવાની રહેશે,
Enable Distributed Cost Center,વિતરિત કિંમત કેન્દ્રને સક્ષમ કરો,
@@ -8901,8 +8823,6 @@
Is Inter State,ઇન્ટર સ્ટેટ છે,
Purchase Details,ખરીદી વિગતો,
Depreciation Posting Date,અવમૂલ્યન પોસ્ટ કરવાની તારીખ,
-Purchase Order Required for Purchase Invoice & Receipt Creation,ખરીદીના ઇન્વ Orderઇસ અને રસીદ બનાવટ માટે ખરીદ Orderર્ડર આવશ્યક છે,
-Purchase Receipt Required for Purchase Invoice Creation,ખરીદીની રસીદ ખરીદી ઇન્વoiceઇસ બનાવટ માટે જરૂરી છે,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","ડિફ defaultલ્ટ રૂપે, સપ્લાયર નામ દાખલ કરેલ સપ્લાયર નામ મુજબ સેટ કરેલું છે. જો તમે ઇચ્છો છો કે સપ્લાયર્સનું નામ એ",
choose the 'Naming Series' option.,'નામકરણ શ્રેણી' વિકલ્પ પસંદ કરો.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,નવો ખરીદી વ્યવહાર બનાવતી વખતે ડિફોલ્ટ ભાવ સૂચિને ગોઠવો. આઇટમના ભાવ આ ભાવ સૂચિમાંથી મેળવવામાં આવશે.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,આવકવેરાના ભાગ છે,
Component properties and references ,ઘટક ગુણધર્મો અને સંદર્ભો,
Additional Salary ,વધારાના પગાર,
-Condtion and formula,સ્થિતિ અને સૂત્ર,
Unmarked days,અંકિત દિવસો,
Absent Days,ગેરહાજર દિવસો,
Conditions and Formula variable and example,શરતો અને ફોર્મ્યુલા ચલ અને ઉદાહરણ,
Feedback By,પ્રતિસાદ દ્વારા,
-MTNG-.YYYY.-.MM.-.DD.-,એમટીએનજી -હાયવાય .-. એમએમ .-. ડીડી.-,
Manufacturing Section,ઉત્પાદન વિભાગ,
-Sales Order Required for Sales Invoice & Delivery Note Creation,વેચાણના ઇન્વોઇસ અને ડિલિવરી નોંધ બનાવટ માટે વેચાણ ઓર્ડર આવશ્યક છે,
-Delivery Note Required for Sales Invoice Creation,ડિલિવરી નોટ વેચાણના ઇન્વoiceઇસ બનાવટ માટે જરૂરી છે,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","ડિફ defaultલ્ટ રૂપે, ગ્રાહકનું નામ દાખલ કરેલા સંપૂર્ણ નામ મુજબ સેટ કરેલું છે. જો તમે ઇચ્છો છો કે ગ્રાહકોના નામ એ",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,નવો વેચાણ વ્યવહાર બનાવતી વખતે ડિફોલ્ટ ભાવ સૂચિને ગોઠવો. આ ભાવ સૂચિમાંથી આઇટમના ભાવ લાવવામાં આવશે.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","જો આ વિકલ્પ 'હા' રૂપરેખાંકિત થયેલ છે, તો ERPNext તમને સેલ્સ oiceવોઇસ અથવા ડિલિવરી નોટ બનાવતા પહેલા સેલ્સ ઓર્ડર બનાવ્યા વિના અટકાવશે. આ રૂપરેખાંકન ગ્રાહક માસ્ટરમાં 'સેલ્સ Orderર્ડર વિના સેલ્સ ઇન્વોઇસ ક્રિએશનની મંજૂરી આપો' ચેકબ byક્સને સક્ષમ કરીને ચોક્કસ ગ્રાહક માટે ઓવરરાઇડ કરી શકાય છે.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,Selected 0} {1 successfully સફળતાપૂર્વક બધા પસંદ કરેલા વિષયોમાં ઉમેરવામાં આવ્યા છે.,
Topics updated,વિષયો અપડેટ થયા,
Academic Term and Program,શૈક્ષણિક મુદત અને કાર્યક્રમ,
-Last Stock Transaction for item {0} was on {1}.,આઇટમ {0} માટે છેલ્લું સ્ટોક ટ્રાંઝેક્શન {1} પર હતું.,
-Stock Transactions for Item {0} cannot be posted before this time.,આઇટમ Stock 0 for માટે સ્ટોક ટ્રાન્ઝેક્શન આ સમય પહેલાં પોસ્ટ કરી શકાતા નથી.,
Please remove this item and try to submit again or update the posting time.,કૃપા કરીને આ વસ્તુને દૂર કરો અને ફરીથી સબમિટ કરવાનો પ્રયાસ કરો અથવા પોસ્ટિંગ સમયને અપડેટ કરો.,
Failed to Authenticate the API key.,API કીને પ્રમાણિત કરવામાં નિષ્ફળ.,
Invalid Credentials,અમાન્ય ઓળખાણપત્ર,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,કૃપા કરી તમારી પ્લેઇડ ક્લાયંટ આઈડી અને ગુપ્ત મૂલ્યો તપાસો,
Bank transaction creation error,બેંક વ્યવહાર બનાવવાની ભૂલ,
Unit of Measurement,માપન એકમ,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},પંક્તિ # {}: આઇટમ for for માટે વેચવાનો દર તેના {than કરતા ઓછો છે. વેચવાનો દર ઓછામાં ઓછો હોવો જોઈએ}},
Fiscal Year {0} Does Not Exist,નાણાકીય વર્ષ {0} અસ્તિત્વમાં નથી,
Row # {0}: Returned Item {1} does not exist in {2} {3},પંક્તિ # {0}: પરત કરેલ આઇટમ {1 {{2} {3 in માં અસ્તિત્વમાં નથી,
Valuation type charges can not be marked as Inclusive,મૂલ્ય પ્રકારનાં ચાર્જને સમાવિષ્ટ તરીકે ચિહ્નિત કરી શકાતા નથી,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Row 0 row પંક્તિમાં અગ્રતા માટેનો પ્રતિસાદ સમય {1 Time રિઝોલ્યુશન સમય કરતા વધુ હોઈ શકતો નથી.,
{0} is not enabled in {1},{0} {1} માં સક્ષમ નથી,
Group by Material Request,સામગ્રી વિનંતી દ્વારા જૂથ,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","પંક્તિ {0}: સપ્લાયર {0} માટે, ઇમેઇલ મોકલવા માટે ઇમેઇલ સરનામું આવશ્યક છે",
Email Sent to Supplier {0},સપ્લાયર Supplier 0} ને મોકલો ઇમેઇલ,
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","પોર્ટલથી અવતરણ માટેની વિનંતીની Disક્સેસ અક્ષમ છે. Allક્સેસને મંજૂરી આપવા માટે, તેને પોર્ટલ સેટિંગ્સમાં સક્ષમ કરો.",
Supplier Quotation {0} Created,સપ્લાયર અવતરણ {0. બનાવ્યું,
Valid till Date cannot be before Transaction Date,માન્ય તારીખ તારીખ ટ્રાંઝેક્શનની તારીખ પહેલાંની હોઈ શકતી નથી,
+Unlink Advance Payment on Cancellation of Order,ઓર્ડર રદ કરવા પર અનલિંક એડવાન્સ ચુકવણી,
+"Simple Python Expression, Example: territory != 'All Territories'","સરળ પાયથોન અભિવ્યક્તિ, ઉદાહરણ: પ્રદેશ! = 'બધા પ્રદેશો'",
+Sales Contributions and Incentives,વેચાણ ફાળો અને પ્રોત્સાહનો,
+Sourced by Supplier,સપ્લાયર દ્વારા સોર્ટેડ,
+Total weightage assigned should be 100%.<br>It is {0},સોંપાયેલું કુલ વજન 100% હોવું જોઈએ.<br> તે {0} છે,
+Account {0} exists in parent company {1}.,એકાઉન્ટ {0 parent પેરેંટ કંપની} 1} માં અસ્તિત્વમાં છે.,
+"To overrule this, enable '{0}' in company {1}","તેને ઉથલાવવા માટે, કંપની {1} માં '{0}' સક્ષમ કરો.",
+Invalid condition expression,અમાન્ય શરત અભિવ્યક્તિ,
+Please Select a Company First,કૃપા કરીને પહેલા કોઈ કંપની પસંદ કરો,
+Please Select Both Company and Party Type First,કૃપા કરીને કંપની અને પાર્ટી પ્રકાર બંને પસંદ કરો,
+Provide the invoice portion in percent,ટકામાં ભરતિયું ભાગ પ્રદાન કરો,
+Give number of days according to prior selection,પૂર્વ પસંદગી મુજબ દિવસોની સંખ્યા આપો,
+Email Details,ઇમેઇલ વિગતો,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","પ્રાપ્તકર્તા માટે શુભેચ્છા પસંદ કરો. દા.ત. શ્રી, કુ., વગેરે.",
+Preview Email,પૂર્વાવલોકન ઇમેઇલ,
+Please select a Supplier,કૃપા કરીને કોઈ સપ્લાયર પસંદ કરો,
+Supplier Lead Time (days),સપ્લાયર લીડ સમય (દિવસ),
+"Home, Work, etc.","ઘર, કાર્ય, વગેરે.",
+Exit Interview Held On,બહાર નીકળો ઇન્ટરવ્યુ,
+Condition and formula,સ્થિતિ અને સૂત્ર,
+Sets 'Target Warehouse' in each row of the Items table.,આઇટમ કોષ્ટકની દરેક પંક્તિમાં 'લક્ષ્ય વેરહાઉસ' સેટ કરો.,
+Sets 'Source Warehouse' in each row of the Items table.,આઇટમ કોષ્ટકની દરેક પંક્તિમાં 'સોર્સ વેરહાઉસ' સેટ કરો.,
+POS Register,પોસ નોંધણી,
+"Can not filter based on POS Profile, if grouped by POS Profile","જો પીઓએસ પ્રોફાઇલ દ્વારા જૂથ થયેલ હોય, તો પીઓએસ પ્રોફાઇલના આધારે ફિલ્ટર કરી શકાતું નથી",
+"Can not filter based on Customer, if grouped by Customer","જો ગ્રાહક દ્વારા જૂથ થયેલ હોય, તો ગ્રાહકના આધારે ફિલ્ટર કરી શકતા નથી",
+"Can not filter based on Cashier, if grouped by Cashier","જો કેશિયર દ્વારા જૂથ થયેલ હોય, તો કેશિયરના આધારે ફિલ્ટર કરી શકતા નથી",
+Payment Method,ચુકવણી પદ્ધતિ,
+"Can not filter based on Payment Method, if grouped by Payment Method","જો ચુકવણી પદ્ધતિ દ્વારા જૂથ થયેલ હોય, તો ચુકવણી પદ્ધતિના આધારે ફિલ્ટર કરી શકાતું નથી",
+Supplier Quotation Comparison,સપ્લાયર અવતરણ સરખામણી,
+Price per Unit (Stock UOM),યુનિટ દીઠ ભાવ (સ્ટોક યુઓએમ),
+Group by Supplier,સપ્લાયર દ્વારા જૂથ,
+Group by Item,આઇટમ દ્વારા જૂથ,
+Remember to set {field_label}. It is required by {regulation}.,{ફીલ્ડ_લેબલ set સેટ કરવાનું યાદ રાખો. તે {નિયમન by દ્વારા આવશ્યક છે.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},નોંધણી તારીખ શૈક્ષણિક વર્ષ Date 0} ની શરૂઆતની તારીખની પહેલાં હોઇ શકે નહીં,
+Enrollment Date cannot be after the End Date of the Academic Term {0},નોંધણી તારીખ શૈક્ષણિક મુદતની સમાપ્તિ તારીખ be 0 after પછીની હોઈ શકતી નથી,
+Enrollment Date cannot be before the Start Date of the Academic Term {0},નોંધણી તારીખ શૈક્ષણિક મુદતની પ્રારંભ તારીખ before 0 before પહેલાંની હોઈ શકતી નથી,
+Future Posting Not Allowed,ભાવિ પોસ્ટિંગની મંજૂરી નથી,
+"To enable Capital Work in Progress Accounting, ","પ્રગતિ એકાઉન્ટિંગમાં કેપિટલ વર્કને સક્ષમ કરવા માટે,",
+you must select Capital Work in Progress Account in accounts table,તમારે એકાઉન્ટ્સ ટેબલમાં પ્રગતિ ખાતામાં મૂડી કાર્ય પસંદ કરવું આવશ્યક છે,
+You can also set default CWIP account in Company {},તમે કંપની default in માં ડિફોલ્ટ CWIP એકાઉન્ટ પણ સેટ કરી શકો છો.,
+The Request for Quotation can be accessed by clicking on the following button,વિનંતી માટેની વિનંતી નીચેના બટન પર ક્લિક કરીને .ક્સેસ કરી શકાય છે,
+Regards,સાદર,
+Please click on the following button to set your new password,કૃપા કરીને તમારો નવો પાસવર્ડ સેટ કરવા માટે નીચેના બટન પર ક્લિક કરો,
+Update Password,પાસવર્ડ અપડેટ કરો,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},પંક્તિ # {}: આઇટમ for for માટે વેચવાનો દર તેના {than કરતા ઓછો છે. {Lling નું વેચાણ ઓછામાં ઓછું હોવું જોઈએ {},
+You can alternatively disable selling price validation in {} to bypass this validation.,આ માન્યતાને બાયપાસ કરવા માટે તમે વૈકલ્પિક રૂપે વેચાણ મૂલ્ય માન્યતાને {in માં અક્ષમ કરી શકો છો.,
+Invalid Selling Price,અમાન્ય વેચાણ કિંમત,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,સરનામાંને કંપની સાથે જોડવાની જરૂર છે. કૃપા કરીને લિંક્સ કોષ્ટકમાં કંપની માટે એક પંક્તિ ઉમેરો.,
+Company Not Linked,કંપની લિંક્ટેડ નથી,
+Import Chart of Accounts from CSV / Excel files,સીએસવી / એક્સેલ ફાઇલોથી એકાઉન્ટ્સનું ચાર્ટ આયાત કરો,
+Completed Qty cannot be greater than 'Qty to Manufacture',પૂર્ણ થયેલી ક્યુટી 'ક્યૂટી ટુ મેન્યુફેક્ચરિંગ' કરતા મોટી ન હોઈ શકે,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","પંક્તિ {0}: સપ્લાયર {1} માટે, ઇમેઇલ મોકલવા માટે ઇમેઇલ સરનામું આવશ્યક છે",
+"If enabled, the system will post accounting entries for inventory automatically","જો સક્ષમ હોય, તો સિસ્ટમ આપમેળે ઇન્વેન્ટરી માટે એકાઉન્ટિંગ પ્રવેશો પોસ્ટ કરશે",
+Accounts Frozen Till Date,તારીખ સુધી એકાઉન્ટ્સ સ્થિર,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,આ તારીખ સુધી હિસાબી પ્રવેશો સ્થિર છે. નીચે જણાવેલ ભૂમિકાવાળા વપરાશકર્તાઓ સિવાય કોઈપણ પ્રવેશો બનાવી અથવા સંશોધિત કરી શકશે નહીં,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,ફ્રોઝન એકાઉન્ટ્સ સેટ કરવા અને ફ્રોઝન એન્ટ્રીઝમાં ફેરફાર કરવાની ભૂમિકાને મંજૂરી છે,
+Address used to determine Tax Category in transactions,વ્યવહારમાં કર શ્રેણી નક્કી કરવા માટે વપરાયેલ સરનામું,
+"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 ","ઓર્ડર કરેલી રકમની તુલનામાં તમને બિલિંગ કરવાની મંજૂરી કેટલી ટકાવારી છે. ઉદાહરણ તરીકે, જો કોઈ વસ્તુ માટે theર્ડર મૂલ્ય $ 100 છે અને સહિષ્ણુતા 10% તરીકે સેટ કરેલી છે, તો પછી તમને $ 110 સુધી બિલ કરવાની મંજૂરી છે",
+This role is allowed to submit transactions that exceed credit limits,આ ભૂમિકાને વ્યવહારો સબમિટ કરવાની મંજૂરી છે જે ક્રેડિટ મર્યાદાથી વધુ છે,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","જો "મહિનાઓ" પસંદ કરવામાં આવે છે, તો એક મહિનામાં દિવસોની સંખ્યાને ધ્યાનમાં લીધા વિના, દર મહિને સ્થગિત રકમ અથવા સ્થગિત આવક અથવા ખર્ચ તરીકે બુક કરવામાં આવશે. જો વિલંબિત આવક અથવા ખર્ચ આખા મહિના માટે બુક ન કરવામાં આવે તો તે પ્રોક્ટેટ કરવામાં આવશે",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","જો આને ચકાસાયેલ નથી, તો સ્થગિત આવક અથવા ખર્ચ બુક કરવા માટે ડાયરેક્ટ જી.એલ. એન્ટ્રીઝ બનાવવામાં આવશે",
+Show Inclusive Tax in Print,છાપવામાં સમાવિષ્ટ કર બતાવો,
+Only select this if you have set up the Cash Flow Mapper documents,ફક્ત આ પસંદ કરો જો તમે કેશ ફ્લો મેપર દસ્તાવેજો સેટ કર્યા હોય,
+Payment Channel,ચુકવણી ચેનલ,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,શું ખરીદીના ઇન્વ Orderઇસ અને રસીદ બનાવટ માટે ખરીદી Orderર્ડર આવશ્યક છે?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,શું ખરીદીની રસીદ ખરીદી ઇન્વoiceઇસ બનાવટ માટે જરૂરી છે?,
+Maintain Same Rate Throughout the Purchase Cycle,ખરીદી ચક્ર દરમ્યાન સમાન દર જાળવો,
+Allow Item To Be Added Multiple Times in a Transaction,વ્યવહારમાં આઇટમને બહુવિધ ટાઇમ્સ ઉમેરવાની મંજૂરી આપો,
+Suppliers,સપ્લાયર્સ,
+Send Emails to Suppliers,સપ્લાયર્સને ઇમેઇલ્સ મોકલો,
+Select a Supplier,સપ્લાયર પસંદ કરો,
+Cannot mark attendance for future dates.,ભાવિ તારીખો માટે હાજરીને માર્ક કરી શકાતી નથી.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},શું તમે હાજરીને અપડેટ કરવા માંગો છો?<br> હાજર: {0}<br> ગેરહાજર: {1},
+Mpesa Settings,એમપેસા સેટિંગ્સ,
+Initiator Name,પ્રારંભિક નામ,
+Till Number,નંબર સુધી,
+Sandbox,સેન્ડબોક્સ,
+ Online PassKey,Passનલાઇન પાસકે,
+Security Credential,સુરક્ષા ઓળખપત્ર,
+Get Account Balance,એકાઉન્ટ બેલેન્સ મેળવો,
+Please set the initiator name and the security credential,કૃપા કરી પ્રારંભિક નામ અને સુરક્ષા ઓળખપત્ર સેટ કરો,
+Inpatient Medication Entry,ઇનપેશન્ટ દવાઓની એન્ટ્રી,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),આઇટમ કોડ (ડ્રગ),
+Medication Orders,દવાનો ઓર્ડર,
+Get Pending Medication Orders,બાકી દવાઓના ઓર્ડર મેળવો,
+Inpatient Medication Orders,ઇનપેશન્ટ દવાઓના ઓર્ડર,
+Medication Warehouse,દવા વેરહાઉસ,
+Warehouse from where medication stock should be consumed,વેરહાઉસ જ્યાંથી દવાઓના સ્ટોકનું સેવન કરવું જોઈએ,
+Fetching Pending Medication Orders,બાકી ચિકિત્સાના ઓર્ડર્સ મેળવવામાં,
+Inpatient Medication Entry Detail,ઇનપેશન્ટ દવાઓની એન્ટ્રી વિગત,
+Medication Details,દવાઓની વિગતો,
+Drug Code,ડ્રગ કોડ,
+Drug Name,ડ્રગ નામ,
+Against Inpatient Medication Order,ઇનપેશન્ટ મેડિકેશન ઓર્ડર સામે,
+Against Inpatient Medication Order Entry,ઇનપેશન્ટ મેડિકેશન ઓર્ડર એન્ટ્રી સામે,
+Inpatient Medication Order,ઇનપેશન્ટ દવા ઓર્ડર,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,કુલ ઓર્ડર,
+Completed Orders,પૂર્ણ ઓર્ડર,
+Add Medication Orders,દવાઓના ઓર્ડર ઉમેરો,
+Adding Order Entries,ઓર્ડર પ્રવેશો ઉમેરવાનું,
+{0} medication orders completed,Orders 0} દવા ઓર્ડર પૂર્ણ,
+{0} medication order completed,Order 0} દવાનો ઓર્ડર પૂર્ણ થયો,
+Inpatient Medication Order Entry,ઇનપેશન્ટ મેડિકેશન ઓર્ડર એન્ટ્રી,
+Is Order Completed,ઓર્ડર પૂર્ણ થયો,
+Employee Records to Be Created By,દ્વારા બનાવનારી કર્મચારી રેકોર્ડ્સ,
+Employee records are created using the selected field,કર્મચારીના રેકોર્ડ્સ પસંદ કરેલા ફીલ્ડનો ઉપયોગ કરીને બનાવવામાં આવે છે,
+Don't send employee birthday reminders,કર્મચારીના જન્મદિવસની રીમાઇન્ડર્સ મોકલશો નહીં,
+Restrict Backdated Leave Applications,બેકડેટેડ રજા એપ્લિકેશનોને પ્રતિબંધિત કરો,
+Sequence ID,સિક્વન્સ આઈડી,
+Sequence Id,સિક્વન્સ આઈડી,
+Allow multiple material consumptions against a Work Order,વર્ક ઓર્ડરની વિરુદ્ધ બહુવિધ સામગ્રી વપરાશની મંજૂરી આપો,
+Plan time logs outside Workstation working hours,વર્કસ્ટેશનના કામના કલાકોની બહાર સમય લ timeગ્સની યોજના બનાવો,
+Plan operations X days in advance,X દિવસ અગાઉથી કામગીરીની યોજના,
+Time Between Operations (Mins),કામગીરી વચ્ચેનો સમય (મિનિટ),
+Default: 10 mins,ડિફaultલ્ટ: 10 મિનિટ,
+Overproduction for Sales and Work Order,વેચાણ અને વર્ક ઓર્ડર માટે વધુ ઉત્પાદન,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","કાચી સામગ્રીના નવીનતમ મૂલ્યાંકન દર / ભાવ સૂચિ દર / છેલ્લી ખરીદી દર પર આધારીત, શેડ્યૂલર દ્વારા BOM ખર્ચને આપમેળે અપડેટ કરો",
+Purchase Order already created for all Sales Order items,ખરીદીના ઓર્ડર પહેલાથી જ બધી સેલ્સ ઓર્ડર આઇટમ્સ માટે બનાવેલ છે,
+Select Items,આઇટમ્સ પસંદ કરો,
+Against Default Supplier,ડિફોલ્ટ સપ્લાયર સામે,
+Auto close Opportunity after the no. of days mentioned above,ના પછી ઓટો બંધ તકો. ઉપર જણાવેલ દિવસો,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,શું સેલ્સ oiceર્ડર વેચાણ ઇન્વoiceઇસ અને ડિલિવરી નોંધ બનાવટ માટે જરૂરી છે?,
+Is Delivery Note Required for Sales Invoice Creation?,શું ડિલિવરી નોટ વેચાણના ઇન્વoiceઇસ બનાવટ માટે જરૂરી છે?,
+How often should Project and Company be updated based on Sales Transactions?,વેચાણ અને વ્યવહારોના આધારે પ્રોજેક્ટ અને કંપનીને કેટલી વાર અપડેટ કરવું જોઈએ?,
+Allow User to Edit Price List Rate in Transactions,વ્યવહારમાં વપરાશકર્તાને ભાવ સૂચિ દરમાં ફેરફાર કરવાની મંજૂરી આપો,
+Allow Item to Be Added Multiple Times in a Transaction,ટ્રાંઝેક્શનમાં આઇટમને બહુવિધ ટાઇમ્સ ઉમેરવાની મંજૂરી આપો,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,ગ્રાહકની ખરીદી ઓર્ડરની વિરુદ્ધ બહુવિધ વેચાણ Ordર્ડર્સને મંજૂરી આપો,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,ખરીદી દર અથવા મૂલ્યાંકન દરની સામે આઇટમ માટે વેચવાની કિંમતને માન્ય કરો,
+Hide Customer's Tax ID from Sales Transactions,વેચાણના વ્યવહારોથી ગ્રાહકનો ટેક્સ આઈડી છુપાવો,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Theર્ડર કરેલા જથ્થાની તુલનામાં તમને જે ટકાવારી પ્રાપ્ત કરવાની અથવા વધુ પહોંચાડવાની મંજૂરી છે. ઉદાહરણ તરીકે, જો તમે 100 એકમોનો ઓર્ડર આપ્યો છે, અને તમારું ભથ્થું 10% છે, તો તમને 110 એકમો પ્રાપ્ત કરવાની મંજૂરી છે.",
+Action If Quality Inspection Is Not Submitted,જો ગુણવત્તા નિરીક્ષણ સબમિટ ન કરાયું હોય તો ક્રિયા,
+Auto Insert Price List Rate If Missing,ગુમ થયેલ હોય તો સ્વત In શામેલ ભાવ સૂચિ દર,
+Automatically Set Serial Nos Based on FIFO,FIFO ના આધારે આપમેળે સીરીયલ નંબર સેટ કરો,
+Set Qty in Transactions Based on Serial No Input,સીરીયલ ના ઇનપુટના આધારે ટ્રાન્ઝેક્શનમાં ક્યુટી સેટ કરો,
+Raise Material Request When Stock Reaches Re-order Level,જ્યારે સ્ટોક રી-ઓર્ડર સ્તર પર પહોંચે છે ત્યારે સામગ્રી વિનંતી વધારવી,
+Notify by Email on Creation of Automatic Material Request,સ્વચાલિત સામગ્રી વિનંતી બનાવટ પર ઇમેઇલ દ્વારા સૂચિત,
+Allow Material Transfer from Delivery Note to Sales Invoice,ડિલિવરી નોટથી સેલ્સ ઇન્વoiceઇસમાં મટિરીયલ ટ્રાન્સફરની મંજૂરી આપો,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,ખરીદી રસીદથી ખરીદી ઇન્વoiceઇસ પર સામગ્રીના સ્થાનાંતરણને મંજૂરી આપો,
+Freeze Stocks Older Than (Days),સ્ટોક્સ થી વધુ જૂના (દિવસો),
+Role Allowed to Edit Frozen Stock,ફ્રોઝન સ્ટોકને સંપાદિત કરવાની ભૂમિકાને મંજૂરી છે,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,"ચુકવણી એન્ટ્રી un 0 The ની અવેજી રકમ, બેંક ટ્રાંઝેક્શનની અનવેલેટેડ રકમ કરતા વધારે છે",
+Payment Received,ચુકવણી પ્રાપ્ત થઈ,
+Attendance cannot be marked outside of Academic Year {0},શૈક્ષણિક વર્ષ of 0 Year ની બહાર હાજરીને ચિહ્નિત કરી શકાતી નથી,
+Student is already enrolled via Course Enrollment {0},વિદ્યાર્થી પહેલાથી જ કોર્સ નોંધણી {0 via દ્વારા નોંધાયેલ છે,
+Attendance cannot be marked for future dates.,ભાવિ તારીખો માટે હાજરી ચિહ્નિત કરી શકાતી નથી.,
+Please add programs to enable admission application.,પ્રવેશ એપ્લિકેશનને સક્ષમ કરવા માટે કૃપા કરીને પ્રોગ્રામ્સ ઉમેરો.,
+The following employees are currently still reporting to {0}:,નીચેના કર્મચારીઓ હાલમાં still 0} ને રિપોર્ટ કરી રહ્યાં છે:,
+Please make sure the employees above report to another Active employee.,કૃપા કરીને ખાતરી કરો કે ઉપરના કર્મચારીઓ બીજા સક્રિય કર્મચારીને જાણ કરે છે.,
+Cannot Relieve Employee,કર્મચારીને રાહત આપી શકાતી નથી,
+Please enter {0},કૃપા કરી enter 0 enter દાખલ કરો,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',કૃપા કરીને બીજી ચુકવણી પદ્ધતિ પસંદ કરો. એમપેસા ચલણ '{0}' માં ટ્રાન્ઝેક્શનનું સમર્થન કરતી નથી,
+Transaction Error,વ્યવહાર ભૂલ,
+Mpesa Express Transaction Error,એમપેસા એક્સપ્રેસ ટ્રાંઝેક્શન ભૂલ,
+"Issue detected with Mpesa configuration, check the error logs for more details","એમપીસા રૂપરેખાંકન સાથે ઇશ્યુ મળી, વધુ વિગતો માટે ભૂલ લsગ્સ તપાસો",
+Mpesa Express Error,એમપેસા એક્સપ્રેસ ભૂલ,
+Account Balance Processing Error,એકાઉન્ટ બેલેન્સ પ્રોસેસીંગ ભૂલ,
+Please check your configuration and try again,કૃપા કરીને તમારું ગોઠવણી તપાસો અને ફરીથી પ્રયાસ કરો,
+Mpesa Account Balance Processing Error,એમપેસા એકાઉન્ટ બેલેન્સ પ્રોસેસિંગ ભૂલ,
+Balance Details,સંતુલન વિગતો,
+Current Balance,વર્તમાન રકમ,
+Available Balance,વધેલી રાશી,
+Reserved Balance,અનામત સંતુલન,
+Uncleared Balance,અસ્પષ્ટ સંતુલન,
+Payment related to {0} is not completed,{0 to થી સંબંધિત ચુકવણી પૂર્ણ થઈ નથી,
+Row #{}: Item Code: {} is not available under warehouse {}.,પંક્તિ # {}: આઇટમ કોડ: {w વેરહાઉસ under under હેઠળ ઉપલબ્ધ નથી.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,પંક્તિ # {}: સ્ટોક જથ્થો આઇટમ કોડ માટે પૂરતો નથી: are w વેરહાઉસ હેઠળ {}. ઉપલબ્ધ જથ્થો {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,પંક્તિ # {}: મહેરબાની કરીને સીરીયલ નંબર અને આઇટમ સામેની બેચ પસંદ કરો: {} અથવા વ્યવહાર પૂર્ણ કરવા માટે તેને દૂર કરો.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,પંક્તિ # {}: આઇટમ સામે કોઈ સીરીયલ નંબર પસંદ નથી:}}. કૃપા કરીને એક પસંદ કરો અથવા વ્યવહાર પૂર્ણ કરવા માટે તેને દૂર કરો.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,પંક્તિ # {}: આઇટમ સામે કોઈ બેચ પસંદ નથી:}}. વ્યવહાર પૂર્ણ કરવા માટે કૃપા કરીને એક બેચ પસંદ કરો અથવા તેને દૂર કરો.,
+Payment amount cannot be less than or equal to 0,ચુકવણીની રકમ 0 કરતા ઓછી અથવા સમાન હોઇ શકે નહીં,
+Please enter the phone number first,કૃપા કરીને પહેલા ફોન નંબર દાખલ કરો,
+Row #{}: {} {} does not exist.,પંક્તિ # {}: {} {} અસ્તિત્વમાં નથી.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,ઉદઘાટન {2} ઇન્વicesઇસેસ બનાવવા માટે પંક્તિ # {0}: {1 required જરૂરી છે,
+You had {} errors while creating opening invoices. Check {} for more details,પ્રારંભિક ઇન્વoicesઇસેસ બનાવતી વખતે તમારી {} ભૂલો હતી. વધુ વિગતો માટે {Check તપાસો,
+Error Occured,ભૂલ થઈ,
+Opening Invoice Creation In Progress,ઇનવોઇસ બનાવટની પ્રક્રિયા ચાલુ છે,
+Creating {} out of {} {},{} {Of માંથી Creat} બનાવી રહ્યા છે,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(સીરીયલ નંબર: {0}) સેવન કરી શકાતું નથી કારણ કે તે ફુલફિલ સેલ્સ ઓર્ડર {1 to માં અનામત છે.,
+Item {0} {1},આઇટમ {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,વેરહાઉસ} 1} હેઠળ આઇટમ {0} માટે છેલ્લું સ્ટોક ટ્રાન્ઝેક્શન {2 on પર હતું.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,વેરહાઉસ} 1} હેઠળ આઇટમ {0 for માટે સ્ટોક ટ્રાન્ઝેક્શન આ સમય પહેલાં પોસ્ટ કરી શકાતા નથી.,
+Posting future stock transactions are not allowed due to Immutable Ledger,ઇમ્યુટેબલ લેજરને કારણે ભાવિ શેરના વ્યવહારોની મંજૂરી નથી,
+A BOM with name {0} already exists for item {1}.,આઇટમ {1} માટે {0 name નામનો BOM પહેલેથી અસ્તિત્વમાં છે.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1 you શું તમે આઇટમનું નામ બદલ્યું છે? કૃપા કરીને એડમિનિસ્ટ્રેટર / ટેક સપોર્ટનો સંપર્ક કરો,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},પંક્તિ પર # {0}: ક્રમ ID {1 previous પહેલાનાં પંક્તિ ક્રમ ID {2 than કરતા ઓછો હોઈ શકતો નથી,
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) {2} ({3}) ની બરાબર હોવું જોઈએ,
+"{0}, complete the operation {1} before the operation {2}.","{0}, ઓપરેશન} 2} પહેલાં ઓપરેશન} 1} પૂર્ણ કરો.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,સીરીયલ નંબર દ્વારા ડિલિવરી સુનિશ્ચિત કરી શકાતી નથી કારણ કે {0 I આઇટમ {0 Ser સિરીયલ નં દ્વારા ડિલિવરીની ખાતરી સાથે અને સાથે ઉમેરવામાં આવે છે.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,આઇટમ {0 no નો સીરીયલ નંબર નથી ફક્ત સીરીયલાઇઝ્ડ વસ્તુઓની સીરીઅલ નંબર પર આધારિત ડિલિવરી થઈ શકે છે,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,આઇટમ {0} માટે કોઈ સક્રિય BOM મળ્યું નથી. સીરીયલ નં દ્વારા ડિલિવરી સુનિશ્ચિત કરી શકાતી નથી,
+No pending medication orders found for selected criteria,પસંદ કરેલા માપદંડ માટે કોઈ બાકી medicationષધ ઓર્ડર મળ્યા નથી,
+From Date cannot be after the current date.,તારીખથી વર્તમાન તારીખ પછીની હોઈ શકતી નથી.,
+To Date cannot be after the current date.,આજની તારીખ વર્તમાન તારીખ પછીની હોઈ શકતી નથી.,
+From Time cannot be after the current time.,સમયનો સમય વર્તમાન સમય પછીનો હોઈ શકતો નથી.,
+To Time cannot be after the current time.,ટુ ટાઈમ વર્તમાન સમય પછી ન હોઈ શકે.,
+Stock Entry {0} created and ,સ્ટોક એન્ટ્રી {0} બનાવી અને,
+Inpatient Medication Orders updated successfully,ઇનપેશન્ટ મેડિકેશન ઓર્ડર્સ સફળતાપૂર્વક અપડેટ થયા,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},પંક્તિ {0}: રદ થયેલ ઇનપેશન્ટ મેડિકેશન ઓર્ડર In 1 against સામે ઇનપેશન્ટ મેડિકેશન એન્ટ્રી બનાવી શકાતી નથી.,
+Row {0}: This Medication Order is already marked as completed,પંક્તિ {0}: આ દવા ઓર્ડર પહેલાથી જ પૂર્ણ થયેલ તરીકે ચિહ્નિત થયેલ છે,
+Quantity not available for {0} in warehouse {1},વેરહાઉસ {1} માં {0 for માટે માત્રા ઉપલબ્ધ નથી,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,કૃપા કરીને સ્ટોક સેટિંગ્સમાં નેગેટિવ સ્ટોકને મંજૂરી આપો અથવા આગળ વધવા માટે સ્ટોક એન્ટ્રી બનાવો.,
+No Inpatient Record found against patient {0},દર્દી against 0 against સામે કોઈ ઇનપેશન્ટ રેકોર્ડ મળ્યો નથી.,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,પેશન્ટ એન્કાઉન્ટર In 1} સામે ઇનપેશન્ટ મેડિકેશન ઓર્ડર {0} પહેલેથી હાજર છે.,
+Allow In Returns,રીટર્ન માં મંજૂરી આપો,
+Hide Unavailable Items,અનુપલબ્ધ વસ્તુઓ છુપાવો,
+Apply Discount on Discounted Rate,ડિસ્કાઉન્ટ દરે ડિસ્કાઉન્ટ લાગુ કરો,
+Therapy Plan Template,ઉપચાર યોજના Templateાંચો,
+Fetching Template Details,Templateાંચો વિગતો લાવી રહ્યું છે,
+Linked Item Details,જોડાયેલ વસ્તુ વિગતો,
+Therapy Types,ઉપચારના પ્રકાર,
+Therapy Plan Template Detail,થેરપી યોજના Templateાંચો વિગતવાર,
+Non Conformance,અનુરૂપ ન હોવું,
+Process Owner,પ્રક્રિયા માલિક,
+Corrective Action,સુધારાત્મક પગલાં,
+Preventive Action,નિવારક ક્રિયા,
+Problem,સમસ્યા,
+Responsible,જવાબદાર,
+Completion By,દ્વારા પૂર્ણ,
+Process Owner Full Name,પ્રક્રિયા માલિકનું સંપૂર્ણ નામ,
+Right Index,જમણું અનુક્રમણિકા,
+Left Index,ડાબું અનુક્રમણિકા,
+Sub Procedure,પેટા કાર્યવાહી,
+Passed,પાસ થઈ,
+Print Receipt,રસીદ રસીદ,
+Edit Receipt,રસીદ સંપાદિત કરો,
+Focus on search input,શોધ ઇનપુટ પર ધ્યાન કેન્દ્રિત કરો,
+Focus on Item Group filter,આઇટમ જૂથ ફિલ્ટર પર ધ્યાન કેન્દ્રિત કરો,
+Checkout Order / Submit Order / New Order,ચેકઆઉટ ઓર્ડર / સબમિટ ઓર્ડર / નવો ઓર્ડર,
+Add Order Discount,ઓર્ડર ડિસ્કાઉન્ટ ઉમેરો,
+Item Code: {0} is not available under warehouse {1}.,આઇટમ કોડ: are 0 w વેરહાઉસ under 1} હેઠળ ઉપલબ્ધ નથી.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,વેરહાઉસ} 1} હેઠળ આઇટમ {0} માટે સીરીયલ નંબરો અનુપલબ્ધ છે. કૃપા કરીને વેરહાઉસ બદલવાનો પ્રયાસ કરો.,
+Fetched only {0} available serial numbers.,ફક્ત {0} ઉપલબ્ધ સિરીયલ નંબરો મેળવ્યાં.,
+Switch Between Payment Modes,ચુકવણી મોડ્સ વચ્ચે સ્વિચ કરો,
+Enter {0} amount.,{0} રકમ દાખલ કરો.,
+You don't have enough points to redeem.,તમારી પાસે રિડીમ કરવા માટે પૂરતા પોઇન્ટ નથી.,
+You can redeem upto {0}.,તમે {0 up સુધી રિડીમ કરી શકો છો.,
+Enter amount to be redeemed.,છૂટકારો મેળવવા માટે રકમ દાખલ કરો.,
+You cannot redeem more than {0}.,તમે {0 more કરતા વધારે રિડીમ કરી શકતા નથી.,
+Open Form View,ફોર્મ વ્યૂ ખોલો,
+POS invoice {0} created succesfully,પોસ ઇન્વoiceઇસ {0 suc સફળતાપૂર્વક બનાવેલ છે,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,આઇટમ કોડ માટે સ્ટોક જથ્થો પૂરતો નથી: are 0 w વેરહાઉસ} 1} હેઠળ. ઉપલબ્ધ જથ્થો {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,સીરીયલ નંબર: {0 નો પહેલેથી જ બીજા POS ઇન્વoiceઇસમાં ટ્રાન્ઝેક્શન કરવામાં આવ્યું છે.,
+Balance Serial No,બેલેન્સ સીરીયલ નં,
+Warehouse: {0} does not belong to {1},વેરહાઉસ: {0 {{1} સાથે સંબંધિત નથી,
+Please select batches for batched item {0},કૃપા કરી બેચેડ આઇટમ bat 0 for માટે બchesચેસ પસંદ કરો,
+Please select quantity on row {0},કૃપા કરી પંક્તિ પર જથ્થો પસંદ કરો {0},
+Please enter serial numbers for serialized item {0},સીરીયલાઇઝ્ડ આઇટમ serial 0 for માટે કૃપા કરી ક્રમાંક નંબરો દાખલ કરો,
+Batch {0} already selected.,બેચ} 0} પહેલેથી જ પસંદ કરેલ છે.,
+Please select a warehouse to get available quantities,કૃપા કરીને ઉપલબ્ધ માત્રા મેળવવા માટે વેરહાઉસ પસંદ કરો,
+"For transfer from source, selected quantity cannot be greater than available quantity","સ્રોતમાંથી સ્થાનાંતરણ માટે, પસંદ કરેલા જથ્થા ઉપલબ્ધ માત્રા કરતા વધારે ન હોઈ શકે",
+Cannot find Item with this Barcode,આ બારકોડથી આઇટમ શોધી શકાતી નથી,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0 mand ફરજિયાત છે. કદાચ ચલણ વિનિમય રેકોર્ડ {1} થી {2 for માટે બનાવવામાં આવ્યો નથી,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{એ તેની સાથે જોડાયેલ સંપત્તિ સબમિટ કરી છે. ખરીદીનું વળતર બનાવવા માટે તમારે સંપત્તિઓને રદ કરવાની જરૂર છે.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,આ દસ્તાવેજ રદ કરી શકાતો નથી કારણ કે તે સબમિટ કરેલી સંપત્તિ {0} સાથે જોડાયેલ છે. કૃપા કરીને ચાલુ રાખવા માટે તેને રદ કરો.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,પંક્તિ # {}: સીરીયલ નંબર {પહેલાથી જ બીજા પીઓએસ ઇન્વ Invઇસમાં ટ્રાંઝેક્ટ કરવામાં આવી છે. કૃપા કરી માન્ય સિરીયલ નં.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,પંક્તિ # {}: સીરીયલ નંબર. કૃપા કરી માન્ય સિરીયલ નં.,
+Item Unavailable,આઇટમ અનુપલબ્ધ,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},પંક્તિ # {}: સીરીયલ નંબર {be પરત કરી શકાતી નથી કારણ કે તેનો મૂળ ભરતિયુંમાં ટ્રાન્ઝેક્શન કરવામાં આવ્યું નથી {},
+Please set default Cash or Bank account in Mode of Payment {},કૃપા કરીને ચુકવણીના મોડમાં ડિફોલ્ટ કેશ અથવા બેંક એકાઉન્ટ સેટ કરો}},
+Please set default Cash or Bank account in Mode of Payments {},કૃપા કરીને ચુકવણીના મોડમાં ડિફ defaultલ્ટ કેશ અથવા બેંક એકાઉન્ટ સેટ કરો}},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,કૃપા કરીને ખાતરી કરો કે}} એકાઉન્ટ એ બેલેન્સ શીટ એકાઉન્ટ છે. તમે પેરેંટ એકાઉન્ટને બેલેન્સ શીટ એકાઉન્ટમાં બદલી શકો છો અથવા કોઈ અલગ એકાઉન્ટ પસંદ કરી શકો છો.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,કૃપા કરીને ખાતરી કરો કે {} એકાઉન્ટ ચૂકવણીપાત્ર એકાઉન્ટ છે. ચૂકવણીપાત્ર પર એકાઉન્ટ પ્રકાર બદલો અથવા કોઈ અલગ એકાઉન્ટ પસંદ કરો.,
+Row {}: Expense Head changed to {} ,પંક્તિ {}: ખર્ચનો માથા બદલીને changed to,
+because account {} is not linked to warehouse {} ,કારણ કે {account એકાઉન્ટ વેરહાઉસ સાથે જોડાયેલ નથી {},
+or it is not the default inventory account,અથવા તે ડિફ defaultલ્ટ ઇન્વેન્ટરી એકાઉન્ટ નથી,
+Expense Head Changed,ખર્ચના વડા બદલાયા,
+because expense is booked against this account in Purchase Receipt {},કારણ કે ખરીદીની રસીદ in in માં આ ખાતા સામે ખર્ચ બુક કરાયો છે,
+as no Purchase Receipt is created against Item {}. ,આઇટમ {against ની વિરુદ્ધ કોઈ ખરીદી રસીદ બનાવવામાં આવી નથી.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,જ્યારે ખરીદી ઇન્વoiceઇસ પછી ખરીદી રસીદ બનાવવામાં આવે છે ત્યારે કેસના હિસાબનું સંચાલન કરવા માટે આ કરવામાં આવે છે,
+Purchase Order Required for item {},આઇટમ for for માટે ખરીદી ઓર્ડર આવશ્યક છે,
+To submit the invoice without purchase order please set {} ,ખરીદી ઓર્ડર વિના ભરતિયું સબમિટ કરવા માટે કૃપા કરીને {{સેટ કરો,
+as {} in {},તરીકે {},
+Mandatory Purchase Order,ફરજિયાત ખરીદી હુકમ,
+Purchase Receipt Required for item {},આઇટમ for for માટે ખરીદીની રસીદ આવશ્યક છે,
+To submit the invoice without purchase receipt please set {} ,ખરીદીની રસીદ વિના ભરતિયું સબમિટ કરવા માટે કૃપા કરીને {set સેટ કરો,
+Mandatory Purchase Receipt,ફરજિયાત ખરીદીની રસીદ,
+POS Profile {} does not belongs to company {},પીઓએસ પ્રોફાઇલ {company કંપનીની નથી {},
+User {} is disabled. Please select valid user/cashier,વપરાશકર્તા} disabled અક્ષમ છે. કૃપા કરી માન્ય વપરાશકર્તા / કેશિયર પસંદ કરો,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,પંક્તિ # {}: રીટર્ન ઇન્વoiceઇસેસનું મૂળ ઇન્વoiceઇસ {} {} છે.,
+Original invoice should be consolidated before or along with the return invoice.,મૂળ ઇન્વ invઇસ પહેલાં અથવા વળતર ઇન્વોઇસ સાથે એકીકૃત થવું જોઈએ.,
+You can add original invoice {} manually to proceed.,આગળ વધવા માટે તમે મેન્યુઅલી અસલ ઇન્વoiceઇસ ઉમેરી શકો છો.,
+Please ensure {} account is a Balance Sheet account. ,કૃપા કરીને ખાતરી કરો કે}} એકાઉન્ટ એ બેલેન્સ શીટ એકાઉન્ટ છે.,
+You can change the parent account to a Balance Sheet account or select a different account.,તમે પેરેંટ એકાઉન્ટને બેલેન્સ શીટ એકાઉન્ટમાં બદલી શકો છો અથવા કોઈ અલગ એકાઉન્ટ પસંદ કરી શકો છો.,
+Please ensure {} account is a Receivable account. ,કૃપા કરીને ખાતરી કરો કે {} એકાઉન્ટ એક પ્રાપ્ય એકાઉન્ટ છે.,
+Change the account type to Receivable or select a different account.,ખાતાના પ્રકારને પ્રાપ્ત કરવા યોગ્યમાં બદલો અથવા કોઈ અલગ એકાઉન્ટ પસંદ કરો.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},earned canceled રદ કરી શકાતી નથી કારણ કે કમાયેલી લોયલ્ટી પોઇંટ્સ રિડીમ થઈ ગઈ છે. પહેલા {} ના {cancel રદ કરો,
+already exists,પહેલાથી અસ્તિત્વમાં,
+POS Closing Entry {} against {} between selected period,પસંદ કરેલી અવધિ વચ્ચે પોસ કલોઝિંગ એન્ટ્રી}} સામે {.,
+POS Invoice is {},પોસ ઇન્વoiceઇસ {is છે,
+POS Profile doesn't matches {},પોસ પ્રોફાઇલ {matches સાથે મેળ ખાતી નથી,
+POS Invoice is not {},પોસ ઇન્વoiceઇસ {is નથી,
+POS Invoice isn't created by user {},પોઝ ઇન્વoiceઇસ વપરાશકર્તા by by દ્વારા બનાવવામાં આવ્યું નથી,
+Row #{}: {},પંક્તિ # {}: {,
+Invalid POS Invoices,અમાન્ય POS ઇન્વvoઇસેસ,
+Please add the account to root level Company - {},કૃપા કરીને એકાઉન્ટને રૂટ લેવલની કંપનીમાં ઉમેરો - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","ચાઇલ્ડ કંપની account 0 for માટે એકાઉન્ટ બનાવતી વખતે, પેરેંટ એકાઉન્ટ {1} મળ્યું નથી. કૃપા કરીને સંબંધિત સીઓએમાં પેરેંટ એકાઉન્ટ બનાવો",
+Account Not Found,એકાઉન્ટ મળ્યું નથી,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","ચાઇલ્ડ કંપની account 0 for માટે એકાઉન્ટ બનાવતી વખતે, ખાતામાં એકાઉન્ટ તરીકે પેરેંટ એકાઉન્ટ. 1. મળ્યું.",
+Please convert the parent account in corresponding child company to a group account.,કૃપા કરીને સંબંધિત બાળક કંપનીમાં પેરેંટ એકાઉન્ટને જૂથ એકાઉન્ટમાં કન્વર્ટ કરો.,
+Invalid Parent Account,અમાન્ય પેરેંટ એકાઉન્ટ,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","ગેરસમજને ટાળવા માટે, નામ બદલવાનું ફક્ત પેરન્ટ કંપની {0} દ્વારા જ માન્ય છે.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","જો તમે આઇટમની માત્રા {2} {0} {1}, તો યોજના {3 the આઇટમ પર લાગુ કરવામાં આવશે.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","જો તમે item 0} {1} મૂલ્યની આઇટમ {2} છો, તો યોજના {3 the આઇટમ પર લાગુ કરવામાં આવશે.",
+"As the field {0} is enabled, the field {1} is mandatory.","ક્ષેત્ર {0} સક્ષમ કરેલ હોવાથી, ક્ષેત્ર {1} ફરજિયાત છે.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","ક્ષેત્ર {0} સક્ષમ કરેલ હોવાથી, ક્ષેત્ર the 1} નું મૂલ્ય 1 કરતા વધારે હોવું જોઈએ.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"આઇટમ {1} ના સીરીયલ નંબર {0 deliver આપી શકાતી નથી, કારણ કે તે ફુલફિલ સેલ્સ ઓર્ડર {2 to માટે અનામત છે",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","સેલ્સ ઓર્ડર {0} પાસે આઇટમ for 1} માટે આરક્ષણ છે, તમે ફક્ત reserved 0} સામે આરક્ષિત {1 deliver આપી શકો છો.",
+{0} Serial No {1} cannot be delivered,. 0} સીરીયલ નંબર {1} વિતરિત કરી શકાતી નથી,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},પંક્તિ {0}: કાચા માલ Sub 1} માટે સબકontન્ટ્રેક્ટ આઇટમ ફરજિયાત છે,
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","જેમ કે ત્યાં પૂરતી કાચી સામગ્રી છે, વેરહાઉસ Material 0} માટે મટીરિયલ વિનંતી આવશ્યક નથી.",
+" If you still want to proceed, please enable {0}.","જો તમે હજી પણ આગળ વધવા માંગતા હો, તો કૃપા કરીને {0 enable સક્ષમ કરો.",
+The item referenced by {0} - {1} is already invoiced,{0} - {1} દ્વારા સંદર્ભિત આઇટમ પહેલેથી જ ભરતિયું છે,
+Therapy Session overlaps with {0},ઉપચાર સત્ર {0 with સાથે ઓવરલેપ થાય છે,
+Therapy Sessions Overlapping,ઉપચાર સત્રો ઓવરલેપિંગ,
+Therapy Plans,ઉપચાર યોજનાઓ,
+"Item Code, warehouse, quantity are required on row {0}","આઇટમ કોડ, વેરહાઉસ, જથ્થો પંક્તિ પર આવશ્યક છે {0}",
+Get Items from Material Requests against this Supplier,આ સપ્લાયર સામે સામગ્રી વિનંતીઓમાંથી આઇટમ્સ મેળવો,
+Enable European Access,યુરોપિયન Enableક્સેસને સક્ષમ કરો,
+Creating Purchase Order ...,ખરીદી Orderર્ડર બનાવી રહ્યાં છે ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","નીચેની આઇટમ્સના ડિફaultલ્ટ સપ્લાયર્સમાંથી સપ્લાયર પસંદ કરો. પસંદગી પર, ફક્ત પસંદ કરેલા સપ્લાયરની વસ્તુઓ સામે ખરીદ ઓર્ડર આપવામાં આવશે.",
+Row #{}: You must select {} serial numbers for item {}.,પંક્તિ # {}: તમારે આઇટમ for for માટે સીરીયલ નંબરો પસંદ કરવા આવશ્યક છે.,
diff --git a/erpnext/translations/he.csv b/erpnext/translations/he.csv
index a3d76d5..29e6f6a 100644
--- a/erpnext/translations/he.csv
+++ b/erpnext/translations/he.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},מס סוג בפועל לא ניתן כלול במחיר הפריט בשורת {0},
Add,להוסיף,
Add / Edit Prices,להוסיף מחירים / עריכה,
-Add All Suppliers,הוסף את כל הספקים,
Add Comment,הוסף תגובה,
Add Customers,הוסף לקוחות,
Add Employees,הוסף עובדים,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',לא ניתן לנכות כאשר הקטגוריה היא עבור 'הערכת שווי' או 'תפוצה וסך הכל',
"Cannot delete Serial No {0}, as it is used in stock transactions","לא יכול למחוק את מספר סידורי {0}, כפי שהוא משמש בעסקות מניות",
Cannot enroll more than {0} students for this student group.,לא יכול לרשום יותר מ {0} סטודנטים עבור קבוצת סטודנטים זה.,
-Cannot find Item with this barcode,לא ניתן למצוא פריט עם ברקוד זה,
Cannot find active Leave Period,לא ניתן למצוא תקופת חופשה פעילה,
Cannot produce more Item {0} than Sales Order quantity {1},לא יכול לייצר יותר פריט {0} מאשר כמות להזמין מכירות {1},
Cannot promote Employee with status Left,לא ניתן לקדם עובד עם סטטוס שמאל,
Cannot refer row number greater than or equal to current row number for this Charge type,לא יכול להתייחס מספר השורה גדול או שווה למספר השורה הנוכחי לסוג השעבוד זה,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"לא ניתן לבחור סוג תשלום כ'בסכום שורה הקודם ""או"" בסך הכל שורה הקודם 'לשורה הראשונה",
-Cannot set a received RFQ to No Quote,לא ניתן להגדיר RFQ שהתקבל ללא הצעת מחיר,
Cannot set as Lost as Sales Order is made.,לא ניתן להגדיר כאבודים כלהזמין מכירות נעשה.,
Cannot set authorization on basis of Discount for {0},לא ניתן להגדיר הרשאות על בסיס הנחה עבור {0},
Cannot set multiple Item Defaults for a company.,לא ניתן להגדיר ברירות מחדל של פריט עבור חברה.,
@@ -521,7 +518,6 @@
Chargeble,חיוב מטען,
Charges are updated in Purchase Receipt against each item,חיובים מתעדכנות בקבלת רכישה כנגד כל פריט,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","תשלום נוסף שיחולק לפי אופן יחסי על כמות פריט או סכום, בהתאם לבחירתך",
-Chart Of Accounts,תרשים של חשבונות,
Chart of Cost Centers,תרשים של מרכזי עלות,
Check all,סמן הכל,
Checkout,לבדוק,
@@ -581,7 +577,6 @@
Compensatory Off,Off המפצה,
Compensatory leave request days not in valid holidays,ימי בקשת חופשת פיצויים שאינם בחגים תקפים,
Complaint,תְלוּנָה,
-Completed Qty can not be greater than 'Qty to Manufacture',"כמות שהושלמה לא יכולה להיות גדולה מ 'כמות לייצור """,
Completion Date,תאריך סיום,
Computer,מחשב,
Condition,מצב,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","יצירה וניהול של מעכל דוא""ל יומי, שבועית וחודשית.",
Create customer quotes,צור הצעות מחיר ללקוחות,
Create rules to restrict transactions based on values.,יצירת כללים להגבלת עסקות המבוססות על ערכים.,
-Created By,נוצר על-ידי,
Created {0} scorecards for {1} between: ,יצר {0} כרטיסי ניקוד עבור {1} בין:,
Creating Company and Importing Chart of Accounts,יצירת חברה וייבוא תרשים חשבונות,
Creating Fees,יצירת עמלות,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,לא ניתן להגיש העברת עובדים לפני תאריך ההעברה,
Employee cannot report to himself.,עובד לא יכול לדווח לעצמו.,
Employee relieved on {0} must be set as 'Left',עובד הקלה על {0} חייב להיות מוגדרים כ'שמאל ',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,לא ניתן להגדיר את מצב העובד כ'שמאל 'מכיוון שהעובדים הבאים מדווחים כעת לעובד זה:,
Employee {0} already submited an apllication {1} for the payroll period {2},עובד {0} כבר הגיש יישום {1} לתקופת השכר {2},
Employee {0} has already applied for {1} between {2} and {3} : ,עובד {0} כבר הגיש בקשה ל {1} בין {2} ל- {3}:,
Employee {0} has no maximum benefit amount,לעובד {0} אין סכום קצבה מקסימלי,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,לשורה {0}: הזן כמות מתוכננת,
"For {0}, only credit accounts can be linked against another debit entry","עבור {0}, רק חשבונות האשראי יכולים להיות מקושרים נגד כניסת חיוב נוספת",
"For {0}, only debit accounts can be linked against another credit entry","עבור {0}, רק חשבונות החיוב יכולים להיות מקושרים נגד כניסת אשראי אחרת",
-Form View,תצוגת טופס,
Forum Activity,פעילות בפורום,
Free item code is not selected,קוד פריט בחינם לא נבחר,
Freight and Forwarding Charges,הוצאות הובלה והשילוח,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","לעזוב לא יכול להיות מוקצה לפני {0}, כאיזון חופשה כבר היה בשיא הקצאת חופשת העתיד יועבר לשאת {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","השאר לא ניתן ליישם / בוטל לפני {0}, כאיזון חופשה כבר היה בשיא הקצאת חופשת העתיד יועבר לשאת {1}",
Leave of type {0} cannot be longer than {1},Leave מסוג {0} אינו יכול להיות ארוך מ- {1},
-Leave the field empty to make purchase orders for all suppliers,השאר את השדה ריק כדי לבצע הזמנות רכש לכל הספקים,
Leaves,משאיר,
Leaves Allocated Successfully for {0},עלים שהוקצו בהצלחה עבור {0},
Leaves has been granted sucessfully,עלים הוענקו בהצלחה,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,אין פריטים עם שטר החומרים לייצור,
No Items with Bill of Materials.,אין פריטים עם כתב חומרים.,
No Permission,אין אישור,
-No Quote,אין הצעת מחיר,
No Remarks,אין הערות,
No Result to submit,אין תוצאה להגיש,
No Salary Structure assigned for Employee {0} on given date {1},לא הוקצה מבנה שכר לעובד {0} בתאריך נתון {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,חפיפה בין תנאים מצאו:,
Owner,בעלים,
PAN,מחבת,
-PO already created for all sales order items,PO כבר נוצר עבור כל פריטי הזמנת המכירה,
POS,POS,
POS Profile,פרופיל קופה,
POS Profile is required to use Point-of-Sale,פרופיל קופה נדרש כדי להשתמש בנקודת המכירה,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,אנא בחר Charge סוג ראשון,
Please select Company,אנא בחר חברה,
Please select Company and Designation,אנא בחר חברה וייעוד,
-Please select Company and Party Type first,אנא בחר סוג החברה והמפלגה ראשון,
Please select Company and Posting Date to getting entries,אנא בחר חברה ותאריך פרסום לקבלת רשומות,
Please select Company first,אנא בחר החברה ראשונה,
Please select Completion Date for Completed Asset Maintenance Log,אנא בחר תאריך סיום עבור יומן תחזוקת הנכסים שהושלם,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,שורת {0}: יחידת מידת המרת פקטור הוא חובה,
Row {0}: select the workstation against the operation {1},שורה {0}: בחר את תחנת העבודה כנגד הפעולה {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,שורה {0}: {1} נדרשים מספרים סידוריים לפריט {2}. סיפקת את {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,שורה {0}: {1} נדרשת ליצירת חשבוניות הפתיחה {2},
Row {0}: {1} must be greater than 0,שורה {0}: {1} חייב להיות גדול מ- 0,
Row {0}: {1} {2} does not match with {3},שורת {0}: {1} {2} אינה תואמת עם {3},
Row {0}:Start Date must be before End Date,{0} שורה: תאריך ההתחלה חייב להיות לפני תאריך הסיום,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,שלח דוא"ל לבדיקת מענק,
Send Now,שלח עכשיו,
Send SMS,שלח SMS,
-Send Supplier Emails,שלח הודעות דוא"ל ספק,
Send mass SMS to your contacts,שלח SMS המוני לאנשי הקשר שלך,
Sensitivity,רְגִישׁוּת,
Sent,נשלח,
-Serial #,סידורי #,
Serial No and Batch,אין ו אצווה סידורי,
Serial No is mandatory for Item {0},מספר סידורי הוא חובה עבור פריט {0},
Serial No {0} does not belong to Batch {1},מספר סידורי {0} אינו שייך לאצווה {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,שמה של החברה שלך שאתה מגדיר את המערכת הזאת.,
The number of shares and the share numbers are inconsistent,מספר המניות ומספרי המניות אינם עקביים,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,חשבון שער התשלום בתכנית {0} שונה מחשבון שער התשלום בבקשת תשלום זו,
-The request for quotation can be accessed by clicking on the following link,ניתן לגשת לבקשה להצעת מחיר על ידי לחיצה על הקישור הבא,
The selected BOMs are not for the same item,בומס שנבחר אינו תמורת אותו הפריט,
The selected item cannot have Batch,הפריט שנבחר לא יכול להיות אצווה,
The seller and the buyer cannot be the same,המוכר והקונה לא יכולים להיות זהים,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},הסכום הכולל של רכיב ההטבה הגמיש {0} לא צריך להיות פחות מההטבות המקסימליות {1},
Total hours: {0},סה"כ שעות: {0},
Total leaves allocated is mandatory for Leave Type {0},סה"כ עלים שהוקצו חובה עבור סוג חופשה {0},
-Total weightage assigned should be 100%. It is {0},"weightage סה""כ הוקצה צריך להיות 100%. זה {0}",
Total working hours should not be greater than max working hours {0},סך שעות העבודה לא צריך להיות גדול משעות העבודה המקסימליות {0},
Total {0} ({1}),סה"כ {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","סה"כ {0} לכל הפריטים הוא אפס, יתכן שתשנה את 'הפץ חיובים על סמך'",
@@ -3316,7 +3299,6 @@
What do you need help with?,עם מה אתה צריך עזרה?,
What does it do?,מה זה עושה?,
Where manufacturing operations are carried.,איפה פעולות ייצור מתבצעות.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","בעת יצירת חשבון עבור חברת ילדים {0}, חשבון האב {1} לא נמצא. אנא צור חשבון הורים בתאריך COA תואם",
White,לבן,
Wire Transfer,העברה בנקאית,
WooCommerce Products,מוצרי WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,נוצרו {0} גרסאות.,
{0} {1} created,{0} {1} נוצר,
{0} {1} does not exist,{0} {1} לא קיים,
-{0} {1} does not exist.,{0} {1} לא קיים.,
{0} {1} has been modified. Please refresh.,{0} {1} כבר שונה. אנא רענן.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} לא הוגש ולכן לא ניתן להשלים את הפעולה,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} משויך ל- {2}, אך חשבון המפלגה הוא {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} לא קיים,
{0}: {1} not found in Invoice Details table,{0}: {1} לא נמצא בטבלת פרטי החשבונית,
{} of {},{} מתוך {},
+Assigned To,מוקצה ל,
Chat,צ'אט,
Completed By,הושלם על ידי,
Conditions,תנאים,
@@ -3506,7 +3488,9 @@
Merge with existing,מיזוג עם קיים,
Office,משרד,
Orientation,נטייה,
+Parent,הורה,
Passive,פסיבי,
+Payment Failed,התשלום נכשל,
Percent,אחוזים,
Permanent,קבוע,
Personal,אישי,
@@ -3544,7 +3528,6 @@
Company field is required,נדרש שדה חברה,
Creating Dimensions...,יוצר מימדים ...,
Duplicate entry against the item code {0} and manufacturer {1},ערך כפול מול קוד הפריט {0} והיצרן {1},
-Import Chart Of Accounts from CSV / Excel files,ייבא תרשים חשבונות מקבצי CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN לא חוקי! הקלט שהזנת אינו תואם לפורמט GSTIN עבור מחזיקי UIN או ספקי שירות OIDAR שאינם תושבים,
Invoice Grand Total,חשבונית גרנד סה"כ,
Last carbon check date cannot be a future date,תאריך בדיקת הפחמן האחרון לא יכול להיות תאריך עתידי,
@@ -3556,6 +3539,7 @@
Show {0},הצג את {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","תווים מיוחדים למעט "-", "#", ".", "/", "{" ו- "}" אינם מורשים בסדרות שמות",
Target Details,פרטי יעד,
+{0} already has a Parent Procedure {1}.,{0} כבר יש נוהל הורים {1}.,
API,ממשק API,
Annual,שנתי,
Approved,אושר,
@@ -3572,6 +3556,8 @@
No data to export,אין נתונים לייצוא,
Portrait,דְיוֹקָן,
Print Heading,כותרת הדפסה,
+Scheduler Inactive,מתזמן לא פעיל,
+Scheduler is inactive. Cannot import data.,המתזמן אינו פעיל. לא ניתן לייבא נתונים.,
Show Document,הצג מסמך,
Show Traceback,הראה מסלול,
Video,וִידֵאוֹ,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},צור בדיקת איכות לפריט {0},
Creating Accounts...,יוצר חשבונות ...,
Creating bank entries...,יוצר רישומי בנק ...,
-Creating {0},יוצר {0},
Credit limit is already defined for the Company {0},מסגרת האשראי כבר מוגדרת עבור החברה {0},
Ctrl + Enter to submit,Ctrl + Enter כדי להגיש,
Ctrl+Enter to submit,Ctrl + Enter כדי להגיש,
@@ -3921,7 +3906,6 @@
Plaid public token error,שגיאת אסימון ציבורי משובץ,
Plaid transactions sync error,שגיאת סנכרון של עסקאות משובצות,
Please check the error log for details about the import errors,אנא בדוק ביומן השגיאות לקבלת פרטים אודות שגיאות הייבוא,
-Please click on the following link to set your new password,אנא לחץ על הקישור הבא כדי להגדיר את הסיסמה החדשה שלך,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,אנא צור <b>הגדרות DATEV</b> לחברה <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,אנא צור ערך יומן התאמה לסכום {0},
Please do not create more than 500 items at a time,נא לא ליצור יותר מ -500 פריטים בכל פעם,
@@ -3997,6 +3981,7 @@
Release date must be in the future,תאריך השחרור חייב להיות בעתיד,
Relieving Date must be greater than or equal to Date of Joining,תאריך הקלה חייב להיות גדול או שווה לתאריך ההצטרפות,
Rename,שינוי שם,
+Rename Not Allowed,שינוי שם אסור,
Repayment Method is mandatory for term loans,שיטת ההחזר הינה חובה עבור הלוואות לתקופה,
Repayment Start Date is mandatory for term loans,מועד התחלת ההחזר הוא חובה עבור הלוואות לתקופה,
Report Item,פריט דוח,
@@ -4043,7 +4028,6 @@
Select All,בחר הכל,
Select Difference Account,בחר חשבון ההבדל,
Select a Default Priority.,בחר עדיפות ברירת מחדל.,
-Select a Supplier from the Default Supplier List of the items below.,בחר ספק מרשימת ספקי ברירת המחדל של הפריטים שלהלן.,
Select a company,בחר חברה,
Select finance book for the item {0} at row {1},בחר ספר פיננסים לפריט {0} בשורה {1},
Select only one Priority as Default.,בחר עדיפות אחת בלבד כברירת מחדל.,
@@ -4247,7 +4231,6 @@
Actual ,בפועל,
Add to cart,הוסף לסל,
Budget,תקציב,
-Chart Of Accounts Importer,תרשים יבואן חשבונות,
Chart of Accounts,תרשים של חשבונות,
Customer database.,מאגר מידע על לקוחות.,
Days Since Last order,ימים מאז הזמנה אחרונה,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,תאריך סיום לא יכול להיות פחות מתאריך ההתחלה,
For Default Supplier (Optional),לספק ברירת מחדל (אופציונלי),
From date cannot be greater than To date,מתאריך לא יכול להיות גדול יותר מאשר תאריך,
-Get items from,קבל פריטים מ,
Group by,קבוצה על ידי,
In stock,במלאי,
Item name,שם פריט,
@@ -4532,32 +4514,22 @@
Accounts Settings,חשבונות הגדרות,
Settings for Accounts,הגדרות עבור חשבונות,
Make Accounting Entry For Every Stock Movement,הפוך חשבונאות כניסה לכל מנית תנועה,
-"If enabled, the system will post accounting entries for inventory automatically.","אם מאופשר, המערכת תפרסם רישומים חשבונאיים עבור המלאי באופן אוטומטי.",
-Accounts Frozen Upto,חשבונות קפואים Upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","כניסת חשבונאות קפואה עד למועד זה, אף אחד לא יכול לעשות / לשנות כניסה מלבד התפקיד שיפורט להלן.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,תפקיד רשאי לקבוע קפואים חשבונות ורשומים קפואים עריכה,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,משתמשים עם תפקיד זה מותר להגדיר חשבונות קפוא וליצור / לשנות רישומים חשבונאיים נגד חשבונות מוקפאים,
Determine Address Tax Category From,קבע קטגוריית מס כתובת מאת,
-Address used to determine Tax Category in transactions.,כתובת המשמשת לקביעת קטגוריית המס בעסקאות.,
Over Billing Allowance (%),קצבת חיוב מוגבלת (%),
-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 for $110.,"אחוז שמותר לך לחייב יותר כנגד הסכום שהוזמן. לדוגמא: אם ערך ההזמנה הוא $ 100 עבור פריט והסובלנות מוגדרת כ -10%, אתה רשאי לחייב 110 $.",
Credit Controller,בקר אשראי,
-Role that is allowed to submit transactions that exceed credit limits set.,תפקיד שמותר להגיש עסקות חריגות ממסגרות אשראי שנקבע.,
Check Supplier Invoice Number Uniqueness,ספק בדוק חשבונית מספר הייחוד,
Make Payment via Journal Entry,בצע תשלום באמצעות הזנת יומן,
Unlink Payment on Cancellation of Invoice,בטל את קישור התשלום בביטול החשבונית,
-Unlink Advance Payment on Cancelation of Order,בטל קישור מקדמה בעת ביטול ההזמנה,
Book Asset Depreciation Entry Automatically,הזן פחת נכסי ספר באופן אוטומטי,
Automatically Add Taxes and Charges from Item Tax Template,הוסף אוטומטית מיסים וחיובים מתבנית מס פריט,
Automatically Fetch Payment Terms,אחזר אוטומטית תנאי תשלום,
-Show Inclusive Tax In Print,הראה מס כולל בדפוס,
Show Payment Schedule in Print,הצג את לוח התשלומים בהדפסה,
Currency Exchange Settings,הגדרות המרת מטבע,
Allow Stale Exchange Rates,אפשר שערי חליפין מעופשים,
Stale Days,ימים מעופשים,
Report Settings,הגדרות דוח,
Use Custom Cash Flow Format,השתמש בפורמט תזרים מזומנים מותאם אישית,
-Only select if you have setup Cash Flow Mapper documents,בחר רק אם הגדרת מסמכי מיפוי תזרים מזומנים,
Allowed To Transact With,מותר לבצע עסקאות עם,
SWIFT number,מספר SWIFT,
Branch Code,קוד סניף,
@@ -4940,7 +4912,6 @@
POS Customer Group,קבוצת לקוחות של קופה,
POS Field,שדה קופה,
POS Item Group,קבוצת פריטי קופה,
-[Select],[בחר],
Company Address,כתובת החברה,
Update Stock,בורסת עדכון,
Ignore Pricing Rule,התעלם כלל תמחור,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Naming ספק ב,
Default Supplier Group,קבוצת ספקים המוגדרת כברירת מחדל,
Default Buying Price List,מחיר מחירון קניית ברירת מחדל,
-Maintain same rate throughout purchase cycle,לשמור על אותו קצב לאורך כל מחזור הרכישה,
-Allow Item to be added multiple times in a transaction,הרשה פריט שיתווסף מספר פעמים בעסקה,
Backflush Raw Materials of Subcontract Based On,הזרמת חומרי גלם חוזרים של קבלני משנה בהתבסס על,
Material Transferred for Subcontract,חומר שהועבר לקבלן משנה,
Over Transfer Allowance (%),קצבת העברה יתר (%),
@@ -5540,7 +5509,6 @@
Current Stock,מלאי נוכחי,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,עבור ספק פרט,
-Supplier Detail,פרטי ספק,
Link to Material Requests,קישור לבקשות חומר,
Message for Supplier,הודעה על ספק,
Request for Quotation Item,בקשה להצעת מחיר הפריט,
@@ -6481,7 +6449,6 @@
Appraisal Template,הערכת תבנית,
For Employee Name,לשם עובדים,
Goals,מטרות,
-Calculate Total Score,חישוב ציון הכולל,
Total Score (Out of 5),ציון כולל (מתוך 5),
"Any other remarks, noteworthy effort that should go in the records.","כל דברים אחרים, מאמץ ראוי לציון שצריכה ללכת ברשומות.",
Appraisal Goal,מטרת הערכה,
@@ -6599,11 +6566,6 @@
Reason for Leaving,סיבה להשארה,
Leave Encashed?,השאר Encashed?,
Encashment Date,תאריך encashment,
-Exit Interview Details,פרטי ראיון יציאה,
-Held On,במוחזק,
-Reason for Resignation,סיבה להתפטרות,
-Better Prospects,סיכויים טובים יותר,
-Health Concerns,חששות בריאות,
New Workplace,חדש במקום העבודה,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,הסכום שהוחזר,
@@ -6740,10 +6702,7 @@
Employee Settings,הגדרות עובד,
Retirement Age,גיל פרישה,
Enter retirement age in years,זן גיל פרישה בשנים,
-Employee Records to be created by,רשומות עובדים שנוצרו על ידי,
-Employee record is created using selected field. ,שיא עובד שנוצר באמצעות שדה שנבחר.,
Stop Birthday Reminders,Stop יום הולדת תזכורות,
-Don't send Employee Birthday Reminders,אל תשלחו לעובדי יום הולדת תזכורות,
Expense Approver Mandatory In Expense Claim,אישור הוצאות חובה בתביעת הוצאות,
Payroll Settings,הגדרות שכר,
Leave,לעזוב,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,אישורי חופשה חובה בבקשת חופשה,
Show Leaves Of All Department Members In Calendar,הצג עלים של כל חברי המחלקה בלוח השנה,
Auto Leave Encashment,השאר אוטומטית את התכולה,
-Restrict Backdated Leave Application,הגבל את בקשת החופשה המאוחרת,
Hiring Settings,הגדרות שכירה,
Check Vacancies On Job Offer Creation,בדוק משרות פנויות ביצירת הצעות עבודה,
Identification Document Type,סוג מסמך זיהוי,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,הגדרות ייצור,
Raw Materials Consumption,צריכת חומרי גלם,
Allow Multiple Material Consumption,אפשר צריכת חומרים מרובה,
-Allow multiple Material Consumption against a Work Order,אפשר צריכת חומרים מרובה כנגד הזמנת עבודה,
Backflush Raw Materials Based On,Backflush חומרי גלם המבוסס על,
Material Transferred for Manufacture,חומר הועבר לייצור,
Capacity Planning,תכנון קיבולת,
Disable Capacity Planning,השבת תכנון קיבולת,
Allow Overtime,לאפשר שעות נוספות,
-Plan time logs outside Workstation Working Hours.,מתכנן יומני זמן מחוץ לשעתי עבודה תחנת עבודה.,
Allow Production on Holidays,לאפשר ייצור בחגים,
Capacity Planning For (Days),תכנון קיבולת ל( ימים),
-Try planning operations for X days in advance.,נסה לתכנן פעולות לימי X מראש.,
-Time Between Operations (in mins),זמן בין פעולות (בדקות),
-Default 10 mins,ברירת מחדל 10 דקות,
Default Warehouses for Production,מחסני ברירת מחדל לייצור,
Default Work In Progress Warehouse,עבודה המוגדרת כברירת מחדל במחסן ההתקדמות,
Default Finished Goods Warehouse,מחסן מוצרים מוגמר ברירת מחדל,
Default Scrap Warehouse,מחסן גרוטאות ברירת מחדל,
-Over Production for Sales and Work Order,ייצור יתר עבור מכירות והזמנת עבודה,
Overproduction Percentage For Sales Order,אחוז ייצור יתר להזמנת מכירה,
Overproduction Percentage For Work Order,אחוז ייצור יתר להזמנת עבודה,
Other Settings,הגדרות אחרות,
Update BOM Cost Automatically,עדכן את עלות ה- BOM באופן אוטומטי,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","עדכן את עלות ה- BOM באופן אוטומטי באמצעות מתזמן, בהתבסס על שיעור הערכת השווי האחרון / מחיר המחירון / שיעור הרכישה האחרון של חומרי הגלם.",
Material Request Plan Item,פריט תוכנית בקשת חומר,
Material Request Type,סוג בקשת חומר,
Material Issue,נושא מהותי,
@@ -7603,10 +7554,6 @@
Quality Goal,מטרה איכותית,
Monitoring Frequency,תדר ניטור,
Weekday,יוֹם חוֹל,
-January-April-July-October,ינואר-אפריל-יולי-אוקטובר,
-Revision and Revised On,עדכון ומתוקן,
-Revision,תיקון,
-Revised On,מתוקן ב,
Objectives,מטרות,
Quality Goal Objective,מטרת יעד איכותית,
Objective,מַטָרָה,
@@ -7619,7 +7566,6 @@
Processes,תהליכים,
Quality Procedure Process,תהליך נוהל איכות,
Process Description,תיאור תהליך,
-Child Procedure,נוהל ילדים,
Link existing Quality Procedure.,קשר נוהל איכות קיים.,
Additional Information,מידע נוסף,
Quality Review Objective,מטרת סקירת איכות,
@@ -7787,15 +7733,9 @@
Default Customer Group,קבוצת לקוחות המוגדרת כברירת מחדל,
Default Territory,טריטורית ברירת מחדל,
Close Opportunity After Days,סגור הזדמנות אחרי ימים,
-Auto close Opportunity after 15 days,אפשרות סגירה אוטומטית לאחר 15 יום,
Default Quotation Validity Days,ברירת מחדל ימי תוקף הצעת מחיר,
Sales Update Frequency,תדירות עדכון מכירות,
-How often should project and company be updated based on Sales Transactions.,באיזו תדירות צריך לעדכן פרויקט וחברה על סמך עסקאות מכירה.,
Each Transaction,כל עסקה,
-Allow user to edit Price List Rate in transactions,לאפשר למשתמש לערוך מחירון שיעור בעסקות,
-Allow multiple Sales Orders against a Customer's Purchase Order,לאפשר הזמנות ומכירות מרובות נגד הלקוח הזמנת הרכש,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,אמת את מחיר המכירה של הפריט כנגד שיעור הרכישה או שיעור ההערכה,
-Hide Customer's Tax Id from Sales Transactions,הסתר את זיהוי המס של הלקוח מעסקאות מכירה,
SMS Center,SMS מרכז,
Send To,שלח אל,
All Contact,כל הקשר,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,יצרנים השתמשו בפריטים,
Limited to 12 characters,מוגבל ל -12 תווים,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,הגדר מחסן,
-Sets 'For Warehouse' in each row of the Items table.,מגדיר 'עבור מחסן' בכל שורה בטבלת הפריטים.,
-Requested For,ביקש ל,
Partially Ordered,הוזמן חלקית,
Transferred,הועבר,
% Ordered,% מסודר,
@@ -8407,24 +8344,14 @@
Default Stock UOM,ברירת מחדל יחידת מידה,
Sample Retention Warehouse,מחסן שימור לדוגמא,
Default Valuation Method,שיטת הערכת ברירת מחדל,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,אחוז מותר לך לקבל או למסור יותר נגד כל הכמות המוזמנת. לדוגמא: אם יש לך הורה 100 יחידות. והפרשה שלך הוא 10% אז אתה רשאי לקבל 110 יחידות.,
-Action if Quality inspection is not submitted,פעולה אם לא מוגשת בדיקת איכות,
Show Barcode Field,הצג ברקוד שדה,
Convert Item Description to Clean HTML,המרת תיאור פריט לניקוי HTML,
-Auto insert Price List rate if missing,הכנס אוטומטי שיעור מחירון אם חסר,
Allow Negative Stock,אפשר מלאי שלילי,
Automatically Set Serial Nos based on FIFO,הגדר סידורי מס באופן אוטומטי על בסיס FIFO,
-Set Qty in Transactions based on Serial No Input,הגדר כמות בעסקאות על סמך קלט ללא סדרתי,
Auto Material Request,בקשת Auto חומר,
-Raise Material Request when stock reaches re-order level,להעלות בקשת חומר כאשר המלאי מגיע לרמה מחדש כדי,
-Notify by Email on creation of automatic Material Request,להודיע באמצעות דואר אלקטרוני על יצירת בקשת חומר אוטומטית,
Inter Warehouse Transfer Settings,הגדרות העברה בין מחסן,
-Allow Material Transfer From Delivery Note and Sales Invoice,אפשר העברת חומרים מתעודת משלוח ומחשבונית מכירה,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,אפשר העברה מהותית מקבלת הרכישה וחשבונית הרכישה,
Freeze Stock Entries,ערכי מלאי הקפאה,
Stock Frozen Upto,המניה קפואה Upto,
-Freeze Stocks Older Than [Days],מניות הקפאת Older Than [ימים],
-Role Allowed to edit frozen stock,תפקיד מחמד לערוך המניה קפוא,
Batch Identification,זיהוי אצווה,
Use Naming Series,השתמש בסדרת שמות,
Naming Series Prefix,קידומת סדרת שמות,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,מגמות קבלת רכישה,
Purchase Register,רכישת הרשמה,
Quotation Trends,מגמות ציטוט,
-Quoted Item Comparison,פריט מצוטט השוואה,
Received Items To Be Billed,פריטים שהתקבלו לחיוב,
Qty to Order,כמות להזמנה,
Requested Items To Be Transferred,פריטים מבוקשים שיועברו,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,בחר מחסן לבקשות חומר,
Transfer Materials For Warehouse {0},העברת חומרים למחסן {0},
Production Plan Material Request Warehouse,מחסן בקשת חומר לתכנית ייצור,
-Set From Warehouse,מוגדר מהמחסן,
-Source Warehouse (Material Transfer),מחסן מקור (העברת חומרים),
Sets 'Source Warehouse' in each row of the items table.,מגדיר 'מחסן מקור' בכל שורה בטבלת הפריטים.,
Sets 'Target Warehouse' in each row of the items table.,מגדיר 'מחסן יעד' בכל שורה בטבלת הפריטים.,
Show Cancelled Entries,הצג ערכים שבוטלו,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,שירות שהתקבל אך לא מחויב,
Deferred Accounting Settings,הגדרות חשבונאות נדחות,
Book Deferred Entries Based On,ספר ערכים נדחים בהתבסס על,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","אם נבחר "חודשים", הסכום הקבוע יוזמן כהכנסות או הוצאות נדחות עבור כל חודש ללא קשר למספר הימים בחודש. יוקצב באופן יחסי אם לא הוזמנו הכנסות או הוצאות נדחות למשך חודש שלם.",
Days,ימים,
Months,חודשים,
Book Deferred Entries Via Journal Entry,ספר ערכים נדחים באמצעות רשומת יומן,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,אם זו לא מסומנת רשומות GL ישירות ייווצרו להזמנת הכנסות / הוצאות נדחות,
Submit Journal Entries,הגש רשומות יומן,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"אם זו לא מסומנת, רשומות היומן יישמרו במצב טיוטה ויהיה צורך להגיש אותן ידנית",
Enable Distributed Cost Center,אפשר מרכז עלויות מבוזר,
@@ -8901,8 +8823,6 @@
Is Inter State,האם אינטר סטייט,
Purchase Details,פרטי רכישה,
Depreciation Posting Date,תאריך רישום פחת,
-Purchase Order Required for Purchase Invoice & Receipt Creation,הזמנת רכש נדרשת לצורך יצירת חשבונית וקבלה,
-Purchase Receipt Required for Purchase Invoice Creation,קבלת רכישה נדרשת ליצירת חשבונית רכישה,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","כברירת מחדל, שם הספק מוגדר לפי שם הספק שהוזן. אם אתה רוצה שספקים יקראו על ידי א",
choose the 'Naming Series' option.,בחר באפשרות 'סדרת שמות'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,הגדר את מחירון ברירת המחדל בעת יצירת עסקת רכישה חדשה. מחירי הפריטים ייאספו ממחירון זה.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,הוא רכיב מס הכנסה,
Component properties and references ,מאפייני רכיבים והפניות,
Additional Salary ,שכר נוסף,
-Condtion and formula,הולכה ונוסחה,
Unmarked days,ימים לא מסומנים,
Absent Days,ימי נעדרים,
Conditions and Formula variable and example,משתנה תנאי ונוסחה ודוגמא,
Feedback By,משוב מאת,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,מדור ייצור,
-Sales Order Required for Sales Invoice & Delivery Note Creation,הזמנת מכר נדרשת ליצירת חשבונית מכירה וליווי הערות משלוח,
-Delivery Note Required for Sales Invoice Creation,תעודת משלוח נדרשת ליצירת חשבונית מכירה,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","כברירת מחדל, שם הלקוח מוגדר לפי השם המלא שהוזן. אם אתה רוצה שלקוחות יקראו על ידי",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,הגדר את מחירון ברירת המחדל בעת יצירת עסקת מכירה חדשה. מחירי הפריטים ייאספו ממחירון זה.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","אם אפשרות זו מוגדרת 'כן', ERPNext ימנע ממך ליצור חשבונית מכירה או תעודת משלוח מבלי שתיצור תחילה הזמנת מכירה. ניתן לעקוף תצורה זו עבור לקוח מסוים על ידי הפעלת תיבת הסימון 'אפשר יצירת חשבונית מכירה ללא הזמנת מכר' במאסטר הלקוח.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} נוסף לכל הנושאים שנבחרו בהצלחה.,
Topics updated,הנושאים עודכנו,
Academic Term and Program,מונח אקדמי ותכנית,
-Last Stock Transaction for item {0} was on {1}.,עסקת המניות האחרונה לפריט {0} הייתה בתאריך {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,לא ניתן לפרסם עסקאות מלאי עבור פריט {0} לפני זמן זה.,
Please remove this item and try to submit again or update the posting time.,אנא הסר פריט זה ונסה להגיש שוב או לעדכן את זמן הפרסום.,
Failed to Authenticate the API key.,אימות מפתח ה- API נכשל.,
Invalid Credentials,אישורים לא חוקיים,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,אנא בדוק את מזהה הלקוח המשובץ שלך ואת הערכים הסודיים שלך,
Bank transaction creation error,שגיאה ביצירת עסקאות בנק,
Unit of Measurement,יחידת מידה,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},שורה מספר {}: שיעור המכירה של הפריט {} נמוך מ- {} שלו. שיעור המכירה צריך להיות לפחות {},
Fiscal Year {0} Does Not Exist,שנת הכספים {0} לא קיימת,
Row # {0}: Returned Item {1} does not exist in {2} {3},שורה מספר {0}: פריט שהוחזר {1} אינו קיים ב {2} {3},
Valuation type charges can not be marked as Inclusive,לא ניתן לסמן חיובים מסוג הערכת שווי כולל,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,זמן התגובה ל {0} עדיפות בשורה {1} לא יכול להיות גדול משעת הרזולוציה.,
{0} is not enabled in {1},{0} אינו מופעל ב- {1},
Group by Material Request,קבץ לפי בקשת חומרים,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","שורה {0}: עבור הספק {0}, כתובת הדוא"ל נדרשת כדי לשלוח דוא"ל",
Email Sent to Supplier {0},אימייל נשלח לספק {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","הגישה לבקשה להצעת מחיר מהפורטל אינה זמינה. כדי לאפשר גישה, הפעל אותו בהגדרות הפורטל.",
Supplier Quotation {0} Created,הצעת מחיר לספק {0} נוצרה,
Valid till Date cannot be before Transaction Date,תוקף עד תאריך לא יכול להיות לפני תאריך העסקה,
+Unlink Advance Payment on Cancellation of Order,בטל קישור של תשלום מקדמה בביטול ההזמנה,
+"Simple Python Expression, Example: territory != 'All Territories'","ביטוי פייתון פשוט, דוגמה: טריטוריה! = 'כל השטחים'",
+Sales Contributions and Incentives,תרומות מכירות ותמריצים,
+Sourced by Supplier,מקור הספק,
+Total weightage assigned should be 100%.<br>It is {0},המשקל הכללי שהוקצה צריך להיות 100%.<br> זה {0},
+Account {0} exists in parent company {1}.,החשבון {0} קיים בחברת האם {1}.,
+"To overrule this, enable '{0}' in company {1}","כדי לבטל את זה, הפעל את '{0}' בחברה {1}",
+Invalid condition expression,ביטוי מצב לא חוקי,
+Please Select a Company First,אנא בחר חברה ראשונה,
+Please Select Both Company and Party Type First,אנא בחר ראשית הן סוג החברה והן סוג המפלגה,
+Provide the invoice portion in percent,ספק את חלק החשבונית באחוזים,
+Give number of days according to prior selection,תן מספר ימים על פי בחירה מוקדמת,
+Email Details,פרטי דוא"ל,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","בחר ברכה למקלט. למשל מר, גב 'וכו'.",
+Preview Email,תצוגה מקדימה של אימייל,
+Please select a Supplier,אנא בחר ספק,
+Supplier Lead Time (days),זמן עופרת ספק (ימים),
+"Home, Work, etc.","בית, עבודה וכו '.",
+Exit Interview Held On,ראיון יציאה נערך,
+Condition and formula,מצב ונוסחה,
+Sets 'Target Warehouse' in each row of the Items table.,מגדיר 'מחסן יעד' בכל שורה בטבלת הפריטים.,
+Sets 'Source Warehouse' in each row of the Items table.,מגדיר 'מחסן מקור' בכל שורה בטבלת הפריטים.,
+POS Register,הרשמת קופה,
+"Can not filter based on POS Profile, if grouped by POS Profile","לא ניתן לסנן על סמך פרופיל קופה, אם מקובצים לפי פרופיל קופה",
+"Can not filter based on Customer, if grouped by Customer","לא ניתן לסנן על בסיס לקוח, אם מקובץ לפי לקוח",
+"Can not filter based on Cashier, if grouped by Cashier","לא ניתן לסנן על בסיס קופאי, אם מקובץ לפי קופאית",
+Payment Method,אמצעי תשלום,
+"Can not filter based on Payment Method, if grouped by Payment Method","לא ניתן לסנן על בסיס אמצעי תשלום, אם מקובצים לפי אמצעי תשלום",
+Supplier Quotation Comparison,השוואת הצעות מחיר לספקים,
+Price per Unit (Stock UOM),מחיר ליחידה (UOM מלאי),
+Group by Supplier,קבץ לפי ספק,
+Group by Item,קבץ לפי פריט,
+Remember to set {field_label}. It is required by {regulation}.,זכור להגדיר את {field_label}. זה נדרש על ידי {Regulation}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},תאריך ההרשמה לא יכול להיות לפני תאריך ההתחלה של השנה האקדמית {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},תאריך ההרשמה לא יכול להיות אחרי תאריך הסיום של הקדנציה האקדמית {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},תאריך ההרשמה לא יכול להיות לפני תאריך ההתחלה של הקדנציה האקדמית {0},
+Future Posting Not Allowed,פרסום עתידי אינו מותר,
+"To enable Capital Work in Progress Accounting, ","כדי לאפשר חשבונאות בביצוע עבודות הון,",
+you must select Capital Work in Progress Account in accounts table,עליך לבחור חשבון עבודות הון בתהליך בטבלת החשבונות,
+You can also set default CWIP account in Company {},ניתן גם להגדיר חשבון CWIP המוגדר כברירת מחדל בחברה {},
+The Request for Quotation can be accessed by clicking on the following button,ניתן לגשת לבקשה להצעת מחיר על ידי לחיצה על הכפתור הבא,
+Regards,בברכה,
+Please click on the following button to set your new password,אנא לחץ על הכפתור הבא כדי להגדיר את הסיסמה החדשה שלך,
+Update Password,עדכן סיסמה,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},שורה מספר {}: שיעור המכירה של הפריט {} נמוך מ- {} שלו. המכירה {} צריכה להיות לפחות {},
+You can alternatively disable selling price validation in {} to bypass this validation.,לחלופין תוכל להשבית את אימות מחיר המכירה ב- {} כדי לעקוף את האימות הזה.,
+Invalid Selling Price,מחיר מכירה לא חוקי,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,כתובת צריכה להיות מקושרת לחברה. אנא הוסף שורה לחברה בטבלת הקישורים.,
+Company Not Linked,חברה לא מקושרת,
+Import Chart of Accounts from CSV / Excel files,ייבא תרשים חשבונות מקבצי CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',כמות שהושלמה לא יכולה להיות גדולה מ- 'כמות לייצור',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","שורה {0}: לספק {1}, נדרשת כתובת דוא"ל כדי לשלוח דוא"ל",
+"If enabled, the system will post accounting entries for inventory automatically","אם היא מופעלת, המערכת תפרסם רשומות חשבונאיות עבור מלאי באופן אוטומטי",
+Accounts Frozen Till Date,חשבונות תאריך קפוא,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,רשומות חשבונאות מוקפאות עד תאריך זה. איש אינו יכול ליצור או לשנות ערכים למעט משתמשים בעלי התפקיד המפורט להלן,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,תפקיד המותר לקביעת חשבונות קפואים ולעריכת ערכים קפואים,
+Address used to determine Tax Category in transactions,כתובת המשמשת לקביעת קטגוריית מס בעסקאות,
+"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 ","האחוז שמותר לך לחייב יותר כנגד הסכום שהוזמן. לדוגמא, אם ערך ההזמנה הוא $ 100 עבור פריט והסובלנות מוגדרת כ- 10%, אתה רשאי לחייב עד $ 110",
+This role is allowed to submit transactions that exceed credit limits,תפקיד זה רשאי להגיש עסקאות החורגות ממגבלות האשראי,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","אם נבחר "חודשים", סכום קבוע יירשם כהכנסות או הוצאות נדחות עבור כל חודש ללא קשר למספר הימים בחודש. זה יחול אם ההכנסות או ההוצאות הנדחים לא יוזמנו למשך חודש שלם",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","אם זה לא מסומן, רשומות GL ישירות ייווצרו כדי להזמין הכנסות או הוצאות נדחות",
+Show Inclusive Tax in Print,הראה מס כולל בדפוס,
+Only select this if you have set up the Cash Flow Mapper documents,בחר באפשרות זו רק אם הגדרת את מסמכי מיפוי תזרים המזומנים,
+Payment Channel,ערוץ תשלום,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,האם נדרשת הזמנת רכש לצורך יצירת חשבונית וקבלה?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,האם נדרשת קבלת רכישה ליצירת חשבונית רכישה?,
+Maintain Same Rate Throughout the Purchase Cycle,שמור על אותו שיעור לאורך כל מחזור הרכישה,
+Allow Item To Be Added Multiple Times in a Transaction,אפשר להוסיף פריט מספר פעמים בעסקה,
+Suppliers,ספקים,
+Send Emails to Suppliers,שלח מיילים לספקים,
+Select a Supplier,בחר ספק,
+Cannot mark attendance for future dates.,לא ניתן לסמן נוכחות לתאריכים עתידיים.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},האם אתה רוצה לעדכן את הנוכחות?<br> נוכח: {0}<br> נעדר: {1},
+Mpesa Settings,הגדרות Mpesa,
+Initiator Name,שם היוזם,
+Till Number,עד מספר,
+Sandbox,ארגז חול,
+ Online PassKey,PassKey מקוון,
+Security Credential,אישורי אבטחה,
+Get Account Balance,קבל יתרה בחשבון,
+Please set the initiator name and the security credential,אנא הגדר את שם היוזם ואת אישורי האבטחה,
+Inpatient Medication Entry,כניסה לתרופות אשפוז,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),קוד פריט (סמים),
+Medication Orders,צווי תרופות,
+Get Pending Medication Orders,קבל הזמנות תרופות ממתינות,
+Inpatient Medication Orders,צווי תרופות באשפוז,
+Medication Warehouse,מחסן תרופות,
+Warehouse from where medication stock should be consumed,מחסן שממנו יש לצרוך מלאי תרופות,
+Fetching Pending Medication Orders,משיכת הזמנות תרופות ממתינות,
+Inpatient Medication Entry Detail,פרטי כניסה לתרופות אשפוז,
+Medication Details,פרטי התרופות,
+Drug Code,קוד סמים,
+Drug Name,שם התרופה,
+Against Inpatient Medication Order,כנגד צו התרופות באשפוז,
+Against Inpatient Medication Order Entry,נגד הזנת צו באשפוז,
+Inpatient Medication Order,צו תרופות לטיפול באשפוז,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,סה"כ הזמנות,
+Completed Orders,הזמנות שהושלמו,
+Add Medication Orders,הוסף צווי תרופות,
+Adding Order Entries,הוספת רשומות הזמנה,
+{0} medication orders completed,{0} הזמנות התרופות הושלמו,
+{0} medication order completed,{0} הושלם הזמנת התרופות,
+Inpatient Medication Order Entry,הזנת הזמנת תרופות באשפוז,
+Is Order Completed,האם ההזמנה הושלמה,
+Employee Records to Be Created By,רשומות עובדים שייווצרו על ידי,
+Employee records are created using the selected field,רשומות עובדים נוצרות באמצעות השדה שנבחר,
+Don't send employee birthday reminders,אל תשלחו תזכורות ליום הולדת לעובדים,
+Restrict Backdated Leave Applications,הגבל יישומי חופשה בתאריך מאוחר,
+Sequence ID,מזהה רצף,
+Sequence Id,מזהה רצף,
+Allow multiple material consumptions against a Work Order,אפשר צריכת חומרים מרובה כנגד הזמנת עבודה,
+Plan time logs outside Workstation working hours,תכנן יומני זמן מחוץ לשעות העבודה של תחנת העבודה,
+Plan operations X days in advance,תכנן פעולות X ימים מראש,
+Time Between Operations (Mins),זמן בין פעולות (דקות),
+Default: 10 mins,ברירת מחדל: 10 דקות,
+Overproduction for Sales and Work Order,ייצור יתר עבור מכירות והזמנת עבודה,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","עדכן את עלות ה- BOM באופן אוטומטי באמצעות מתזמן, בהתבסס על שיעור הערכת השווי האחרון / מחיר המחירון / שיעור הרכישה האחרון של חומרי הגלם",
+Purchase Order already created for all Sales Order items,הזמנת הרכש כבר נוצרה עבור כל פריטי הזמנת המכירה,
+Select Items,בחר פריטים,
+Against Default Supplier,כנגד ספק ברירת מחדל,
+Auto close Opportunity after the no. of days mentioned above,הזדמנות אוטומטית לאחר המס ' של הימים שהוזכרו לעיל,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,האם נדרשת הזמנת מכר לצורך יצירת חשבונית מכירה ויצירת הערות משלוח?,
+Is Delivery Note Required for Sales Invoice Creation?,האם נדרש תעודת משלוח לצורך יצירת חשבונית מכר?,
+How often should Project and Company be updated based on Sales Transactions?,באיזו תדירות צריך לעדכן פרויקט וחברה בהתבסס על עסקאות מכירה?,
+Allow User to Edit Price List Rate in Transactions,אפשר למשתמש לערוך את מחיר המחירון בעסקאות,
+Allow Item to Be Added Multiple Times in a Transaction,אפשר להוסיף פריט מספר פעמים בעסקה,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,אפשר הזמנות מכירה מרובות כנגד הזמנת הרכש של הלקוח,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,אמת מחיר מכירה לפריט כנגד שיעור קנייה או שיעור הערכה,
+Hide Customer's Tax ID from Sales Transactions,הסתר את מזהה המס של הלקוח מעסקאות מכירה,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","האחוז שמותר לך לקבל או לספק יותר כנגד הכמות שהוזמנה. לדוגמא, אם הזמנת 100 יחידות והקצבה שלך היא 10%, אז אתה רשאי לקבל 110 יחידות.",
+Action If Quality Inspection Is Not Submitted,פעולה אם לא הוגשה בדיקת איכות,
+Auto Insert Price List Rate If Missing,הכנס אוטומטית תעריף מחירון אם חסר,
+Automatically Set Serial Nos Based on FIFO,הגדר אוטומטית מספרים סידוריים על בסיס FIFO,
+Set Qty in Transactions Based on Serial No Input,הגדר כמות בעסקאות על בסיס קלט ללא סדרתי,
+Raise Material Request When Stock Reaches Re-order Level,הגדל את בקשת החומר כאשר המלאי מגיע לרמת ההזמנה מחדש,
+Notify by Email on Creation of Automatic Material Request,הודע בדוא"ל על יצירת בקשת חומרים אוטומטית,
+Allow Material Transfer from Delivery Note to Sales Invoice,אפשר העברת חומרים מתעודת משלוח לחשבונית מכירה,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,אפשר העברה מהותית מקבלת הרכישה לחשבונית הרכישה,
+Freeze Stocks Older Than (Days),הקפאת מניות ישנות מ (ימים),
+Role Allowed to Edit Frozen Stock,תפקיד המותר לערוך מלאי קפוא,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,הסכום שלא הוקצה של הזנת התשלום {0} גדול מהסכום שלא הוקצה של עסקת הבנק,
+Payment Received,תשלום התקבל,
+Attendance cannot be marked outside of Academic Year {0},לא ניתן לסמן נוכחות מחוץ לשנת הלימודים {0},
+Student is already enrolled via Course Enrollment {0},התלמיד כבר נרשם באמצעות הרשמה לקורס {0},
+Attendance cannot be marked for future dates.,לא ניתן לסמן את הנוכחות לתאריכים עתידיים.,
+Please add programs to enable admission application.,אנא הוסף תוכניות כדי לאפשר בקשה לקבלה.,
+The following employees are currently still reporting to {0}:,העובדים הבאים עדיין מדווחים ל- {0}:,
+Please make sure the employees above report to another Active employee.,אנא ודא שהעובדים לעיל מדווחים לעובד פעיל אחר.,
+Cannot Relieve Employee,לא יכול להקל על העובד,
+Please enter {0},הזן {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',אנא בחר אמצעי תשלום אחר. Mpesa אינה תומכת בעסקאות במטבע '{0}',
+Transaction Error,שגיאת עסקה,
+Mpesa Express Transaction Error,שגיאת עסקה Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","הבעיה זוהתה בתצורת Mpesa, בדוק ביומני השגיאה לקבלת פרטים נוספים",
+Mpesa Express Error,שגיאת Mpesa Express,
+Account Balance Processing Error,שגיאת עיבוד יתרה בחשבון,
+Please check your configuration and try again,אנא בדוק את התצורה שלך ונסה שוב,
+Mpesa Account Balance Processing Error,שגיאת עיבוד יתרת חשבון Mpesa,
+Balance Details,פרטי יתרה,
+Current Balance,יתרה נוכחית,
+Available Balance,יתרה זמינה,
+Reserved Balance,יתרה שמורה,
+Uncleared Balance,איזון לא ברור,
+Payment related to {0} is not completed,התשלום הקשור ל- {0} לא הושלם,
+Row #{}: Item Code: {} is not available under warehouse {}.,שורה מספר {}: קוד פריט: {} אינו זמין במחסן {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,שורה מספר {}: כמות המלאי אינה מספיקה עבור קוד הפריט: {} מתחת למחסן {}. כמות זמינה {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,שורה מספר {}: בחר מספר סדרתי ואצווה כנגד פריט: {} או הסר אותו כדי להשלים את העסקה.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,שורה מספר {}: לא נבחר מספר סידורי מול פריט: {}. אנא בחר אחד או הסר אותו להשלמת העסקה.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,שורה מספר {}: לא נבחרה אצווה כנגד פריט: {}. אנא בחר אצווה או הסר אותה להשלמת העסקה.,
+Payment amount cannot be less than or equal to 0,סכום התשלום לא יכול להיות קטן מ- 0 או שווה,
+Please enter the phone number first,אנא הזן תחילה את מספר הטלפון,
+Row #{}: {} {} does not exist.,שורה מספר {}: {} {} לא קיים.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,שורה מספר {0}: {1} נדרשת ליצירת חשבוניות הפתיחה {2},
+You had {} errors while creating opening invoices. Check {} for more details,היו לך {} שגיאות בעת יצירת חשבוניות פתיחה. בדוק {} לפרטים נוספים,
+Error Occured,אירעה שגיאה,
+Opening Invoice Creation In Progress,פתיחת יצירת חשבוניות מתבצעת,
+Creating {} out of {} {},יוצר {} מתוך {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(מספר סידורי: {0}) לא ניתן לצרוך מכיוון שהוא מוגדר למילוי מלא של הזמנת המכירה {1}.,
+Item {0} {1},פריט {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,עסקת המניות האחרונה של פריט {0} במחסן {1} הייתה בתאריך {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,לא ניתן לפרסם עסקאות מלאי עבור פריט {0} במחסן {1} לפני זמן זה.,
+Posting future stock transactions are not allowed due to Immutable Ledger,לא ניתן לפרסם עסקאות מניות עתידיות בגלל חשבונאות בלתי ניתנות לשינוי,
+A BOM with name {0} already exists for item {1}.,BOM עם השם {0} כבר קיים לפריט {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} האם שינית את שם הפריט? אנא צרו קשר עם מנהל / תמיכה טכנית,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},בשורה מספר {0}: מזהה הרצף {1} לא יכול להיות פחות מזהה הרצף של השורה הקודמת {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) חייב להיות שווה ל- {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, השלם את הפעולה {1} לפני הפעולה {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,לא ניתן להבטיח אספקה באמצעות מספר סידורי כאשר פריט {0} מתווסף עם ובלי להבטיח אספקה על ידי מספר סידורי.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,פריט {0} אינו מס 'סידורי. רק פריטים מסווגים יכולים לקבל משלוח על בסיס מספר סידורי,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,לא נמצא BOM פעיל לפריט {0}. לא ניתן להבטיח משלוח באמצעות סידורי לא,
+No pending medication orders found for selected criteria,לא נמצאו הזמנות תרופות ממתינות לקריטריונים שנבחרו,
+From Date cannot be after the current date.,מ- Date לא יכול להיות אחרי התאריך הנוכחי.,
+To Date cannot be after the current date.,עד תאריך לא יכול להיות אחרי התאריך הנוכחי.,
+From Time cannot be after the current time.,מ- Time לא יכול להיות אחרי הזמן הנוכחי.,
+To Time cannot be after the current time.,To Time לא יכול להיות אחרי הזמן הנוכחי.,
+Stock Entry {0} created and ,הזנת מניות {0} נוצרה ו,
+Inpatient Medication Orders updated successfully,צווי התרופות באשפוז עודכנו בהצלחה,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},שורה {0}: לא ניתן ליצור כניסה לתרופות אשפוז כנגד צו התרופות המאושש שבוטל {1},
+Row {0}: This Medication Order is already marked as completed,שורה {0}: צו התרופות הזה כבר מסומן כמושלם,
+Quantity not available for {0} in warehouse {1},כמות לא זמינה עבור {0} במחסן {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,אנא אפשר הרשאה למניה שלילית בהגדרות המניה או צור הזנת מלאי כדי להמשיך.,
+No Inpatient Record found against patient {0},לא נמצא רישום אשפוז כנגד המטופל {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,כבר קיים צו תרופות לטיפול באשפוז {0} נגד מפגש חולים {1}.,
+Allow In Returns,אפשר החזרות,
+Hide Unavailable Items,הסתר פריטים שאינם זמינים,
+Apply Discount on Discounted Rate,החל הנחה בשיעור מוזל,
+Therapy Plan Template,תבנית תכנית טיפול,
+Fetching Template Details,אחזור פרטי תבנית,
+Linked Item Details,פרטי פריט מקושר,
+Therapy Types,סוגי הטיפול,
+Therapy Plan Template Detail,פרט תבנית תכנית טיפול,
+Non Conformance,אי התאמה,
+Process Owner,בעל תהליך,
+Corrective Action,פעולה מתקנת,
+Preventive Action,פעולה מונעת,
+Problem,בְּעָיָה,
+Responsible,אחראי,
+Completion By,השלמה מאת,
+Process Owner Full Name,שם מלא של בעל התהליך,
+Right Index,אינדקס נכון,
+Left Index,אינדקס שמאל,
+Sub Procedure,נוהל משנה,
+Passed,עבר,
+Print Receipt,הדפס קבלה,
+Edit Receipt,ערוך קבלה,
+Focus on search input,התמקדו בקלט חיפוש,
+Focus on Item Group filter,התמקדו במסנן קבוצת הפריטים,
+Checkout Order / Submit Order / New Order,הזמנת קופה / הגשת הזמנה / הזמנה חדשה,
+Add Order Discount,הוסף הנחת הזמנה,
+Item Code: {0} is not available under warehouse {1}.,קוד פריט: {0} אינו זמין במחסן {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,מספרים סידוריים לא זמינים עבור פריט {0} במחסן {1}. נסה להחליף מחסן.,
+Fetched only {0} available serial numbers.,הביא רק {0} מספרים סידוריים זמינים.,
+Switch Between Payment Modes,החלף בין אמצעי תשלום,
+Enter {0} amount.,הזן סכום {0}.,
+You don't have enough points to redeem.,אין לך מספיק נקודות למימוש.,
+You can redeem upto {0}.,אתה יכול לממש עד {0}.,
+Enter amount to be redeemed.,הזן סכום למימוש.,
+You cannot redeem more than {0}.,אינך יכול לממש יותר מ- {0}.,
+Open Form View,פתח את תצוגת הטופס,
+POS invoice {0} created succesfully,חשבונית קופה {0} נוצרה בהצלחה,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,כמות המלאי לא מספיקה עבור קוד הפריט: {0} מתחת למחסן {1}. כמות זמינה {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,מספר סידורי: {0} כבר הועבר לחשבונית קופה אחרת.,
+Balance Serial No,איזון סידורי מס,
+Warehouse: {0} does not belong to {1},מחסן: {0} אינו שייך ל {1},
+Please select batches for batched item {0},בחר קבוצות עבור פריט אצווה {0},
+Please select quantity on row {0},בחר כמות בשורה {0},
+Please enter serial numbers for serialized item {0},הזן מספרים סידוריים עבור פריט מסדרת {0},
+Batch {0} already selected.,אצווה {0} כבר נבחרה.,
+Please select a warehouse to get available quantities,אנא בחר מחסן לקבלת כמויות זמינות,
+"For transfer from source, selected quantity cannot be greater than available quantity","להעברה ממקור, הכמות שנבחרה לא יכולה להיות גדולה מהכמות הזמינה",
+Cannot find Item with this Barcode,לא ניתן למצוא פריט עם ברקוד זה,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},חובה {0}. אולי רשומת המרת מטבע לא נוצרה עבור {1} עד {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} הגיש נכסים המקושרים אליו. עליך לבטל את הנכסים כדי ליצור החזר רכישה.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,לא ניתן לבטל מסמך זה מכיוון שהוא מקושר לנכס שהוגש {0}. אנא בטל אותו כדי להמשיך.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,שורה מספר {}: מספר סידורי {} כבר הועבר לחשבונית קופה אחרת. אנא בחר מס 'סדרתי תקף.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,שורה מספר {}: מספר סידורי. {} כבר הועבר לחשבונית קופה אחרת. אנא בחר מס 'סדרתי תקף.,
+Item Unavailable,הפריט לא זמין,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},שורה מספר {}: לא ניתן להחזיר מספר סידורי {} מכיוון שהוא לא בוצע בחשבונית המקורית {},
+Please set default Cash or Bank account in Mode of Payment {},הגדר ברירת מחדל של מזומן או חשבון בנק במצב תשלום {},
+Please set default Cash or Bank account in Mode of Payments {},הגדר ברירת מחדל של מזומן או חשבון בנק במצב תשלומים {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,ודא ש- {} חשבון הוא חשבון מאזן. באפשרותך לשנות את חשבון האב לחשבון מאזן או לבחור חשבון אחר.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,ודא ש- {} החשבון הוא חשבון בתשלום. שנה את סוג החשבון לתשלום או בחר חשבון אחר.,
+Row {}: Expense Head changed to {} ,שורה {}: ראש ההוצאות השתנה ל- {},
+because account {} is not linked to warehouse {} ,מכיוון שהחשבון {} אינו מקושר למחסן {},
+or it is not the default inventory account,או שזה לא חשבון המלאי המוגדר כברירת מחדל,
+Expense Head Changed,ראש ההוצאות הוחלף,
+because expense is booked against this account in Purchase Receipt {},מכיוון שההוצאה נרשמת בחשבון זה בקבלת הרכישה {},
+as no Purchase Receipt is created against Item {}. ,מכיוון שלא נוצר קבלת רכישה כנגד פריט {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,זה נעשה כדי לטפל בחשבונאות במקרים בהם קבלת רכישה נוצרת לאחר חשבונית רכישה,
+Purchase Order Required for item {},הזמנת רכש נדרשת לפריט {},
+To submit the invoice without purchase order please set {} ,"להגשת החשבונית ללא הזמנת רכש, הגדר {}",
+as {} in {},כמו {} ב- {},
+Mandatory Purchase Order,הזמנת רכש חובה,
+Purchase Receipt Required for item {},נדרש קבלת רכישה עבור פריט {},
+To submit the invoice without purchase receipt please set {} ,"להגשת החשבונית ללא קבלת רכישה, הגדר {}",
+Mandatory Purchase Receipt,קבלת קנייה חובה,
+POS Profile {} does not belongs to company {},פרופיל קופה {} אינו שייך לחברה {},
+User {} is disabled. Please select valid user/cashier,המשתמש {} מושבת. אנא בחר משתמש / קופאין תקף,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,שורה מספר {}: חשבונית מקורית {} של חשבונית החזר {} היא {}.,
+Original invoice should be consolidated before or along with the return invoice.,יש לאחד את החשבונית המקורית לפני או יחד עם החשבונית.,
+You can add original invoice {} manually to proceed.,תוכל להוסיף חשבונית מקורית {} באופן ידני כדי להמשיך.,
+Please ensure {} account is a Balance Sheet account. ,ודא ש- {} חשבון הוא חשבון מאזן.,
+You can change the parent account to a Balance Sheet account or select a different account.,באפשרותך לשנות את חשבון האב לחשבון מאזן או לבחור חשבון אחר.,
+Please ensure {} account is a Receivable account. ,אנא וודא ש- {} החשבון הוא חשבון שניתן לקבל.,
+Change the account type to Receivable or select a different account.,שנה את סוג החשבון ל- Receivable או בחר חשבון אחר.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},לא ניתן לבטל את {} מכיוון שנקודות הנאמנות שנצברו מומשו. ראשית בטל את ה- {} לא {},
+already exists,כבר קיים,
+POS Closing Entry {} against {} between selected period,ערך סגירת קופה {} כנגד {} בין התקופה שנבחרה,
+POS Invoice is {},חשבונית קופה היא {},
+POS Profile doesn't matches {},פרופיל קופה אינו תואם {},
+POS Invoice is not {},חשבונית קופה אינה {},
+POS Invoice isn't created by user {},חשבונית קופה לא נוצרה על ידי המשתמש {},
+Row #{}: {},שורה מספר {}: {},
+Invalid POS Invoices,חשבוניות קופה לא חוקיות,
+Please add the account to root level Company - {},אנא הוסף את החשבון לחברה ברמת הבסיס - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","בעת יצירת חשבון עבור חברת Child {0}, חשבון האב {1} לא נמצא. אנא צור חשבון הורים בתאריך COA תואם",
+Account Not Found,החשבון לא נמצא,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","בעת יצירת חשבון עבור חברת Child {0}, חשבון האם {1} נמצא כחשבון ספר חשבונות.",
+Please convert the parent account in corresponding child company to a group account.,המיר את חשבון האם בחברת ילדים מתאימה לחשבון קבוצתי.,
+Invalid Parent Account,חשבון הורה לא חוקי,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","שינוי שם זה מותר רק דרך חברת האם {0}, כדי למנוע אי התאמה.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","אם אתה {0} {1} כמויות של הפריט {2}, התוכנית {3} תחול על הפריט.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","אם אתה {0} {1} שווה פריט {2}, התוכנית {3} תחול על הפריט.",
+"As the field {0} is enabled, the field {1} is mandatory.","מאחר שהשדה {0} מופעל, השדה {1} הוא חובה.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","מאחר שהשדה {0} מופעל, הערך של השדה {1} צריך להיות יותר מ -1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},לא ניתן לספק מספר סידורי {0} של פריט {1} מכיוון שהוא שמור להזמנת מכירה מלאה {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","להזמנת מכר {0} יש הזמנה לפריט {1}, אתה יכול לספק שמורה רק {1} כנגד {0}.",
+{0} Serial No {1} cannot be delivered,לא ניתן לספק {0} מספר סידורי {1},
+Row {0}: Subcontracted Item is mandatory for the raw material {1},שורה {0}: פריט בקבלנות משנה הוא חובה עבור חומר הגלם {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","מכיוון שיש מספיק חומרי גלם, בקשת החומרים אינה נדרשת עבור מחסן {0}.",
+" If you still want to proceed, please enable {0}.","אם אתה עדיין רוצה להמשיך, הפעל את {0}.",
+The item referenced by {0} - {1} is already invoiced,הפריט אליו הוזכר {0} - {1} כבר מחויב,
+Therapy Session overlaps with {0},מושב טיפולי חופף עם {0},
+Therapy Sessions Overlapping,מפגשי טיפול חופפים,
+Therapy Plans,תוכניות טיפול,
+"Item Code, warehouse, quantity are required on row {0}","קוד פריט, מחסן, כמות נדרשים בשורה {0}",
+Get Items from Material Requests against this Supplier,קבל פריטים מבקשות חומר נגד ספק זה,
+Enable European Access,אפשר גישה אירופית,
+Creating Purchase Order ...,יוצר הזמנת רכש ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","בחר ספק מבין ספקי ברירת המחדל של הפריטים למטה. בבחירה, הזמנת רכש תתבצע כנגד פריטים השייכים לספק שנבחר בלבד.",
+Row #{}: You must select {} serial numbers for item {}.,שורה מספר {}: עליך לבחור {} מספרים סידוריים לפריט {}.,
diff --git a/erpnext/translations/hi.csv b/erpnext/translations/hi.csv
index 3e7db82..c385fc6 100644
--- a/erpnext/translations/hi.csv
+++ b/erpnext/translations/hi.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},वास्तविक प्रकार टैक्स पंक्ति में आइटम की दर में शामिल नहीं किया जा सकता {0},
Add,जोड़ना,
Add / Edit Prices,/ संपादित कीमतों में जोड़ें,
-Add All Suppliers,सभी आपूर्तिकर्ता जोड़ें,
Add Comment,टिप्पणी जोड़ें,
Add Customers,ग्राहक जोड़ें,
Add Employees,कर्मचारियों को जोड़ने,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',घटा नहीं सकते जब श्रेणी 'मूल्यांकन' या 'Vaulation और कुल' के लिए है,
"Cannot delete Serial No {0}, as it is used in stock transactions","नहीं हटा सकते सीरियल नहीं {0}, यह शेयर लेनदेन में इस्तेमाल किया जाता है के रूप में",
Cannot enroll more than {0} students for this student group.,{0} इस छात्र समूह के लिए छात्रों की तुलना में अधिक नामांकन नहीं कर सकता।,
-Cannot find Item with this barcode,इस बारकोड के साथ आइटम नहीं मिल सकता है,
Cannot find active Leave Period,सक्रिय छुट्टी अवधि नहीं मिल सका,
Cannot produce more Item {0} than Sales Order quantity {1},अधिक आइटम उत्पादन नहीं कर सकते {0} से बिक्री आदेश मात्रा {1},
Cannot promote Employee with status Left,स्थिति के साथ कर्मचारी को बढ़ावा नहीं दे सकता है,
Cannot refer row number greater than or equal to current row number for this Charge type,इस आरोप प्रकार के लिए अधिक से अधिक या वर्तमान पंक्ति संख्या के बराबर पंक्ति संख्या का उल्लेख नहीं कर सकते,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"पहली पंक्ति के लिए ' पिछली पंक्ति कुल पर ', ' पिछली पंक्ति पर राशि ' या के रूप में कार्यभार प्रकार का चयन नहीं कर सकते",
-Cannot set a received RFQ to No Quote,कोई उद्धरण नहीं प्राप्त करने के लिए प्राप्त आरएफक्यू को सेट नहीं किया जा सकता,
Cannot set as Lost as Sales Order is made.,बिक्री आदेश किया जाता है के रूप में खो के रूप में सेट नहीं कर सकता .,
Cannot set authorization on basis of Discount for {0},के लिए छूट के आधार पर प्राधिकरण सेट नहीं कर सकता {0},
Cannot set multiple Item Defaults for a company.,किसी कंपनी के लिए एकाधिक आइटम डिफ़ॉल्ट सेट नहीं कर सकते हैं।,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,प्रभार प्रत्येक आइटम के खिलाफ खरीद रसीद में नवीनीकृत कर रहे हैं,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","प्रभार अनुपात में अपने चयन के अनुसार, मद मात्रा या राशि के आधार पर वितरित किया जाएगा",
-Chart Of Accounts,खातों का चार्ट,
Chart of Cost Centers,लागत केंद्र के चार्ट,
Check all,सभी की जांच करो,
Checkout,चेक आउट,
@@ -581,7 +577,6 @@
Compensatory Off,प्रतिपूरक बंद,
Compensatory leave request days not in valid holidays,मुआवजा छोड़ने के अनुरोध दिन वैध छुट्टियों में नहीं,
Complaint,शिकायत,
-Completed Qty can not be greater than 'Qty to Manufacture',की तुलना में 'मात्रा निर्माण करने के लिए' पूरी की गई मात्रा अधिक नहीं हो सकता,
Completion Date,पूरा करने की तिथि,
Computer,कंप्यूटर,
Condition,शर्त,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","बनाएँ और दैनिक, साप्ताहिक और मासिक ईमेल हज़म का प्रबंधन .",
Create customer quotes,ग्राहक उद्धरण बनाएँ,
Create rules to restrict transactions based on values.,मूल्यों पर आधारित लेनदेन को प्रतिबंधित करने के नियम बनाएँ .,
-Created By,द्वारा बनाया गया,
Created {0} scorecards for {1} between: ,{1} के लिए {1} स्कोरकार्ड बनाया:,
Creating Company and Importing Chart of Accounts,कंपनी बनाना और खातों का चार्ट आयात करना,
Creating Fees,फीस बनाना,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,स्थानांतरण तिथि से पहले कर्मचारी स्थानांतरण जमा नहीं किया जा सकता है,
Employee cannot report to himself.,कर्मचारी खुद को रिपोर्ट नहीं कर सकते हैं।,
Employee relieved on {0} must be set as 'Left',{0} को राहत मिली कर्मचारी 'वाम ' के रूप में स्थापित किया जाना चाहिए,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,कर्मचारी की स्थिति वर्तमान में इस कर्मचारी को रिपोर्ट कर रहे निम्नलिखित के रूप में 'वाम' के लिए सेट नहीं किया जा सकता है:,
Employee {0} already submited an apllication {1} for the payroll period {2},नियोक्ता {0} ने पेरोल अवधि के लिए पहले से ही एक आवेदन {1} जमा किया है {2},
Employee {0} has already applied for {1} between {2} and {3} : ,कर्मचारी {0} पहले से {2} और {3} के बीच {1} के लिए आवेदन कर चुका है:,
Employee {0} has no maximum benefit amount,कर्मचारी {0} में अधिकतम लाभ राशि नहीं है,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,पंक्ति {0} के लिए: नियोजित मात्रा दर्ज करें,
"For {0}, only credit accounts can be linked against another debit entry","{0}, केवल ऋण खातों अन्य डेबिट प्रविष्टि के खिलाफ जोड़ा जा सकता है के लिए",
"For {0}, only debit accounts can be linked against another credit entry","{0}, केवल डेबिट खातों एक और क्रेडिट प्रविष्टि के खिलाफ जोड़ा जा सकता है के लिए",
-Form View,फॉर्म देखें,
Forum Activity,फोरम गतिविधि,
Free item code is not selected,नि: शुल्क आइटम कोड का चयन नहीं किया गया है,
Freight and Forwarding Charges,फ्रेट और अग्रेषण शुल्क,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","पहले आवंटित नहीं किया जा सकता छोड़ दो {0}, छुट्टी संतुलन पहले से ही ले अग्रेषित भविष्य छुट्टी आवंटन रिकॉर्ड में किया गया है के रूप में {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","छुट्टी संतुलन पहले से ही ले अग्रेषित भविष्य छुट्टी आवंटन रिकॉर्ड में किया गया है, के रूप में पहले {0} रद्द / लागू नहीं किया जा सकते हैं छोड़ दो {1}",
Leave of type {0} cannot be longer than {1},प्रकार की छुट्टी {0} से बड़ा नहीं हो सकता है {1},
-Leave the field empty to make purchase orders for all suppliers,सभी आपूर्तिकर्ताओं के लिए खरीद आदेश बनाने के लिए खाली क्षेत्र छोड़ दें,
Leaves,पत्ते,
Leaves Allocated Successfully for {0},पत्तियों के लिए सफलतापूर्वक आवंटित {0},
Leaves has been granted sucessfully,पत्तियां सफलतापूर्वक दी गई हैं,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,सामग्री के बिल के साथ कोई वस्तुओं का निर्माण करने के लिए,
No Items with Bill of Materials.,सामग्री के बिल के साथ कोई आइटम नहीं।,
No Permission,अनुमति नहीं है,
-No Quote,कोई उद्धरण नहीं,
No Remarks,कोई टिप्पणी,
No Result to submit,प्रस्तुत करने के लिए कोई भी परिणाम नहीं है,
No Salary Structure assigned for Employee {0} on given date {1},दिए गए दिनांक पर कर्मचारी {0} के लिए आवंटित कोई वेतन संरचना {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,बीच पाया ओवरलैपिंग की स्थिति :,
Owner,स्वामी,
PAN,पैन,
-PO already created for all sales order items,पीओ पहले से ही सभी बिक्री आदेश वस्तुओं के लिए बनाया गया है,
POS,पीओएस,
POS Profile,पीओएस प्रोफाइल,
POS Profile is required to use Point-of-Sale,पॉस की बिक्री का उपयोग पॉइंट-ऑफ-सेल के लिए आवश्यक है,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,प्रभारी प्रकार पहले का चयन करें,
Please select Company,कंपनी का चयन करें,
Please select Company and Designation,कृपया कंपनी और पदनाम का चयन करें,
-Please select Company and Party Type first,पहले कंपनी और पार्टी के प्रकार का चयन करें,
Please select Company and Posting Date to getting entries,कृपया प्रविष्टियां प्राप्त करने के लिए कंपनी और पोस्टिंग तिथि का चयन करें,
Please select Company first,पहले कंपनी का चयन करें,
Please select Completion Date for Completed Asset Maintenance Log,कृपया पूर्ण संपत्ति रखरखाव लॉग के लिए समापन तिथि का चयन करें,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,पंक्ति {0}: UoM रूपांतरण कारक है अनिवार्य है,
Row {0}: select the workstation against the operation {1},पंक्ति {0}: ऑपरेशन के खिलाफ वर्कस्टेशन का चयन करें {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,पंक्ति {0}: {1} आइटम {2} के लिए आवश्यक सीरियल नंबर आपने {3} प्रदान किया है,
-Row {0}: {1} is required to create the Opening {2} Invoices,पंक्ति {0}: {1} खोलने {2} चालान बनाने के लिए आवश्यक है,
Row {0}: {1} must be greater than 0,पंक्ति {0}: {1} 0 से अधिक होना चाहिए,
Row {0}: {1} {2} does not match with {3},पंक्ति {0}: {1} {2} के साथ मेल नहीं खाता {3},
Row {0}:Start Date must be before End Date,पंक्ति {0} : आरंभ तिथि समाप्ति तिथि से पहले होना चाहिए,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,अनुदान भेजें ईमेल भेजें,
Send Now,अब भेजें,
Send SMS,एसएमएस भेजें,
-Send Supplier Emails,प्रदायक ईमेल भेजें,
Send mass SMS to your contacts,अपने संपर्कों के लिए बड़े पैमाने पर एसएमएस भेजें,
Sensitivity,संवेदनशीलता,
Sent,भेजे गए,
-Serial #,सीरियल #,
Serial No and Batch,सीरियल नहीं और बैच,
Serial No is mandatory for Item {0},सीरियल मद के लिए अनिवार्य है {0},
Serial No {0} does not belong to Batch {1},सीरियल नंबर {0} बैच से संबंधित नहीं है {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"आप इस प्रणाली स्थापित कर रहे हैं , जिसके लिए आपकी कंपनी का नाम .",
The number of shares and the share numbers are inconsistent,शेयरों की संख्या और शेयर संख्याएं असंगत हैं,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,योजना {0} में भुगतान गेटवे खाता इस भुगतान अनुरोध में भुगतान गेटवे खाते से अलग है,
-The request for quotation can be accessed by clicking on the following link,उद्धरण के लिए अनुरोध नीचे दिए गए लिंक पर क्लिक करके पहुँचा जा सकता है,
The selected BOMs are not for the same item,चुने गए BOMs एक ही मद के लिए नहीं हैं,
The selected item cannot have Batch,चयनित आइटम बैच नहीं हो सकता,
The seller and the buyer cannot be the same,विक्रेता और खरीदार एक ही नहीं हो सकता,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},कुल लचीला लाभ घटक राशि {0} अधिकतम लाभ से कम नहीं होनी चाहिए {1},
Total hours: {0},कुल घंटे: {0},
Total leaves allocated is mandatory for Leave Type {0},आवंटित कुल पत्तियां छुट्टी प्रकार {0} के लिए अनिवार्य है,
-Total weightage assigned should be 100%. It is {0},कुल आवंटित वेटेज 100 % होना चाहिए . यह है {0},
Total working hours should not be greater than max working hours {0},कुल काम के घंटे अधिकतम काम के घंटे से अधिक नहीं होना चाहिए {0},
Total {0} ({1}),कुल {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","कुल {0} सभी मदों के लिए शून्य है, तो आप 'के आधार पर शुल्क वितरित' परिवर्तन होना चाहिए हो सकता है",
@@ -3316,7 +3299,6 @@
What do you need help with?,तुम्हें किसमें मदद चाहिए?,
What does it do?,यह क्या करता है?,
Where manufacturing operations are carried.,निर्माण कार्यों कहां किया जाता है।,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","चाइल्ड कंपनी {0} के लिए खाता बनाते समय, पैरेंट अकाउंट {1} नहीं मिला। कृपया संबंधित COA में मूल खाता बनाएँ",
White,सफेद,
Wire Transfer,वायर ट्रांसफर,
WooCommerce Products,WooCommerce उत्पाद,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} बनाए गए संस्करण।,
{0} {1} created,{0} {1} बनाया,
{0} {1} does not exist,{0} {1} मौजूद नहीं है,
-{0} {1} does not exist.,{0} {1} मौजूद नहीं है,
{0} {1} has been modified. Please refresh.,{0} {1} संशोधित किया गया है . फ़िर से दूबारा करें.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} जमा नहीं किया गया है अतः कार्रवाई पूरी नहीं की जा सकती,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} {2} के साथ जुड़ा हुआ है, लेकिन पक्ष खाता {3} है",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} करता नहीं मौजूद है,
{0}: {1} not found in Invoice Details table,{0} {1} चालान विवरण तालिका में नहीं मिला,
{} of {},{} का {},
+Assigned To,को सौंपा,
Chat,बातचीत,
Completed By,द्वारा पूरा किया गया,
Conditions,शर्तेँ,
@@ -3506,7 +3488,9 @@
Merge with existing,मौजूदा साथ मर्ज,
Office,कार्यालय,
Orientation,अभिविन्यास,
+Parent,माता-पिता,
Passive,निष्क्रिय,
+Payment Failed,भुगतान असफल हुआ,
Percent,प्रतिशत,
Permanent,स्थायी,
Personal,व्यक्तिगत,
@@ -3544,7 +3528,6 @@
Company field is required,कंपनी क्षेत्र की आवश्यकता है,
Creating Dimensions...,आयाम बनाना ...,
Duplicate entry against the item code {0} and manufacturer {1},आइटम कोड {0} और निर्माता {1} के खिलाफ डुप्लिकेट प्रविष्टि,
-Import Chart Of Accounts from CSV / Excel files,CSV / Excel फ़ाइलों से खातों का आयात चार्ट,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,अमान्य GSTIN! आपके द्वारा दर्ज किया गया इनपुट UIN धारकों या गैर-निवासी OIDAR सेवा प्रदाताओं के लिए GSTIN प्रारूप से मेल नहीं खाता है,
Invoice Grand Total,इनवॉइस ग्रैंड टोटल,
Last carbon check date cannot be a future date,अंतिम कार्बन जांच की तारीख भविष्य की तारीख नहीं हो सकती,
@@ -3556,6 +3539,7 @@
Show {0},{0} दिखाएं,
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", "।", "/", "{" और "}" को छोड़कर विशेष वर्ण श्रृंखला में अनुमति नहीं है",
Target Details,लक्ष्य विवरण,
+{0} already has a Parent Procedure {1}.,{0} पहले से ही एक पेरेंट प्रोसीजर {1} है।,
API,एपीआई,
Annual,वार्षिक,
Approved,अनुमोदित,
@@ -3572,6 +3556,8 @@
No data to export,निर्यात करने के लिए कोई डेटा नहीं,
Portrait,चित्र,
Print Heading,शीर्षक प्रिंट,
+Scheduler Inactive,अनुसूचक निष्क्रिय,
+Scheduler is inactive. Cannot import data.,शेड्यूलर निष्क्रिय है। डेटा आयात नहीं कर सकता।,
Show Document,दस्तावेज़ दिखाएं,
Show Traceback,ट्रेसेबैक दिखाएं,
Video,वीडियो,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},आइटम के लिए गुणवत्ता निरीक्षण बनाएं {0},
Creating Accounts...,खाते बनाना ...,
Creating bank entries...,बैंक प्रविष्टियां बनाना ...,
-Creating {0},{0} बनाना,
Credit limit is already defined for the Company {0},क्रेडिट सीमा पहले से ही कंपनी के लिए परिभाषित है {0},
Ctrl + Enter to submit,सबमिट करने के लिए Ctrl + Enter करें,
Ctrl+Enter to submit,सबमिट करने के लिए Ctrl + Enter,
@@ -3921,7 +3906,6 @@
Plaid public token error,प्लेड पब्लिक टोकन एरर,
Plaid transactions sync error,प्लेड ट्रांजेक्शन सिंक एरर,
Please check the error log for details about the import errors,कृपया आयात त्रुटियों के बारे में विवरण के लिए त्रुटि लॉग की जांच करें,
-Please click on the following link to set your new password,अपना नया पासवर्ड सेट करने के लिए नीचे दिए गए लिंक पर क्लिक करें,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,कृपया कंपनी <b>{} के</b> लिए <b>DATEV सेटिंग</b> बनाएं।,
Please create adjustment Journal Entry for amount {0} ,कृपया राशि {0} के लिए समायोजन जर्नल प्रविष्टि बनाएँ,
Please do not create more than 500 items at a time,कृपया एक बार में 500 से अधिक आइटम न बनाएं,
@@ -3997,6 +3981,7 @@
Release date must be in the future,रिलीज की तारीख भविष्य में होनी चाहिए,
Relieving Date must be greater than or equal to Date of Joining,"राहत की तारीख, ज्वाइनिंग की तारीख से अधिक या उसके बराबर होनी चाहिए",
Rename,नाम बदलें,
+Rename Not Allowed,नाम नहीं दिया गया,
Repayment Method is mandatory for term loans,सावधि ऋण के लिए चुकौती विधि अनिवार्य है,
Repayment Start Date is mandatory for term loans,सावधि ऋण के लिए चुकौती प्रारंभ तिथि अनिवार्य है,
Report Item,वस्तु की सूचना,
@@ -4043,7 +4028,6 @@
Select All,सभी का चयन,
Select Difference Account,अंतर खाता चुनें,
Select a Default Priority.,एक डिफ़ॉल्ट प्राथमिकता चुनें।,
-Select a Supplier from the Default Supplier List of the items below.,नीचे दी गई वस्तुओं की डिफ़ॉल्ट आपूर्तिकर्ता सूची से एक आपूर्तिकर्ता का चयन करें।,
Select a company,एक कंपनी का चयन करें,
Select finance book for the item {0} at row {1},पंक्ति {1} पर आइटम {0} के लिए वित्त पुस्तक चुनें,
Select only one Priority as Default.,डिफ़ॉल्ट के रूप में केवल एक प्राथमिकता का चयन करें।,
@@ -4247,7 +4231,6 @@
Actual ,वास्तविक,
Add to cart,कार्ट में जोड़ें,
Budget,बजट,
-Chart Of Accounts Importer,लेखा आयातक का चार्ट,
Chart of Accounts,लेखा जोखा का व्यौरा,
Customer database.,ग्राहक डेटाबेस।,
Days Since Last order,दिनों से पिछले आदेश,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,समाप्ति तिथि आरंभ तिथि से कम नहीं हो सकता,
For Default Supplier (Optional),डिफ़ॉल्ट प्रदायक (वैकल्पिक) के लिए,
From date cannot be greater than To date,दिनांक से दिनांक से अधिक नहीं हो सकता है,
-Get items from,से आइटम प्राप्त,
Group by,समूह द्वारा,
In stock,स्टॉक में,
Item name,मद का नाम,
@@ -4532,32 +4514,22 @@
Accounts Settings,लेखा सेटिंग्स,
Settings for Accounts,खातों के लिए सेटिंग्स,
Make Accounting Entry For Every Stock Movement,हर शेयर आंदोलन के लिए लेखा प्रविष्टि बनाओ,
-"If enabled, the system will post accounting entries for inventory automatically.","यदि सक्रिय है, प्रणाली स्वतः सूची के लिए लेखांकन प्रविष्टियों के बाद होगा.",
-Accounts Frozen Upto,लेखा तक जमे हुए,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","इस तारीख तक कर जम लेखा प्रविष्टि, कोई नहीं / नीचे निर्दिष्ट भूमिका छोड़कर प्रविष्टि को संशोधित कर सकते हैं.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,भूमिका जमे लेखा एवं संपादित जमे प्रविष्टियां सेट करने की अनुमति,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,इस भूमिका के साथ उपयोक्ता जमे हुए खातों के खिलाफ लेखांकन प्रविष्टियों को संशोधित / जमे हुए खातों सेट और बनाने के लिए अनुमति दी जाती है,
Determine Address Tax Category From,पता कर श्रेणी से निर्धारित करें,
-Address used to determine Tax Category in transactions.,लेनदेन में कर श्रेणी निर्धारित करने के लिए उपयोग किया जाने वाला पता।,
Over Billing Allowance (%),बिलिंग भत्ता (%),
-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 for $110.,प्रतिशत आपको आदेश दी गई राशि के मुकाबले अधिक बिल करने की अनुमति है। उदाहरण के लिए: यदि किसी वस्तु के लिए ऑर्डर मूल्य $ 100 है और सहिष्णुता 10% के रूप में सेट की जाती है तो आपको $ 110 का बिल करने की अनुमति है।,
Credit Controller,क्रेडिट नियंत्रक,
-Role that is allowed to submit transactions that exceed credit limits set.,निर्धारित ऋण सीमा से अधिक लेनदेन है कि प्रस्तुत करने की अनुमति दी है कि भूमिका.,
Check Supplier Invoice Number Uniqueness,चेक आपूर्तिकर्ता चालान संख्या अद्वितीयता,
Make Payment via Journal Entry,जर्नल प्रविष्टि के माध्यम से भुगतान करने के,
Unlink Payment on Cancellation of Invoice,चालान को रद्द करने पर भुगतान अनलिंक,
-Unlink Advance Payment on Cancelation of Order,आदेश को रद्द करने पर अग्रिम भुगतान अनलिंक करें,
Book Asset Depreciation Entry Automatically,पुस्तक परिसंपत्ति मूल्यह्रास प्रविष्टि स्वचालित रूप से,
Automatically Add Taxes and Charges from Item Tax Template,आइटम टैक्स टेम्पलेट से स्वचालित रूप से टैक्स और शुल्क जोड़ें,
Automatically Fetch Payment Terms,स्वचालित रूप से भुगतान शर्तें प्राप्त करें,
-Show Inclusive Tax In Print,प्रिंट में समावेशी कर दिखाएं,
Show Payment Schedule in Print,प्रिंट में भुगतान शेड्यूल दिखाएं,
Currency Exchange Settings,मुद्रा विनिमय सेटिंग्स,
Allow Stale Exchange Rates,स्टेले एक्सचेंज दरें अनुमति दें,
Stale Days,स्टेल डेज़,
Report Settings,रिपोर्ट सेटिंग,
Use Custom Cash Flow Format,कस्टम कैश फ्लो प्रारूप का उपयोग करें,
-Only select if you have setup Cash Flow Mapper documents,केवल तभी चुनें यदि आपके पास कैश फ्लो मैपर दस्तावेज सेटअप है,
Allowed To Transact With,साथ लेनदेन करने की अनुमति है,
SWIFT number,स्विफ़्ट नंबर,
Branch Code,शाखा क्र्मांक,
@@ -4940,7 +4912,6 @@
POS Customer Group,पीओएस ग्राहक समूह,
POS Field,पीओएस फील्ड,
POS Item Group,पीओएस मद समूह,
-[Select],[ चुनें ],
Company Address,कंपनी का पता,
Update Stock,स्टॉक अद्यतन,
Ignore Pricing Rule,मूल्य निर्धारण नियम की अनदेखी,
@@ -5495,8 +5466,6 @@
Supplier Naming By,द्वारा नामकरण प्रदायक,
Default Supplier Group,डिफ़ॉल्ट प्रदायक समूह,
Default Buying Price List,डिफ़ॉल्ट खरीद मूल्य सूची,
-Maintain same rate throughout purchase cycle,खरीद चक्र के दौरान एक ही दर बनाए रखें,
-Allow Item to be added multiple times in a transaction,आइटम एक सौदे में कई बार जोड़े जाने की अनुमति दें,
Backflush Raw Materials of Subcontract Based On,सबकंट्रैक्ट के आधार पर बैकफ्लश कच्चे माल,
Material Transferred for Subcontract,उपखंड के लिए सामग्री हस्तांतरित,
Over Transfer Allowance (%),ट्रांसफर अलाउंस (%),
@@ -5540,7 +5509,6 @@
Current Stock,मौजूदा स्टॉक,
PUR-RFQ-.YYYY.-,पुर-आरएफक्यू-.YYYY.-,
For individual supplier,व्यक्तिगत आपूर्तिकर्ता,
-Supplier Detail,प्रदायक विस्तार,
Link to Material Requests,सामग्री अनुरोधों के लिए लिंक,
Message for Supplier,प्रदायक के लिए संदेश,
Request for Quotation Item,कोटेशन मद के लिए अनुरोध,
@@ -6481,7 +6449,6 @@
Appraisal Template,मूल्यांकन टेम्पलेट,
For Employee Name,कर्मचारी का नाम,
Goals,लक्ष्य,
-Calculate Total Score,कुल स्कोर की गणना,
Total Score (Out of 5),कुल स्कोर (5 से बाहर),
"Any other remarks, noteworthy effort that should go in the records.","किसी भी अन्य टिप्पणी, अभिलेखों में जाना चाहिए कि उल्लेखनीय प्रयास।",
Appraisal Goal,मूल्यांकन लक्ष्य,
@@ -6599,11 +6566,6 @@
Reason for Leaving,छोड़ने के लिए कारण,
Leave Encashed?,भुनाया छोड़ दो?,
Encashment Date,नकदीकरण तिथि,
-Exit Interview Details,साक्षात्कार विवरण से बाहर निकलें,
-Held On,पर Held,
-Reason for Resignation,इस्तीफे का कारण,
-Better Prospects,बेहतर संभावनाओं,
-Health Concerns,स्वास्थ्य चिंताएं,
New Workplace,नए कार्यस्थल,
HR-EAD-.YYYY.-,मानव संसाधन-EAD-.YYYY.-,
Returned Amount,लौटाई गई राशि,
@@ -6740,10 +6702,7 @@
Employee Settings,कर्मचारी सेटिंग्स,
Retirement Age,सेवानिवृत्ति आयु,
Enter retirement age in years,साल में सेवानिवृत्ति की आयु दर्ज,
-Employee Records to be created by,कर्मचारी रिकॉर्ड्स द्वारा पैदा किए जाने की,
-Employee record is created using selected field. ,कर्मचारी रिकॉर्ड चयनित क्षेत्र का उपयोग कर बनाया जाता है.,
Stop Birthday Reminders,बंद करो जन्मदिन अनुस्मारक,
-Don't send Employee Birthday Reminders,कर्मचारी जन्मदिन अनुस्मारक न भेजें,
Expense Approver Mandatory In Expense Claim,व्यय दावा में व्यय अनुमान अनिवार्य है,
Payroll Settings,पेरोल सेटिंग्स,
Leave,छोड़ना,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,छोड़ने आवेदन में स्वीकार्य अनिवार्य छोड़ दें,
Show Leaves Of All Department Members In Calendar,कैलेंडर में सभी विभाग के सदस्यों की पत्तियां दिखाएं,
Auto Leave Encashment,ऑटो लीव एनकैशमेंट,
-Restrict Backdated Leave Application,बैकडेटेड लीव एप्लीकेशन को प्रतिबंधित करें,
Hiring Settings,हायरिंग सेटिंग्स,
Check Vacancies On Job Offer Creation,नौकरी की पेशकश निर्माण पर रिक्तियों की जाँच करें,
Identification Document Type,पहचान दस्तावेज प्रकार,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,विनिर्माण सेटिंग्स,
Raw Materials Consumption,कच्चे माल की खपत,
Allow Multiple Material Consumption,एकाधिक सामग्री की खपत की अनुमति दें,
-Allow multiple Material Consumption against a Work Order,कार्य आदेश के विरुद्ध कई सामग्री की अनुमति दें,
Backflush Raw Materials Based On,Backflush आधारित कच्चे माल पर,
Material Transferred for Manufacture,सामग्री निर्माण के लिए हस्तांतरित,
Capacity Planning,क्षमता की योजना,
Disable Capacity Planning,क्षमता योजना को अक्षम करें,
Allow Overtime,ओवरटाइम की अनुमति दें,
-Plan time logs outside Workstation Working Hours.,कार्य केंद्र के कार्य के घंटे के बाहर समय लॉग्स की योजना बनाएँ।,
Allow Production on Holidays,छुट्टियों पर उत्पादन की अनुमति,
Capacity Planning For (Days),(दिन) के लिए क्षमता योजना,
-Try planning operations for X days in advance.,अग्रिम में एक्स दिनों के लिए आपरेशन की योजना बना प्रयास करें।,
-Time Between Operations (in mins),(मिनट में) संचालन के बीच का समय,
-Default 10 mins,10 मिनट चूक,
Default Warehouses for Production,उत्पादन के लिए डिफ़ॉल्ट गोदाम,
Default Work In Progress Warehouse,प्रगति गोदाम में डिफ़ॉल्ट वर्क,
Default Finished Goods Warehouse,डिफ़ॉल्ट तैयार माल गोदाम,
Default Scrap Warehouse,डिफ़ॉल्ट स्क्रैप वेयरहाउस,
-Over Production for Sales and Work Order,बिक्री और कार्य आदेश के लिए उत्पादन,
Overproduction Percentage For Sales Order,बिक्री आदेश के लिए अधिक उत्पादन प्रतिशत,
Overproduction Percentage For Work Order,कार्य आदेश के लिए अधिक उत्पादन प्रतिशत,
Other Settings,अन्य सेटिंग,
Update BOM Cost Automatically,स्वचालित रूप से अद्यतन BOM लागत,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","नवीनतम मूल्यांकन दर / मूल्य सूची दर / कच्ची सामग्रियों की अंतिम खरीदारी दर के आधार पर, स्वचालित रूप से समय-समय पर बीओएम लागत को शेड्यूलर के माध्यम से अपडेट करें।",
Material Request Plan Item,सामग्री अनुरोध योजना मद,
Material Request Type,सामग्री अनुरोध प्रकार,
Material Issue,महत्त्वपूर्ण विषय,
@@ -7603,10 +7554,6 @@
Quality Goal,गुणवत्ता लक्ष्य,
Monitoring Frequency,निगरानी की आवृत्ति,
Weekday,काम करने के दिन,
-January-April-July-October,जनवरी से अप्रैल-जुलाई से अक्टूबर,
-Revision and Revised On,संशोधन और संशोधित पर,
-Revision,संशोधन,
-Revised On,पर संशोधित,
Objectives,उद्देश्य,
Quality Goal Objective,गुणवत्ता लक्ष्य उद्देश्य,
Objective,लक्ष्य,
@@ -7619,7 +7566,6 @@
Processes,प्रक्रियाओं,
Quality Procedure Process,गुणवत्ता प्रक्रिया प्रक्रिया,
Process Description,प्रक्रिया वर्णन,
-Child Procedure,बाल प्रक्रिया,
Link existing Quality Procedure.,लिंक मौजूदा गुणवत्ता प्रक्रिया।,
Additional Information,अतिरिक्त जानकारी,
Quality Review Objective,गुणवत्ता की समीक्षा उद्देश्य,
@@ -7787,15 +7733,9 @@
Default Customer Group,डिफ़ॉल्ट ग्राहक समूह,
Default Territory,Default टेरिटरी,
Close Opportunity After Days,बंद के मौके दिनों के बाद,
-Auto close Opportunity after 15 days,15 दिनों के बाद ऑटो बंद के मौके,
Default Quotation Validity Days,डिफ़ॉल्ट कोटेशन वैधता दिन,
Sales Update Frequency,बिक्री अद्यतन आवृत्ति,
-How often should project and company be updated based on Sales Transactions.,बिक्री लेनदेन के आधार पर परियोजना और कंपनी को कितनी बार अपडेट किया जाना चाहिए।,
Each Transaction,प्रत्येक लेनदेन,
-Allow user to edit Price List Rate in transactions,उपयोगकर्ता लेनदेन में मूल्य सूची दर को संपादित करने की अनुमति दें,
-Allow multiple Sales Orders against a Customer's Purchase Order,एक ग्राहक की खरीद के आदेश के खिलाफ कई विक्रय आदेश की अनुमति दें,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,मान्य बिक्री मूल्य खरीद दर या मूल्यांकन दर के खिलाफ मद के लिए,
-Hide Customer's Tax Id from Sales Transactions,बिक्री लेन-देन से ग्राहक के कर आईडी छुपाएं,
SMS Center,एसएमएस केंद्र,
Send To,इन्हें भेजें,
All Contact,सभी संपर्क,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,वस्तुओं में इस्तेमाल किया निर्माता,
Limited to 12 characters,12 अक्षरों तक सीमित,
MAT-MR-.YYYY.-,मेट-एमआर .YYYY.-,
-Set Warehouse,वेयरहाउस सेट करें,
-Sets 'For Warehouse' in each row of the Items table.,आइटम तालिका की प्रत्येक पंक्ति में 'वेयरहाउस के लिए' सेट करता है।,
-Requested For,के लिए अनुरोध,
Partially Ordered,आंशिक रूप से आदेश दिया गया,
Transferred,का तबादला,
% Ordered,% का आदेश दिया,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Default स्टॉक UOM,
Sample Retention Warehouse,नमूना रिटेंशन गोदाम,
Default Valuation Method,डिफ़ॉल्ट मूल्यन विधि,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,आप मात्रा के खिलाफ और अधिक प्राप्त या वितरित करने के लिए अनुमति दी जाती प्रतिशत का आदेश दिया. उदाहरण के लिए: यदि आप 100 यूनिट का आदेश दिया है. और अपने भत्ता 10% तो आप 110 इकाइयों को प्राप्त करने के लिए अनुमति दी जाती है.,
-Action if Quality inspection is not submitted,यदि गुणवत्ता निरीक्षण प्रस्तुत नहीं किया गया तो कार्रवाई की जाएगी,
Show Barcode Field,शो बारकोड फील्ड,
Convert Item Description to Clean HTML,HTML को साफ करने के लिए आइटम विवरण कन्वर्ट करें,
-Auto insert Price List rate if missing,ऑटो डालने मूल्य सूची दर लापता यदि,
Allow Negative Stock,नकारात्मक स्टॉक की अनुमति दें,
Automatically Set Serial Nos based on FIFO,स्वचालित रूप से फीफो पर आधारित नग सीरियल सेट,
-Set Qty in Transactions based on Serial No Input,सीरियल नो इनपुट के आधार पर लेनदेन में मात्रा निर्धारित करें,
Auto Material Request,ऑटो सामग्री अनुरोध,
-Raise Material Request when stock reaches re-order level,सामग्री अनुरोध उठाएँ जब शेयर पुनः आदेश के स्तर तक पहुँच,
-Notify by Email on creation of automatic Material Request,स्वचालित सामग्री अनुरोध के निर्माण पर ईमेल द्वारा सूचित करें,
Inter Warehouse Transfer Settings,इंटर वेयरहाउस ट्रांसफर सेटिंग्स,
-Allow Material Transfer From Delivery Note and Sales Invoice,वितरण नोट और बिक्री चालान से सामग्री स्थानांतरण की अनुमति दें,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,खरीद रसीद और खरीद चालान से सामग्री हस्तांतरण की अनुमति दें,
Freeze Stock Entries,स्टॉक प्रविष्टियां रुक,
Stock Frozen Upto,स्टॉक तक जमे हुए,
-Freeze Stocks Older Than [Days],रुक स्टॉक से अधिक उम्र [ दिन],
-Role Allowed to edit frozen stock,जमे हुए शेयर संपादित करने के लिए रख सकते है भूमिका,
Batch Identification,बैच की पहचान,
Use Naming Series,नामकरण श्रृंखला का उपयोग करें,
Naming Series Prefix,नामकरण श्रृंखला उपसर्ग,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,खरीद रसीद रुझान,
Purchase Register,इन पंजीकृत खरीद,
Quotation Trends,कोटेशन रुझान,
-Quoted Item Comparison,उद्धरित मद तुलना,
Received Items To Be Billed,बिल करने के लिए प्राप्त आइटम,
Qty to Order,मात्रा आदेश को,
Requested Items To Be Transferred,हस्तांतरित करने का अनुरोध आइटम,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,भौतिक अनुरोधों के लिए वेयरहाउस का चयन करें,
Transfer Materials For Warehouse {0},गोदाम {0} के लिए स्थानांतरण सामग्री,
Production Plan Material Request Warehouse,उत्पादन योजना सामग्री अनुरोध गोदाम,
-Set From Warehouse,वेयरहाउस से सेट करें,
-Source Warehouse (Material Transfer),स्रोत वेयरहाउस (सामग्री स्थानांतरण),
Sets 'Source Warehouse' in each row of the items table.,आइटम तालिका की प्रत्येक पंक्ति में 'स्रोत वेयरहाउस' सेट करता है।,
Sets 'Target Warehouse' in each row of the items table.,आइटम तालिका की प्रत्येक पंक्ति में 'लक्ष्य वेयरहाउस' सेट करता है।,
Show Cancelled Entries,रद्द प्रविष्टियाँ दिखाएँ,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"सेवा प्राप्त हुई, लेकिन बिल नहीं दिया गया",
Deferred Accounting Settings,आस्थगित लेखा सेटिंग्स,
Book Deferred Entries Based On,पुस्तक आस्थगित प्रविष्टियाँ आधारित,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","यदि "महीने" का चयन किया जाता है, तो निश्चित राशि को आस्थगित राजस्व के रूप में बुक किया जाएगा या प्रत्येक महीने के खर्च के बावजूद महीने में कई दिनों की संख्या। यदि पुरे महीने के लिए राजस्व या व्यय बुक नहीं किया जाता है, तो पहले से भुगतान किया जाएगा।",
Days,दिन,
Months,महीने,
Book Deferred Entries Via Journal Entry,बुक डिफर्ड एंट्री वाया जर्नल एंट्री,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,यदि यह अनियंत्रित है तो प्रत्यक्ष जीएल प्रविष्टियाँ Deferred Revenue / Expense को बुक करने के लिए बनाई जाएंगी,
Submit Journal Entries,जर्नल प्रविष्टियाँ भेजें,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,यदि यह अनियंत्रित है तो जर्नल एंट्रीज़ को ड्राफ्ट स्थिति में सहेजा जाएगा और इसे मैन्युअल रूप से सबमिट करना होगा,
Enable Distributed Cost Center,वितरित लागत केंद्र सक्षम करें,
@@ -8901,8 +8823,6 @@
Is Inter State,इंटर स्टेट है,
Purchase Details,खरीदारी का ब्योरा,
Depreciation Posting Date,मूल्यह्रास पोस्टिंग की तारीख,
-Purchase Order Required for Purchase Invoice & Receipt Creation,खरीद आदेश और रसीद निर्माण के लिए खरीद आदेश आवश्यक है,
-Purchase Receipt Required for Purchase Invoice Creation,खरीद चालान निर्माण के लिए आवश्यक खरीद रसीद,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","डिफ़ॉल्ट रूप से, प्रदायक नाम दर्ज किए गए आपूर्तिकर्ता नाम के अनुसार सेट किया जाता है। यदि आप चाहते हैं कि आपूर्तिकर्ताओं का नाम ए",
choose the 'Naming Series' option.,'नामकरण श्रृंखला' विकल्प चुनें।,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,नया खरीद लेनदेन बनाते समय डिफ़ॉल्ट मूल्य सूची कॉन्फ़िगर करें। इस मूल्य सूची से आइटम मूल्य प्राप्त किए जाएंगे।,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,इनकम टैक्स कंपोनेंट है,
Component properties and references ,घटक गुण और संदर्भ,
Additional Salary ,अतिरिक्त वेतन,
-Condtion and formula,संक्षेपण और सूत्र,
Unmarked days,अचिंतित दिन,
Absent Days,अनुपस्थित दिन,
Conditions and Formula variable and example,शर्तें और सूत्र चर और उदाहरण,
Feedback By,प्रतिक्रिया द्वारा,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-। एम.एम. .-। DD.-,
Manufacturing Section,विनिर्माण अनुभाग,
-Sales Order Required for Sales Invoice & Delivery Note Creation,बिक्री चालान और वितरण नोट निर्माण के लिए आवश्यक बिक्री आदेश,
-Delivery Note Required for Sales Invoice Creation,वितरण नोट बिक्री चालान निर्माण के लिए आवश्यक है,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","डिफ़ॉल्ट रूप से, ग्राहक का नाम पूर्ण नाम के अनुसार सेट किया गया है। यदि आप चाहते हैं कि ग्राहक एक के नाम से हों",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,नया विक्रय लेनदेन बनाते समय डिफ़ॉल्ट मूल्य सूची कॉन्फ़िगर करें। इस मूल्य सूची से आइटम मूल्य प्राप्त किए जाएंगे।,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","यदि यह विकल्प 'हां' कॉन्फ़िगर किया गया है, तो ERPNext आपको पहले सेल्स ऑर्डर बनाए बिना सेल्स इनवॉइस या डिलीवरी नोट बनाने से रोकेगा। ग्राहक मास्टर में 'बिक्री की अनुमति के बिना निर्माण आदेश की अनुमति दें' चेकबॉक्स को सक्षम करके किसी विशेष ग्राहक के लिए इस कॉन्फ़िगरेशन को ओवरराइड किया जा सकता है।",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,सभी चयनित विषयों में सफलतापूर्वक {0} {1} जोड़ा गया है।,
Topics updated,विषय अपडेट किए गए,
Academic Term and Program,शैक्षणिक शब्द और कार्यक्रम,
-Last Stock Transaction for item {0} was on {1}.,आइटम {0} के लिए अंतिम स्टॉक लेनदेन {1} पर था।,
-Stock Transactions for Item {0} cannot be posted before this time.,आइटम {0} के लिए स्टॉक लेनदेन इस समय से पहले पोस्ट नहीं किया जा सकता है।,
Please remove this item and try to submit again or update the posting time.,कृपया इस आइटम को निकालें और पुन: सबमिट करने का प्रयास करें या पोस्टिंग समय को अपडेट करें।,
Failed to Authenticate the API key.,API कुंजी को प्रमाणित करने में विफल।,
Invalid Credentials,अवैध प्रत्यय पत्र,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,कृपया अपने प्लेड क्लाइंट आईडी और गुप्त मूल्यों की जाँच करें,
Bank transaction creation error,बैंक लेनदेन निर्माण त्रुटि,
Unit of Measurement,माप की इकाई,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},"पंक्ति # {}: आइटम {} के लिए विक्रय दर, इसके {} से कम है। विक्रय दर कम से कम {} होनी चाहिए",
Fiscal Year {0} Does Not Exist,वित्तीय वर्ष {0} का अस्तित्व नहीं है,
Row # {0}: Returned Item {1} does not exist in {2} {3},पंक्ति # {0}: लौटाई गई वस्तु {1} {2} {3} में मौजूद नहीं है,
Valuation type charges can not be marked as Inclusive,मूल्यांकन प्रकार के आरोपों को समावेशी के रूप में चिह्नित नहीं किया जा सकता है,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,{0} प्राथमिकता के लिए पंक्ति {1} में प्रतिक्रिया का समय रिज़ॉल्यूशन समय से अधिक नहीं हो सकता है।,
{0} is not enabled in {1},{0} {1} में सक्षम नहीं है,
Group by Material Request,सामग्री अनुरोध द्वारा समूह,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","पंक्ति {0}: आपूर्तिकर्ता {0} के लिए, ईमेल पता ईमेल भेजने के लिए आवश्यक है",
Email Sent to Supplier {0},आपूर्तिकर्ता को ईमेल भेजा गया {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","पोर्टल से कोटेशन के लिए अनुरोध तक पहुँच अक्षम है। एक्सेस की अनुमति देने के लिए, इसे पोर्टल सेटिंग्स में सक्षम करें।",
Supplier Quotation {0} Created,आपूर्तिकर्ता उद्धरण {0} बनाया गया,
Valid till Date cannot be before Transaction Date,तिथि तक मान्य लेन-देन की तारीख से पहले नहीं हो सकता है,
+Unlink Advance Payment on Cancellation of Order,ऑर्डर रद्द करने पर अनलिंक अग्रिम भुगतान,
+"Simple Python Expression, Example: territory != 'All Territories'","सरल अजगर अभिव्यक्ति, उदाहरण: क्षेत्र! = 'सभी क्षेत्र'",
+Sales Contributions and Incentives,बिक्री योगदान और प्रोत्साहन,
+Sourced by Supplier,आपूर्तिकर्ता द्वारा शोक,
+Total weightage assigned should be 100%.<br>It is {0},निर्धारित कुल भार 100% होना चाहिए।<br> यह {0} है,
+Account {0} exists in parent company {1}.,खाता {0} मूल कंपनी में मौजूद है {1}।,
+"To overrule this, enable '{0}' in company {1}","इसे पूरा करने के लिए, '{0}' को कंपनी {1} में सक्षम करें",
+Invalid condition expression,अमान्य स्थिति अभिव्यक्ति,
+Please Select a Company First,कृपया पहले एक कंपनी चुनें,
+Please Select Both Company and Party Type First,कृपया कंपनी और पार्टी दोनों प्रकार का चयन करें,
+Provide the invoice portion in percent,प्रतिशत में चालान भाग प्रदान करें,
+Give number of days according to prior selection,पूर्व चयन के अनुसार दिनों की संख्या दें,
+Email Details,ईमेल विवरण,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","रिसीवर के लिए एक ग्रीटिंग का चयन करें। जैसे श्री, सुश्री, आदि।",
+Preview Email,ईमेल का पूर्वावलोकन करें,
+Please select a Supplier,कृपया एक आपूर्तिकर्ता का चयन करें,
+Supplier Lead Time (days),आपूर्तिकर्ता लीड समय (दिन),
+"Home, Work, etc.","घर, काम, आदि।",
+Exit Interview Held On,साक्षात्कार से बाहर निकलें,
+Condition and formula,स्थिति और सूत्र,
+Sets 'Target Warehouse' in each row of the Items table.,आइटम तालिका की प्रत्येक पंक्ति में 'लक्ष्य वेयरहाउस' सेट करता है।,
+Sets 'Source Warehouse' in each row of the Items table.,आइटम तालिका की प्रत्येक पंक्ति में 'स्रोत वेयरहाउस' सेट करता है।,
+POS Register,पीओएस रजिस्टर,
+"Can not filter based on POS Profile, if grouped by POS Profile","पीओएस प्रोफ़ाइल के आधार पर फ़िल्टर नहीं किया जा सकता है, अगर पीओएस प्रोफ़ाइल द्वारा समूहीकृत किया गया हो",
+"Can not filter based on Customer, if grouped by Customer","यदि ग्राहक द्वारा समूहीकृत किया गया है, तो ग्राहक के आधार पर फ़िल्टर नहीं किया जा सकता है",
+"Can not filter based on Cashier, if grouped by Cashier","कैशियर के आधार पर फ़िल्टर नहीं किया जा सकता है, यदि कैशियर द्वारा समूहीकृत किया गया है",
+Payment Method,भुगतान का तरीका,
+"Can not filter based on Payment Method, if grouped by Payment Method","यदि भुगतान विधि द्वारा समूहीकृत किया गया है, तो भुगतान विधि के आधार पर फ़िल्टर नहीं किया जा सकता है",
+Supplier Quotation Comparison,आपूर्तिकर्ता उद्धरण तुलना,
+Price per Unit (Stock UOM),मूल्य प्रति यूनिट (स्टॉक यूओएम),
+Group by Supplier,आपूर्तिकर्ता द्वारा समूह,
+Group by Item,आइटम द्वारा समूह,
+Remember to set {field_label}. It is required by {regulation}.,{फ़ील्ड_लैब} सेट करना याद रखें। यह {विनियमन} द्वारा आवश्यक है।,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},नामांकन तिथि शैक्षणिक वर्ष की शुरुआत तिथि {0} से पहले नहीं हो सकती है,
+Enrollment Date cannot be after the End Date of the Academic Term {0},नामांकन तिथि शैक्षणिक अवधि की अंतिम तिथि के बाद नहीं हो सकती {{},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},नामांकन तिथि शैक्षणिक अवधि के प्रारंभ दिनांक से पहले नहीं हो सकती {0},
+Future Posting Not Allowed,भविष्य पोस्टिंग अनुमति नहीं है,
+"To enable Capital Work in Progress Accounting, ","प्रगति लेखा में पूंजी कार्य को सक्षम करने के लिए,",
+you must select Capital Work in Progress Account in accounts table,आपको अकाउंट टेबल में प्रोग्रेस अकाउंट में कैपिटल वर्क का चयन करना होगा,
+You can also set default CWIP account in Company {},आप कंपनी {} में डिफ़ॉल्ट सीडब्ल्यूआईपी खाता भी सेट कर सकते हैं,
+The Request for Quotation can be accessed by clicking on the following button,निम्नलिखित बटन पर क्लिक करके कोटेशन के लिए अनुरोध तक पहुँचा जा सकता है,
+Regards,सादर,
+Please click on the following button to set your new password,अपना नया पासवर्ड सेट करने के लिए कृपया निम्नलिखित बटन पर क्लिक करें,
+Update Password,पासवर्ड अपडेट करें,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},"पंक्ति # {}: वस्तु {} के लिए विक्रय दर, इसके {} से कम है। {} बेचना कम से कम {} होना चाहिए",
+You can alternatively disable selling price validation in {} to bypass this validation.,आप वैकल्पिक रूप से इस मान्यता को दरकिनार करने के लिए {} में विक्रय सत्यापन को अक्षम कर सकते हैं।,
+Invalid Selling Price,अवैध विक्रय मूल्य,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,पता किसी कंपनी से जुड़ा होना चाहिए। कृपया लिंक तालिका में कंपनी के लिए एक पंक्ति जोड़ें।,
+Company Not Linked,कंपनी लिंक नहीं है,
+Import Chart of Accounts from CSV / Excel files,CSV / Excel फ़ाइलों से खातों का आयात चार्ट,
+Completed Qty cannot be greater than 'Qty to Manufacture',पूर्ण मात्रा 'Qty to Manufacturing' से बड़ी नहीं हो सकती,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","पंक्ति {0}: आपूर्तिकर्ता {1} के लिए, ईमेल पता ईमेल भेजने के लिए आवश्यक है",
+"If enabled, the system will post accounting entries for inventory automatically","सक्षम होने पर, सिस्टम स्वचालित रूप से इन्वेंट्री के लिए लेखांकन प्रविष्टियां पोस्ट करेगा",
+Accounts Frozen Till Date,अब तक जमे हुए खाते,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,इस तिथि तक लेखा प्रविष्टियां जमी हुई हैं। नीचे दी गई भूमिका वाले उपयोगकर्ताओं को छोड़कर कोई भी प्रविष्टियों को बना या संशोधित नहीं कर सकता है,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,जमे हुए खातों को सेट करने और जमे हुए प्रविष्टियों को संपादित करने की अनुमति है,
+Address used to determine Tax Category in transactions,लेनदेन में कर श्रेणी निर्धारित करने के लिए उपयोग किया जाने वाला पता,
+"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 ","आदेशित राशि के मुकाबले आपको अधिक बिल देने की अनुमति है। उदाहरण के लिए, यदि किसी वस्तु के लिए ऑर्डर का मूल्य $ 100 है और सहिष्णुता 10% है, तो आपको $ 110 तक बिल करने की अनुमति है",
+This role is allowed to submit transactions that exceed credit limits,इस भूमिका को लेन-देन प्रस्तुत करने की अनुमति है जो क्रेडिट सीमा से अधिक है,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","यदि "महीने" का चयन किया जाता है, तो एक निश्चित राशि को प्रत्येक माह के लिए आस्थगित राजस्व या व्यय के रूप में बुक किया जाएगा, भले ही महीने में कितने दिन हो। यह स्थगित कर दिया जाएगा यदि आस्थगित राजस्व या व्यय एक पूरे महीने के लिए बुक नहीं किया गया है",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","यदि यह अनियंत्रित है, तो आस्थगित राजस्व या व्यय को बुक करने के लिए प्रत्यक्ष जीएल प्रविष्टियां बनाई जाएंगी",
+Show Inclusive Tax in Print,प्रिंट में समावेशी कर दिखाएं,
+Only select this if you have set up the Cash Flow Mapper documents,"यदि आपने कैश फ़्लो मैपर दस्तावेज़ सेट किए हैं, तो केवल इसका चयन करें",
+Payment Channel,पेमेंट चैनल,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,क्या क्रय आदेश खरीद और प्राप्ति निर्माण के लिए आवश्यक है?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,क्या खरीद चालान निर्माण के लिए खरीद रसीद आवश्यक है?,
+Maintain Same Rate Throughout the Purchase Cycle,खरीद चक्र के दौरान समान दर बनाए रखें,
+Allow Item To Be Added Multiple Times in a Transaction,आइटम को एक लेनदेन में कई बार जोड़े जाने की अनुमति दें,
+Suppliers,आपूर्तिकर्ता,
+Send Emails to Suppliers,आपूर्तिकर्ताओं को ईमेल भेजें,
+Select a Supplier,आपूर्तिकर्ता का चयन करें,
+Cannot mark attendance for future dates.,भविष्य की तारीखों के लिए उपस्थिति को चिह्नित नहीं कर सकते।,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},क्या आप उपस्थिति अपडेट करना चाहते हैं?<br> वर्तमान: {0}<br> अनुपस्थित: {1},
+Mpesa Settings,Mpesa सेटिंग्स,
+Initiator Name,पहल का नाम,
+Till Number,तक का नंबर,
+Sandbox,सैंडबॉक्स,
+ Online PassKey,ऑनलाइन पासकी,
+Security Credential,सुरक्षा क्रेडेंशियल,
+Get Account Balance,खाता शेष प्राप्त करें,
+Please set the initiator name and the security credential,कृपया आरंभकर्ता का नाम और सुरक्षा क्रेडेंशियल सेट करें,
+Inpatient Medication Entry,रोगी दवा प्रवेश,
+HLC-IME-.YYYY.-,उच्च स्तरीय समिति-IME-.YYYY.-,
+Item Code (Drug),आइटम कोड (औषधि),
+Medication Orders,दवा आदेश,
+Get Pending Medication Orders,लंबित दवा आदेश प्राप्त करें,
+Inpatient Medication Orders,रोगी दवा के आदेश,
+Medication Warehouse,दवा गोदाम,
+Warehouse from where medication stock should be consumed,वेयरहाउस जहां से दवा का स्टॉक होना चाहिए,
+Fetching Pending Medication Orders,पेंडिंग मेडिकेशन ऑर्डर प्राप्त करना,
+Inpatient Medication Entry Detail,असंगत दवा प्रवेश प्रविष्टि,
+Medication Details,दवा विवरण,
+Drug Code,ड्रग कोड,
+Drug Name,औषधि का नाम,
+Against Inpatient Medication Order,रोगी दवा ऑर्डर के खिलाफ,
+Against Inpatient Medication Order Entry,Inpatient Medication आर्डर एंट्री के विरुद्ध,
+Inpatient Medication Order,रोगी दवा आदेश,
+HLC-IMO-.YYYY.-,उच्च स्तरीय समिति-IMO-.YYYY.-,
+Total Orders,कुल आदेश,
+Completed Orders,पूर्ण आदेश,
+Add Medication Orders,दवा आदेश जोड़ें,
+Adding Order Entries,आदेश प्रविष्टियाँ जोड़ना,
+{0} medication orders completed,{0} दवा के ऑर्डर पूरे हुए,
+{0} medication order completed,{0} दवा क्रम पूरा हुआ,
+Inpatient Medication Order Entry,रोगी दवा क्रम प्रवेश,
+Is Order Completed,आदेश पूरा हो गया है,
+Employee Records to Be Created By,कर्मचारी रिकॉर्ड बनाए जाने के लिए,
+Employee records are created using the selected field,चयनित क्षेत्र का उपयोग करके कर्मचारी रिकॉर्ड बनाए जाते हैं,
+Don't send employee birthday reminders,कर्मचारी जन्मदिन अनुस्मारक न भेजें,
+Restrict Backdated Leave Applications,बैकडेटेड लीव एप्लीकेशन को प्रतिबंधित करें,
+Sequence ID,अनुक्रम आईडी,
+Sequence Id,अनुक्रम आईडी,
+Allow multiple material consumptions against a Work Order,वर्क ऑर्डर के विरुद्ध कई सामग्री उपभोग की अनुमति दें,
+Plan time logs outside Workstation working hours,कार्यस्थान कार्य समय के बाहर योजना समय लॉग,
+Plan operations X days in advance,योजना संचालन X दिन पहले,
+Time Between Operations (Mins),संचालन के बीच का समय (मिनट),
+Default: 10 mins,डिफ़ॉल्ट: 10 मिनट,
+Overproduction for Sales and Work Order,बिक्री और कार्य आदेश के लिए अतिउत्पादन,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","अद्यतन BOM लागत स्वचालित रूप से शेड्यूलर के माध्यम से, नवीनतम मूल्यांकन दर / मूल्य सूची दर / कच्चे माल की अंतिम खरीद दर के आधार पर",
+Purchase Order already created for all Sales Order items,क्रय आदेश पहले से ही सभी विक्रय आदेश आइटम के लिए बनाया गया है,
+Select Items,वस्तुएं चुनें,
+Against Default Supplier,डिफ़ॉल्ट आपूर्तिकर्ता के खिलाफ,
+Auto close Opportunity after the no. of days mentioned above,ऑटो बंद अवसर के बाद नहीं। ऊपर वर्णित दिनों के,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,क्या सेल्स इनवॉइस और डिलीवरी नोट क्रिएशन के लिए सेल्स ऑर्डर जरूरी है?,
+Is Delivery Note Required for Sales Invoice Creation?,क्या डिलिवरी नोट की बिक्री चालान निर्माण के लिए आवश्यक है?,
+How often should Project and Company be updated based on Sales Transactions?,बिक्री लेनदेन के आधार पर कितनी बार प्रोजेक्ट और कंपनी को अपडेट किया जाना चाहिए?,
+Allow User to Edit Price List Rate in Transactions,उपयोगकर्ता को लेनदेन में मूल्य सूची दर संपादित करने की अनुमति दें,
+Allow Item to Be Added Multiple Times in a Transaction,आइटम को एक लेनदेन में कई बार जोड़े जाने की अनुमति दें,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,एक ग्राहक के खरीद आदेश के खिलाफ कई बिक्री आदेश की अनुमति दें,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,खरीद दर या मूल्यांकन दर के विरुद्ध वस्तु के विक्रय मूल्य को मान्य करें,
+Hide Customer's Tax ID from Sales Transactions,बिक्री लेनदेन से ग्राहक की कर आईडी छिपाएँ,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","आपके द्वारा दिए गए मात्रा के मुकाबले अधिक प्रतिशत प्राप्त करने या वितरित करने की अनुमति है। उदाहरण के लिए, यदि आपने 100 यूनिट का ऑर्डर दिया है, और आपका भत्ता 10% है, तो आपको 110 यूनिट प्राप्त करने की अनुमति है।",
+Action If Quality Inspection Is Not Submitted,कार्रवाई अगर गुणवत्ता निरीक्षण प्रस्तुत नहीं है,
+Auto Insert Price List Rate If Missing,ऑटो डालें मूल्य सूची दर यदि गुम है,
+Automatically Set Serial Nos Based on FIFO,एफआईएफओ के आधार पर सीरियल सेट को स्वचालित रूप से सेट करें,
+Set Qty in Transactions Based on Serial No Input,सीरियल नो इनपुट के आधार पर लेन-देन में मात्रा निर्धारित करें,
+Raise Material Request When Stock Reaches Re-order Level,जब स्टॉक री-ऑर्डर स्तर पर पहुंचता है तब सामग्री अनुरोध बढ़ाएं,
+Notify by Email on Creation of Automatic Material Request,निर्माण सामग्री के स्वत: अनुरोध पर ईमेल द्वारा सूचित करें,
+Allow Material Transfer from Delivery Note to Sales Invoice,वितरण नोट से बिक्री चालान तक सामग्री स्थानांतरण की अनुमति दें,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,क्रय रसीद से सामग्री स्थानांतरण को खरीद चालान की अनुमति दें,
+Freeze Stocks Older Than (Days),फ्रीज स्टॉक्स पुराने दिन (दिन),
+Role Allowed to Edit Frozen Stock,भूमिका जमे हुए स्टॉक को संपादित करने की अनुमति दी,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,पेमेंट एंट्री {0} की अनऑलोकेटेड राशि बैंक ट्रांजेक्शन की अनऑलोकेटेड राशि से अधिक है,
+Payment Received,भुगतान प्राप्त,
+Attendance cannot be marked outside of Academic Year {0},उपस्थिति को शैक्षणिक वर्ष {0} के बाहर चिह्नित नहीं किया जा सकता है,
+Student is already enrolled via Course Enrollment {0},छात्र पहले से ही पाठ्यक्रम नामांकन {0} के माध्यम से नामांकित है,
+Attendance cannot be marked for future dates.,भविष्य की तारीखों के लिए उपस्थिति को चिह्नित नहीं किया जा सकता है।,
+Please add programs to enable admission application.,कृपया प्रवेश एप्लिकेशन को सक्षम करने के लिए प्रोग्राम जोड़ें।,
+The following employees are currently still reporting to {0}:,निम्नलिखित कर्मचारी अभी भी {0} की रिपोर्ट कर रहे हैं:,
+Please make sure the employees above report to another Active employee.,कृपया सुनिश्चित करें कि उपरोक्त कर्मचारी किसी अन्य सक्रिय कर्मचारी को रिपोर्ट करें।,
+Cannot Relieve Employee,कर्मचारी को राहत नहीं दे सकते,
+Please enter {0},कृपया {0} दर्ज करें,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',कृपया अन्य भुगतान विधि चुनें। Mpesa मुद्रा में लेनदेन का समर्थन नहीं करता है '{0}',
+Transaction Error,लेन-देन में त्रुटि,
+Mpesa Express Transaction Error,Mpesa एक्सप्रेस लेनदेन त्रुटि,
+"Issue detected with Mpesa configuration, check the error logs for more details","Mpesa कॉन्फ़िगरेशन के साथ समस्या का पता लगाया, अधिक विवरण के लिए त्रुटि लॉग की जाँच करें",
+Mpesa Express Error,Mpesa एक्सप्रेस त्रुटि,
+Account Balance Processing Error,खाता शेष प्रसंस्करण त्रुटि,
+Please check your configuration and try again,कृपया अपना कॉन्फ़िगरेशन जांचें और पुनः प्रयास करें,
+Mpesa Account Balance Processing Error,Mpesa खाता शेष प्रसंस्करण त्रुटि,
+Balance Details,शेष विवरण,
+Current Balance,वर्तमान शेष,
+Available Balance,उपलब्ध शेष राशि,
+Reserved Balance,आरक्षित शेष,
+Uncleared Balance,अस्पष्ट शेष,
+Payment related to {0} is not completed,{0} से संबंधित भुगतान पूरा नहीं हुआ है,
+Row #{}: Item Code: {} is not available under warehouse {}.,पंक्ति # {}: आइटम कोड: {} गोदाम {} के तहत उपलब्ध नहीं है।,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,पंक्ति # {}: आइटम कोड के लिए स्टॉक मात्रा पर्याप्त नहीं है: {} गोदाम {} के तहत। उपलब्ध मात्रा {}।,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,पंक्ति # {}: कृपया आइटम के खिलाफ एक सीरियल नंबर और बैच चुनें: {} या लेनदेन को पूरा करने के लिए इसे हटा दें।,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,पंक्ति # {}: आइटम के विरुद्ध कोई सीरियल नंबर नहीं चुना गया: {}। कृपया लेन-देन पूरा करने के लिए इसे चुनें या हटाएं,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,पंक्ति # {}: आइटम के विरुद्ध कोई बैच चयनित नहीं: {}। कृपया एक बैच का चयन करें या लेनदेन को पूरा करने के लिए इसे हटा दें।,
+Payment amount cannot be less than or equal to 0,भुगतान राशि 0 से कम या उसके बराबर नहीं हो सकती,
+Please enter the phone number first,कृपया पहले फ़ोन नंबर दर्ज करें,
+Row #{}: {} {} does not exist.,रो # {}: {} {} मौजूद नहीं है।,
+Row #{0}: {1} is required to create the Opening {2} Invoices,पंक्ति # {0}: {1} को खोलने के लिए आवश्यक है {2} चालान,
+You had {} errors while creating opening invoices. Check {} for more details,उद्घाटन चालान बनाते समय आपके पास {} त्रुटियां थीं। अधिक विवरण के लिए {} की जाँच करें,
+Error Occured,त्रुटि हुई,
+Opening Invoice Creation In Progress,प्रगति में उद्घाटन सृजन,
+Creating {} out of {} {},{} {} में से {} बनाना,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(क्रम संख्या: {0}) का उपभोग नहीं किया जा सकता क्योंकि यह पूर्ण बिक्री आदेश {1} के लिए फिर से तैयार है।,
+Item {0} {1},आइटम {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,गोदाम {1} के तहत आइटम {0} के लिए अंतिम स्टॉक लेनदेन {2} पर था।,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,गोदाम {1} के तहत आइटम {0} के लिए स्टॉक लेनदेन इस समय से पहले पोस्ट नहीं किया जा सकता है।,
+Posting future stock transactions are not allowed due to Immutable Ledger,Immutable लेजर के कारण भविष्य के स्टॉक लेनदेन को पोस्ट करने की अनुमति नहीं है,
+A BOM with name {0} already exists for item {1}.,{0} नाम वाला एक BOM पहले से ही आइटम {1} के लिए मौजूद है।,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} क्या आपने आइटम का नाम बदला? कृपया प्रशासक / तकनीकी सहायता से संपर्क करें,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},पंक्ति # {0} पर: अनुक्रम आईडी {1} पिछली पंक्ति अनुक्रम आईडी {2} से कम नहीं हो सकती,
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) को {2} ({3}) के बराबर होना चाहिए,
+"{0}, complete the operation {1} before the operation {2}.","{0}, ऑपरेशन {1} से पहले ऑपरेशन {1} पूरा करें।",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,सीरियल नंबर द्वारा वितरण सुनिश्चित नहीं किया जा सकता क्योंकि आइटम {0} के साथ जोड़ा जाता है और सीरियल नंबर द्वारा सुनिश्चित वितरण के बिना।,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,आइटम {0} का कोई सीरियल नंबर नहीं है। केवल सीरियल किए गए आइटम में सीरियल नंबर के आधार पर डिलीवरी हो सकती है,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,आइटम {0} के लिए कोई सक्रिय बॉम नहीं मिला। सीरियल नंबर द्वारा वितरण सुनिश्चित नहीं किया जा सकता है,
+No pending medication orders found for selected criteria,चयनित मानदंडों के लिए कोई भी लंबित दवा आदेश नहीं मिला,
+From Date cannot be after the current date.,वर्तमान तिथि के बाद दिनांक नहीं हो सकती।,
+To Date cannot be after the current date.,वर्तमान तिथि के बाद दिनांक नहीं हो सकती।,
+From Time cannot be after the current time.,वर्तमान समय के बाद से नहीं हो सकता है।,
+To Time cannot be after the current time.,वर्तमान समय के बाद का समय नहीं हो सकता।,
+Stock Entry {0} created and ,स्टॉक एंट्री {0} बनाया और,
+Inpatient Medication Orders updated successfully,रोगी दवा के आदेश सफलतापूर्वक अपडेट किए गए,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},पंक्ति {0}: रद्द किए गए इनपेंटिएंट मेडिकेशन ऑर्डर {1} के खिलाफ रोगी दवा प्रविष्टि नहीं बना सकते हैं,
+Row {0}: This Medication Order is already marked as completed,पंक्ति {0}: यह दवा आदेश पहले से ही पूर्ण के रूप में चिह्नित है,
+Quantity not available for {0} in warehouse {1},गोदाम में {0} के लिए उपलब्ध मात्रा {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,कृपया शेयर सेटिंग्स में नकारात्मक स्टॉक को अनुमति दें या आगे बढ़ने के लिए स्टॉक एंट्री बनाएं।,
+No Inpatient Record found against patient {0},रोगी के खिलाफ कोई असंगत रिकॉर्ड नहीं मिला {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,रोगी एनकाउंटर {1} के खिलाफ एक रोगी दवा ऑर्डर {0} पहले से मौजूद है।,
+Allow In Returns,रिटर्न में अनुमति दें,
+Hide Unavailable Items,अनुपलब्ध आइटम छिपाएँ,
+Apply Discount on Discounted Rate,रियायती दर पर छूट लागू करें,
+Therapy Plan Template,थेरेपी प्लान टेम्पलेट,
+Fetching Template Details,टेम्पलेट विवरण प्राप्त करना,
+Linked Item Details,लिंक्ड आइटम विवरण,
+Therapy Types,थेरेपी के प्रकार,
+Therapy Plan Template Detail,थेरेपी योजना टेम्पलेट विस्तार,
+Non Conformance,गैर अनुरूपता,
+Process Owner,कार्यचालक,
+Corrective Action,सुधार कार्य,
+Preventive Action,निवारक कार्रवाई,
+Problem,मुसीबत,
+Responsible,उत्तरदायी,
+Completion By,द्वारा पूर्ण करना,
+Process Owner Full Name,प्रोसेस ओनर पूरा नाम,
+Right Index,सही सूचकांक,
+Left Index,बायाँ सूचकांक,
+Sub Procedure,उप प्रक्रिया,
+Passed,बीतने के,
+Print Receipt,प्रिंट रसीद,
+Edit Receipt,रसीद संपादित करें,
+Focus on search input,खोज इनपुट पर ध्यान दें,
+Focus on Item Group filter,आइटम समूह फ़िल्टर पर ध्यान दें,
+Checkout Order / Submit Order / New Order,चेकआउट आदेश / आदेश भेजें / नया आदेश,
+Add Order Discount,आदेश छूट जोड़ें,
+Item Code: {0} is not available under warehouse {1}.,आइटम कोड: {0} गोदाम {1} के तहत उपलब्ध नहीं है।,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,वेयरहाउस {1} के तहत आइटम {0} के लिए सीरियल नंबर अनुपलब्ध है। कृपया गोदाम बदलने का प्रयास करें।,
+Fetched only {0} available serial numbers.,केवल {0} उपलब्ध सीरियल नंबर।,
+Switch Between Payment Modes,भुगतान मोड के बीच स्विच करें,
+Enter {0} amount.,{0} राशि दर्ज करें।,
+You don't have enough points to redeem.,आपके पास रिडीम करने के लिए पर्याप्त बिंदु नहीं हैं।,
+You can redeem upto {0}.,आप {0} तक रिडीम कर सकते हैं।,
+Enter amount to be redeemed.,भुनाने के लिए राशि दर्ज करें।,
+You cannot redeem more than {0}.,आप {0} से अधिक नहीं भुना सकते।,
+Open Form View,प्रपत्र देखें खोलें,
+POS invoice {0} created succesfully,पीओएस चालान {0} सफलतापूर्वक बनाया गया,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,स्टॉक कोड आइटम कोड के लिए पर्याप्त नहीं है: {0} गोदाम {1} के तहत। उपलब्ध मात्रा {2}।,
+Serial No: {0} has already been transacted into another POS Invoice.,सीरियल नंबर: {0} को पहले ही एक और पीओएस चालान में बदल दिया गया है।,
+Balance Serial No,बैलेंस सीरियल नं,
+Warehouse: {0} does not belong to {1},वेयरहाउस: {0} का संबंध {1} से नहीं है,
+Please select batches for batched item {0},कृपया बैच आइटम {0} के लिए बैच चुनें,
+Please select quantity on row {0},कृपया पंक्ति {0} पर मात्रा का चयन करें,
+Please enter serial numbers for serialized item {0},कृपया क्रमांकित आइटम {0} के लिए सीरियल नंबर दर्ज करें,
+Batch {0} already selected.,बैच {0} पहले से चयनित है।,
+Please select a warehouse to get available quantities,कृपया उपलब्ध मात्रा प्राप्त करने के लिए एक गोदाम का चयन करें,
+"For transfer from source, selected quantity cannot be greater than available quantity","स्रोत से स्थानांतरण के लिए, चयनित मात्रा उपलब्ध मात्रा से अधिक नहीं हो सकती है",
+Cannot find Item with this Barcode,इस बारकोड के साथ आइटम नहीं मिल सकता है,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} अनिवार्य है। शायद मुद्रा विनिमय रिकॉर्ड {1} से {2} के लिए नहीं बनाया गया है,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} ने इससे जुड़ी संपत्ति जमा की है। आपको खरीद वापसी बनाने के लिए परिसंपत्तियों को रद्द करने की आवश्यकता है।,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,इस दस्तावेज़ को रद्द नहीं किया जा सकता क्योंकि यह सबमिट की गई संपत्ति {0} से जुड़ा हुआ है। कृपया इसे जारी रखने के लिए रद्द करें।,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,पंक्ति # {}: सीरियल नंबर {} को पहले से ही एक और पीओएस चालान में बदल दिया गया है। कृपया मान्य क्रम संख्या का चयन करें।,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,पंक्ति # {}: सीरियल नं। {} को पहले से ही एक और पीओएस चालान में बदल दिया गया है। कृपया मान्य क्रम संख्या का चयन करें।,
+Item Unavailable,आइटम उपलब्ध नहीं है,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},पंक्ति # {}: सीरियल नंबर {} को वापस नहीं किया जा सकता क्योंकि इसे मूल चालान में नहीं भेजा गया था {},
+Please set default Cash or Bank account in Mode of Payment {},कृपया भुगतान के मोड में डिफ़ॉल्ट कैश या बैंक खाते को सेट करें {},
+Please set default Cash or Bank account in Mode of Payments {},कृपया भुगतान के मोड में डिफ़ॉल्ट कैश या बैंक खाते को सेट करें {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,कृपया सुनिश्चित करें कि {} खाता एक बैलेंस शीट खाता है। आप मूल खाते को एक बैलेंस शीट खाते में बदल सकते हैं या एक अलग खाते का चयन कर सकते हैं।,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,कृपया सुनिश्चित करें कि {} खाता एक देय खाता है। खाता प्रकार को देय में बदलें या एक अलग खाता चुनें।,
+Row {}: Expense Head changed to {} ,पंक्ति {}: व्यय हेड को बदलकर {},
+because account {} is not linked to warehouse {} ,खाता {} गोदाम से जुड़ा नहीं है {},
+or it is not the default inventory account,या यह डिफ़ॉल्ट इन्वेंट्री खाता नहीं है,
+Expense Head Changed,व्यय सिर बदल गया,
+because expense is booked against this account in Purchase Receipt {},क्योंकि इस खाते के खिलाफ खरीद रसीद {} में खर्च की गई है,
+as no Purchase Receipt is created against Item {}. ,जैसा कि कोई खरीद रसीद आइटम {} के विरुद्ध नहीं बनाई गई है।,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,यह उन मामलों के लिए लेखांकन को संभालने के लिए किया जाता है जब खरीद चालान के बाद खरीद रसीद बनाई जाती है,
+Purchase Order Required for item {},आइटम के लिए आवश्यक खरीद आदेश {},
+To submit the invoice without purchase order please set {} ,खरीद आदेश के बिना चालान जमा करने के लिए कृपया {} सेट करें,
+as {} in {},जैसे की {},
+Mandatory Purchase Order,अनिवार्य खरीद आदेश,
+Purchase Receipt Required for item {},आइटम {} के लिए खरीद रसीद आवश्यक,
+To submit the invoice without purchase receipt please set {} ,खरीद रसीद के बिना चालान जमा करने के लिए कृपया {} सेट करें,
+Mandatory Purchase Receipt,अनिवार्य खरीद रसीद,
+POS Profile {} does not belongs to company {},POS प्रोफ़ाइल {} कंपनी {} से संबंधित नहीं है,
+User {} is disabled. Please select valid user/cashier,उपयोगकर्ता {} अक्षम है। कृपया मान्य उपयोगकर्ता / कैशियर का चयन करें,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,पंक्ति # {}: मूल चालान {} का रिटर्न चालान {} {} है।,
+Original invoice should be consolidated before or along with the return invoice.,मूल चालान को वापसी चालान से पहले या साथ में समेकित किया जाना चाहिए।,
+You can add original invoice {} manually to proceed.,आगे बढ़ने के लिए आप मैन्युअल रूप से मूल इनवॉइस {} जोड़ सकते हैं।,
+Please ensure {} account is a Balance Sheet account. ,कृपया सुनिश्चित करें कि {} खाता एक बैलेंस शीट खाता है।,
+You can change the parent account to a Balance Sheet account or select a different account.,आप मूल खाते को एक बैलेंस शीट खाते में बदल सकते हैं या एक अलग खाते का चयन कर सकते हैं।,
+Please ensure {} account is a Receivable account. ,कृपया सुनिश्चित करें कि {} खाता एक प्राप्य खाता है।,
+Change the account type to Receivable or select a different account.,खाता प्रकार को प्राप्य में बदलें या किसी अन्य खाते का चयन करें।,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{- अर्जित किए गए वफादारी अंक को भुनाया नहीं जा सकता है। पहले {} नहीं {} रद्द करें,
+already exists,पहले से ही मौजूद है,
+POS Closing Entry {} against {} between selected period,पीओएस क्लोजिंग एंट्री {} चयनित अवधि के बीच {} के खिलाफ,
+POS Invoice is {},पीओएस चालान {} है,
+POS Profile doesn't matches {},POS प्रोफ़ाइल {} से मेल नहीं खाती,
+POS Invoice is not {},पीओएस चालान {} नहीं है,
+POS Invoice isn't created by user {},POS चालान उपयोगकर्ता द्वारा नहीं बनाया गया है {},
+Row #{}: {},रो # {}: {},
+Invalid POS Invoices,अमान्य POS चालान,
+Please add the account to root level Company - {},कृपया खाते को रूट लेवल कंपनी में जोड़ें - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","चाइल्ड कंपनी {0} के लिए खाता बनाते समय, मूल खाता {1} नहीं मिला। कृपया संबंधित COA में मूल खाता बनाएँ",
+Account Not Found,खता नहीं मिला,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","चाइल्ड कंपनी {0} के लिए खाता बनाते समय, माता-पिता खाता {1} खाता बही के रूप में पाया गया।",
+Please convert the parent account in corresponding child company to a group account.,कृपया संबंधित चाइल्ड कंपनी में पैरेंट अकाउंट को ग्रुप अकाउंट में बदलें।,
+Invalid Parent Account,अमान्य जनक खाता,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",नाम बदलने से बचने के लिए केवल मूल कंपनी {0} के माध्यम से इसका नाम बदलने की अनुमति है।,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","यदि आप {0} {1} आइटम {2} की मात्रा, स्कीम {3} को आइटम पर लागू करेंगे।",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","यदि आप {0} {1} मूल्य की वस्तु {2}, योजना {3} को आइटम पर लागू किया जाएगा।",
+"As the field {0} is enabled, the field {1} is mandatory.","जैसा कि फ़ील्ड {0} सक्षम है, फ़ील्ड {1} अनिवार्य है।",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","जैसा कि फ़ील्ड {0} सक्षम है, फ़ील्ड {1} का मान 1 से अधिक होना चाहिए।",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},यह आइटम {1} के सीरियल नंबर {0} को वितरित नहीं कर सकता क्योंकि यह पूर्ण बिक्री आदेश {2} के लिए आरक्षित है।,
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","विक्रय आदेश {0} में आइटम {1} के लिए आरक्षण है, आप केवल {0} के खिलाफ आरक्षित {1} वितरित कर सकते हैं।",
+{0} Serial No {1} cannot be delivered,{0} सीरियल नंबर {1} वितरित नहीं किया जा सकता है,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},पंक्ति {0}: कच्चे माल के लिए उप-खंडित वस्तु अनिवार्य है {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","चूंकि पर्याप्त कच्चे माल हैं, वेयरहाउस {0} के लिए सामग्री अनुरोध की आवश्यकता नहीं है।",
+" If you still want to proceed, please enable {0}.","यदि आप अभी भी आगे बढ़ना चाहते हैं, तो कृपया {0} को सक्षम करें।",
+The item referenced by {0} - {1} is already invoiced,{0} - {1} द्वारा संदर्भित आइटम का पहले से ही चालान है,
+Therapy Session overlaps with {0},थेरेपी सत्र {0} से ओवरलैप होता है,
+Therapy Sessions Overlapping,थेरेपी सेशन ओवरलैपिंग,
+Therapy Plans,थेरेपी योजनाएं,
+"Item Code, warehouse, quantity are required on row {0}","पंक्ति {0} पर आइटम कोड, गोदाम, मात्रा आवश्यक है",
+Get Items from Material Requests against this Supplier,इस आपूर्तिकर्ता के विरुद्ध सामग्री अनुरोध से आइटम प्राप्त करें,
+Enable European Access,यूरोपीय पहुँच सक्षम करें,
+Creating Purchase Order ...,क्रय आदेश बनाना ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","नीचे दी गई वस्तुओं के डिफ़ॉल्ट आपूर्तिकर्ता से एक आपूर्तिकर्ता का चयन करें। चयन पर, केवल चयनित आपूर्तिकर्ता से संबंधित वस्तुओं के खिलाफ एक खरीद ऑर्डर किया जाएगा।",
+Row #{}: You must select {} serial numbers for item {}.,पंक्ति # {}: आपको आइटम {} के लिए {} सीरियल नंबर का चयन करना होगा।,
diff --git a/erpnext/translations/hr.csv b/erpnext/translations/hr.csv
index e23006d..a544e98 100644
--- a/erpnext/translations/hr.csv
+++ b/erpnext/translations/hr.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Stvarni tipa porez ne može biti uključen u stopu stavka u nizu {0},
Add,Dodaj,
Add / Edit Prices,Dodaj / uredi cijene,
-Add All Suppliers,Dodaj sve dobavljače,
Add Comment,Dodaj komentar,
Add Customers,Dodaj korisnike,
Add Employees,Dodavanje zaposlenika,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Ne mogu odbiti kada je kategorija za "vrednovanje" ili "Vaulation i ukupni ',
"Cannot delete Serial No {0}, as it is used in stock transactions","Ne možete izbrisati Serijski broj {0}, kao što se koristi na lageru transakcija",
Cannot enroll more than {0} students for this student group.,Ne može se prijaviti više od {0} studenata za ovaj grupe studenata.,
-Cannot find Item with this barcode,Stavka nije moguće pronaći s ovim barkodom,
Cannot find active Leave Period,Nije moguće pronaći aktivno razdoblje odmora,
Cannot produce more Item {0} than Sales Order quantity {1},Ne može proizvesti više predmeta {0} od prodajnog naloga količina {1},
Cannot promote Employee with status Left,Ne mogu promovirati zaposlenika sa statusom lijevo,
Cannot refer row number greater than or equal to current row number for this Charge type,Ne mogu se odnositi broj retka veći ili jednak trenutnom broju red za ovu vrstu Charge,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"Ne možete odabrati vrstu naboja kao ' na prethodnim Row Iznos ""ili"" u odnosu na prethodnu Row Ukupno ""za prvi red",
-Cannot set a received RFQ to No Quote,Nije moguće postaviti primljeni RFQ na nijedan citat,
Cannot set as Lost as Sales Order is made.,Ne mogu se postaviti kao izgubljen kao prodajnog naloga je napravio .,
Cannot set authorization on basis of Discount for {0},Ne mogu postaviti odobrenje na temelju popusta za {0},
Cannot set multiple Item Defaults for a company.,Nije moguće postaviti više zadanih postavki za tvrtku.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Optužbe su ažurirani u KUPNJE protiv svake stavke,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Troškovi će se distribuirati proporcionalno na temelju točke kom ili iznos, kao i po svom izboru",
-Chart Of Accounts,Kontni plan,
Chart of Cost Centers,Grafikon troškovnih centara,
Check all,Provjeri sve,
Checkout,Provjeri,
@@ -581,7 +577,6 @@
Compensatory Off,kompenzacijski Off,
Compensatory leave request days not in valid holidays,Doplativi dopusti za dane naplate nisu u važećem odmoru,
Complaint,prigovor,
-Completed Qty can not be greater than 'Qty to Manufacture',Završen Qty ne može biti veći od 'Kol proizvoditi',
Completion Date,Završetak Datum,
Computer,Računalo,
Condition,Stanje,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Stvaranje i upravljanje automatskih mailova na dnevnoj, tjednoj i mjesečnoj bazi.",
Create customer quotes,Stvaranje kupaca citati,
Create rules to restrict transactions based on values.,Napravi pravila za ograničavanje prometa na temelju vrijednosti.,
-Created By,Stvorio,
Created {0} scorecards for {1} between: ,Izrađeno {0} bodovne kartice za {1} između:,
Creating Company and Importing Chart of Accounts,Stvaranje tvrtke i uvoz računa,
Creating Fees,Stvaranje naknada,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Prijenos zaposlenika ne može se poslati prije datuma prijenosa,
Employee cannot report to himself.,Zaposlenik se ne može prijaviti na sebe.,
Employee relieved on {0} must be set as 'Left',Zaposlenik razriješen na {0} mora biti postavljen kao 'lijevo ',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Status zaposlenika ne može se postaviti na "Lijevo", jer sljedeći zaposlenici trenutno prijavljuju ovog zaposlenika:",
Employee {0} already submited an apllication {1} for the payroll period {2},Zaposlenik {0} već je poslao apllicaciju {1} za razdoblje plaće {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Zaposlenik {0} već je podnio zahtjev za {1} između {2} i {3}:,
Employee {0} has no maximum benefit amount,Zaposlenik {0} nema maksimalnu naknadu,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Za redak {0}: unesite planirani iznos,
"For {0}, only credit accounts can be linked against another debit entry","Za {0}, samo kreditne računi se mogu povezati protiv drugog ulaska debitnom",
"For {0}, only debit accounts can be linked against another credit entry","Za {0}, samo debitne računi se mogu povezati protiv druge kreditne stupanja",
-Form View,Prikaz obrasca,
Forum Activity,Aktivnost na forumu,
Free item code is not selected,Besplatni kod predmeta nije odabran,
Freight and Forwarding Charges,Teretni i Forwarding Optužbe,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Ostavite se ne može dodijeliti prije {0}, kao dopust ravnoteža je već ručne proslijeđena u buduće dodjele dopusta rekord {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Ostavite se ne može primijeniti / otkazan prije {0}, kao dopust ravnoteža je već ručne proslijeđena u buduće dodjele dopusta rekord {1}",
Leave of type {0} cannot be longer than {1},Odsustvo tipa {0} ne može biti duže od {1},
-Leave the field empty to make purchase orders for all suppliers,Ostavite prazno polje za narudžbenice za sve dobavljače,
Leaves,lišće,
Leaves Allocated Successfully for {0},Odsustvo uspješno dodijeljeno za {0},
Leaves has been granted sucessfully,Lišće je dobilo uspješno,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Nema Stavke sa Bill materijala za proizvodnju,
No Items with Bill of Materials.,Nema predmeta s računom materijala.,
No Permission,Nemate dopuštenje,
-No Quote,Nijedan citat,
No Remarks,Nema primjedbi,
No Result to submit,Nema rezultata za slanje,
No Salary Structure assigned for Employee {0} on given date {1},Struktura plaće nije dodijeljena za zaposlenika {0} na određeni datum {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Preklapanje uvjeti nalaze između :,
Owner,vlasnik,
PAN,PAN,
-PO already created for all sales order items,PO već stvoren za sve stavke prodajnog naloga,
POS,POS,
POS Profile,POS profil,
POS Profile is required to use Point-of-Sale,POS Profil je potreban za korištenje Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Odaberite Naknada za prvi,
Please select Company,Odaberite tvrtke,
Please select Company and Designation,Odaberite Tvrtka i Oznaka,
-Please select Company and Party Type first,Odaberite Društvo i Zabava Tip prvi,
Please select Company and Posting Date to getting entries,Odaberite unos za tvrtku i datum knjiženja,
Please select Company first,Odaberite tvrtka prvi,
Please select Completion Date for Completed Asset Maintenance Log,Molimo odaberite Datum završetka za Dovršeni dnevnik održavanja imovine,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Red {0}: UOM pretvorbe faktor je obavezno,
Row {0}: select the workstation against the operation {1},Red {0}: odaberite radnu stanicu protiv operacije {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Redak {0}: {1} Serijski brojevi potrebni za stavku {2}. Naveli ste {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Redak {0}: {1} potreban je za izradu faktura otvaranja {2},
Row {0}: {1} must be greater than 0,Redak {0}: {1} mora biti veći od 0,
Row {0}: {1} {2} does not match with {3},Red {0}: {1} {2} ne odgovara {3},
Row {0}:Start Date must be before End Date,Red {0} : Datum početka mora biti prije datuma završetka,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Slanje e-pošte za evaluaciju potpore,
Send Now,Pošalji odmah,
Send SMS,Pošalji SMS,
-Send Supplier Emails,Pošalji Supplier e-pošte,
Send mass SMS to your contacts,Pošalji grupne SMS poruke svojim kontaktima,
Sensitivity,Osjetljivost,
Sent,Poslano,
-Serial #,Serijski #,
Serial No and Batch,Serijski broj i serije,
Serial No is mandatory for Item {0},Serijski Nema je obvezna za točke {0},
Serial No {0} does not belong to Batch {1},Serijski broj {0} ne pripada skupini {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Ime vaše tvrtke za koje ste postavljanje ovog sustava .,
The number of shares and the share numbers are inconsistent,Broj dionica i brojeva udjela nedosljedni su,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Račun za gateway plaćanja u planu {0} se razlikuje od računa za pristupnik plaćanja u ovom zahtjevu za plaćanje,
-The request for quotation can be accessed by clicking on the following link,Zahtjev za ponudu se može pristupiti klikom na sljedeći link,
The selected BOMs are not for the same item,Odabrane sastavnice nisu za istu stavku,
The selected item cannot have Batch,Izabrani predmet ne može imati Hrpa,
The seller and the buyer cannot be the same,Prodavatelj i kupac ne mogu biti isti,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Ukupni iznos komponente fleksibilne naknade {0} ne smije biti manji od maksimalnih naknada {1},
Total hours: {0},Ukupno vrijeme: {0},
Total leaves allocated is mandatory for Leave Type {0},Ukupni dopušteni dopusti obvezni su za vrstu napuštanja {0},
-Total weightage assigned should be 100%. It is {0},Ukupno bi trebalo biti dodijeljena weightage 100 % . To je {0},
Total working hours should not be greater than max working hours {0},Ukupno radno vrijeme ne smije biti veći od max radnog vremena {0},
Total {0} ({1}),Ukupno {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Ukupno {0} za sve stavke nula, možda biste trebali promijeniti 'Podijeliti optužbi na temelju'",
@@ -3316,7 +3299,6 @@
What do you need help with?,Što vam je potrebna pomoć?,
What does it do?,Što učiniti ?,
Where manufacturing operations are carried.,Gdje se odvija proizvodni postupci.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Tijekom stvaranja računa za podmlađivanje Company {0}, nadređeni račun {1} nije pronađen. Napravite nadređeni račun u odgovarajućem COA",
White,bijela,
Wire Transfer,Wire Transfer,
WooCommerce Products,WooCommerce proizvodi,
@@ -3448,7 +3430,6 @@
{0} variants created.,Stvorene su varijante {0}.,
{0} {1} created,{0} {1} stvorio,
{0} {1} does not exist,{0} {1} ne postoji,
-{0} {1} does not exist.,{0} {1} ne postoji.,
{0} {1} has been modified. Please refresh.,{0} {1} je izmijenjen. Osvježi stranicu.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} nije poslano tako da se radnja ne može dovršiti,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} povezan je s {2}, ali račun stranke je {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} Ne radi postoji,
{0}: {1} not found in Invoice Details table,{0}: {1} nije pronađen u Pojedinosti dostavnice stolu,
{} of {},{} od {},
+Assigned To,Dodijeljeno,
Chat,Razgovor,
Completed By,Završio,
Conditions,Uvjeti,
@@ -3506,7 +3488,9 @@
Merge with existing,Spoji sa postojećim,
Office,Ured,
Orientation,Orijentacija,
+Parent,Nadređen,
Passive,Pasiva,
+Payment Failed,Plaćanje nije uspjelo,
Percent,Postotak,
Permanent,trajan,
Personal,Osobno,
@@ -3544,7 +3528,6 @@
Company field is required,Polje tvrtke je obavezno,
Creating Dimensions...,Izrada dimenzija ...,
Duplicate entry against the item code {0} and manufacturer {1},Duplikat unosa sa šifrom artikla {0} i proizvođačem {1},
-Import Chart Of Accounts from CSV / Excel files,Uvezi račun s računa iz CSV / Excel datoteka,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Nevažeći GSTIN! Uneseni unos ne odgovara formatu GSTIN za vlasnike UIN-a ili nerezidentne davatelje usluga OIDAR-a,
Invoice Grand Total,Faktura ukupno,
Last carbon check date cannot be a future date,Posljednji datum provjere ugljika ne može biti budući datum,
@@ -3556,6 +3539,7 @@
Show {0},Prikaži {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Posebni znakovi osim "-", "#", ".", "/", "{" I "}" nisu dopušteni u imenovanju serija",
Target Details,Pojedinosti cilja,
+{0} already has a Parent Procedure {1}.,{0} već ima roditeljski postupak {1}.,
API,API,
Annual,godišnji,
Approved,Odobren,
@@ -3572,6 +3556,8 @@
No data to export,Nema podataka za izvoz,
Portrait,Portret,
Print Heading,Ispis naslova,
+Scheduler Inactive,Planer neaktivan,
+Scheduler is inactive. Cannot import data.,Planer je neaktivan. Nije moguće uvesti podatke.,
Show Document,Prikaži dokument,
Show Traceback,Prikaži Traceback,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Napravite inspekciju kvalitete za predmet {0},
Creating Accounts...,Stvaranje računa ...,
Creating bank entries...,Izrada bankovnih unosa ...,
-Creating {0},Stvaranje {0},
Credit limit is already defined for the Company {0},Kreditni limit je već definiran za Društvo {0},
Ctrl + Enter to submit,Ctrl + Enter za slanje,
Ctrl+Enter to submit,Ctrl + Enter za slanje,
@@ -3921,7 +3906,6 @@
Plaid public token error,Pogreška javnog tokena u obliku video zapisa,
Plaid transactions sync error,Pogreška sinkronizacije plaidnih transakcija,
Please check the error log for details about the import errors,Provjerite dnevnik pogrešaka za detalje o uvoznim pogreškama,
-Please click on the following link to set your new password,Molimo kliknite na sljedeći link kako bi postavili novu lozinku,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Izradite <b>DATEV postavke</b> za tvrtku <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Napravite unos prilagodbe u časopisu za iznos {0},
Please do not create more than 500 items at a time,Ne stvarajte više od 500 predmeta odjednom,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Datum izlaska mora biti u budućnosti,
Relieving Date must be greater than or equal to Date of Joining,Datum oslobađanja mora biti veći ili jednak datumu pridruživanja,
Rename,Preimenuj,
+Rename Not Allowed,Preimenovanje nije dopušteno,
Repayment Method is mandatory for term loans,Način otplate je obvezan za oročene kredite,
Repayment Start Date is mandatory for term loans,Datum početka otplate je obvezan za oročene kredite,
Report Item,Stavka izvješća,
@@ -4043,7 +4028,6 @@
Select All,Odaberite sve,
Select Difference Account,Odaberite račun razlike,
Select a Default Priority.,Odaberite zadani prioritet.,
-Select a Supplier from the Default Supplier List of the items below.,Odaberite dobavljača sa zadanog popisa dobavljača dolje navedenih stavki.,
Select a company,Odaberite tvrtku,
Select finance book for the item {0} at row {1},Odaberite knjigu financija za stavku {0} u retku {1},
Select only one Priority as Default.,Odaberite samo jedan prioritet kao zadani.,
@@ -4247,7 +4231,6 @@
Actual ,stvaran,
Add to cart,Dodaj u košaricu,
Budget,budžet,
-Chart Of Accounts Importer,Uvoznik računa računa,
Chart of Accounts,Kontni plan,
Customer database.,Baza podataka korisnika.,
Days Since Last order,Dana od posljednje narudžbe,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Datum završetka ne može biti manja od početnog datuma,
For Default Supplier (Optional),Za dobavljača zadano (neobavezno),
From date cannot be greater than To date,Datum ne može biti veći od datuma,
-Get items from,Nabavite stavke iz,
Group by,Grupiranje prema,
In stock,Na lageru,
Item name,Naziv proizvoda,
@@ -4532,32 +4514,22 @@
Accounts Settings,Postavke računa,
Settings for Accounts,Postavke za račune,
Make Accounting Entry For Every Stock Movement,Provjerite knjiženje za svaki burzi pokreta,
-"If enabled, the system will post accounting entries for inventory automatically.","Ako je omogućeno, sustav će objaviti računovodstvene stavke za popis automatski.",
-Accounts Frozen Upto,Računi Frozen Upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Knjiženje zamrznuta do tog datuma, nitko ne može učiniti / mijenjati ulazak, osim uloge naveden u nastavku.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Uloga dopušteno postavljanje blokada računa i uređivanje Frozen Entries,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Korisnici s ovom ulogom smiju postaviti zamrznute račune i izradu / izmjenu računovodstvenih unosa protiv zamrznutih računa,
Determine Address Tax Category From,Odredite kategoriju adrese poreza od,
-Address used to determine Tax Category in transactions.,Adresa koja se koristi za određivanje porezne kategorije u transakcijama.,
Over Billing Allowance (%),Preko dopunske naplate (%),
-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 for $110.,"Postotak koji vam dopušta naplatu više u odnosu na naručeni iznos. Na primjer: Ako je vrijednost narudžbe za artikl 100 USD, a tolerancija postavljena na 10%, tada vam je dopušteno naplaćivanje 110 USD.",
Credit Controller,Kreditne kontroler,
-Role that is allowed to submit transactions that exceed credit limits set.,Uloga koja je dopušteno podnijeti transakcije koje premašuju kreditnih ograničenja postavljena.,
Check Supplier Invoice Number Uniqueness,Provjerite Dobavljač Račun broj Jedinstvenost,
Make Payment via Journal Entry,Plaćanje putem Temeljnica,
Unlink Payment on Cancellation of Invoice,Prekini vezu Plaćanje o otkazu fakture,
-Unlink Advance Payment on Cancelation of Order,Prekini vezu s predujmom otkazivanja narudžbe,
Book Asset Depreciation Entry Automatically,Automatski ulazi u amortizaciju imovine u knjizi,
Automatically Add Taxes and Charges from Item Tax Template,Automatski dodajte poreze i pristojbe sa predloška poreza na stavke,
Automatically Fetch Payment Terms,Automatski preuzmi Uvjete plaćanja,
-Show Inclusive Tax In Print,Pokaži porez na inkluziju u tisku,
Show Payment Schedule in Print,Prikaži raspored plaćanja u ispisu,
Currency Exchange Settings,Postavke mjenjačke valute,
Allow Stale Exchange Rates,Dopusti stale tečaj,
Stale Days,Dani tišine,
Report Settings,Postavke izvješća,
Use Custom Cash Flow Format,Koristite prilagođeni format novčanog toka,
-Only select if you have setup Cash Flow Mapper documents,Odaberite samo ako imate postavke dokumenata Cash Flow Mapper,
Allowed To Transact With,Dopušteno za transakciju s,
SWIFT number,SWIFT broj,
Branch Code,Kod podružnice,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Korisnička Grupa,
POS Field,POS polje,
POS Item Group,POS Točka Grupa,
-[Select],[Odaberi],
Company Address,adresa tvrtke,
Update Stock,Ažuriraj zalihe,
Ignore Pricing Rule,Ignorirajte Cijene pravilo,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Dobavljač nazivanje,
Default Supplier Group,Zadana skupina dobavljača,
Default Buying Price List,Zadani kupovni cjenik,
-Maintain same rate throughout purchase cycle,Održavaj istu stopu tijekom cijelog ciklusa kupnje,
-Allow Item to be added multiple times in a transaction,Dopusti Stavka biti dodan više puta u transakciji,
Backflush Raw Materials of Subcontract Based On,Na temelju sirovina povratne fluktuacije podugovaranja,
Material Transferred for Subcontract,Prijenos materijala za podugovaranje,
Over Transfer Allowance (%),Naknada za prebacivanje prijenosa (%),
@@ -5540,7 +5509,6 @@
Current Stock,Trenutačno stanje skladišta,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Za pojedinog opskrbljivača,
-Supplier Detail,Dobavljač Detalj,
Link to Material Requests,Link do zahtjeva za materijalom,
Message for Supplier,Poruka za dobavljača,
Request for Quotation Item,Zahtjev za ponudu točke,
@@ -6481,7 +6449,6 @@
Appraisal Template,Procjena Predložak,
For Employee Name,Za ime zaposlenika,
Goals,Golovi,
-Calculate Total Score,Izračunajte ukupni rezultat,
Total Score (Out of 5),Ukupna ocjena (od 5),
"Any other remarks, noteworthy effort that should go in the records.","Sve ostale primjedbe, značajan napor da bi trebao ići u evidenciji.",
Appraisal Goal,Procjena gol,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Razlog za odlazak,
Leave Encashed?,Odsustvo naplaćeno?,
Encashment Date,Encashment Datum,
-Exit Interview Details,Izlaz Intervju Detalji,
-Held On,Održanoj,
-Reason for Resignation,Razlog za ostavku,
-Better Prospects,Bolji izgledi,
-Health Concerns,Zdravlje Zabrinutost,
New Workplace,Novo radno mjesto,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Povratni iznos,
@@ -6740,10 +6702,7 @@
Employee Settings,Postavke zaposlenih,
Retirement Age,Umirovljenje Dob,
Enter retirement age in years,Unesite dob za umirovljenje u godinama,
-Employee Records to be created by,Zaposlenik Records bi se stvorili,
-Employee record is created using selected field. ,Zaposlenika rekord je stvorio pomoću odabranog polja.,
Stop Birthday Reminders,Zaustavi Rođendan Podsjetnici,
-Don't send Employee Birthday Reminders,Ne šaljite podsjetnik za rođendan zaposlenika,
Expense Approver Mandatory In Expense Claim,Potrošač troškova obvezan u zahtjevu za trošak,
Payroll Settings,Postavke plaće,
Leave,Napustiti,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Odustani od odobrenja Obvezni zahtjev za napuštanje,
Show Leaves Of All Department Members In Calendar,Prikaži lišće svih članova odjela u kalendaru,
Auto Leave Encashment,Automatski napustite enkaš,
-Restrict Backdated Leave Application,Ograničite unaprijed ostavljeni zahtjev,
Hiring Settings,Postavke zapošljavanja,
Check Vacancies On Job Offer Creation,Provjerite slobodna radna mjesta na izradi ponude posla,
Identification Document Type,Vrsta dokumenta identifikacije,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Postavke proizvodnje,
Raw Materials Consumption,Potrošnja sirovina,
Allow Multiple Material Consumption,Omogući višestruku potrošnju materijala,
-Allow multiple Material Consumption against a Work Order,Dopustite višestruku potrošnju materijala prema radnom nalogu,
Backflush Raw Materials Based On,Jedinice za pranje sirovine na temelju,
Material Transferred for Manufacture,Materijal prenose Proizvodnja,
Capacity Planning,Planiranje kapaciteta,
Disable Capacity Planning,Onemogući planiranje kapaciteta,
Allow Overtime,Dopusti Prekovremeni,
-Plan time logs outside Workstation Working Hours.,Planirajte vrijeme za rezanje izvan radne stanice radnog vremena.,
Allow Production on Holidays,Dopustite proizvodnje na odmor,
Capacity Planning For (Days),Planiranje kapaciteta za (dani),
-Try planning operations for X days in advance.,Pokušajte planirati poslovanje za X dana unaprijed.,
-Time Between Operations (in mins),Vrijeme između operacije (u minutama),
-Default 10 mins,Default 10 min,
Default Warehouses for Production,Zadana skladišta za proizvodnju,
Default Work In Progress Warehouse,Zadana rad u tijeku Skladište,
Default Finished Goods Warehouse,Zadane gotovih proizvoda Skladište,
Default Scrap Warehouse,Zadana skladišta otpada,
-Over Production for Sales and Work Order,Prekomjerna proizvodnja za prodaju i radni nalog,
Overproduction Percentage For Sales Order,Postotak prekomjerne proizvodnje za prodajni nalog,
Overproduction Percentage For Work Order,Postotak prekomjerne proizvodnje za radni nalog,
Other Settings,Ostale postavke,
Update BOM Cost Automatically,Ažurirajte automatski trošak BOM-a,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Ažuriranje BOM-a automatski se naplaćuje putem Planera, temeljeno na najnovijoj stopi vrednovanja / stopi cjenika / zadnje stope kupnje sirovina.",
Material Request Plan Item,Stavka plana materijala,
Material Request Type,Tip zahtjeva za robom,
Material Issue,Materijal Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Cilj kvalitete,
Monitoring Frequency,Učestalost nadgledanja,
Weekday,radni dan,
-January-April-July-October,Siječanj-travanj-srpanj-listopad,
-Revision and Revised On,Revizija i revizija dana,
-Revision,Revizija,
-Revised On,Revidirano dana,
Objectives,Ciljevi,
Quality Goal Objective,Cilj kvaliteta kvalitete,
Objective,Cilj,
@@ -7619,7 +7566,6 @@
Processes,procesi,
Quality Procedure Process,Postupak postupka kvalitete,
Process Description,Opis procesa,
-Child Procedure,Postupak za dijete,
Link existing Quality Procedure.,Povežite postojeći postupak kvalitete.,
Additional Information,dodatne informacije,
Quality Review Objective,Cilj pregleda kvalitete,
@@ -7787,15 +7733,9 @@
Default Customer Group,Zadana grupa kupaca,
Default Territory,Zadani teritorij,
Close Opportunity After Days,Zatvori Prilika Nakon dana,
-Auto close Opportunity after 15 days,Automatski zatvori Priliku nakon 15 dana,
Default Quotation Validity Days,Zadani rokovi valjanosti ponude,
Sales Update Frequency,Ažuriranje ažuriranja prodaje,
-How often should project and company be updated based on Sales Transactions.,Koliko često se projekt i tvrtka trebaju ažurirati na temelju prodajnih transakcija.,
Each Transaction,Svaka transakcija,
-Allow user to edit Price List Rate in transactions,Dopusti korisniku uređivanje cjenika u transakcijama,
-Allow multiple Sales Orders against a Customer's Purchase Order,Dopusti višestruke prodajne naloge protiv kupca narudžbenice,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Provjera valjanosti prodajna cijena za točku protiv Cijena za plaćanje ili procijenjena stopa,
-Hide Customer's Tax Id from Sales Transactions,Sakrij Porezni Kupca od prodajnih transakcija,
SMS Center,SMS centar,
Send To,Pošalji,
All Contact,Svi kontakti,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Proizvođači se koriste u stavkama,
Limited to 12 characters,Ograničiti na 12 znakova,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Postavite skladište,
-Sets 'For Warehouse' in each row of the Items table.,Postavlja "Za skladište" u svakom retku tablice Predmeti.,
-Requested For,Traženi Za,
Partially Ordered,Djelomično uređeno,
Transferred,prebačen,
% Ordered,% Naručeno,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Zadana kataloška mjerna jedinica,
Sample Retention Warehouse,Skladište za uzorkovanje uzoraka,
Default Valuation Method,Zadana metoda vrednovanja,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Postotak koju smiju primiti ili isporučiti više od naručene količine. Na primjer: Ako ste naručili 100 jedinica. i tvoj ispravak je 10% onda se smiju primati 110 jedinica.,
-Action if Quality inspection is not submitted,Postupak ako se ne preda inspekcija kakvoće,
Show Barcode Field,Prikaži Barkod Polje,
Convert Item Description to Clean HTML,Pretvori opis stavke u čisti HTML,
-Auto insert Price List rate if missing,"Ako ne postoji, automatski ubaciti cjenik",
Allow Negative Stock,Dopustite negativnu zalihu,
Automatically Set Serial Nos based on FIFO,Automatski Postavljanje Serijski broj na temelju FIFO,
-Set Qty in Transactions based on Serial No Input,Postavite količinu u transakcijama na temelju serijskog unosa,
Auto Material Request,Automatski zahtjev za materijalom,
-Raise Material Request when stock reaches re-order level,Podignite Materijal Zahtjev kad dionica dosegne ponovno poredak razinu,
-Notify by Email on creation of automatic Material Request,Obavijest putem maila prilikom stvaranja automatskog Zahtjeva za robom,
Inter Warehouse Transfer Settings,Postavke prijenosa skladišta Inter,
-Allow Material Transfer From Delivery Note and Sales Invoice,Omogućite prijenos materijala iz otpremnice i fakture o prodaji,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Omogućite prijenos materijala s potvrde o kupnji i fakture za kupnju,
Freeze Stock Entries,Zamrzavanje Stock Unosi,
Stock Frozen Upto,Kataloški Frozen Upto,
-Freeze Stocks Older Than [Days],Freeze Dionice stariji od [ dana ],
-Role Allowed to edit frozen stock,Uloga dopuštenih urediti smrznute zalihe,
Batch Identification,Identifikacija serije,
Use Naming Series,Upotrijebite seriju naziva,
Naming Series Prefix,Imenujte prefiks serije,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Trend primki,
Purchase Register,Popis nabave,
Quotation Trends,Trend ponuda,
-Quoted Item Comparison,Citirano predmeta za usporedbu,
Received Items To Be Billed,Primljeni Proizvodi se naplaćuje,
Qty to Order,Količina za narudžbu,
Requested Items To Be Transferred,Traženi proizvodi spremni za transfer,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Odaberite skladište za zahtjeve za materijalom,
Transfer Materials For Warehouse {0},Prijenos materijala za skladište {0},
Production Plan Material Request Warehouse,Skladište zahtjeva za planom proizvodnje,
-Set From Warehouse,Postavljeno iz skladišta,
-Source Warehouse (Material Transfer),Izvorno skladište (prijenos materijala),
Sets 'Source Warehouse' in each row of the items table.,Postavlja 'Izvorno skladište' u svaki redak tablice stavki.,
Sets 'Target Warehouse' in each row of the items table.,Postavlja 'Ciljano skladište' u svaki redak tablice stavki.,
Show Cancelled Entries,Prikaži otkazane unose,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Usluga primljena, ali ne i naplaćena",
Deferred Accounting Settings,Postavke odgođenog računovodstva,
Book Deferred Entries Based On,Rezervirajte unose na osnovi,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ako je odabrano "Mjeseci", fiksni iznos knjižiti će se kao odgođeni prihod ili rashod za svaki mjesec, bez obzira na broj dana u mjesecu. Bit će proporcionalno ako odgođeni prihodi ili rashodi ne budu knjiženi za cijeli mjesec.",
Days,Dana,
Months,Mjeseci,
Book Deferred Entries Via Journal Entry,Rezervirajte unose putem odlozaka,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Ako ovo nije potvrđeno, stvorit će se izravni GL unosi za knjiženje odgođenih prihoda / rashoda",
Submit Journal Entries,Pošaljite članke u časopisu,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Ako ovo nije označeno, unosi u dnevnik bit će spremljeni u stanje nacrta i morat će se slati ručno",
Enable Distributed Cost Center,Omogući distribuirano mjesto troškova,
@@ -8901,8 +8823,6 @@
Is Inter State,Je li Inter State,
Purchase Details,Pojedinosti o kupnji,
Depreciation Posting Date,Datum knjiženja amortizacije,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Narudžbenica potrebna za fakturu i izradu računa,
-Purchase Receipt Required for Purchase Invoice Creation,Potvrda o kupovini potrebna za stvaranje računa za kupovinu,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Prema zadanim postavkama, naziv dobavljača postavljeno je prema upisanom imenu dobavljača. Ako želite da dobavljače imenuje",
choose the 'Naming Series' option.,odaberite opciju 'Naming Series'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Konfigurirajte zadani cjenik prilikom izrade nove transakcije kupnje. Cijene stavki dohvaćaju se iz ovog cjenika.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Je komponenta poreza na dohodak,
Component properties and references ,Svojstva i reference komponenata,
Additional Salary ,Dodatna plaća,
-Condtion and formula,Stanje i formula,
Unmarked days,Neoznačeni dani,
Absent Days,Dani odsutnosti,
Conditions and Formula variable and example,Uvjeti i varijabla formule i primjer,
Feedback By,Povratne informacije od,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.GGGG .-. MM .-. DD.-,
Manufacturing Section,Odjel za proizvodnju,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Prodajni nalog potreban je za fakturu prodaje i izradu otpremnice,
-Delivery Note Required for Sales Invoice Creation,Za izradu fakture o prodaji potrebna je dostava,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Prema zadanim postavkama, ime kupca postavlja se prema unesenom punom imenu. Ako želite da kupce imenuje",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Konfigurirajte zadani cjenik prilikom izrade nove prodajne transakcije. Cijene stavki dohvaćaju se iz ovog cjenika.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ako je ova opcija konfigurirana kao "Da", ERPNext će vas spriječiti u stvaranju prodajne fakture ili dostavnice bez prethodnog kreiranja prodajnog naloga. Ovu se konfiguraciju može nadjačati za određenog Kupca omogućavanjem potvrdnog okvira "Dopusti izradu fakture za prodaju bez prodajnog naloga" u masteru kupca.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} uspješno je dodan u sve odabrane teme.,
Topics updated,Teme ažurirane,
Academic Term and Program,Akademski pojam i program,
-Last Stock Transaction for item {0} was on {1}.,Posljednja transakcija zaliha za stavku {0} bila je {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Transakcije dionicama za stavku {0} ne mogu se objaviti prije ovog vremena.,
Please remove this item and try to submit again or update the posting time.,Uklonite ovu stavku i pokušajte je ponovo poslati ili ažurirajte vrijeme objavljivanja.,
Failed to Authenticate the API key.,Autentifikacija API ključa nije uspjela.,
Invalid Credentials,Nevažeće vjerodajnice,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Molimo provjerite svoj ID klijenta i tajne vrijednosti,
Bank transaction creation error,Pogreška pri stvaranju bankovne transakcije,
Unit of Measurement,Jedinica mjere,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Redak {{}: Stopa prodaje stavke {} niža je od {}. Stopa prodaje trebala bi biti najmanje {},
Fiscal Year {0} Does Not Exist,Fiskalna godina {0} ne postoji,
Row # {0}: Returned Item {1} does not exist in {2} {3},Redak {0}: Vraćena stavka {1} ne postoji u {2} {3},
Valuation type charges can not be marked as Inclusive,Naknade vrste procjene ne mogu se označiti kao Uključujuće,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Vrijeme odziva za {0} prioritet u retku {1} ne može biti veće od vremena razlučivanja.,
{0} is not enabled in {1},{0} nije omogućen u {1},
Group by Material Request,Grupiraj prema zahtjevu za materijal,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Redak {0}: Za dobavljača {0} adresa e-pošte potrebna je za slanje e-pošte,
Email Sent to Supplier {0},E-pošta poslana dobavljaču {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Pristup zahtjevu za ponudu s portala je onemogućen. Da biste omogućili pristup, omogućite ga u postavkama portala.",
Supplier Quotation {0} Created,Ponuda dobavljača {0} Izrađena,
Valid till Date cannot be before Transaction Date,Važi do Datum ne može biti prije datuma transakcije,
+Unlink Advance Payment on Cancellation of Order,Prekinite vezu s predujmom pri otkazivanju narudžbe,
+"Simple Python Expression, Example: territory != 'All Territories'","Jednostavan Python izraz, Primjer: teritorij! = 'Svi teritoriji'",
+Sales Contributions and Incentives,Doprinosi prodaji i poticaji,
+Sourced by Supplier,Izvor dobavljača,
+Total weightage assigned should be 100%.<br>It is {0},Ukupna dodijeljena težina trebala bi biti 100%.<br> {0} je,
+Account {0} exists in parent company {1}.,Račun {0} postoji u matičnoj tvrtki {1}.,
+"To overrule this, enable '{0}' in company {1}","Da biste to poništili, omogućite "{0}" u tvrtki {1}",
+Invalid condition expression,Nevažeći izraz stanja,
+Please Select a Company First,Prvo odaberite tvrtku,
+Please Select Both Company and Party Type First,Molimo odaberite prvo vrstu tvrtke i stranke,
+Provide the invoice portion in percent,Dio fakture navedite u postocima,
+Give number of days according to prior selection,Navedite broj dana prema prethodnom odabiru,
+Email Details,Pojedinosti e-pošte,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Odaberite pozdrav za slušalicu. Npr. Gospodin, gospođa itd.",
+Preview Email,Pregled e-pošte,
+Please select a Supplier,Molimo odaberite dobavljača,
+Supplier Lead Time (days),Vrijeme isporuke dobavljača (dana),
+"Home, Work, etc.","Kuća, posao itd.",
+Exit Interview Held On,Izlazni intervju održan,
+Condition and formula,Stanje i formula,
+Sets 'Target Warehouse' in each row of the Items table.,Postavlja 'Ciljano skladište' u svaki redak tablice Stavke.,
+Sets 'Source Warehouse' in each row of the Items table.,Postavlja 'Izvorno skladište' u svaki redak tablice Stavke.,
+POS Register,POS registar,
+"Can not filter based on POS Profile, if grouped by POS Profile",Ne može se filtrirati na temelju POS profila ako je grupirano po POS profilu,
+"Can not filter based on Customer, if grouped by Customer",Ne može se filtrirati na temelju kupca ako ga je grupirao kupac,
+"Can not filter based on Cashier, if grouped by Cashier","Ne može se filtrirati na temelju blagajne, ako je grupirana po blagajni",
+Payment Method,Način plaćanja,
+"Can not filter based on Payment Method, if grouped by Payment Method",Nije moguće filtrirati na temelju načina plaćanja ako je grupirano prema načinu plaćanja,
+Supplier Quotation Comparison,Usporedba ponuda dobavljača,
+Price per Unit (Stock UOM),Cijena po jedinici (dionica UOM),
+Group by Supplier,Grupiraj prema dobavljaču,
+Group by Item,Grupiraj po stavkama,
+Remember to set {field_label}. It is required by {regulation}.,Ne zaboravite postaviti {field_label}. To zahtijeva {propis}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Datum upisa ne može biti prije datuma početka akademske godine {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Datum upisa ne može biti nakon datuma završetka akademskog roka {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Datum upisa ne može biti prije datuma početka akademskog roka {0},
+Future Posting Not Allowed,Objavljivanje u budućnosti nije dozvoljeno,
+"To enable Capital Work in Progress Accounting, ","Da biste omogućili računovodstvo kapitalnog rada u tijeku,",
+you must select Capital Work in Progress Account in accounts table,u tablici računa morate odabrati račun kapitalnog rada u tijeku,
+You can also set default CWIP account in Company {},Također možete postaviti zadani CWIP račun u tvrtki {},
+The Request for Quotation can be accessed by clicking on the following button,Zahtjevu za ponudu možete pristupiti klikom na sljedeći gumb,
+Regards,Pozdrav,
+Please click on the following button to set your new password,Kliknite sljedeći gumb za postavljanje nove lozinke,
+Update Password,Ažuriraj lozinku,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Redak {{}: Stopa prodaje stavke {} niža je od {}. Prodaja {} trebala bi biti najmanje {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Alternativno možete onemogućiti provjeru prodajne cijene u {} da biste zaobišli ovu provjeru.,
+Invalid Selling Price,Nevažeća prodajna cijena,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Adresa mora biti povezana s tvrtkom. U tablici veza dodajte redak za tvrtku.,
+Company Not Linked,Tvrtka nije povezana,
+Import Chart of Accounts from CSV / Excel files,Uvoz kontnog plana iz CSV / Excel datoteka,
+Completed Qty cannot be greater than 'Qty to Manufacture',Završena količina ne može biti veća od „Količina za proizvodnju“,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Redak {0}: Za dobavljača {1} adresa e-pošte potrebna je za slanje e-pošte,
+"If enabled, the system will post accounting entries for inventory automatically","Ako je omogućeno, sustav će automatski knjižiti knjigovodstvene evidencije zaliha",
+Accounts Frozen Till Date,Računi zamrznuti do datuma,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Računovodstvene stavke su zamrznute do danas. Nitko ne može stvarati ili mijenjati unose osim korisnika s ulogom navedenom u nastavku,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Dopuštena uloga za postavljanje zamrznutih računa i uređivanje zamrznutih unosa,
+Address used to determine Tax Category in transactions,Adresa koja se koristi za određivanje porezne kategorije u transakcijama,
+"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 ","Postotak koji smijete naplatiti više u odnosu na naručeni iznos. Na primjer, ako vrijednost narudžbe iznosi 100 USD za artikl, a tolerancija je postavljena na 10%, tada možete naplatiti do 110 USD",
+This role is allowed to submit transactions that exceed credit limits,Ovom je ulogom dopušteno podnošenje transakcija koje premašuju kreditna ograničenja,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ako je odabrano "Mjeseci", fiksni iznos knjižiti će se kao odgođeni prihod ili rashod za svaki mjesec, bez obzira na broj dana u mjesecu. Bit će proporcionalno ako odgođeni prihodi ili rashodi ne budu knjiženi cijeli mjesec",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Ako ovo nije označeno, stvorit će se izravni GL unosi za knjiženje odgođenih prihoda ili rashoda",
+Show Inclusive Tax in Print,Prikaži uključeni porez u tiskanom obliku,
+Only select this if you have set up the Cash Flow Mapper documents,Odaberite ovo samo ako ste postavili dokumente Mape tokova gotovine,
+Payment Channel,Kanal plaćanja,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Je li narudžbenica potrebna za izradu fakture i potvrde o kupnji?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Je li za izradu računa za kupovinu potrebna potvrda o kupnji?,
+Maintain Same Rate Throughout the Purchase Cycle,Održavajte istu cijenu tijekom ciklusa kupnje,
+Allow Item To Be Added Multiple Times in a Transaction,Dopusti dodavanje predmeta u transakciji više puta,
+Suppliers,Dobavljači,
+Send Emails to Suppliers,Pošaljite e-poštu dobavljačima,
+Select a Supplier,Odaberite dobavljača,
+Cannot mark attendance for future dates.,Nije moguće označiti prisustvo za buduće datume.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Želite li ažurirati prisustvo?<br> Prisutno: {0}<br> Odsutan: {1},
+Mpesa Settings,Postavke Mpesa,
+Initiator Name,Ime inicijatora,
+Till Number,Do broja,
+Sandbox,Pješčanik,
+ Online PassKey,Online PassKey,
+Security Credential,Vjerodajnica o sigurnosti,
+Get Account Balance,Nabavite stanje računa,
+Please set the initiator name and the security credential,Molimo postavite ime inicijatora i sigurnosne vjerodajnice,
+Inpatient Medication Entry,Stacionarni unos lijekova,
+HLC-IME-.YYYY.-,FHP-IME-.GGGG.-,
+Item Code (Drug),Šifra artikla (lijek),
+Medication Orders,Narudžbe lijekova,
+Get Pending Medication Orders,Primajte narudžbe lijekova na čekanju,
+Inpatient Medication Orders,Stacionarni lijekovi,
+Medication Warehouse,Skladište lijekova,
+Warehouse from where medication stock should be consumed,Skladište odakle treba potrošiti zalihe lijekova,
+Fetching Pending Medication Orders,Preuzimanje naloga za lijekove na čekanju,
+Inpatient Medication Entry Detail,Pojedinosti o ulazu u stacionarne lijekove,
+Medication Details,Pojedinosti o lijekovima,
+Drug Code,Kod lijekova,
+Drug Name,Naziv lijeka,
+Against Inpatient Medication Order,Protiv naloga za bolničko liječenje,
+Against Inpatient Medication Order Entry,Protiv ulaza u stacionarne lijekove,
+Inpatient Medication Order,Stacionarni lijek,
+HLC-IMO-.YYYY.-,FHP-IMO-.GGGG.-,
+Total Orders,Ukupno narudžbi,
+Completed Orders,Izvršene narudžbe,
+Add Medication Orders,Dodajte narudžbe za lijekove,
+Adding Order Entries,Dodavanje unosa u narudžbu,
+{0} medication orders completed,Dovršeno je {0} narudžbi lijekova,
+{0} medication order completed,{0} narudžba lijekova dovršena,
+Inpatient Medication Order Entry,Unos naloga za stacionarne lijekove,
+Is Order Completed,Je li narudžba dovršena,
+Employee Records to Be Created By,Zapisi o zaposlenicima koje će stvoriti,
+Employee records are created using the selected field,Evidencija o zaposlenicima kreira se pomoću odabranog polja,
+Don't send employee birthday reminders,Ne šaljite podsjetnike za rođendan zaposlenika,
+Restrict Backdated Leave Applications,Ograničite aplikacije za napuštanje sa zadnjim datumom,
+Sequence ID,ID sekvence,
+Sequence Id,Slijed Id,
+Allow multiple material consumptions against a Work Order,Omogućite višestruku potrošnju materijala prema radnom nalogu,
+Plan time logs outside Workstation working hours,Planirajte evidenciju vremena izvan radnog vremena radne stanice,
+Plan operations X days in advance,Planirajte operacije X dana unaprijed,
+Time Between Operations (Mins),Vrijeme između operacija (minuta),
+Default: 10 mins,Zadano: 10 min,
+Overproduction for Sales and Work Order,Prekomjerna proizvodnja za prodaju i radni nalog,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Ažurirajte BOM trošak automatski putem planera, na temelju najnovije stope procjene / stope cjenika / stope zadnje kupnje sirovina",
+Purchase Order already created for all Sales Order items,Narudžbenica je već stvorena za sve stavke narudžbenice,
+Select Items,Odaberite stavke,
+Against Default Supplier,Protiv zadanog dobavljača,
+Auto close Opportunity after the no. of days mentioned above,Automatsko zatvaranje Prilika nakon br. dana gore spomenutih,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Da li je narudžbenica potrebna za izradu fakture za prodaju i otpremnice?,
+Is Delivery Note Required for Sales Invoice Creation?,Je li za izradu računa za prodaju potrebna dostavnica?,
+How often should Project and Company be updated based on Sales Transactions?,Koliko često projekt i tvrtka trebaju biti ažurirani na temelju prodajnih transakcija?,
+Allow User to Edit Price List Rate in Transactions,Omogućite korisniku da uređuje cijenu cjenika u transakcijama,
+Allow Item to Be Added Multiple Times in a Transaction,Dopusti dodavanje predmeta u transakciji više puta,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Omogućite više narudžbi za prodaju u odnosu na narudžbenice kupca,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Provjerite prodajnu cijenu za stavku naspram stope nabave ili stope procjene,
+Hide Customer's Tax ID from Sales Transactions,Sakrijte porezni broj kupca iz prodajnih transakcija,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Postotak koji smijete primiti ili isporučiti više u odnosu na naručenu količinu. Na primjer, ako ste naručili 100 jedinica, a Vaš dodatak iznosi 10%, tada možete primiti 110 jedinica.",
+Action If Quality Inspection Is Not Submitted,Postupak ako se inspekcija kvalitete ne podnese,
+Auto Insert Price List Rate If Missing,Automatsko umetanje cijene cjenika ako nedostaje,
+Automatically Set Serial Nos Based on FIFO,Automatski postavi serijske brojeve na temelju FIFO-a,
+Set Qty in Transactions Based on Serial No Input,Postavi količinu u transakcijama na temelju serijskog unosa,
+Raise Material Request When Stock Reaches Re-order Level,Podignite zahtjev za materijal kada zalihe dosegnu razinu ponovnog naručivanja,
+Notify by Email on Creation of Automatic Material Request,Obavijestite e-poštom o stvaranju automatskog zahtjeva za materijalom,
+Allow Material Transfer from Delivery Note to Sales Invoice,Omogućite prijenos materijala s otpremnice na fakturu prodaje,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Omogućite prijenos materijala s potvrde o kupnji na fakturu kupnje,
+Freeze Stocks Older Than (Days),Zamrznite zalihe starije od (dana),
+Role Allowed to Edit Frozen Stock,Dopuštena uloga za uređivanje smrznutih zaliha,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Neraspoređeni iznos Unosa za plaćanje {0} veći je od neraspoređenog iznosa Bankovne transakcije,
+Payment Received,Primljena uplata,
+Attendance cannot be marked outside of Academic Year {0},Prisutnost se ne može označiti izvan akademske godine {0},
+Student is already enrolled via Course Enrollment {0},Student je već upisan putem upisa na predmet {0},
+Attendance cannot be marked for future dates.,Prisustvo se ne može označiti za buduće datume.,
+Please add programs to enable admission application.,Dodajte programe kako biste omogućili prijavu.,
+The following employees are currently still reporting to {0}:,Sljedeći zaposlenici trenutno se još uvijek prijavljuju {0}:,
+Please make sure the employees above report to another Active employee.,Molimo osigurajte da se gore navedeni zaposlenici prijave drugom aktivnom djelatniku.,
+Cannot Relieve Employee,Ne mogu olakšati zaposlenika,
+Please enter {0},Unesite {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Odaberite drugi način plaćanja. Mpesa ne podržava transakcije u valuti "{0}",
+Transaction Error,Pogreška transakcije,
+Mpesa Express Transaction Error,Pogreška Mpesa Express Transakcije,
+"Issue detected with Mpesa configuration, check the error logs for more details","Otkriven je problem s Mpesa konfiguracijom, za više detalja provjerite zapisnike pogrešaka",
+Mpesa Express Error,Pogreška Mpesa Expressa,
+Account Balance Processing Error,Pogreška pri obradi stanja računa,
+Please check your configuration and try again,Provjerite svoju konfiguraciju i pokušajte ponovo,
+Mpesa Account Balance Processing Error,Pogreška pri obradi stanja računa Mpesa,
+Balance Details,Pojedinosti stanja,
+Current Balance,Trenutno stanje,
+Available Balance,Dostupno Stanje,
+Reserved Balance,Rezervirano stanje,
+Uncleared Balance,Nerazjašnjena ravnoteža,
+Payment related to {0} is not completed,Isplata vezana uz {0} nije dovršena,
+Row #{}: Item Code: {} is not available under warehouse {}.,Redak {{}: Šifra artikla: {} nije dostupan u skladištu {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Redak {{}: Količina zaliha nije dovoljna za šifru artikla: {} ispod skladišta {}. Dostupna količina {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Redak {{}: Odaberite serijski broj i skup prema stavci: {} ili ga uklonite da biste dovršili transakciju.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Redak {{}: Nije odabran serijski broj za stavku: {}. Odaberite jedan ili ga uklonite da biste dovršili transakciju.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Redak {{}: Nije odabrana serija za stavku: {}. Odaberite skup ili ga uklonite da biste dovršili transakciju.,
+Payment amount cannot be less than or equal to 0,Iznos plaćanja ne može biti manji ili jednak 0,
+Please enter the phone number first,Prvo unesite telefonski broj,
+Row #{}: {} {} does not exist.,Redak {{}: {} {} ne postoji.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Redak {0}: {1} potreban je za stvaranje uvodnih {2} faktura,
+You had {} errors while creating opening invoices. Check {} for more details,Imali ste {} pogrešaka prilikom izrade faktura za otvaranje. Više pojedinosti potražite u {},
+Error Occured,Dogodila se pogreška,
+Opening Invoice Creation In Progress,Otvaranje izrade fakture u tijeku,
+Creating {} out of {} {},Izrada {} od {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Serijski broj: {0}) ne može se potrošiti jer je rezerviran za punjenje prodajnog naloga {1}.,
+Item {0} {1},Stavka {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Posljednja transakcija zaliha za artikl {0} u skladištu {1} bila je {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Transakcije dionicama za stavku {0} u skladištu {1} ne mogu se objaviti prije ovog vremena.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Knjiženje budućih transakcija dionicama nije dopušteno zbog Nepromjenjive knjige,
+A BOM with name {0} already exists for item {1}.,BOM s imenom {0} već postoji za stavku {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Jeste li preimenovali stavku? Molimo kontaktirajte administratora / tehničku podršku,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},U retku # {0}: ID sekvence {1} ne može biti manji od ID-a sekvence prethodnog retka {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) mora biti jednako {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, dovršite operaciju {1} prije operacije {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Ne možemo osigurati dostavu serijskim brojem jer se dodaje stavka {0} sa i bez osiguranja isporuke serijskim br.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Stavka {0} nema serijski broj. Samo serilizirane stavke mogu isporučivati na temelju serijskog broja,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Nije pronađena aktivna specifikacija za stavku {0}. Dostava serijskim brojem ne može se osigurati,
+No pending medication orders found for selected criteria,Nije pronađena nijedna narudžba lijekova za odabrane kriterije,
+From Date cannot be after the current date.,Od datuma ne može biti nakon trenutnog datuma.,
+To Date cannot be after the current date.,Do datuma ne može biti nakon trenutnog datuma.,
+From Time cannot be after the current time.,Iz vremena ne može biti nakon trenutnog vremena.,
+To Time cannot be after the current time.,To Time ne može biti nakon trenutnog vremena.,
+Stock Entry {0} created and ,Unos dionica {0} stvoren i,
+Inpatient Medication Orders updated successfully,Nalozi za stacionarne lijekove uspješno su ažurirani,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Redak {0}: Nije moguće stvoriti unos stacionarnih lijekova protiv otkazane narudžbe stacionarnih lijekova {1},
+Row {0}: This Medication Order is already marked as completed,Redak {0}: Ova je narudžba lijekova već označena kao ispunjena,
+Quantity not available for {0} in warehouse {1},Količina nije dostupna za {0} u skladištu {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,U nastavku omogućite Dopusti negativnu zalihu ili stvorite unos dionica.,
+No Inpatient Record found against patient {0},Nije pronađena bolnička evidencija protiv pacijenta {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Nalog za stacionarne lijekove {0} protiv susreta s pacijentima {1} već postoji.,
+Allow In Returns,Dopusti povratak,
+Hide Unavailable Items,Sakrij nedostupne stavke,
+Apply Discount on Discounted Rate,Primijenite popust na sniženu stopu,
+Therapy Plan Template,Predložak plana terapije,
+Fetching Template Details,Dohvaćanje pojedinosti predloška,
+Linked Item Details,Povezani detalji stavke,
+Therapy Types,Vrste terapije,
+Therapy Plan Template Detail,Pojedinosti predloška plana terapije,
+Non Conformance,Neusklađenost,
+Process Owner,Vlasnik procesa,
+Corrective Action,Korektivne mjere,
+Preventive Action,Preventivna akcija,
+Problem,Problem,
+Responsible,Odgovoran,
+Completion By,Završetak,
+Process Owner Full Name,Puno ime vlasnika postupka,
+Right Index,Desni indeks,
+Left Index,Lijevi indeks,
+Sub Procedure,Potprocedura,
+Passed,Prošao,
+Print Receipt,Ispisnica,
+Edit Receipt,Uredi potvrdu,
+Focus on search input,Usredotočite se na unos pretraživanja,
+Focus on Item Group filter,Usredotočite se na filter grupe predmeta,
+Checkout Order / Submit Order / New Order,Narudžba za plaćanje / Predaja naloga / Nova narudžba,
+Add Order Discount,Dodajte popust za narudžbu,
+Item Code: {0} is not available under warehouse {1}.,Šifra artikla: {0} nije dostupno u skladištu {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Serijski brojevi nisu dostupni za artikl {0} u skladištu {1}. Pokušajte promijeniti skladište.,
+Fetched only {0} available serial numbers.,Dohvaćeno samo {0} dostupnih serijskih brojeva.,
+Switch Between Payment Modes,Prebacivanje između načina plaćanja,
+Enter {0} amount.,Unesite iznos od {0}.,
+You don't have enough points to redeem.,Nemate dovoljno bodova za iskorištavanje.,
+You can redeem upto {0}.,Možete iskoristiti do {0}.,
+Enter amount to be redeemed.,Unesite iznos koji treba iskoristiti.,
+You cannot redeem more than {0}.,Ne možete iskoristiti više od {0}.,
+Open Form View,Otvorite prikaz obrasca,
+POS invoice {0} created succesfully,POS račun {0} uspješno je stvoren,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Količina zaliha nije dovoljna za šifru artikla: {0} ispod skladišta {1}. Dostupna količina {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Serijski broj: {0} već je pretvoren u drugu POS fakturu.,
+Balance Serial No,Serijski br,
+Warehouse: {0} does not belong to {1},Skladište: {0} ne pripada tvrtki {1},
+Please select batches for batched item {0},Odaberite serije za skupljenu stavku {0},
+Please select quantity on row {0},Odaberite količinu u retku {0},
+Please enter serial numbers for serialized item {0},Unesite serijske brojeve za serijsku stavku {0},
+Batch {0} already selected.,Skupina {0} već je odabrana.,
+Please select a warehouse to get available quantities,Odaberite skladište da biste dobili dostupne količine,
+"For transfer from source, selected quantity cannot be greater than available quantity","Za prijenos iz izvora, odabrana količina ne može biti veća od dostupne količine",
+Cannot find Item with this Barcode,Ne mogu pronaći predmet s ovim crtičnim kodom,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} je obavezan. Možda zapis mjenjačnice nije stvoren za {1} do {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} je poslao elemente povezane s tim. Morate otkazati imovinu da biste stvorili povrat kupnje.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Ovaj dokument nije moguće otkazati jer je povezan s poslanim materijalom {0}. Otkažite ga da biste nastavili.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Redak {{}: Serijski broj {} je već prebačen na drugu POS fakturu. Odaberite valjani serijski br.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Redak {{}: Serijski brojevi. {} Već su prebačeni u drugu POS fakturu. Odaberite valjani serijski br.,
+Item Unavailable,Predmet nije dostupan,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Redak {{}: serijski broj {} ne može se vratiti jer nije izvršen u izvornoj fakturi {},
+Please set default Cash or Bank account in Mode of Payment {},Postavite zadani gotovinski ili bankovni račun u načinu plaćanja {},
+Please set default Cash or Bank account in Mode of Payments {},Postavite zadani gotovinski ili bankovni račun u načinu plaćanja {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Molimo provjerite je li račun {} račun bilance. Možete promijeniti roditeljski račun u račun bilance ili odabrati drugi račun.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Molimo provjerite je li račun {} račun koji se plaća. Promijenite vrstu računa u Plativo ili odaberite drugi račun.,
+Row {}: Expense Head changed to {} ,Red {}: Glava rashoda promijenjena je u {},
+because account {} is not linked to warehouse {} ,jer račun {} nije povezan sa skladištem {},
+or it is not the default inventory account,ili nije zadani račun zaliha,
+Expense Head Changed,Promijenjena glava rashoda,
+because expense is booked against this account in Purchase Receipt {},jer je trošak knjižen na ovaj račun u potvrdi o kupnji {},
+as no Purchase Receipt is created against Item {}. ,jer se prema stavci {} ne stvara potvrda o kupnji.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,To se radi radi obračunavanja slučajeva kada se potvrda o kupnji kreira nakon fakture za kupnju,
+Purchase Order Required for item {},Narudžbenica potrebna za stavku {},
+To submit the invoice without purchase order please set {} ,"Da biste predali račun bez narudžbenice, postavite {}",
+as {} in {},kao {} u {},
+Mandatory Purchase Order,Obavezna narudžbenica,
+Purchase Receipt Required for item {},Potvrda o kupnji potrebna za stavku {},
+To submit the invoice without purchase receipt please set {} ,"Da biste predali račun bez potvrde o kupnji, postavite {}",
+Mandatory Purchase Receipt,Potvrda o obaveznoj kupnji,
+POS Profile {} does not belongs to company {},POS profil {} ne pripada tvrtki {},
+User {} is disabled. Please select valid user/cashier,Korisnik {} je onemogućen. Odaberite valjanog korisnika / blagajnika,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Redak {{}: Izvorna faktura {} fakture za povrat {} je {}.,
+Original invoice should be consolidated before or along with the return invoice.,Izvorni račun treba objediniti prije ili zajedno s povratnim računom.,
+You can add original invoice {} manually to proceed.,"Da biste nastavili, možete ručno dodati {} fakturu {}.",
+Please ensure {} account is a Balance Sheet account. ,Molimo provjerite je li račun {} račun bilance.,
+You can change the parent account to a Balance Sheet account or select a different account.,Možete promijeniti roditeljski račun u račun bilance ili odabrati drugi račun.,
+Please ensure {} account is a Receivable account. ,Molimo provjerite je li račun} račun potraživanja.,
+Change the account type to Receivable or select a different account.,Promijenite vrstu računa u Potraživanje ili odaberite drugi račun.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} se ne može otkazati jer su iskorišteni bodovi za lojalnost. Prvo otkažite {} Ne {},
+already exists,već postoji,
+POS Closing Entry {} against {} between selected period,Zatvaranje unosa POS-a {} protiv {} između odabranog razdoblja,
+POS Invoice is {},POS račun je {},
+POS Profile doesn't matches {},POS profil se ne podudara s {},
+POS Invoice is not {},POS faktura nije {},
+POS Invoice isn't created by user {},POS račun ne izrađuje korisnik {},
+Row #{}: {},Red # {}: {},
+Invalid POS Invoices,Nevažeći POS računi,
+Please add the account to root level Company - {},Dodajte račun korijenskoj tvrtki - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Tijekom stvaranja računa za podređenu tvrtku {0}, nadređeni račun {1} nije pronađen. Molimo stvorite roditeljski račun u odgovarajućem COA",
+Account Not Found,Račun nije pronađen,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Tijekom stvaranja računa za podređenu tvrtku {0}, nadređeni račun {1} pronađen je kao račun glavne knjige.",
+Please convert the parent account in corresponding child company to a group account.,Molimo pretvorite roditeljski račun u odgovarajućoj podređenoj tvrtki u grupni račun.,
+Invalid Parent Account,Nevažeći roditeljski račun,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Preimenovanje je dopušteno samo putem matične tvrtke {0}, kako bi se izbjegla neusklađenost.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Ako {0} {1} količinu predmeta {2}, na proizvod će primijeniti shema {3}.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ako {0} {1} vrijedite stavku {2}, shema {3} primijenit će se na stavku.",
+"As the field {0} is enabled, the field {1} is mandatory.","Kako je polje {0} omogućeno, polje {1} je obavezno.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Kako je polje {0} omogućeno, vrijednost polja {1} trebala bi biti veća od 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Nije moguće isporučiti serijski broj {0} stavke {1} jer je rezerviran za puni prodajni nalog {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Prodajni nalog {0} ima rezervaciju za artikl {1}, a možete dostaviti samo rezervirani {1} u odnosu na {0}.",
+{0} Serial No {1} cannot be delivered,{0} Serijski broj {1} nije moguće isporučiti,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Redak {0}: Predmet podugovaranja obvezan je za sirovinu {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Budući da ima dovoljno sirovina, zahtjev za materijal nije potreban za Skladište {0}.",
+" If you still want to proceed, please enable {0}.","Ako i dalje želite nastaviti, omogućite {0}.",
+The item referenced by {0} - {1} is already invoiced,Stavka na koju se poziva {0} - {1} već je fakturirana,
+Therapy Session overlaps with {0},Sjednica terapije preklapa se s {0},
+Therapy Sessions Overlapping,Preklapajuće se terapijske sesije,
+Therapy Plans,Planovi terapije,
+"Item Code, warehouse, quantity are required on row {0}","Šifra artikla, skladište, količina potrebni su na retku {0}",
+Get Items from Material Requests against this Supplier,Nabavite stavke iz materijalnih zahtjeva protiv ovog dobavljača,
+Enable European Access,Omogućiti europski pristup,
+Creating Purchase Order ...,Izrada narudžbenice ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Odaberite dobavljača od zadanih dobavljača dolje navedenih stavki. Nakon odabira, narudžbenica će se izvršiti samo za proizvode koji pripadaju odabranom dobavljaču.",
+Row #{}: You must select {} serial numbers for item {}.,Redak {{}: Morate odabrati {} serijske brojeve za stavku {}.,
diff --git a/erpnext/translations/hu.csv b/erpnext/translations/hu.csv
index d4e2216..29f347e 100644
--- a/erpnext/translations/hu.csv
+++ b/erpnext/translations/hu.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Tényleges adó típust nem lehet hozzárendelni a Tétel értékéhez a {0} sorban,
Add,Hozzáadás,
Add / Edit Prices,Árak hozzáadása / szerkesztése,
-Add All Suppliers,Összes beszállító hozzáadása,
Add Comment,Megjegyzés hozzáadása,
Add Customers,Vevők hozzáadása,
Add Employees,Alkalmazottak hozzáadása,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Nem vonható le, ha a kategória a 'Készletérték' vagy 'Készletérték és Teljes érték'",
"Cannot delete Serial No {0}, as it is used in stock transactions","Nem lehet törölni a sorozatszámot: {0}, mivel ezt használja a részvény tranzakcióknál",
Cannot enroll more than {0} students for this student group.,"Nem lehet regisztrálni, több mint {0} diákot erre a diákcsoportra.",
-Cannot find Item with this barcode,Nem található az elem ezzel a vonalkóddal,
Cannot find active Leave Period,Nem található aktív távolléti időszak,
Cannot produce more Item {0} than Sales Order quantity {1},"Nem lehet több mint ennyit {0} gyártani a tételből, mint amennyi a Vevői rendelési mennyiség {1}",
Cannot promote Employee with status Left,Nem támogathatja a távolléten lévő Alkalmazottat,
Cannot refer row number greater than or equal to current row number for this Charge type,"Nem lehet hivatkozni nagyobb vagy egyenlő sor számra, mint az aktuális sor szám erre a terehelés típusra",
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Nem lehet kiválasztani az első sorra az 'Előző sor összegére' vagy 'Előző sor Összesen' terhelés típust,
-Cannot set a received RFQ to No Quote,"Nem állítható be beérkezettnek az Árajánlatkérés , nincs Árajánlat",
Cannot set as Lost as Sales Order is made.,"Nem lehet beállítani elveszettnek ezt a Vevői rendelést, mivel végre van hajtva.",
Cannot set authorization on basis of Discount for {0},Nem lehet beállítani engedélyt a kedvezmény alapján erre: {0},
Cannot set multiple Item Defaults for a company.,Nem állíthat be több elem-alapértelmezést egy vállalat számára.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Díjak frissülnek a vásárláskor kapott nyugtán a tételek szerint,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Díjak arányosan kerülnek kiosztásra a tétel mennyiség vagy összegei alapján, a kiválasztása szerint",
-Chart Of Accounts,Számlatükör,
Chart of Cost Centers,Költséghelyek listája,
Check all,Összes ellenőrzése,
Checkout,kijelentkezés,
@@ -581,7 +577,6 @@
Compensatory Off,Kompenzációs ki,
Compensatory leave request days not in valid holidays,Korengedményes szabadságnapok nem az érvényes ünnepnapokon,
Complaint,Panasz,
-Completed Qty can not be greater than 'Qty to Manufacture',"Befejezett Menny nem lehet nagyobb, mint 'Gyártandó Menny'",
Completion Date,teljesítési dátum,
Computer,Számítógép,
Condition,Feltétel,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Létrehoz és kezeli a napi, heti és havi e-mail összefoglalókat.",
Create customer quotes,Árajánlatok létrehozása vevők részére,
Create rules to restrict transactions based on values.,Készítsen szabályokat az ügyletek korlátozására az értékek alapján.,
-Created By,Létrehozta,
Created {0} scorecards for {1} between: ,Létrehozta a (z) {0} eredménymutatókat {1} között:,
Creating Company and Importing Chart of Accounts,Vállalat létrehozása és számlaábra importálása,
Creating Fees,Díjak létrehozása,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Az alkalmazotti átutalást nem lehet benyújtani az átutalás dátuma előtt,
Employee cannot report to himself.,Alkalmazott nem jelent magának.,
Employee relieved on {0} must be set as 'Left',"Elengedett alkalmazott: {0} , be kell állítani mint 'Távol'",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Az alkalmazotti státuszt nem lehet "Balra" beállítani, mivel a következő alkalmazottak jelenleg jelentést tesznek ennek a munkavállalónak:",
Employee {0} already submited an apllication {1} for the payroll period {2},A (z) {0} alkalmazott már benyújtotta a {1} alkalmazást a bérszámfejtési időszakra {2},
Employee {0} has already applied for {1} between {2} and {3} : ,A (z) {0} alkalmazott már {2} és {3} között kérte a következőket {1}:,
Employee {0} has no maximum benefit amount,A (z) {0} alkalmazottnak nincs maximális juttatási összege,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,A(z) {0} sorhoz: Írja be a tervezett mennyiséget,
"For {0}, only credit accounts can be linked against another debit entry","{0} -hoz, csak jóváírási számlákat lehet kapcsolni a másik ellen terheléshez",
"For {0}, only debit accounts can be linked against another credit entry","{0} -hoz, csak terhelés számlákat lehet kapcsolni a másik ellen jóváíráshoz",
-Form View,Űrlap nézet,
Forum Activity,Fórum aktivitás,
Free item code is not selected,Az ingyenes cikkkód nincs kiválasztva,
Freight and Forwarding Charges,Árufuvarozási és szállítmányozási költségek,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Távollétet nem lehet kiosztani előbb mint {0}, mivel a távollét egyenleg már továbbított ehhez a jövőbeni távollét kiosztás rekordhoz {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Távollét nem alkalmazható / törölhető előbb mint: {0}, mivel a távollét egyenleg már továbbított ehhez a jövőbeni távollét kioszts rekordhoz {1}",
Leave of type {0} cannot be longer than {1},"Távollét típusa {0}, nem lehet hosszabb, mint {1}",
-Leave the field empty to make purchase orders for all suppliers,"Hagyja üresen a mezőt, hogy minden beszállító számára megrendelést tegyen",
Leaves,A levelek,
Leaves Allocated Successfully for {0},Távollét foglalása sikeres erre {0},
Leaves has been granted sucessfully,Távollétek létrehozása sikerült,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Nincs elem az Anyagjegyzéken a Gyártáshoz,
No Items with Bill of Materials.,Nincs tétel az anyagjegyzékkel.,
No Permission,Nincs jogosultság,
-No Quote,Nincs árajánlat,
No Remarks,Nincs megjegyzés,
No Result to submit,Nem érkezik eredmény,
No Salary Structure assigned for Employee {0} on given date {1},Nincs fizetési struktúra a(z) {0} munkatársakhoz a megadott időponton {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Átfedő feltételek találhatók ezek között:,
Owner,Tulajdonos,
PAN,PÁN,
-PO already created for all sales order items,A PO már létrehozott minden vevői rendelési tételhez,
POS,Értékesítési hely kassza (POS),
POS Profile,POS profil,
POS Profile is required to use Point-of-Sale,POS-profil szükséges a Értékesítési kassza használatához,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,"Kérjük, válasszon Terhelés típust először",
Please select Company,"Kérjük, válasszon Vállalkozást először",
Please select Company and Designation,"Kérjük, válassza a Vállalkozást és a Titulus lehetőséget",
-Please select Company and Party Type first,"Kérjük, válasszon Vállalkozást és Ügyfél típust először",
Please select Company and Posting Date to getting entries,A bejegyzések beírásához válassza a Cég és a rögzítés dátuma lehetőséget,
Please select Company first,"Kérjük, válasszon Vállalkozást először",
Please select Completion Date for Completed Asset Maintenance Log,"Kérem, válassza ki a befejezés dátumát a Befejezett Vagyontárgy gazdálkodási naplóhoz",
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Sor {0}: UOM átváltási arányra is kötelező,
Row {0}: select the workstation against the operation {1},{0} sor: válassza ki a munkaállomást a művelet ellen {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,{0} sor: {1} A {2} tételhez szükséges sorozatszámok. Ön ezt adta meg {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,{0} sor: {1} szükséges a nyitó {2} számlák létrehozásához,
Row {0}: {1} must be greater than 0,"A {0} sor {1} értékének nagyobbnak kell lennie, mint 0",
Row {0}: {1} {2} does not match with {3},Sor {0}: {1} {2} nem egyezik a {3},
Row {0}:Start Date must be before End Date,Row {0}: kezdő dátumot kell lennie a befejezés dátuma,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Küldjön támogatás áttekintő e-mailt,
Send Now,Küldés most,
Send SMS,SMS küldése,
-Send Supplier Emails,Beszállítói e-mailek küldése,
Send mass SMS to your contacts,Küldjön tömeges SMS-t a kapcsolatainak,
Sensitivity,Érzékenység,
Sent,Elküldött,
-Serial #,Szériasz #,
Serial No and Batch,Széria sz. és Köteg,
Serial No is mandatory for Item {0},Széria sz. kötelező tétel {0},
Serial No {0} does not belong to Batch {1},A {0} sorozatszám nem tartozik a {1} köteghez,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"A vállalkozásának a neve, amelyre ezt a rendszert beállítja.",
The number of shares and the share numbers are inconsistent,A részvények száma és a részvények számozása nem konzisztens,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,A {0} tervezett fizetési átjáró-fiók eltér a fizetési átjáró fiókjában ebben a fizetési kérelemben,
-The request for quotation can be accessed by clicking on the following link,Az ajánlatkérés elérhető a következő linkre kattintással,
The selected BOMs are not for the same item,A kiválasztott darabjegyzékeket nem ugyanarra a tételre,
The selected item cannot have Batch,A kiválasztott elemnek nem lehet Kötege,
The seller and the buyer cannot be the same,Eladó és a vevő nem lehet ugyanaz,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},"A {0} rugalmas juttatási összegek teljes összege nem lehet kevesebb, mint a maximális ellátások {1}",
Total hours: {0},Összesen az órák: {0},
Total leaves allocated is mandatory for Leave Type {0},A kihelyezett összes tűvollét kötelező a {0} távollét típushoz,
-Total weightage assigned should be 100%. It is {0},Összesen kijelölés súlyozásának 100% -nak kell lennie. Ez: {0},
Total working hours should not be greater than max working hours {0},"Teljes munkaidő nem lehet nagyobb, mint a max munkaidő {0}",
Total {0} ({1}),Összesen {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Összesen {0} az összes tételre nulla, lehet, hogy meg kell változtatnia 'Forgalmazói díjak ez alapján'",
@@ -3316,7 +3299,6 @@
What do you need help with?,Mivel kapcsolatban van szükséged segítségre?,
What does it do?,Mit csinal?,
Where manufacturing operations are carried.,Ahol a gyártási műveleteket végzik.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","A (z) {0} gyermekvállalat számára fiók létrehozása közben a (z) {1} szülői fiók nem található. Kérjük, hozza létre a szülői fiókot a megfelelő COA-ban",
White,fehér,
Wire Transfer,Banki átutalás,
WooCommerce Products,WooCommerce termékek,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} változatokat hoztak létre.,
{0} {1} created,{0} {1} létrehozott,
{0} {1} does not exist,{0} {1} nem létezik,
-{0} {1} does not exist.,{0} {1} nem létezik.,
{0} {1} has been modified. Please refresh.,"{0} {1} módosításra került. Kérjük, frissítse.",
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} nem nyújtották be, így a művelet nem végrehajtható",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} társítva a (z) {2} -hez, de a felek számlája a {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} nem létezik,
{0}: {1} not found in Invoice Details table,{0}: {1} nem található a Számla részletek táblázatban,
{} of {},"{} nak,-nek {}",
+Assigned To,Felelős érte,
Chat,Csevegés,
Completed By,Által befejeztve,
Conditions,Körülmények,
@@ -3506,7 +3488,9 @@
Merge with existing,Meglévővel összefésülni,
Office,Iroda,
Orientation,Irányultság,
+Parent,Fő,
Passive,Passzív,
+Payment Failed,Fizetés meghiúsult,
Percent,Százalék,
Permanent,Állandó,
Personal,Személyes,
@@ -3544,7 +3528,6 @@
Company field is required,A vállalati mező kitöltése kötelező,
Creating Dimensions...,Méretek létrehozása ...,
Duplicate entry against the item code {0} and manufacturer {1},Másolatos bejegyzés a {0} cikkszámhoz és a {1} gyártóhoz,
-Import Chart Of Accounts from CSV / Excel files,Fióktelep importálása CSV / Excel fájlokból,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Érvénytelen GSTIN! A beírt adat nem felel meg a GSTIN formátumnak az UIN-tulajdonosok vagy a nem rezidens OIDAR szolgáltatók esetében,
Invoice Grand Total,Összesen számla,
Last carbon check date cannot be a future date,Az utolsó szén-dioxid-ellenőrzési dátum nem lehet jövőbeli dátum,
@@ -3556,6 +3539,7 @@
Show {0},Mutasd {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Speciális karakterek, kivéve "-", "#", ".", "/", "{" És "}", a sorozatok elnevezése nem megengedett",
Target Details,Cél részletei,
+{0} already has a Parent Procedure {1}.,A (z) {0} már rendelkezik szülői eljárással {1}.,
API,API,
Annual,Éves,
Approved,Jóváhagyott,
@@ -3572,6 +3556,8 @@
No data to export,Nincs adat exportálni,
Portrait,portré,
Print Heading,Címsor nyomtatás,
+Scheduler Inactive,Ütemező inaktív,
+Scheduler is inactive. Cannot import data.,Az ütemező inaktív. Nem lehet adatokat importálni.,
Show Document,A dokumentum megjelenítése,
Show Traceback,A Traceback megjelenítése,
Video,Videó,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Hozzon létre minőségi ellenőrzést a (z) {0} elemhez,
Creating Accounts...,Fiókok létrehozása ...,
Creating bank entries...,Banki bejegyzések létrehozása ...,
-Creating {0},{0} létrehozása,
Credit limit is already defined for the Company {0},A hitelkeret már meg van határozva a vállalat számára {0},
Ctrl + Enter to submit,Ctrl + Enter a beküldéshez,
Ctrl+Enter to submit,Ctrl + Enter beadni,
@@ -3921,7 +3906,6 @@
Plaid public token error,Nyilvános nyilvános token hiba,
Plaid transactions sync error,Kockás tranzakciók szinkronizálási hibája,
Please check the error log for details about the import errors,Ellenőrizze a hibanaplót az importálási hibák részleteivel kapcsolatban,
-Please click on the following link to set your new password,"Kérjük, kattintson az alábbi linkre, az új jelszó beállításához",
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,"Kérjük, hozzon létre <b>DATEV beállításokat</b> a <b>(z) {} vállalat számára</b> .",
Please create adjustment Journal Entry for amount {0} ,"Kérjük, hozzon létre korrekciós naplóbejegyzést a (z) {0} összeghez",
Please do not create more than 500 items at a time,"Kérjük, ne hozzon létre egynél több 500 elemet",
@@ -3997,6 +3981,7 @@
Release date must be in the future,A kiadás dátumának a jövőben kell lennie,
Relieving Date must be greater than or equal to Date of Joining,A megváltás dátumának legalább a csatlakozás dátumával kell egyenlőnek lennie,
Rename,Átnevezés,
+Rename Not Allowed,Átnevezés nem megengedett,
Repayment Method is mandatory for term loans,A visszafizetési módszer kötelező a lejáratú kölcsönök esetében,
Repayment Start Date is mandatory for term loans,A visszafizetés kezdete kötelező a lejáratú hiteleknél,
Report Item,Jelentés elem,
@@ -4043,7 +4028,6 @@
Select All,Mindent kijelöl,
Select Difference Account,Válassza a Különbség fiókot,
Select a Default Priority.,Válasszon alapértelmezett prioritást.,
-Select a Supplier from the Default Supplier List of the items below.,Válasszon szállítót az alábbi tételek alapértelmezett szállító listájából.,
Select a company,Válasszon társaságot,
Select finance book for the item {0} at row {1},Válassza ki a {0} tétel pénzügyi könyvét a (z) {1} sorban,
Select only one Priority as Default.,Csak egy prioritást válasszon alapértelmezésként.,
@@ -4247,7 +4231,6 @@
Actual ,Tényleges,
Add to cart,Adja a kosárhoz,
Budget,Költségkeret,
-Chart Of Accounts Importer,Számlakezelő importőr,
Chart of Accounts,Számlatükör,
Customer database.,Ügyféladatbázis.,
Days Since Last order,Utolsó rendeléstől eltel napok,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,"A befejezés dátuma nem lehet kevesebb, mint a kezdő dátum",
For Default Supplier (Optional),Az alapértelmezett beszállító számára (opcionális),
From date cannot be greater than To date,"A dátum nem lehet nagyobb, mint a dátum",
-Get items from,Tételeket kér le innen,
Group by,Csoportosítva,
In stock,Raktáron,
Item name,Tétel neve,
@@ -4532,32 +4514,22 @@
Accounts Settings,Könyvelés beállításai,
Settings for Accounts,Fiókok beállítása,
Make Accounting Entry For Every Stock Movement,Hozzon létre számviteli könyvelést minden Készletmozgásra,
-"If enabled, the system will post accounting entries for inventory automatically.","Ha engedélyezve van, a rendszer automatikusan kiküldi a könyvelési tételeket a leltárhoz.",
-Accounts Frozen Upto,A számlák be vannak fagyasztva eddig,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Könyvelési tételt zárolt eddig a dátumig, senkinek nincs joga végrehajtani / módosítani a bejegyzést kivéve az alább meghatározott beosztásokkal rendelkezőket.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Beosztás élesítheni a zárolt számlákat & szerkeszthesse a zárolt bejegyzéseket,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,"A felhasználók ezzel a Beosztással engedélyt kapnak, hogy zároljanak számlákat és létrehozzanek / módosítsanak könyvelési tételeket a zárolt számlákon",
Determine Address Tax Category From,Határozza meg a cím adókategóriáját -tól,
-Address used to determine Tax Category in transactions.,A tranzakciók adókategóriájának meghatározására szolgáló cím.,
Over Billing Allowance (%),Túlfizetési támogatás (%),
-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 for $110.,"Százalékos arányban számolhat többet a megrendelt összeggel szemben. Például: Ha az elem rendelési értéke 100 USD, és a tűrést 10% -ra állítják be, akkor számolhat 110 USD-ért.",
Credit Controller,Követelés felügyelője,
-Role that is allowed to submit transactions that exceed credit limits set.,"Beosztást, amely lehetővé tette, hogy nyújtson be tranzakciókat, amelyek meghaladják a követelés határértékeket.",
Check Supplier Invoice Number Uniqueness,Ellenőrizze a Beszállítói Számlák számait Egyediségre,
Make Payment via Journal Entry,Naplókönyvelésen keresztüli befizetés létrehozás,
Unlink Payment on Cancellation of Invoice,Fizetetlen számlához tartozó Fizetés megszüntetése,
-Unlink Advance Payment on Cancelation of Order,Kapcsolja le az előleget a megrendelés törlésekor,
Book Asset Depreciation Entry Automatically,Könyv szerinti értékcsökkenés automatikus bejegyzés,
Automatically Add Taxes and Charges from Item Tax Template,Adók és díjak automatikus hozzáadása az elemadó sablonból,
Automatically Fetch Payment Terms,A fizetési feltételek automatikus lehívása,
-Show Inclusive Tax In Print,Adóval együtt megjelenítése a nyomtatáson,
Show Payment Schedule in Print,Fizetési ütemezés megjelenítése a nyomtatásban,
Currency Exchange Settings,Valutaváltási beállítások,
Allow Stale Exchange Rates,Engedélyezze az átmeneti árfolyam értékeket,
Stale Days,Átmeneti napok,
Report Settings,Jelentésbeállítások,
Use Custom Cash Flow Format,Használja az egyéni pénzforgalom formátumot,
-Only select if you have setup Cash Flow Mapper documents,"Csak akkor válassza ki, ha beállította a Pénzforgalom térképező dokumentumokat",
Allowed To Transact With,Tranzakcióhoz ezzel engedélyezése,
SWIFT number,SWIFT szám,
Branch Code,Fiók-kód,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Vásárlói csoport,
POS Field,POS mező,
POS Item Group,POS tétel csoport,
-[Select],[Válasszon],
Company Address,Vállalkozás címe,
Update Stock,Készlet frissítése,
Ignore Pricing Rule,Árképzési szabály figyelmen kívül hagyása,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Beszállító elnevezve által,
Default Supplier Group,Alapértelmezett beszállítói csoport,
Default Buying Price List,Alapértelmezett Vásárlási árjegyzék,
-Maintain same rate throughout purchase cycle,Ugyanazt az árat tartani az egész beszerzési ciklusban,
-Allow Item to be added multiple times in a transaction,Egy tranzakción belül a tétel többszöri hozzáadásának engedélyedzése,
Backflush Raw Materials of Subcontract Based On,Alvállalkozói visszatartandó nyersanyagok ez alapján,
Material Transferred for Subcontract,Alvállalkozásra átadott anyag,
Over Transfer Allowance (%),Túllépési juttatás (%),
@@ -5540,7 +5509,6 @@
Current Stock,Jelenlegi raktárkészlet,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Az egyéni beszállítónak,
-Supplier Detail,Beszállító adatai,
Link to Material Requests,Link az anyagigényekre,
Message for Supplier,Üzenet a Beszállítónak,
Request for Quotation Item,Árajánlatkérés tételre,
@@ -6481,7 +6449,6 @@
Appraisal Template,Teljesítmény értékelő sablon,
For Employee Name,Alkalmazott neve,
Goals,Célok,
-Calculate Total Score,Összes pontszám kiszámolása,
Total Score (Out of 5),Összes pontszám (5–ből),
"Any other remarks, noteworthy effort that should go in the records.","Bármely egyéb megjegyzések, említésre méltó erőfeszítés, aminek a nyilvántartásba kell kerülnie.",
Appraisal Goal,Teljesítmény értékelés célja,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Kilépés indoka,
Leave Encashed?,Távollét beváltása?,
Encashment Date,Beváltás dátuma,
-Exit Interview Details,Interjú részleteiből kilépés,
-Held On,Tartott,
-Reason for Resignation,Felmondás indoka,
-Better Prospects,Jobb kilátások,
-Health Concerns,Egészségügyi problémák,
New Workplace,Új munkahely,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Visszatérített összeg,
@@ -6740,10 +6702,7 @@
Employee Settings,Alkalmazott beállítások,
Retirement Age,Nyugdíjas kor,
Enter retirement age in years,Adja meg a nyugdíjkorhatárt (év),
-Employee Records to be created by,Alkalmazott bejegyzést létrehozó,
-Employee record is created using selected field. ,Alkalmazott rekord jön létre a kiválasztott mezővel.,
Stop Birthday Reminders,Születésnapi emlékeztetők kikapcsolása,
-Don't send Employee Birthday Reminders,Ne küldjön alkalmazotti születésnap emlékeztetőt,
Expense Approver Mandatory In Expense Claim,Költségvetési jóváhagyó kötelezõ a költségigénylésben,
Payroll Settings,Bérszámfejtés beállításai,
Leave,Elhagy,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Távollét jóváhagyó kötelező a szabadságra vonatkozó kérelemhez,
Show Leaves Of All Department Members In Calendar,Az összes osztály távolléteinek megjelenítése a naptárban,
Auto Leave Encashment,Automatikus elhagyási kódolás,
-Restrict Backdated Leave Application,Korlátozza a hátralevő szabadsági alkalmazást,
Hiring Settings,Bérleti beállítások,
Check Vacancies On Job Offer Creation,Ellenőrizze az állásajánlatok létrehozásának megüresedését,
Identification Document Type,Azonosító dokumentumtípus,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Gyártás Beállítások,
Raw Materials Consumption,Nyersanyag-fogyasztás,
Allow Multiple Material Consumption,Többféle anyagfelhasználás engedélyezése,
-Allow multiple Material Consumption against a Work Order,Többszörös anyagfelhasználás engedélyezése egy munkadarabhoz,
Backflush Raw Materials Based On,Visszatartandó nyersanyagok ez alapján,
Material Transferred for Manufacture,Anyag átadott gyártáshoz,
Capacity Planning,Kapacitástervezés,
Disable Capacity Planning,Kapcsolja ki a kapacitástervezést,
Allow Overtime,Túlóra engedélyezése,
-Plan time logs outside Workstation Working Hours.,Tervezési idő naplók a Munkaállomés munkaidején kívül.,
Allow Production on Holidays,Termelés engedélyezése az ünnepnapokon,
Capacity Planning For (Days),Kapacitás tervezés enyi időre (napok),
-Try planning operations for X days in advance.,Próbáljon tervezni tevékenységet X nappal előre.,
-Time Between Operations (in mins),Műveletek közti idő (percben),
-Default 10 mins,Alapértelmezett 10 perc,
Default Warehouses for Production,Alapértelmezett raktárak gyártáshoz,
Default Work In Progress Warehouse,Alapértelmezett Folyamatban lévő munka raktára,
Default Finished Goods Warehouse,Alapértelmezett készáru raktár,
Default Scrap Warehouse,Alapértelmezett hulladékraktár,
-Over Production for Sales and Work Order,Túltermelés értékesítés és megrendelés esetén,
Overproduction Percentage For Sales Order,Túltermelés százaléka az értékesítési vevői rendelésre,
Overproduction Percentage For Work Order,Túltermelés százaléka a munkarendelésre,
Other Settings,Egyéb beállítások,
Update BOM Cost Automatically,Automatikusan frissítse az ANYAGJ költségét,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Az ANYAGJ frissítése automatikusan az ütemezőn keresztül történik, a legfrissebb készletérték ár / árlisták ára / a nyersanyagok utolsó beszerzési ára alapján.",
Material Request Plan Item,Anyagigénylés tervelem tétel,
Material Request Type,Anyagigénylés típusa,
Material Issue,Anyag probléma,
@@ -7603,10 +7554,6 @@
Quality Goal,Minőségi cél,
Monitoring Frequency,Frekvencia figyelése,
Weekday,Hétköznap,
-January-April-July-October,Január-április-július-október,
-Revision and Revised On,Felülvizsgálva és felülvizsgálva,
-Revision,Felülvizsgálat,
-Revised On,Felülvizsgálva,
Objectives,célok,
Quality Goal Objective,Minőségi cél,
Objective,Célkitűzés,
@@ -7619,7 +7566,6 @@
Processes,Eljárások,
Quality Procedure Process,Minőségi eljárás folyamata,
Process Description,Folyamatleírás,
-Child Procedure,Gyermek eljárás,
Link existing Quality Procedure.,Kapcsolja össze a meglévő minőségi eljárást.,
Additional Information,további információ,
Quality Review Objective,Minőségértékelési célkitűzés,
@@ -7787,15 +7733,9 @@
Default Customer Group,Alapértelmezett Vevői csoport,
Default Territory,Alapértelmezett tartomány,
Close Opportunity After Days,Ügyek bezárása ennyi eltelt nap után,
-Auto close Opportunity after 15 days,Automatikus lezárása az ügyeknek 15 nap után,
Default Quotation Validity Days,Alapértelmezett árajánlat érvényességi napok,
Sales Update Frequency,Értékesítési frissítési gyakoriság,
-How often should project and company be updated based on Sales Transactions.,Milyen gyakran kell frissíteni a projektet és a vállalatot az értékesítési tranzakciók alapján.,
Each Transaction,Minden tranzakció,
-Allow user to edit Price List Rate in transactions,"Lehetővé teszi, hogy a felhasználó szerkeszthesse az Árlista értékeinek adóit a tranzakciókban",
-Allow multiple Sales Orders against a Customer's Purchase Order,Többszöri Vevő rendelések engedélyezése egy Beszerzési megrendelés ellen,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Eladási ár érvényesítése a tételre a Beszerzési árra vagy Készletértékre,
-Hide Customer's Tax Id from Sales Transactions,Ügyfél adóazonosító elrejtése az Értékesítési tranzakciókból,
SMS Center,SMS Központ,
Send To,Küldés Címzettnek,
All Contact,Összes Kapcsolattartó,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Gyártókat használt ebben a tételekben,
Limited to 12 characters,12 karakterre korlátozva,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,A Warehouse beállítása,
-Sets 'For Warehouse' in each row of the Items table.,Beállítja a „For Warehouse” elemet az Elemek táblázat minden sorában.,
-Requested For,Igény erre,
Partially Ordered,Részben megrendelt,
Transferred,Átvitt,
% Ordered,% Rendezve,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Alapértelmezett raktár mértékegység,
Sample Retention Warehouse,Mintavételi megörzési raktár,
Default Valuation Method,Alapértelmezett készletérték számítási mód,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Százalék amennyivel többet kaphat és adhat a megrendelt mennyiségnél. Például: Ha Ön által megrendelt 100 egység, és az engedmény 10%, akkor kaphat 110 egységet.",
-Action if Quality inspection is not submitted,"Intézkedés, ha a minőség-ellenőrzést nem nyújtják be",
Show Barcode Field,Vonalkód mező mutatása,
Convert Item Description to Clean HTML,Az elem leírásának átkonvertálása tiszta HTML-re,
-Auto insert Price List rate if missing,"Auto Árlista érték beillesztés, ha hiányzik",
Allow Negative Stock,Negatív készlet engedélyezése,
Automatically Set Serial Nos based on FIFO,Automatikusan beállítja a Sorozat számot a FIFO alapján /ElőszörBeElöszörKi/,
-Set Qty in Transactions based on Serial No Input,Mennyiség megadása a sorozatszámos bemeneten alapuló tranzakciókhoz,
Auto Material Request,Automata anyagigénylés,
-Raise Material Request when stock reaches re-order level,"Keletkezzen Anyag igény, ha a raktárállomány eléri az újrarendelés szintjét",
-Notify by Email on creation of automatic Material Request,Email értesítő létrehozása automatikus Anyag igény létrehozásához,
Inter Warehouse Transfer Settings,Inter Warehouse Transfer Settings,
-Allow Material Transfer From Delivery Note and Sales Invoice,Anyagátadás engedélyezése a szállítólevélről és az értékesítési számláról,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Anyagátadás engedélyezése a vásárlási nyugtáról és a számláról,
Freeze Stock Entries,Készlet zárolás,
Stock Frozen Upto,Készlet zárolása eddig,
-Freeze Stocks Older Than [Days],Ennél régebbi készletek zárolása [Napok],
-Role Allowed to edit frozen stock,Beosztás engedélyezi a zárolt készlet szerkesztését,
Batch Identification,Tétel azonosítás,
Use Naming Series,Használjon elnevezési sorozatokat,
Naming Series Prefix,Elnevezési sorozatok előtagja,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Beszerzési nyugták alakulása,
Purchase Register,Beszerzési Regisztráció,
Quotation Trends,Árajánlatok alakulása,
-Quoted Item Comparison,Ajánlott tétel összehasonlítás,
Received Items To Be Billed,Számlázandó Beérkezett tételek,
Qty to Order,Mennyiség Rendeléshez,
Requested Items To Be Transferred,Kérte az átvinni kívánt elemeket,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Válassza ki a raktárt az anyagkérésekhez,
Transfer Materials For Warehouse {0},Anyagok átadása raktárhoz {0},
Production Plan Material Request Warehouse,Termelési terv Anyagigény-raktár,
-Set From Warehouse,Készlet a raktárból,
-Source Warehouse (Material Transfer),Forrásraktár (anyagátadás),
Sets 'Source Warehouse' in each row of the items table.,Az elemtábla minden sorában beállítja a „Forrásraktár” elemet.,
Sets 'Target Warehouse' in each row of the items table.,Az elemtábla minden sorában beállítja a „Célraktár” elemet.,
Show Cancelled Entries,A törölt bejegyzések megjelenítése,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Szolgáltatás fogadott, de nem számlázott",
Deferred Accounting Settings,Halasztott könyvelési beállítások,
Book Deferred Entries Based On,Halasztott bejegyzések könyvelése ennek alapján,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ha a "Hónapok" lehetőséget választja, akkor a fix összeget minden hónapra halasztott bevételként vagy ráfordításként könyvelik el, függetlenül a hónap napjainak számától. Arányos lesz, ha a halasztott bevételt vagy kiadást nem egy teljes hónapra könyvelik el.",
Days,Napok,
Months,Hónapok,
Book Deferred Entries Via Journal Entry,Halasztott bejegyzések könyvelése folyóirat-bejegyzéssel,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Ha ez nincs bejelölve, akkor a GL elküldi a halasztott bevétel / ráfordítás könyvelését",
Submit Journal Entries,Naplóbejegyzések elküldése,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Ha ez nincs bejelölve, akkor a naplóbejegyzéseket Piszkozat állapotban menti és manuálisan kell elküldeni",
Enable Distributed Cost Center,Engedélyezze az Elosztott Költségközpontot,
@@ -8901,8 +8823,6 @@
Is Inter State,Inter állam,
Purchase Details,Vásárlás részletei,
Depreciation Posting Date,Amortizációs könyvelés dátuma,
-Purchase Order Required for Purchase Invoice & Receipt Creation,A vásárlási számla és a nyugta készítéséhez szükséges megrendelés,
-Purchase Receipt Required for Purchase Invoice Creation,A vásárlási számla létrehozásához szükséges vásárlási bizonylat,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Alapértelmezés szerint a beszállító neve a megadott beszállító neve szerint van beállítva. Ha azt szeretné, hogy a szállítókat a",
choose the 'Naming Series' option.,válassza a 'Sorozat elnevezése' opciót.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Új vásárlási tranzakció létrehozásakor konfigurálja az alapértelmezett Árlistát. A cikkek árait ebből az Árjegyzékből fogják lekérni.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,A jövedelemadó-összetevő,
Component properties and references ,Az alkatrészek tulajdonságai és hivatkozásai,
Additional Salary ,További fizetés,
-Condtion and formula,Feltétel és képlet,
Unmarked days,Jelöletlen napok,
Absent Days,Hiányzó napok,
Conditions and Formula variable and example,Feltételek és Formula változó és példa,
Feedback By,Visszajelzés:,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Gyártási részleg,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Az értékesítési számla és a szállítólevél készítéséhez eladási megrendelés szükséges,
-Delivery Note Required for Sales Invoice Creation,Szállítási bizonylat szükséges az értékesítési számla létrehozásához,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Alapértelmezés szerint az Ügyfél neve a megadott Teljes név szerint van beállítva. Ha azt szeretné, hogy az ügyfeleket a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Új értékesítési tranzakció létrehozásakor konfigurálja az alapértelmezett Árlistát. A cikkek árait ebből az Árjegyzékből fogják lekérni.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ha ez az opció „Igen” -re van konfigurálva, az ERPNext megakadályozza, hogy értékesítési számlát vagy szállítási jegyzetet hozzon létre anélkül, hogy először vevői rendelést hozna létre. Ez a konfiguráció felülbírálható egy adott ügyfél számára azáltal, hogy engedélyezi az Ügyfél-mester „Értékesítési számla létrehozásának engedélyezése vevői rendelés nélkül” jelölőnégyzetét.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} sikeresen hozzáadva az összes kiválasztott témához.,
Topics updated,Témák frissítve,
Academic Term and Program,Akadémiai kifejezés és program,
-Last Stock Transaction for item {0} was on {1}.,A (z) {0} tétel utolsó részvény tranzakciója ekkor volt: {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,A (z) {0} tétel részvénytranzakciói ezen időpont előtt nem könyvelhetők el.,
Please remove this item and try to submit again or update the posting time.,"Kérjük, távolítsa el ezt az elemet, és próbálja meg újra elküldeni, vagy frissítse a feladás idejét.",
Failed to Authenticate the API key.,Nem sikerült hitelesíteni az API kulcsot.,
Invalid Credentials,Érvénytelen hitelesítő adatok,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,"Kérjük, ellenőrizze Plaid kliens azonosítóját és titkos értékeit",
Bank transaction creation error,Banki tranzakció létrehozási hiba,
Unit of Measurement,Mértékegység,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},"{}. Sor: A (z) {} elem értékesítési aránya alacsonyabb, mint a (z) {}. Az eladási árfolyamnak legalább {}",
Fiscal Year {0} Does Not Exist,Pénzügyi év {0} nem létezik,
Row # {0}: Returned Item {1} does not exist in {2} {3},{0}. Sor: A (z) {1} visszaküldött tétel nem létezik itt: {2} {3},
Valuation type charges can not be marked as Inclusive,Az értékelési típusú díjak nem jelölhetők befogadónak,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,"A {0} {1}. Sor prioritásának válaszideje nem lehet hosszabb, mint a felbontási idő.",
{0} is not enabled in {1},A (z) {0} nincs engedélyezve itt: {1},
Group by Material Request,Anyagigény szerinti csoportosítás,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",{0} sor: A szállító {0} esetében e-mail cím szükséges az e-mail küldéséhez,
Email Sent to Supplier {0},E-mail elküldve a beszállítónak {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",A portálról történő ajánlatkéréshez való hozzáférés le van tiltva. A hozzáférés engedélyezéséhez engedélyezze a Portal beállításai között.,
Supplier Quotation {0} Created,Beszállítói ajánlat {0} létrehozva,
Valid till Date cannot be before Transaction Date,Az érvényes dátum nem lehet korábbi a tranzakció dátumánál,
+Unlink Advance Payment on Cancellation of Order,Válassza le az előleg visszavonását a megrendelés törlésekor,
+"Simple Python Expression, Example: territory != 'All Territories'","Egyszerű Python kifejezés, példa: territoorium! = 'Minden terület'",
+Sales Contributions and Incentives,Értékesítési hozzájárulások és ösztönzők,
+Sourced by Supplier,Beszállító által beszerzett,
+Total weightage assigned should be 100%.<br>It is {0},A teljes hozzárendelt súlynak 100% -nak kell lennie.<br> {0},
+Account {0} exists in parent company {1}.,A {0} fiók létezik az anyavállalatnál {1}.,
+"To overrule this, enable '{0}' in company {1}",Ennek felülbírálásához engedélyezze a (z) „{0}” lehetőséget a vállalatnál {1},
+Invalid condition expression,Érvénytelen feltétel kifejezés,
+Please Select a Company First,"Kérjük, először válasszon egy vállalatot",
+Please Select Both Company and Party Type First,"Kérjük, először válassza a Vállalat és a Buli típusát",
+Provide the invoice portion in percent,Adja meg a számla részét százalékban,
+Give number of days according to prior selection,Adja meg a napok számát az előzetes kiválasztás szerint,
+Email Details,E-mail részletei,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Válasszon üdvözletet a vevőnek. Pl. Mr., Ms., stb.",
+Preview Email,E-mail előnézete,
+Please select a Supplier,"Kérjük, válasszon szállítót",
+Supplier Lead Time (days),Szállítói leadási idő (nap),
+"Home, Work, etc.","Otthon, Munkahely stb.",
+Exit Interview Held On,Kilépés az interjúból tartott,
+Condition and formula,Feltétel és képlet,
+Sets 'Target Warehouse' in each row of the Items table.,Beállítja a „Célraktár” elemet az Elemek táblázat minden sorában.,
+Sets 'Source Warehouse' in each row of the Items table.,Beállítja a „Forrásraktár” elemet az Elemek táblázat minden sorában.,
+POS Register,POS regisztráció,
+"Can not filter based on POS Profile, if grouped by POS Profile","Nem lehet POS-profil alapján szűrni, ha POS-profil szerint van csoportosítva",
+"Can not filter based on Customer, if grouped by Customer","Nem lehet az Ügyfél alapján szűrni, ha az Ügyfél csoportosítja",
+"Can not filter based on Cashier, if grouped by Cashier","Nem lehet pénztár alapján szűrni, ha pénztáros csoportosítja",
+Payment Method,Fizetési mód,
+"Can not filter based on Payment Method, if grouped by Payment Method","Nem lehet a Fizetési mód alapján szűrni, ha Fizetési mód szerint van csoportosítva",
+Supplier Quotation Comparison,Beszállítói ajánlat összehasonlítása,
+Price per Unit (Stock UOM),Egységár (készlet UOM),
+Group by Supplier,Szállító szerint csoportosítva,
+Group by Item,Csoportosítás tételenként,
+Remember to set {field_label}. It is required by {regulation}.,Ne felejtse el beállítani a {field_label} mezőt. A {rendelet} előírja.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},A beiratkozás dátuma nem lehet korábbi a tanév kezdési dátumánál {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},A beiratkozás dátuma nem lehet későbbi a tanulmányi időszak végének dátumánál {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},A beiratkozási dátum nem lehet korábbi a tanulmányi időszak kezdő dátumánál {0},
+Future Posting Not Allowed,A jövőbeni közzététel nem engedélyezett,
+"To enable Capital Work in Progress Accounting, ",A tőkemunka folyamatban lévő könyvelésének engedélyezéséhez,
+you must select Capital Work in Progress Account in accounts table,ki kell választania a Folyamatban lévő tőkemunka számlát a számlák táblázatban,
+You can also set default CWIP account in Company {},Alapértelmezett CWIP-fiókot is beállíthat a Vállalatnál {},
+The Request for Quotation can be accessed by clicking on the following button,Az Ajánlatkérés a következő gombra kattintva érhető el,
+Regards,Üdvözlettel,
+Please click on the following button to set your new password,"Kérjük, kattintson a következő gombra az új jelszó beállításához",
+Update Password,Jelszó frissítése,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},"{}. Sor: A (z) {} elem értékesítési aránya alacsonyabb, mint a (z) {}. A (z) {} értékesítésnek legalább {} legyen",
+You can alternatively disable selling price validation in {} to bypass this validation.,"Alternatív megoldásként letilthatja az eladási ár érvényesítését itt: {}, hogy ezt az érvényesítést megkerülje.",
+Invalid Selling Price,Érvénytelen eladási ár,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,"A címet társítani kell egy vállalathoz. Kérjük, adjon meg egy sort a Vállalat számára a Linkek táblában.",
+Company Not Linked,A vállalat nincs összekapcsolva,
+Import Chart of Accounts from CSV / Excel files,Számlatáblázat importálása CSV / Excel fájlokból,
+Completed Qty cannot be greater than 'Qty to Manufacture',"Az elkészült mennyiség nem lehet nagyobb, mint a „gyártási mennyiség”",
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",{0} sor: A szállító {1} esetében e-mail címre van szükség az e-mail küldéséhez,
+"If enabled, the system will post accounting entries for inventory automatically","Ha engedélyezve van, a rendszer automatikusan könyveli a könyvelési bejegyzéseket",
+Accounts Frozen Till Date,Fiókok befagyasztva a dátumig,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"A könyvelési bejegyzések mindeddig be vannak zárva. Senki sem hozhat létre vagy módosíthat bejegyzéseket, kivéve az alábbiakban meghatározott szereplőkkel rendelkező felhasználókat",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,A fagyasztott számlák beállításához és a befagyott bejegyzések szerkesztéséhez megengedett szerepkör,
+Address used to determine Tax Category in transactions,Az adókategória meghatározásához használt cím a tranzakciókban,
+"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 ","Az a százalékos arány, amellyel többet számlázhat a megrendelt összeghez képest. Például, ha egy tétel rendelési értéke 100 USD, és a tűréshatár 10%, akkor legfeljebb 110 USD számlázhat",
+This role is allowed to submit transactions that exceed credit limits,Ez a szerepkör engedélyezheti a hitelkereteket meghaladó tranzakciók benyújtását,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ha a "Hónapok" lehetőséget választja, akkor egy fix összeget minden hónapra halasztott bevételként vagy ráfordításként könyvelnek el, függetlenül a hónapban töltött napok számától. Arányos lesz, ha a halasztott bevételt vagy kiadást nem egy teljes hónapra könyvelik el",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Ha ez nincs bejelölve, akkor közvetlen GL bejegyzések jönnek létre a halasztott bevételek vagy ráfordítások könyvelésére",
+Show Inclusive Tax in Print,Mutassa az inkluzív adót nyomtatásban,
+Only select this if you have set up the Cash Flow Mapper documents,"Csak akkor válassza ezt, ha beállította a Cash Flow Mapper dokumentumokat",
+Payment Channel,Fizetési csatorna,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Szükséges-e megrendelés a vásárlási számla és a nyugta létrehozásához?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Szükséges-e a vásárlási bizonylat a vásárlási számla létrehozásához?,
+Maintain Same Rate Throughout the Purchase Cycle,Ugyanazon arány fenntartása a vásárlási ciklus alatt,
+Allow Item To Be Added Multiple Times in a Transaction,Tétel többszörös hozzáadásának engedélyezése egy tranzakció során,
+Suppliers,Beszállítók,
+Send Emails to Suppliers,Küldjön e-maileket a beszállítóknak,
+Select a Supplier,Válasszon szállítót,
+Cannot mark attendance for future dates.,Nem lehet megjelölni a részvételt a jövőbeli dátumokra.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Szeretné frissíteni a látogatottságot?<br> Jelen van: {0}<br> Hiányzik: {1},
+Mpesa Settings,Mpesa beállítások,
+Initiator Name,Kezdeményező neve,
+Till Number,Számszámig,
+Sandbox,Homokozó,
+ Online PassKey,Online PassKey,
+Security Credential,Biztonsági hitelesítő adatok,
+Get Account Balance,Fiókegyenleg beszerzése,
+Please set the initiator name and the security credential,"Kérjük, állítsa be a kezdeményező nevét és a biztonsági hitelesítő adatot",
+Inpatient Medication Entry,Fekvőbeteg gyógyszeres bejegyzés,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Cikkszám (gyógyszer),
+Medication Orders,Gyógyszeres rendelések,
+Get Pending Medication Orders,Kérjen függőben lévő gyógyszeres rendeléseket,
+Inpatient Medication Orders,Fekvőbeteg gyógyszeres rendelések,
+Medication Warehouse,Gyógyszeres raktár,
+Warehouse from where medication stock should be consumed,"Raktár, ahonnan gyógyszerkészletet kell fogyasztani",
+Fetching Pending Medication Orders,Függőben lévő gyógyszeres rendelések lekérése,
+Inpatient Medication Entry Detail,Fekvőbeteg gyógyszeres bejegyzés részletei,
+Medication Details,A gyógyszeres kezelés részletei,
+Drug Code,Gyógyszerkód,
+Drug Name,Gyógyszer neve,
+Against Inpatient Medication Order,A fekvőbeteg gyógyszeres kezelés ellen,
+Against Inpatient Medication Order Entry,A fekvőbeteg gyógyszeres rendelési bejegyzés ellen,
+Inpatient Medication Order,Fekvőbeteg gyógyszeres kezelés,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Rendelések összesen,
+Completed Orders,Befejezett megrendelések,
+Add Medication Orders,Adja hozzá a gyógyszeres rendeléseket,
+Adding Order Entries,Megrendelési bejegyzések hozzáadása,
+{0} medication orders completed,{0} gyógyszerrendelés teljesítve,
+{0} medication order completed,{0} gyógyszerrendelés elkészült,
+Inpatient Medication Order Entry,Fekvőbeteg-rendelési bejegyzés,
+Is Order Completed,A megrendelés teljes,
+Employee Records to Be Created By,"Munkavállalói nyilvántartások, amelyeket létrehozni kell",
+Employee records are created using the selected field,Az alkalmazotti rekordok a kiválasztott mező használatával jönnek létre,
+Don't send employee birthday reminders,Ne küldjön az alkalmazottak születésnapi emlékeztetőit,
+Restrict Backdated Leave Applications,Korlátozott idejű szabadságra vonatkozó alkalmazások korlátozása,
+Sequence ID,Szekvenciaazonosító,
+Sequence Id,Szekvencia azonosító,
+Allow multiple material consumptions against a Work Order,Több anyagfogyasztás engedélyezése a Megrendelés ellen,
+Plan time logs outside Workstation working hours,Az időnaplók megtervezése a munkaállomás munkaidején kívül,
+Plan operations X days in advance,Tervezze meg a műveleteket X nappal előre,
+Time Between Operations (Mins),Műveletek közötti idő (perc),
+Default: 10 mins,Alapértelmezés: 10 perc,
+Overproduction for Sales and Work Order,Túltermelés az értékesítés és a munkarend szempontjából,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","A BOM költségeinek automatikus frissítése az ütemezőn keresztül, a legfrissebb értékelési arány / árlista / utolsó nyersanyag vásárlási arány alapján",
+Purchase Order already created for all Sales Order items,Az összes vevői rendelési tételhez már létrehozott megrendelés,
+Select Items,Válassza az Elemek lehetőséget,
+Against Default Supplier,Alapértelmezett szállítóval szemben,
+Auto close Opportunity after the no. of days mentioned above,Automatikus bezárási lehetőség a nem után. a fent említett napokból,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Szükséges-e értékesítési megrendelés az értékesítési számla és a szállítólevél készítéséhez?,
+Is Delivery Note Required for Sales Invoice Creation?,Szükséges-e szállítólevél az értékesítési számla létrehozásához?,
+How often should Project and Company be updated based on Sales Transactions?,Milyen gyakran kell frissíteni a projektet és a vállalatot az értékesítési tranzakciók alapján?,
+Allow User to Edit Price List Rate in Transactions,"Engedje meg a felhasználónak, hogy szerkessze az árlistát a tranzakciókban",
+Allow Item to Be Added Multiple Times in a Transaction,Tétel többszörös hozzáadása egy tranzakció során,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Több értékesítési megrendelés engedélyezése az ügyfél megrendelése ellen,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Érvényesítse a termék eladási árát a vételárral vagy az értékelési árral szemben,
+Hide Customer's Tax ID from Sales Transactions,Az ügyfél adóazonosítójának elrejtése az értékesítési tranzakciók között,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Az a százalékos arány, amellyel többet kaphat vagy szállíthat a megrendelt mennyiséghez képest. Például, ha 100 egységet rendelt, és a juttatása 10%, akkor 110 egységet kaphat.",
+Action If Quality Inspection Is Not Submitted,"Teendő, ha a minőségellenőrzést nem nyújtják be",
+Auto Insert Price List Rate If Missing,"Automatikus beszúrási árlista, ha hiányzik",
+Automatically Set Serial Nos Based on FIFO,A sorozatszámok automatikus beállítása a FIFO alapján,
+Set Qty in Transactions Based on Serial No Input,"Állítsa be a mennyiséget a tranzakciókban, soros bemenet nélkül",
+Raise Material Request When Stock Reaches Re-order Level,"Növelje az anyagigényt, amikor a készlet eléri az újrarendelési szintet",
+Notify by Email on Creation of Automatic Material Request,Értesítés e-mailben az automatikus anyagigénylés létrehozásáról,
+Allow Material Transfer from Delivery Note to Sales Invoice,Anyagátadás engedélyezése a szállítólevéltől az értékesítési számláig,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Anyagátvitel engedélyezése a vásárlási nyugtáról a vásárlási számlára,
+Freeze Stocks Older Than (Days),Készletek befagyasztása (napok),
+Role Allowed to Edit Frozen Stock,A fagyott készlet szerkesztésének szerepe megengedett,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,"A Fizetési tétel {0} kiosztatlan összege nagyobb, mint a banki tranzakció kiosztatlan összege",
+Payment Received,Fizetés beérkezett,
+Attendance cannot be marked outside of Academic Year {0},A részvétel nem jelölhető meg a tanéven kívül {0},
+Student is already enrolled via Course Enrollment {0},A hallgató már beiratkozott a tanfolyamra való beiratkozáson keresztül,
+Attendance cannot be marked for future dates.,A jövőbeni részvétel nem jelölhető meg.,
+Please add programs to enable admission application.,"Kérjük, adjon hozzá programokat a felvételi jelentkezés engedélyezéséhez.",
+The following employees are currently still reporting to {0}:,A következő alkalmazottak jelenleg is jelentést tesznek a következőnek: {0}:,
+Please make sure the employees above report to another Active employee.,"Kérjük, győződjön meg arról, hogy a fenti alkalmazottak beszámolnak-e egy másik aktív alkalmazottnak.",
+Cannot Relieve Employee,A munkavállalót nem lehet enyhíteni,
+Please enter {0},Írja be a következőt: {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',"Kérjük, válasszon másik fizetési módot. Az Mpesa nem támogatja a (z) „{0}” pénznemben végzett tranzakciókat",
+Transaction Error,Tranzakciós hiba,
+Mpesa Express Transaction Error,Mpesa Express tranzakciós hiba,
+"Issue detected with Mpesa configuration, check the error logs for more details",Mpesa konfigurációval észlelt probléma. További részletekért ellenőrizze a hibanaplókat,
+Mpesa Express Error,Mpesa Express hiba,
+Account Balance Processing Error,Fiókegyenleg-feldolgozási hiba,
+Please check your configuration and try again,"Kérjük, ellenőrizze a konfigurációt és próbálja újra",
+Mpesa Account Balance Processing Error,Mpesa számlaegyenleg-feldolgozási hiba,
+Balance Details,Egyenleg részletei,
+Current Balance,Aktuális egyenleg,
+Available Balance,Rendelkezésre álló egyenleg,
+Reserved Balance,Fenntartott egyenleg,
+Uncleared Balance,Tisztázatlan egyenleg,
+Payment related to {0} is not completed,A (z) {0} domainhez kapcsolódó fizetés nem fejeződött be,
+Row #{}: Item Code: {} is not available under warehouse {}.,{}. Sor: Az elem kódja: {} nem érhető el a raktárban {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,#. Sor: A készletmennyiség nem elegendő a Cikkszámhoz: {} raktár alatt {}. Elérhető mennyiség {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,"#. Sor: Kérjük, válasszon sorszámot, és tegye a tételhez: {}, vagy távolítsa el a tranzakció befejezéséhez.",
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"{}. Sor: Nincs kiválasztva sorozatszám a következő elemhez: {}. Kérjük, válasszon egyet, vagy távolítsa el a tranzakció befejezéséhez.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,"#. Sor: Nincs kiválasztva köteg az elemhez: {}. Kérjük, válasszon egy köteget, vagy távolítsa el a tranzakció befejezéséhez.",
+Payment amount cannot be less than or equal to 0,A befizetés összege nem lehet kisebb vagy egyenlő 0-val,
+Please enter the phone number first,"Kérjük, először írja be a telefonszámot",
+Row #{}: {} {} does not exist.,{}. Sor: {} {} nem létezik.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,{0} sor: {1} szükséges a nyitó {2} számlák létrehozásához,
+You had {} errors while creating opening invoices. Check {} for more details,A számlák nyitása során {} hibát észlelt. További részletekért lásd: {},
+Error Occured,Hiba lépett fel,
+Opening Invoice Creation In Progress,Folyamatban lévő számla létrehozásának megnyitása,
+Creating {} out of {} {},Létrehozás: {} / {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Sorszám: {0}) nem fogyasztható, mivel teljes értékesítési megrendelésre van fenntartva {1}.",
+Item {0} {1},{0} {1} tétel,
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,A (z) {0} raktár alatt lévő {1} elem utolsó készlet tranzakciója ekkor volt: {2},
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,A (z) {0} raktár alatt lévő {1} tétel készlettranzakciói ezen időpont előtt nem tehetők közzé.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Jövőbeni részvénytranzakciók könyvelése az Immutable Ledger miatt nem megengedett,
+A BOM with name {0} already exists for item {1}.,A (z) {1} elemhez már létezik egy {0} nevű BOM.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,"{0} {1} Átnevezte az elemet? Kérjük, lépjen kapcsolatba az adminisztrátorral / műszaki ügyfélszolgálattal",
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},"A (z) {0} sorban: a sorozat azonosítója {1} nem lehet kevesebb, mint az előző sor sorozat azonosítója {2}",
+The {0} ({1}) must be equal to {2} ({3}),A (z) {0} ({1}) egyenlőnek kell lennie a következővel: {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, fejezze be a műveletet {1} a művelet előtt {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Nem biztosítható a sorozatszám szerinti kézbesítés, mivel a (z) {0} tétel hozzá van adva a sorozatszámmal történő szállítás biztosításával és anélkül.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,A (z) {0} tételnek nincs sorszáma. A sorozatszám alapján csak a szerilizált termékek szállíthatók,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Nem található aktív BOM a (z) {0} elemhez. Sorozatszámmal történő kézbesítés nem biztosítható,
+No pending medication orders found for selected criteria,Nem található függőben lévő gyógyszerrendelés a kiválasztott szempontok szerint,
+From Date cannot be after the current date.,"A Dátumtól kezdve nem lehet későbbi, mint az aktuális dátum.",
+To Date cannot be after the current date.,A Dátum nem lehet későbbi az aktuális dátumnál.,
+From Time cannot be after the current time.,Az Időtől kezdve nem lehet az aktuális idő után.,
+To Time cannot be after the current time.,Az Idő nem lehet az aktuális idő után.,
+Stock Entry {0} created and ,Készletbejegyzés {0} létrehozva és,
+Inpatient Medication Orders updated successfully,A fekvőbeteg gyógyszeres rendelések sikeresen frissítve,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},{0} sor: Nem lehet létrehozni fekvőbeteg-gyógyszeres bejegyzést törölt fekvőbeteg-gyógyszeres rendelés ellen {1},
+Row {0}: This Medication Order is already marked as completed,{0} sor: Ez a gyógyszeres rendelés már befejezettként van megjelölve,
+Quantity not available for {0} in warehouse {1},Nem áll rendelkezésre mennyiség a (z) {0} raktárban {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"A folytatáshoz engedélyezze a Negatív részvény engedélyezése lehetőséget a részvénybeállításokban, vagy hozzon létre készletbejegyzést.",
+No Inpatient Record found against patient {0},Nem található fekvőbeteg-nyilvántartás a beteg ellen {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Már létezik fekvőbeteg-kezelési végzés {0} a beteg találkozása ellen {1}.,
+Allow In Returns,Engedélyezz viszonzva,
+Hide Unavailable Items,Nem elérhető elemek elrejtése,
+Apply Discount on Discounted Rate,Alkalmazzon kedvezményt a kedvezményes árfolyamon,
+Therapy Plan Template,Terápiás terv sablon,
+Fetching Template Details,A sablon részleteinek lekérése,
+Linked Item Details,Összekapcsolt elem részletei,
+Therapy Types,Terápiás típusok,
+Therapy Plan Template Detail,Terápiás terv sablon részlete,
+Non Conformance,Nem megfelelőség,
+Process Owner,Folyamat tulajdonos,
+Corrective Action,Korrekciós intézkedéseket,
+Preventive Action,Megelőző akció,
+Problem,Probléma,
+Responsible,Felelős,
+Completion By,Befejezés:,
+Process Owner Full Name,A folyamat tulajdonosának teljes neve,
+Right Index,Jobb index,
+Left Index,Bal oldali index,
+Sub Procedure,Sub eljárás,
+Passed,Elhaladt,
+Print Receipt,Nyugta nyomtatása,
+Edit Receipt,Nyugta szerkesztése,
+Focus on search input,Összpontosítson a keresési bevitelre,
+Focus on Item Group filter,Összpontosítson a Tételcsoport szűrőre,
+Checkout Order / Submit Order / New Order,Pénztári rendelés / Megrendelés benyújtása / Új megrendelés,
+Add Order Discount,Rendelési kedvezmény hozzáadása,
+Item Code: {0} is not available under warehouse {1}.,Cikkszám: {0} nem érhető el a raktárban {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,"A (z) {0} raktár alatti raktárban {1} nem áll rendelkezésre sorszám. Kérjük, próbálja meg megváltoztatni a raktárt.",
+Fetched only {0} available serial numbers.,Csak {0} elérhető sorozatszámot kapott.,
+Switch Between Payment Modes,Váltás a fizetési módok között,
+Enter {0} amount.,Adja meg a (z) {0} összeget.,
+You don't have enough points to redeem.,Nincs elég pontod a beváltáshoz.,
+You can redeem upto {0}.,Legfeljebb {0} beválthatja.,
+Enter amount to be redeemed.,Adja meg a beváltandó összeget.,
+You cannot redeem more than {0}.,{0} -nál többet nem válthat be.,
+Open Form View,Nyissa meg az Űrlap nézetet,
+POS invoice {0} created succesfully,POS számla {0} sikeresen létrehozva,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,A készletmennyiség nem elegendő a Cikkszámhoz: {0} raktár alatt {1}. Rendelkezésre álló mennyiség {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Sorszám: A (z) {0} már tranzakcióba került egy másik POS-számlával.,
+Balance Serial No,Egyenleg Sorszám,
+Warehouse: {0} does not belong to {1},Raktár: {0} nem tartozik a (z) {1} domainhez,
+Please select batches for batched item {0},Válassza ki a kötegelt tételeket a kötegelt tételhez {0},
+Please select quantity on row {0},"Kérjük, válassza ki a mennyiséget a (z) {0} sorban",
+Please enter serial numbers for serialized item {0},"Kérjük, adja meg a (z) {0} sorosított tétel sorozatszámát",
+Batch {0} already selected.,A (z) {0} köteg már kiválasztva.,
+Please select a warehouse to get available quantities,"Kérjük, válasszon egy raktárt a rendelkezésre álló mennyiségek megszerzéséhez",
+"For transfer from source, selected quantity cannot be greater than available quantity","Forrásból történő átvitelhez a kiválasztott mennyiség nem lehet nagyobb, mint a rendelkezésre álló mennyiség",
+Cannot find Item with this Barcode,Nem található elem ezzel a vonalkóddal,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},"A (z) {0} kötelező kitölteni. Lehet, hogy a (z) {1} és a (z) {2} számára nem jön létre pénzváltási rekord",
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,A (z) {} ehhez kapcsolódó eszközöket nyújtott be. A vásárlási hozam létrehozásához le kell mondania az eszközöket.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Nem törölhető ez a dokumentum, mivel a beküldött eszközhöz ({0}) kapcsolódik. Kérjük, törölje a folytatáshoz.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,"{}. Sor: A (z) {} sorszám már be van kapcsolva egy másik POS számlába. Kérjük, válasszon érvényes sorozatszámot.",
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,"{}. Sor: A (z) {} sorszámokat már bevezették egy másik POS-számlába. Kérjük, válasszon érvényes sorozatszámot.",
+Item Unavailable,Elem nem érhető el,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"{}. Sor: {0} sorszám nem adható vissza, mivel az eredeti számlán nem történt meg {0}",
+Please set default Cash or Bank account in Mode of Payment {},"Kérjük, állítsa be az alapértelmezett készpénzt vagy bankszámlát a Fizetési módban {}",
+Please set default Cash or Bank account in Mode of Payments {},"Kérjük, állítsa be az alapértelmezett készpénzt vagy bankszámlát a Fizetési módban {}",
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Győződjön meg arról, hogy a (z) {} fiók egy mérlegfiók. Módosíthatja a szülői fiókot mérlegfiókra, vagy kiválaszthat másik fiókot.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Győződjön meg arról, hogy a (z) {} fiók fizetendő fiók. Módosítsa a számla típusát Kötelezőre, vagy válasszon másik számlát.",
+Row {}: Expense Head changed to {} ,{}. Sor: A költségfej megváltozott erre: {},
+because account {} is not linked to warehouse {} ,mert a {} fiók nincs összekapcsolva a raktárral {},
+or it is not the default inventory account,vagy nem ez az alapértelmezett készletszámla,
+Expense Head Changed,A költségfej megváltozott,
+because expense is booked against this account in Purchase Receipt {},mert a költség a számlán van elszámolva a vásárlási nyugtán {},
+as no Purchase Receipt is created against Item {}. ,mivel a (z) {} tételhez nem jön létre vásárlási nyugta.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Ez az esetek elszámolásának kezelésére szolgál, amikor a vásárlási nyugta a vásárlási számla után jön létre",
+Purchase Order Required for item {},A (z) {} tételhez megrendelés szükséges,
+To submit the invoice without purchase order please set {} ,A számla beküldéséhez megrendelés nélkül adja meg a következőt: {},
+as {} in {},mint a {},
+Mandatory Purchase Order,Kötelező megrendelés,
+Purchase Receipt Required for item {},A (z) {} tételhez vásárlási bizonylat szükséges,
+To submit the invoice without purchase receipt please set {} ,A számla vásárlási nyugta nélküli benyújtásához állítsa be a következőt:,
+Mandatory Purchase Receipt,Kötelező vásárlási nyugta,
+POS Profile {} does not belongs to company {},A POS-profil {} nem tartozik a (z) {} céghez,
+User {} is disabled. Please select valid user/cashier,"A (z) {} felhasználó le van tiltva. Kérjük, válassza ki az érvényes felhasználót / pénztárt",
+Row #{}: Original Invoice {} of return invoice {} is {}. ,{}. Sor: A (z) {} eredeti számla {} a következő:,
+Original invoice should be consolidated before or along with the return invoice.,Az eredeti számlát a beváltó számla előtt vagy azzal együtt kell konszolidálni.,
+You can add original invoice {} manually to proceed.,A folytatáshoz manuálisan hozzáadhatja az eredeti számlát {}.,
+Please ensure {} account is a Balance Sheet account. ,"Győződjön meg arról, hogy a (z) {} fiók egy mérlegfiók.",
+You can change the parent account to a Balance Sheet account or select a different account.,"Módosíthatja a szülői fiókot mérlegfiókra, vagy kiválaszthat másik fiókot.",
+Please ensure {} account is a Receivable account. ,"Győződjön meg arról, hogy a (z) {} fiók vevő-fiók.",
+Change the account type to Receivable or select a different account.,"Változtassa a számlatípust Követelésre, vagy válasszon másik számlát.",
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"A (z) {} nem törölhető, mivel a megszerzett Hűségpontok beváltásra kerültek. Először törölje a {} Nem {} lehetőséget",
+already exists,már létezik,
+POS Closing Entry {} against {} between selected period,POS záró bejegyzés {} ellen {} a kiválasztott időszak között,
+POS Invoice is {},POS számla: {},
+POS Profile doesn't matches {},A POS-profil nem egyezik a következővel:},
+POS Invoice is not {},A POS számla nem {},
+POS Invoice isn't created by user {},A POS számlát nem a (z) {0} felhasználó hozta létre,
+Row #{}: {},#. Sor: {},
+Invalid POS Invoices,Érvénytelen POS-számlák,
+Please add the account to root level Company - {},"Kérjük, adja hozzá a fiókot a root szintű vállalathoz - {}",
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","A (z) {0} gyermekvállalat fiókjának létrehozása közben a (z) {1} szülőfiók nem található. Kérjük, hozza létre a szülői fiókot a megfelelő COA-ban",
+Account Not Found,Fiók nem található,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",A (z) {0} gyermekvállalat fiókjának létrehozása közben a (z) {1} szülőfiók főkönyv-fiókként található.,
+Please convert the parent account in corresponding child company to a group account.,"Kérjük, konvertálja a megfelelő alárendelt vállalat szülői fiókját csoportos fiókra.",
+Invalid Parent Account,Érvénytelen szülői fiók,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Az átnevezés csak az {0} anyavállalaton keresztül engedélyezett, az eltérések elkerülése érdekében.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Ha {0} {1} mennyiségű elemet tartalmaz {2}, akkor a sémát {3} alkalmazzák az elemre.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ha {0} {1} érdemes egy elemet {2}, akkor a sémát {3} alkalmazzák az elemre.",
+"As the field {0} is enabled, the field {1} is mandatory.","Mivel a {0} mező engedélyezve van, a {1} mező kötelező.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Mivel a {0} mező engedélyezve van, a {1} mező értékének 1-nél nagyobbnak kell lennie.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Nem lehet kézbesíteni a (z) {1} tétel sorszámát {1}, mivel az teljes értékesítési megrendelésre van fenntartva {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Az értékesítési rendelés {0} foglalást foglal a tételre {1}, csak lefoglalt {1} szállíthat {0} ellen.",
+{0} Serial No {1} cannot be delivered,A {0} sorszám {1} nem szállítható,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},{0} sor: Az alvállalkozói tétel kötelező a nyersanyaghoz {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Mivel elegendő alapanyag van, a raktárhoz {0} nem szükséges anyagkérelem.",
+" If you still want to proceed, please enable {0}.","Ha továbbra is folytatni szeretné, engedélyezze a {0} lehetőséget.",
+The item referenced by {0} - {1} is already invoiced,A (z) {0} - {1} által hivatkozott tételt már számlázzák,
+Therapy Session overlaps with {0},A terápiás munkamenet átfedésben van a következővel: {0},
+Therapy Sessions Overlapping,A terápiás foglalkozások átfedésben vannak,
+Therapy Plans,Terápiás tervek,
+"Item Code, warehouse, quantity are required on row {0}","A (z) {0} sorban tételszám, raktár, mennyiség szükséges",
+Get Items from Material Requests against this Supplier,Tételeket szerezhet a szállítóval szembeni anyagi igényekből,
+Enable European Access,Engedélyezze az európai hozzáférést,
+Creating Purchase Order ...,Megrendelés létrehozása ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",Válasszon szállítót az alábbi elemek alapértelmezett szállítói közül. A kiválasztáskor csak a kiválasztott szállítóhoz tartozó termékekre készül megrendelés.,
+Row #{}: You must select {} serial numbers for item {}.,#. Sor:} {0} sorszámokat kell kiválasztania.,
diff --git a/erpnext/translations/id.csv b/erpnext/translations/id.csv
index 00d167a..7175ad2 100644
--- a/erpnext/translations/id.csv
+++ b/erpnext/translations/id.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Jenis pajak aktual tidak dapat dimasukkan dalam tarif di baris {0},
Add,Tambahkan,
Add / Edit Prices,Tambah / Edit Harga,
-Add All Suppliers,Tambahkan Semua Pemasok,
Add Comment,Tambahkan komentar,
Add Customers,Tambahkan Pelanggan,
Add Employees,Tambahkan Karyawan,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',tidak bisa memotong ketika kategori adalah untuk 'Penilaian' atau 'Vaulation dan Total',
"Cannot delete Serial No {0}, as it is used in stock transactions","Tidak dapat menghapus No. Seri {0}, karena digunakan dalam transaksi persediaan",
Cannot enroll more than {0} students for this student group.,tidak bisa mendaftar lebih dari {0} siswa untuk kelompok siswa ini.,
-Cannot find Item with this barcode,Tidak dapat menemukan Item dengan barcode ini,
Cannot find active Leave Period,Tidak dapat menemukan Periode Keluar aktif,
Cannot produce more Item {0} than Sales Order quantity {1},Tidak dapat menghasilkan lebih Stok Barang {0} daripada kuantitas Sales Order {1},
Cannot promote Employee with status Left,Tidak dapat mempromosikan Karyawan dengan status Kiri,
Cannot refer row number greater than or equal to current row number for this Charge type,Tidak dapat merujuk nomor baris yang lebih besar dari atau sama dengan nomor baris saat ini untuk jenis Biaya ini,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Tidak dapat memilih jenis biaya sebagai 'Pada Row Sebelumnya Jumlah' atau 'On Sebelumnya Row Jumlah' untuk baris terlebih dahulu,
-Cannot set a received RFQ to No Quote,Tidak dapat mengatur RFQ yang diterima ke No Quote,
Cannot set as Lost as Sales Order is made.,Tidak dapat ditetapkan sebagai Hilang sebagai Sales Order dibuat.,
Cannot set authorization on basis of Discount for {0},Tidak dapat mengatur otorisasi atas dasar Diskon untuk {0},
Cannot set multiple Item Defaults for a company.,Tidak dapat menetapkan beberapa Default Item untuk sebuah perusahaan.,
@@ -521,7 +518,6 @@
Chargeble,Chargeble,
Charges are updated in Purchase Receipt against each item,Ongkos dalam Nota Pembelian diperbarui terhadap setiap barang,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Biaya akan didistribusikan secara proporsional berdasarkan pada item qty atau jumlah, sesuai pilihan Anda",
-Chart Of Accounts,Bagan Akun,
Chart of Cost Centers,Bagan Pusat Biaya,
Check all,Periksa semua,
Checkout,Periksa,
@@ -581,7 +577,6 @@
Compensatory Off,Kompensasi Off,
Compensatory leave request days not in valid holidays,Hari permintaan cuti kompensasi tidak dalam hari libur yang sah,
Complaint,Keluhan,
-Completed Qty can not be greater than 'Qty to Manufacture',Selesai Qty tidak dapat lebih besar dari 'Jumlah untuk Produksi',
Completion Date,tanggal penyelesaian,
Computer,Komputer,
Condition,Kondisi,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Buat dan kelola surel ringkasan harian, mingguan dan bulanan.",
Create customer quotes,Buat kutipan pelanggan,
Create rules to restrict transactions based on values.,Buat aturan untuk membatasi transaksi berdasarkan nilai-nilai.,
-Created By,Dibuat Oleh,
Created {0} scorecards for {1} between: ,Menciptakan {0} scorecard untuk {1} antara:,
Creating Company and Importing Chart of Accounts,Membuat Perusahaan dan Mengimpor Bagan Akun,
Creating Fees,Menciptakan Biaya,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Transfer karyawan tidak dapat diserahkan sebelum Tanggal Transfer,
Employee cannot report to himself.,Karyawan tidak bisa melaporkan kepada dirinya sendiri.,
Employee relieved on {0} must be set as 'Left',Karyawan lega pada {0} harus ditetapkan sebagai 'Kiri',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,Status karyawan tidak dapat diatur ke 'Kiri' karena karyawan berikut sedang melaporkan kepada karyawan ini:,
Employee {0} already submited an apllication {1} for the payroll period {2},Karyawan {0} sudah mengajukan apllication {1} untuk periode penggajian {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Karyawan {0} telah mengajukan permohonan untuk {1} antara {2} dan {3}:,
Employee {0} has no maximum benefit amount,Karyawan {0} tidak memiliki jumlah manfaat maksimal,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Untuk baris {0}: Masuki rencana qty,
"For {0}, only credit accounts can be linked against another debit entry","Untuk {0}, hanya rekening kredit dapat dihubungkan dengan entri debit lain",
"For {0}, only debit accounts can be linked against another credit entry","Untuk {0}, hanya rekening debit dapat dihubungkan dengan entri kredit lain",
-Form View,Tampilan Formulir,
Forum Activity,Kegiatan Forum,
Free item code is not selected,Kode item gratis tidak dipilih,
Freight and Forwarding Charges,Pengangkutan dan Forwarding Biaya,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Cuti tidak dapat dialokasikan sebelum {0}, saldo cuti sudah pernah membawa-diteruskan dalam catatan alokasi cuti masa depan {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Cuti tidak dapat diterapkan / dibatalkan sebelum {0}, saldo cuti sudah pernah membawa-diteruskan dalam catatan alokasi cuti masa depan {1}",
Leave of type {0} cannot be longer than {1},Cuti jenis {0} tidak boleh lebih dari {1},
-Leave the field empty to make purchase orders for all suppliers,Biarkan bidang kosong untuk membuat pesanan pembelian untuk semua pemasok,
Leaves,Daun-daun,
Leaves Allocated Successfully for {0},cuti Dialokasikan Berhasil untuk {0},
Leaves has been granted sucessfully,Daun telah diberikan dengan sukses,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Tidak ada Item dengan Bill of Material untuk Industri,
No Items with Bill of Materials.,Tidak Ada Item dengan Bill of Material.,
No Permission,Tidak ada izin,
-No Quote,Tidak ada kutipan,
No Remarks,Tidak ada Keterangan,
No Result to submit,Tidak ada hasil untuk disampaikan,
No Salary Structure assigned for Employee {0} on given date {1},Tidak ada Struktur Gaji yang ditugaskan untuk Karyawan {0} pada tanggal tertentu {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Kondisi Tumpang Tindih ditemukan antara:,
Owner,Pemilik,
PAN,PANCI,
-PO already created for all sales order items,PO sudah dibuat untuk semua item pesanan penjualan,
POS,POS,
POS Profile,POS Profil,
POS Profile is required to use Point-of-Sale,Profil POS diharuskan menggunakan Point of Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Silakan pilih Mengisi Tipe terlebih dahulu,
Please select Company,Silakan pilih Perusahaan,
Please select Company and Designation,Silakan pilih Perusahaan dan Penunjukan,
-Please select Company and Party Type first,Silakan pilih Perusahaan dan Partai Jenis terlebih dahulu,
Please select Company and Posting Date to getting entries,Silakan pilih Perusahaan dan Tanggal Posting untuk mendapatkan entri,
Please select Company first,Silakan pilih Perusahaan terlebih dahulu,
Please select Completion Date for Completed Asset Maintenance Log,Silakan pilih Tanggal Penyelesaian untuk Pemeriksaan Pemeliharaan Aset Selesai,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Row {0}: UOM Faktor Konversi adalah wajib,
Row {0}: select the workstation against the operation {1},Baris {0}: pilih workstation terhadap operasi {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Baris {0}: {1} Nomor seri diperlukan untuk Item {2}. Anda telah memberikan {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Baris {0}: {1} diperlukan untuk membuat Pembukaan {2} Faktur,
Row {0}: {1} must be greater than 0,Baris {0}: {1} harus lebih besar dari 0,
Row {0}: {1} {2} does not match with {3},Baris {0}: {1} {2} tidak cocok dengan {3},
Row {0}:Start Date must be before End Date,Row {0}: Tanggal awal harus sebelum Tanggal Akhir,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Kirim Email Peninjauan Donasi,
Send Now,Kirim sekarang,
Send SMS,Kirim SMS,
-Send Supplier Emails,Kirim Email Pemasok,
Send mass SMS to your contacts,Kirim SMS massal ke kontak Anda,
Sensitivity,Kepekaan,
Sent,Terkirim,
-Serial #,Serial #,
Serial No and Batch,Serial dan Batch,
Serial No is mandatory for Item {0},Serial ada adalah wajib untuk Item {0},
Serial No {0} does not belong to Batch {1},Serial No {0} bukan milik Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Nama perusahaan Anda yang Anda sedang mengatur sistem ini.,
The number of shares and the share numbers are inconsistent,Jumlah saham dan jumlah saham tidak konsisten,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Akun gateway pembayaran dalam rencana {0} berbeda dari akun gateway pembayaran dalam permintaan pembayaran ini,
-The request for quotation can be accessed by clicking on the following link,Permintaan untuk kutipan dapat diakses dengan mengklik link berikut,
The selected BOMs are not for the same item,BOMs yang dipilih tidak untuk item yang sama,
The selected item cannot have Batch,Item yang dipilih tidak dapat memiliki Batch,
The seller and the buyer cannot be the same,Penjual dan pembeli tidak bisa sama,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Total jumlah komponen manfaat fleksibel {0} tidak boleh kurang dari manfaat maksimal {1},
Total hours: {0},Jumlah jam: {0},
Total leaves allocated is mandatory for Leave Type {0},Total cuti yang dialokasikan adalah wajib untuk Tipe Cuti {0},
-Total weightage assigned should be 100%. It is {0},Jumlah weightage ditugaskan harus 100%. Ini adalah {0},
Total working hours should not be greater than max working hours {0},Jumlah jam kerja tidak boleh lebih besar dari max jam kerja {0},
Total {0} ({1}),Total {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Total {0} untuk semua item adalah nol, mungkin Anda harus mengubah 'Distribusikan Biaya Berdasarkan'",
@@ -3316,7 +3299,6 @@
What do you need help with?,Apa yang Anda perlu bantuan dengan?,
What does it do?,Apa pekerjaannya?,
Where manufacturing operations are carried.,Dimana operasi manufaktur dilakukan.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Saat membuat akun untuk Perusahaan anak {0}, akun induk {1} tidak ditemukan. Harap buat akun induk di COA yang sesuai",
White,putih,
Wire Transfer,Transfer Kliring,
WooCommerce Products,Produk WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} varian dibuat.,
{0} {1} created,{0} {1} dibuat,
{0} {1} does not exist,{0} {1} tidak ada,
-{0} {1} does not exist.,{0} {1} tidak ada,
{0} {1} has been modified. Please refresh.,{0} {1} telah diubah. Silahkan refresh.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} belum dikirim sehingga tindakan tidak dapat diselesaikan,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} dikaitkan dengan {2}, namun Akun Para Pihak adalah {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} tidak ada,
{0}: {1} not found in Invoice Details table,{0}: {1} tidak ditemukan dalam tabel Rincian Tagihan,
{} of {},{} dari {},
+Assigned To,Ditugaskan Kepada,
Chat,Obrolan,
Completed By,Diselesaikan oleh,
Conditions,Kondisi,
@@ -3506,7 +3488,9 @@
Merge with existing,Merger dengan yang ada,
Office,Kantor,
Orientation,Orientasi,
+Parent,Induk,
Passive,Pasif,
+Payment Failed,Pembayaran gagal,
Percent,Persen,
Permanent,Permanen,
Personal,Pribadi,
@@ -3544,7 +3528,6 @@
Company field is required,Bidang perusahaan wajib diisi,
Creating Dimensions...,Membuat Dimensi ...,
Duplicate entry against the item code {0} and manufacturer {1},Entri duplikat terhadap kode item {0} dan pabrikan {1},
-Import Chart Of Accounts from CSV / Excel files,Impor Bagan Akun dari file CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN tidak valid! Input yang Anda masukkan tidak cocok dengan format GSTIN untuk Pemegang UIN atau Penyedia Layanan OIDAR Non-Resident,
Invoice Grand Total,Faktur Jumlah Total,
Last carbon check date cannot be a future date,Tanggal pemeriksaan karbon terakhir tidak bisa menjadi tanggal di masa depan,
@@ -3556,6 +3539,7 @@
Show {0},Tampilkan {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Karakter Khusus kecuali "-", "#", ".", "/", "{" Dan "}" tidak diizinkan dalam rangkaian penamaan",
Target Details,Detail Target,
+{0} already has a Parent Procedure {1}.,{0} sudah memiliki Prosedur Induk {1}.,
API,API,
Annual,Tahunan,
Approved,Disetujui,
@@ -3572,6 +3556,8 @@
No data to export,Tidak ada data untuk diekspor,
Portrait,Potret,
Print Heading,Cetak Pos,
+Scheduler Inactive,Penjadwal Tidak Aktif,
+Scheduler is inactive. Cannot import data.,Penjadwal tidak aktif. Tidak dapat mengimpor data.,
Show Document,Perlihatkan Dokumen,
Show Traceback,Perlihatkan Traceback,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Buat Pemeriksaan Kualitas untuk Barang {0},
Creating Accounts...,Membuat Akun ...,
Creating bank entries...,Membuat entri bank ...,
-Creating {0},Membuat {0},
Credit limit is already defined for the Company {0},Batas kredit sudah ditentukan untuk Perusahaan {0},
Ctrl + Enter to submit,Ctrl + Enter untuk mengirim,
Ctrl+Enter to submit,Ctrl + Enter untuk mengirim,
@@ -3921,7 +3906,6 @@
Plaid public token error,Kesalahan token publik kotak-kotak,
Plaid transactions sync error,Kesalahan sinkronisasi transaksi kotak-kotak,
Please check the error log for details about the import errors,Silakan periksa log kesalahan untuk detail tentang kesalahan impor,
-Please click on the following link to set your new password,Silahkan klik pada link berikut untuk mengatur password baru anda,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Harap buat <b>Pengaturan DATEV</b> untuk Perusahaan <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Harap buat penyesuaian Entri Jurnal untuk jumlah {0},
Please do not create more than 500 items at a time,Tolong jangan membuat lebih dari 500 item sekaligus,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Tanggal rilis harus di masa mendatang,
Relieving Date must be greater than or equal to Date of Joining,Tanggal pelepasan harus lebih besar dari atau sama dengan Tanggal Bergabung,
Rename,Ubah nama,
+Rename Not Allowed,Ganti nama Tidak Diizinkan,
Repayment Method is mandatory for term loans,Metode Pembayaran wajib untuk pinjaman berjangka,
Repayment Start Date is mandatory for term loans,Tanggal Mulai Pembayaran wajib untuk pinjaman berjangka,
Report Item,Laporkan Item,
@@ -4043,7 +4028,6 @@
Select All,Pilih semua,
Select Difference Account,Pilih Perbedaan Akun,
Select a Default Priority.,Pilih Prioritas Default.,
-Select a Supplier from the Default Supplier List of the items below.,Pilih Pemasok dari Daftar Pemasok Default untuk item di bawah ini.,
Select a company,Pilih perusahaan,
Select finance book for the item {0} at row {1},Pilih buku keuangan untuk item {0} di baris {1},
Select only one Priority as Default.,Pilih hanya satu Prioritas sebagai Default.,
@@ -4247,7 +4231,6 @@
Actual ,Aktual,
Add to cart,Tambahkan ke Keranjang Belanja,
Budget,Anggaran belanja,
-Chart Of Accounts Importer,Grafik Pengimpor Akun,
Chart of Accounts,Bagan Akun,
Customer database.,Database Pelanggan.,
Days Since Last order,Hari Sejak Pemesanan Terakhir,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Tanggal Berakhir tidak boleh kurang dari Tanggal Mulai,
For Default Supplier (Optional),Untuk Pemasok Default (Opsional),
From date cannot be greater than To date,Dari Tanggal tidak dapat lebih besar dari To Date,
-Get items from,Mendapatkan Stok Barang-Stok Barang dari,
Group by,Kelompok Dengan,
In stock,Persediaan,
Item name,Nama Item,
@@ -4532,32 +4514,22 @@
Accounts Settings,Pengaturan Akun,
Settings for Accounts,Pengaturan Akun,
Make Accounting Entry For Every Stock Movement,Membuat Entri Akuntansi Untuk Setiap Perpindahan Persediaan,
-"If enabled, the system will post accounting entries for inventory automatically.","Jika diaktifkan, sistem akan posting entri akuntansi untuk persediaan otomatis.",
-Accounts Frozen Upto,Akun dibekukan sampai dengan,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Pencatatan Akuntansi telah dibekukan sampai tanggal ini, tidak seorang pun yang bisa melakukan / memodifikasi pencatatan kecuali peran yang telah ditentukan di bawah ini.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Peran Diizinkan Set Beku Account & Edit Frozen Entri,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Pengguna dengan peran ini diperbolehkan untuk mengatur account beku dan membuat / memodifikasi entri akuntansi terhadap rekening beku,
Determine Address Tax Category From,Tentukan Alamat Dari Kategori Pajak Dari,
-Address used to determine Tax Category in transactions.,Alamat yang digunakan untuk menentukan Kategori Pajak dalam transaksi.,
Over Billing Allowance (%),Kelonggaran Penagihan Berlebih (%),
-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 for $110.,"Persentase Anda dapat menagih lebih banyak dari jumlah yang dipesan. Misalnya: Jika nilai pesanan adalah $ 100 untuk item dan toleransi ditetapkan 10%, maka Anda diizinkan untuk menagih $ 110.",
Credit Controller,Kredit Kontroller,
-Role that is allowed to submit transactions that exceed credit limits set.,Peran yang diperbolehkan untuk mengirimkan transaksi yang melebihi batas kredit yang ditetapkan.,
Check Supplier Invoice Number Uniqueness,Periksa keunikan nomor Faktur Supplier,
Make Payment via Journal Entry,Lakukan Pembayaran via Journal Entri,
Unlink Payment on Cancellation of Invoice,Membatalkan tautan Pembayaran pada Pembatalan Faktur,
-Unlink Advance Payment on Cancelation of Order,Putuskan Tautan Pembayaran Muka pada Pembatalan pesanan,
Book Asset Depreciation Entry Automatically,Rekam Entri Depresiasi Asset secara Otomatis,
Automatically Add Taxes and Charges from Item Tax Template,Secara otomatis Menambahkan Pajak dan Tagihan dari Item Pajak Template,
Automatically Fetch Payment Terms,Ambil Ketentuan Pembayaran secara otomatis,
-Show Inclusive Tax In Print,Menunjukkan Pajak Inklusif Dalam Cetak,
Show Payment Schedule in Print,Tampilkan Jadwal Pembayaran di Cetak,
Currency Exchange Settings,Pengaturan Pertukaran Mata Uang,
Allow Stale Exchange Rates,Izinkan Menggunakan Nilai Tukar Kaldaluarsa,
Stale Days,Hari basi,
Report Settings,Setelan Laporan,
Use Custom Cash Flow Format,Gunakan Format Arus Kas Khusus,
-Only select if you have setup Cash Flow Mapper documents,Pilih saja apakah Anda sudah menyiapkan dokumen Flow Flow Mapper,
Allowed To Transact With,Diizinkan Untuk Bertransaksi Dengan,
SWIFT number,Nomor SWIFT,
Branch Code,Kode cabang,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Pelanggan Grup,
POS Field,Bidang POS,
POS Item Group,POS Barang Grup,
-[Select],[Pilih],
Company Address,Alamat perusahaan,
Update Stock,Perbarui Persediaan,
Ignore Pricing Rule,Abaikan Aturan Harga,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Penamaan Supplier Berdasarkan,
Default Supplier Group,Grup Pemasok Default,
Default Buying Price List,Standar Membeli Daftar Harga,
-Maintain same rate throughout purchase cycle,Pertahankan tarif yang sama sepanjang siklus pembelian,
-Allow Item to be added multiple times in a transaction,Izinkan Stok Barang yang sama untuk ditambahkan beberapa kali dalam suatu transaksi,
Backflush Raw Materials of Subcontract Based On,Bahan Baku Backflush dari Subkontrak Berdasarkan,
Material Transferred for Subcontract,Material Ditransfer untuk Subkontrak,
Over Transfer Allowance (%),Kelebihan Transfer (%),
@@ -5540,7 +5509,6 @@
Current Stock,Persediaan saat ini,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Untuk pemasok individual,
-Supplier Detail,pemasok Detil,
Link to Material Requests,Tautan ke Permintaan Material,
Message for Supplier,Pesan Supplier,
Request for Quotation Item,Permintaan Quotation Barang,
@@ -6481,7 +6449,6 @@
Appraisal Template,Template Penilaian,
For Employee Name,Untuk Nama Karyawan,
Goals,tujuan,
-Calculate Total Score,Hitung Total Skor,
Total Score (Out of 5),Skor Total (Out of 5),
"Any other remarks, noteworthy effort that should go in the records.","Setiap komentar lain, upaya penting yang harus pergi dalam catatan.",
Appraisal Goal,Penilaian Pencapaian,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Alasan Meninggalkan,
Leave Encashed?,Cuti dicairkan?,
Encashment Date,Pencairan Tanggal,
-Exit Interview Details,Detail Exit Interview,
-Held On,Diadakan Pada,
-Reason for Resignation,Alasan pengunduran diri,
-Better Prospects,Prospek yang Lebih Baik,
-Health Concerns,Kekhawatiran Kesehatan,
New Workplace,Tempat Kerja Baru,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Jumlah yang dikembalikan,
@@ -6740,10 +6702,7 @@
Employee Settings,Pengaturan Karyawan,
Retirement Age,Umur pensiun,
Enter retirement age in years,Memasuki usia pensiun di tahun,
-Employee Records to be created by,Rekaman Karyawan yang akan dibuat oleh,
-Employee record is created using selected field. ,,
Stop Birthday Reminders,Stop Pengingat Ulang Tahun,
-Don't send Employee Birthday Reminders,Jangan Kirim Pengingat Ulang Tahun,
Expense Approver Mandatory In Expense Claim,Expense Approver Mandatory In Expense Claim,
Payroll Settings,Pengaturan Payroll,
Leave,Meninggalkan,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Tinggalkan Persetujuan Wajib Di Tinggalkan Aplikasi,
Show Leaves Of All Department Members In Calendar,Tampilkan Cuti Dari Semua Anggota Departemen Dalam Kalender,
Auto Leave Encashment,Encashment Cuti Otomatis,
-Restrict Backdated Leave Application,Batasi Aplikasi Cuti Backdated,
Hiring Settings,Pengaturan Perekrutan,
Check Vacancies On Job Offer Creation,Lihat Lowongan Penciptaan Tawaran Kerja,
Identification Document Type,Identifikasi Jenis Dokumen,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Pengaturan manufaktur,
Raw Materials Consumption,Konsumsi Bahan Baku,
Allow Multiple Material Consumption,Izinkan Penggunaan Beberapa Material Sekaligus,
-Allow multiple Material Consumption against a Work Order,Perbolehkan beberapa Konsumsi Material terhadap Perintah Kerja,
Backflush Raw Materials Based On,Backflush Bahan Baku Berbasis Pada,
Material Transferred for Manufacture,Bahan Ditransfer untuk Produksi,
Capacity Planning,Perencanaan Kapasitas,
Disable Capacity Planning,Nonaktifkan Perencanaan Kapasitas,
Allow Overtime,Izinkan Lembur,
-Plan time logs outside Workstation Working Hours.,Rencana waktu log luar Jam Kerja Workstation.,
Allow Production on Holidays,Izinkan Produksi di hari libur,
Capacity Planning For (Days),Perencanaan Kapasitas Untuk (Hari),
-Try planning operations for X days in advance.,Coba operasi untuk hari X perencanaan di muka.,
-Time Between Operations (in mins),Waktu diantara Operasi (di menit),
-Default 10 mins,Standar 10 menit,
Default Warehouses for Production,Gudang Default untuk Produksi,
Default Work In Progress Warehouse,Standar Gudang Work In Progress,
Default Finished Goods Warehouse,Gudang bawaan Selesai Stok Barang,
Default Scrap Warehouse,Gudang Memo Default,
-Over Production for Sales and Work Order,Kelebihan Produksi untuk Penjualan dan Perintah Kerja,
Overproduction Percentage For Sales Order,Overproduction Persentase Untuk Order Penjualan,
Overproduction Percentage For Work Order,Overproduction Persentase Untuk Pesanan Pekerjaan,
Other Settings,Pengaturan lainnya,
Update BOM Cost Automatically,Perbarui Biaya BOM secara otomatis,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Perbarui biaya BOM secara otomatis melalui Penjadwalan, berdasarkan hitungan penilaian / daftar harga / hitungan pembelian bahan baku terakhir.",
Material Request Plan Item,Item Rencana Permintaan Material,
Material Request Type,Permintaan Jenis Bahan,
Material Issue,Keluar Barang,
@@ -7603,10 +7554,6 @@
Quality Goal,Tujuan Kualitas,
Monitoring Frequency,Frekuensi Pemantauan,
Weekday,Hari kerja,
-January-April-July-October,Januari-April-Juli-Oktober,
-Revision and Revised On,Revisi dan Revisi Aktif,
-Revision,Revisi,
-Revised On,Direvisi Aktif,
Objectives,Tujuan,
Quality Goal Objective,Tujuan Sasaran Kualitas,
Objective,Objektif,
@@ -7619,7 +7566,6 @@
Processes,Proses,
Quality Procedure Process,Proses Prosedur Mutu,
Process Description,Deskripsi proses,
-Child Procedure,Prosedur Anak,
Link existing Quality Procedure.,Tautkan Prosedur Mutu yang ada.,
Additional Information,informasi tambahan,
Quality Review Objective,Tujuan Tinjauan Kualitas,
@@ -7787,15 +7733,9 @@
Default Customer Group,Kelompok Pelanggan Standar,
Default Territory,Wilayah Standar,
Close Opportunity After Days,Tutup Peluang Setelah Days,
-Auto close Opportunity after 15 days,Auto Peluang dekat setelah 15 hari,
Default Quotation Validity Days,Hari Validasi Kutipan Default,
Sales Update Frequency,Frekuensi Pembaruan Penjualan,
-How often should project and company be updated based on Sales Transactions.,Seberapa sering proyek dan perusahaan harus diperbarui berdasarkan Transaksi Penjualan.,
Each Transaction,Setiap Transaksi,
-Allow user to edit Price List Rate in transactions,Izinkan user/pengguna untuk mengubah rate daftar harga di dalam transaksi,
-Allow multiple Sales Orders against a Customer's Purchase Order,Memungkinkan beberapa Order Penjualan terhadap Order Pembelian dari Pelanggan,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Memvalidasi Harga Jual untuk Item terhadap Purchase Rate atau Tingkat Penilaian,
-Hide Customer's Tax Id from Sales Transactions,Menyembunyikan Id Pajak Nasabah Transaksi Penjualan,
SMS Center,SMS Center,
Send To,Kirim Ke,
All Contact,Semua Kontak,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Produsen yang digunakan dalam Produk,
Limited to 12 characters,Terbatas untuk 12 karakter,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Atur Gudang,
-Sets 'For Warehouse' in each row of the Items table.,Set 'Untuk Gudang' di setiap baris tabel Item.,
-Requested For,Diminta Untuk,
Partially Ordered,Dipesan Sebagian,
Transferred,Ditransfer,
% Ordered,% Tersusun,
@@ -8407,24 +8344,14 @@
Default Stock UOM,UOM Persediaan Standar,
Sample Retention Warehouse,Contoh Retensi Gudang,
Default Valuation Method,Metode Perhitungan Standar,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Persentase Anda diijinkan untuk menerima atau memberikan lebih terhadap kuantitas memerintahkan. Misalnya: Jika Anda telah memesan 100 unit. dan Tunjangan Anda adalah 10% maka Anda diperbolehkan untuk menerima 110 unit.,
-Action if Quality inspection is not submitted,Tindakan jika Pemeriksaan mutu tidak diajukan,
Show Barcode Field,Tampilkan Barcode Lapangan,
Convert Item Description to Clean HTML,Mengkonversi Deskripsi Item untuk Bersihkan HTML,
-Auto insert Price List rate if missing,Insert auto tingkat Daftar Harga jika hilang,
Allow Negative Stock,Izinkan persediaan negatif,
Automatically Set Serial Nos based on FIFO,Nomor Seri Otomatis berdasarkan FIFO,
-Set Qty in Transactions based on Serial No Input,Tentukan Qty dalam Transaksi berdasarkan Serial No Input,
Auto Material Request,Permintaan Material Otomatis,
-Raise Material Request when stock reaches re-order level,Munculkan Permintaan Material ketika persediaan mencapai tingkat pesan ulang,
-Notify by Email on creation of automatic Material Request,Beritahu melalui Surel pada pembuatan Permintaan Material otomatis,
Inter Warehouse Transfer Settings,Pengaturan Transfer Antar Gudang,
-Allow Material Transfer From Delivery Note and Sales Invoice,Izinkan Transfer Material Dari Nota Pengiriman dan Faktur Penjualan,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Izinkan Transfer Material Dari Tanda Terima Pembelian dan Faktur Pembelian,
Freeze Stock Entries,Bekukan Entri Persediaan,
Stock Frozen Upto,Stock Frozen Upto,
-Freeze Stocks Older Than [Days],Bekukan Persediaan Lebih Lama Dari [Hari],
-Role Allowed to edit frozen stock,Peran diizinkan mengedit persediaan dibekukan,
Batch Identification,Identifikasi Batch,
Use Naming Series,Gunakan Seri Penamaan,
Naming Series Prefix,Awalan Seri Penamaan,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Tren Nota Penerimaan,
Purchase Register,Register Pembelian,
Quotation Trends,Trend Penawaran,
-Quoted Item Comparison,Perbandingan Produk/Barang yang ditawarkan,
Received Items To Be Billed,Produk Diterima Akan Ditagih,
Qty to Order,Kuantitas untuk diorder,
Requested Items To Be Transferred,Permintaan Produk Akan Ditransfer,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Pilih gudang untuk permintaan material,
Transfer Materials For Warehouse {0},Mentransfer Bahan Untuk Gudang {0},
Production Plan Material Request Warehouse,Gudang Permintaan Material Rencana Produksi,
-Set From Warehouse,Atur Dari Gudang,
-Source Warehouse (Material Transfer),Gudang Sumber (Transfer Material),
Sets 'Source Warehouse' in each row of the items table.,Set 'Source Warehouse' di setiap baris tabel item.,
Sets 'Target Warehouse' in each row of the items table.,Menetapkan 'Gudang Target' di setiap baris tabel item.,
Show Cancelled Entries,Tunjukkan Entri yang Dibatalkan,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Layanan Diterima Tapi Tidak Ditagih,
Deferred Accounting Settings,Pengaturan Akuntansi yang Ditangguhkan,
Book Deferred Entries Based On,Buku Entri Ditunda Berdasarkan,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Jika "Bulan" dipilih, jumlah tetap akan dibukukan sebagai pendapatan atau beban yang ditangguhkan untuk setiap bulan terlepas dari jumlah hari dalam sebulan. Akan diprorata jika pendapatan atau beban yang ditangguhkan tidak dipesan untuk satu bulan penuh.",
Days,Hari,
Months,Bulan,
Book Deferred Entries Via Journal Entry,Buku Entri Ditunda Melalui Entri Jurnal,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Jika ini tidak dicentang, Entri GL langsung akan dibuat untuk memesan Pendapatan / Beban yang Ditangguhkan",
Submit Journal Entries,Kirimkan Entri Jurnal,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Jika ini tidak dicentang, Entri Jurnal akan disimpan dalam status Draf dan harus diserahkan secara manual",
Enable Distributed Cost Center,Aktifkan Pusat Biaya Terdistribusi,
@@ -8901,8 +8823,6 @@
Is Inter State,Apakah Inter State,
Purchase Details,Rincian Pembelian,
Depreciation Posting Date,Tanggal Posting Depresiasi,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Pesanan Pembelian Diperlukan untuk Pembuatan Faktur Pembelian & Tanda Terima,
-Purchase Receipt Required for Purchase Invoice Creation,Tanda Terima Pembelian Diperlukan untuk Pembuatan Faktur Pembelian,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Secara default, Nama Pemasok diatur sesuai Nama Pemasok yang dimasukkan. Jika Anda ingin Pemasok diberi nama oleh a",
choose the 'Naming Series' option.,pilih opsi 'Seri Penamaan'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Konfigurasikan Daftar Harga default saat membuat transaksi Pembelian baru. Harga item akan diambil dari Daftar Harga ini.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Adalah Komponen Pajak Penghasilan,
Component properties and references ,Properti dan referensi komponen,
Additional Salary ,Gaji Tambahan,
-Condtion and formula,Condtion dan formula,
Unmarked days,Hari tak bertanda,
Absent Days,Hari Absen,
Conditions and Formula variable and example,Kondisi dan variabel Rumus dan contoh,
Feedback By,Umpan Balik Oleh,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Bagian Manufaktur,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Pesanan Penjualan Diperlukan untuk Pembuatan Faktur Penjualan & Nota Pengiriman,
-Delivery Note Required for Sales Invoice Creation,Nota Pengiriman Diperlukan untuk Pembuatan Faktur Penjualan,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Secara default, Nama Pelanggan diatur sesuai Nama Lengkap yang dimasukkan. Jika Anda ingin Pelanggan diberi nama oleh a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Konfigurasikan Daftar Harga default saat membuat transaksi Penjualan baru. Harga item akan diambil dari Daftar Harga ini.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Jika opsi ini dikonfigurasi 'Ya', ERPNext akan mencegah Anda membuat Faktur Penjualan atau Nota Pengiriman tanpa membuat Pesanan Penjualan terlebih dahulu. Konfigurasi ini dapat diganti untuk Pelanggan tertentu dengan mengaktifkan kotak centang 'Izinkan Pembuatan Faktur Penjualan Tanpa Pesanan Penjualan' di master Pelanggan.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} berhasil ditambahkan ke semua topik yang dipilih.,
Topics updated,Topik diperbarui,
Academic Term and Program,Istilah dan Program Akademik,
-Last Stock Transaction for item {0} was on {1}.,Transaksi Stok Terakhir untuk item {0} adalah pada {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Transaksi Stok untuk Item {0} tidak dapat diposting sebelum waktu ini.,
Please remove this item and try to submit again or update the posting time.,Harap hapus item ini dan coba kirim lagi atau perbarui waktu posting.,
Failed to Authenticate the API key.,Gagal Mengautentikasi kunci API.,
Invalid Credentials,Kredensial tidak valid,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Harap periksa ID klien Kotak-kotak dan nilai rahasia Anda,
Bank transaction creation error,Kesalahan pembuatan transaksi bank,
Unit of Measurement,Satuan Pengukuran,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Baris # {}: Tarif jual item {} lebih rendah daripada {}. Tingkat penjualan harus minimal {},
Fiscal Year {0} Does Not Exist,Tahun Fiskal {0} Tidak Ada,
Row # {0}: Returned Item {1} does not exist in {2} {3},Baris # {0}: Item yang Dikembalikan {1} tidak ada di {2} {3},
Valuation type charges can not be marked as Inclusive,Biaya jenis penilaian tidak dapat ditandai sebagai Inklusif,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Waktu Respons untuk {0} prioritas di baris {1} tidak boleh lebih dari Waktu Resolusi.,
{0} is not enabled in {1},{0} tidak diaktifkan di {1},
Group by Material Request,Kelompokkan berdasarkan Permintaan Material,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Baris {0}: Untuk Pemasok {0}, Alamat Email Diperlukan untuk Mengirim Email",
Email Sent to Supplier {0},Email Dikirim ke Pemasok {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Akses ke Permintaan Penawaran Dari Portal Dinonaktifkan. Untuk Mengizinkan Akses, Aktifkan di Pengaturan Portal.",
Supplier Quotation {0} Created,Penawaran Pemasok {0} Dibuat,
Valid till Date cannot be before Transaction Date,Berlaku hingga Tanggal tidak boleh sebelum Tanggal Transaksi,
+Unlink Advance Payment on Cancellation of Order,Batalkan Tautan Pembayaran Di Muka pada Pembatalan Pesanan,
+"Simple Python Expression, Example: territory != 'All Territories'","Ekspresi Python Sederhana, Contoh: teritori! = 'Semua Wilayah'",
+Sales Contributions and Incentives,Kontribusi Penjualan dan Insentif,
+Sourced by Supplier,Bersumber dari Pemasok,
+Total weightage assigned should be 100%.<br>It is {0},Bobot total yang ditetapkan harus 100%.<br> Ini adalah {0},
+Account {0} exists in parent company {1}.,Akun {0} ada di perusahaan induk {1}.,
+"To overrule this, enable '{0}' in company {1}","Untuk mengesampingkan ini, aktifkan '{0}' di perusahaan {1}",
+Invalid condition expression,Ekspresi kondisi tidak valid,
+Please Select a Company First,Harap Pilih Perusahaan Terlebih Dahulu,
+Please Select Both Company and Party Type First,Harap Pilih Kedua Perusahaan dan Jenis Pesta Pertama,
+Provide the invoice portion in percent,Berikan porsi faktur dalam persen,
+Give number of days according to prior selection,Beri jumlah hari menurut seleksi sebelumnya,
+Email Details,Rincian Email,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Pilih salam untuk penerima. Misal Mr., Ms., dll.",
+Preview Email,Pratinjau Email,
+Please select a Supplier,Silakan pilih a Pemasok,
+Supplier Lead Time (days),Supplier Lead Time (hari),
+"Home, Work, etc.","Rumah, Kantor, dll.",
+Exit Interview Held On,Exit Interview Diadakan,
+Condition and formula,Kondisi dan formula,
+Sets 'Target Warehouse' in each row of the Items table.,Set 'Gudang Target' di setiap baris tabel Item.,
+Sets 'Source Warehouse' in each row of the Items table.,Set 'Source Warehouse' di setiap baris tabel Item.,
+POS Register,Daftar POS,
+"Can not filter based on POS Profile, if grouped by POS Profile","Tidak dapat memfilter berdasarkan Profil POS, jika dikelompokkan berdasarkan Profil POS",
+"Can not filter based on Customer, if grouped by Customer","Tidak dapat memfilter berdasarkan Pelanggan, jika dikelompokkan berdasarkan Pelanggan",
+"Can not filter based on Cashier, if grouped by Cashier","Tidak dapat memfilter berdasarkan Kasir, jika dikelompokkan berdasarkan Kasir",
+Payment Method,Cara Pembayaran,
+"Can not filter based on Payment Method, if grouped by Payment Method","Tidak dapat memfilter berdasarkan Metode Pembayaran, jika dikelompokkan berdasarkan Metode Pembayaran",
+Supplier Quotation Comparison,Perbandingan Penawaran Pemasok,
+Price per Unit (Stock UOM),Harga per Unit (Stock UOM),
+Group by Supplier,Kelompokkan berdasarkan Pemasok,
+Group by Item,Kelompokkan berdasarkan Item,
+Remember to set {field_label}. It is required by {regulation}.,Ingatlah untuk menyetel {field_label}. Ini diwajibkan oleh {regulasi}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Tanggal Pendaftaran tidak boleh sebelum Tanggal Mulai Tahun Akademik {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Tanggal Pendaftaran tidak boleh setelah Tanggal Akhir Masa Akademik {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Tanggal Pendaftaran tidak boleh sebelum Tanggal Mulai dari Syarat Akademik {0},
+Future Posting Not Allowed,Posting Mendatang Tidak Diizinkan,
+"To enable Capital Work in Progress Accounting, ","Untuk mengaktifkan Capital Work dalam Progress Accounting,",
+you must select Capital Work in Progress Account in accounts table,Anda harus memilih Capital Work in Progress Account di tabel akun,
+You can also set default CWIP account in Company {},Anda juga dapat menyetel akun CWIP default di Perusahaan {},
+The Request for Quotation can be accessed by clicking on the following button,Permintaan Penawaran dapat diakses dengan mengklik tombol berikut,
+Regards,Salam,
+Please click on the following button to set your new password,Silakan klik tombol berikut untuk menyetel kata sandi baru Anda,
+Update Password,Perbarui Kata Sandi,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Baris # {}: Tarif jual item {} lebih rendah daripada {}. Menjual {} harus minimal {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Anda juga bisa menonaktifkan validasi harga jual di {} untuk melewati validasi ini.,
+Invalid Selling Price,Harga Jual Tidak Valid,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Alamat harus ditautkan ke Perusahaan. Harap tambahkan baris untuk Perusahaan di tabel Tautan.,
+Company Not Linked,Perusahaan Tidak Tertaut,
+Import Chart of Accounts from CSV / Excel files,Impor Bagan Akun dari file CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',Kuantitas Lengkap tidak boleh lebih besar dari 'Kuantitas hingga Pembuatan',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Baris {0}: Untuk Pemasok {1}, Alamat Email Diperlukan untuk mengirim email",
+"If enabled, the system will post accounting entries for inventory automatically","Jika diaktifkan, sistem akan memposting entri akuntansi untuk inventaris secara otomatis",
+Accounts Frozen Till Date,Akun Dibekukan Hingga Tanggal,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Entri akuntansi dibekukan sampai tanggal ini. Tidak ada yang dapat membuat atau mengubah entri kecuali pengguna dengan peran yang ditentukan di bawah ini,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Peran Diizinkan untuk Mengatur Akun Beku dan Mengedit Entri Beku,
+Address used to determine Tax Category in transactions,Alamat yang digunakan untuk menentukan Kategori Pajak dalam transaksi,
+"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 ","Persentase Anda diizinkan untuk menagih lebih banyak dari jumlah yang dipesan. Misalnya, jika nilai pesanan adalah $ 100 untuk satu item dan toleransi ditetapkan sebagai 10%, maka Anda diizinkan untuk menagih hingga $ 110",
+This role is allowed to submit transactions that exceed credit limits,Peran ini diperbolehkan untuk mengirimkan transaksi yang melebihi batas kredit,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Jika "Bulan" dipilih, jumlah tetap akan dibukukan sebagai pendapatan atau beban yang ditangguhkan untuk setiap bulan terlepas dari jumlah hari dalam sebulan. Ini akan diprorata jika pendapatan atau beban yang ditangguhkan tidak dibukukan selama satu bulan penuh",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Jika ini tidak dicentang, entri GL langsung akan dibuat untuk membukukan pendapatan atau beban yang ditangguhkan",
+Show Inclusive Tax in Print,Tunjukkan Pajak Termasuk dalam Cetakan,
+Only select this if you have set up the Cash Flow Mapper documents,Pilih ini hanya jika Anda telah menyiapkan dokumen Pemeta Arus Kas,
+Payment Channel,Saluran Pembayaran,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Apakah Pesanan Pembelian Diperlukan untuk Pembuatan Faktur Pembelian & Tanda Terima?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Apakah Bukti Pembelian Diperlukan untuk Pembuatan Faktur Pembelian?,
+Maintain Same Rate Throughout the Purchase Cycle,Pertahankan Tarif yang Sama Sepanjang Siklus Pembelian,
+Allow Item To Be Added Multiple Times in a Transaction,Izinkan Item Ditambahkan Beberapa Kali dalam Transaksi,
+Suppliers,Pemasok,
+Send Emails to Suppliers,Kirim Email ke Pemasok,
+Select a Supplier,Pilih Pemasok,
+Cannot mark attendance for future dates.,Tidak dapat menandai kehadiran untuk tanggal yang akan datang.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Apakah Anda ingin memperbarui kehadiran?<br> Sekarang: {0}<br> Absen: {1},
+Mpesa Settings,Pengaturan Mpesa,
+Initiator Name,Nama Pemrakarsa,
+Till Number,Sampai Nomor,
+Sandbox,Bak pasir,
+ Online PassKey,PassKey Online,
+Security Credential,Kredensial Keamanan,
+Get Account Balance,Dapatkan Saldo Akun,
+Please set the initiator name and the security credential,Harap setel nama pemrakarsa dan kredensial keamanan,
+Inpatient Medication Entry,Masuk Obat Rawat Inap,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Kode Barang (Obat),
+Medication Orders,Perintah Pengobatan,
+Get Pending Medication Orders,Dapatkan Pesanan Obat Tertunda,
+Inpatient Medication Orders,Perintah Pengobatan Rawat Inap,
+Medication Warehouse,Gudang Obat,
+Warehouse from where medication stock should be consumed,Gudang tempat persediaan obat harus dikonsumsi,
+Fetching Pending Medication Orders,Mengambil Perintah Obat yang Tertunda,
+Inpatient Medication Entry Detail,Detail Entri Obat Rawat Inap,
+Medication Details,Rincian Obat,
+Drug Code,Kode Obat,
+Drug Name,Nama Obat,
+Against Inpatient Medication Order,Terhadap Perintah Pengobatan Rawat Inap,
+Against Inpatient Medication Order Entry,Terhadap Masuknya Pesanan Obat Rawat Inap,
+Inpatient Medication Order,Perintah Pengobatan Rawat Inap,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Total Pesanan,
+Completed Orders,Pesanan Selesai,
+Add Medication Orders,Tambahkan Perintah Pengobatan,
+Adding Order Entries,Menambahkan Entri Pesanan,
+{0} medication orders completed,{0} pesanan pengobatan selesai,
+{0} medication order completed,{0} pesanan pengobatan selesai,
+Inpatient Medication Order Entry,Entri Pesanan Obat Rawat Inap,
+Is Order Completed,Apakah Pesanan Selesai,
+Employee Records to Be Created By,Catatan Karyawan yang Akan Dibuat,
+Employee records are created using the selected field,Catatan karyawan dibuat menggunakan bidang yang dipilih,
+Don't send employee birthday reminders,Jangan mengirim pengingat ulang tahun karyawan,
+Restrict Backdated Leave Applications,Batasi Aplikasi Cuti Berawal,
+Sequence ID,ID Urutan,
+Sequence Id,Id Urutan,
+Allow multiple material consumptions against a Work Order,Izinkan beberapa konsumsi material terhadap Perintah Kerja,
+Plan time logs outside Workstation working hours,Rencanakan log waktu di luar jam kerja Workstation,
+Plan operations X days in advance,Rencanakan operasi X hari sebelumnya,
+Time Between Operations (Mins),Waktu Antar Operasi (Menit),
+Default: 10 mins,Default: 10 menit,
+Overproduction for Sales and Work Order,Produksi Berlebih untuk Penjualan dan Perintah Kerja,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Perbarui biaya BOM secara otomatis melalui penjadwal, berdasarkan Tingkat Penilaian / Harga Daftar Harga / Tingkat Pembelian Terakhir bahan baku terbaru",
+Purchase Order already created for all Sales Order items,Pesanan Pembelian telah dibuat untuk semua item Pesanan Penjualan,
+Select Items,Pilih Item,
+Against Default Supplier,Melawan Pemasok Default,
+Auto close Opportunity after the no. of days mentioned above,Peluang tutup otomatis setelah no. hari yang disebutkan di atas,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Apakah Sales Order Diperlukan untuk Pembuatan Faktur Penjualan & Nota Pengiriman?,
+Is Delivery Note Required for Sales Invoice Creation?,Apakah Nota Pengiriman Diperlukan untuk Pembuatan Faktur Penjualan?,
+How often should Project and Company be updated based on Sales Transactions?,Seberapa sering Proyek dan Perusahaan harus diperbarui berdasarkan Transaksi Penjualan?,
+Allow User to Edit Price List Rate in Transactions,Izinkan Pengguna untuk Mengedit Tarif Daftar Harga dalam Transaksi,
+Allow Item to Be Added Multiple Times in a Transaction,Izinkan Item Ditambahkan Beberapa Kali dalam Transaksi,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Izinkan Beberapa Pesanan Penjualan Terhadap Pesanan Pembelian Pelanggan,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Validasi Harga Jual untuk Item Terhadap Tingkat Pembelian atau Tingkat Penilaian,
+Hide Customer's Tax ID from Sales Transactions,Sembunyikan ID Pajak Pelanggan dari Transaksi Penjualan,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Persentase Anda diperbolehkan untuk menerima atau mengirim lebih dari jumlah yang dipesan. Misalnya, jika Anda sudah memesan 100 unit, dan Tunjangan Anda 10%, maka Anda boleh menerima 110 unit.",
+Action If Quality Inspection Is Not Submitted,Tindakan Jika Pemeriksaan Kualitas Tidak Diserahkan,
+Auto Insert Price List Rate If Missing,Sisipkan Otomatis Harga Daftar Harga Jika Hilang,
+Automatically Set Serial Nos Based on FIFO,Atur Nomor Seri Secara Otomatis Berdasarkan FIFO,
+Set Qty in Transactions Based on Serial No Input,Atur Qty dalam Transaksi Berdasarkan Serial No Input,
+Raise Material Request When Stock Reaches Re-order Level,Angkat Permintaan Material Saat Stok Mencapai Tingkat Pemesanan Ulang,
+Notify by Email on Creation of Automatic Material Request,Beritahu melalui Email tentang Pembuatan Permintaan Material Otomatis,
+Allow Material Transfer from Delivery Note to Sales Invoice,Izinkan Transfer Material dari Nota Pengiriman ke Faktur Penjualan,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Izinkan Transfer Material dari Tanda Terima Pembelian ke Faktur Pembelian,
+Freeze Stocks Older Than (Days),Bekukan Saham Lebih Lama Dari (Hari),
+Role Allowed to Edit Frozen Stock,Peran Diizinkan untuk Mengedit Stok Beku,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Jumlah Entri Pembayaran yang tidak dialokasikan {0} lebih besar daripada jumlah Transaksi Bank yang tidak dialokasikan,
+Payment Received,Pembayaran diterima,
+Attendance cannot be marked outside of Academic Year {0},Kehadiran tidak dapat ditandai di luar Tahun Akademik {0},
+Student is already enrolled via Course Enrollment {0},Siswa sudah terdaftar melalui Pendaftaran Kursus {0},
+Attendance cannot be marked for future dates.,Kehadiran tidak dapat ditandai untuk tanggal yang akan datang.,
+Please add programs to enable admission application.,Harap tambahkan program untuk mengaktifkan aplikasi penerimaan.,
+The following employees are currently still reporting to {0}:,Karyawan berikut saat ini masih melapor ke {0}:,
+Please make sure the employees above report to another Active employee.,Harap pastikan karyawan di atas melapor kepada karyawan Aktif lainnya.,
+Cannot Relieve Employee,Tidak Bisa Meringankan Karyawan,
+Please enter {0},Harap masukkan {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Pilih metode pembayaran lain. Mpesa tidak mendukung transaksi dalam mata uang '{0}',
+Transaction Error,Kesalahan Transaksi,
+Mpesa Express Transaction Error,Kesalahan Transaksi Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Masalah terdeteksi dengan konfigurasi Mpesa, periksa log kesalahan untuk lebih jelasnya",
+Mpesa Express Error,Kesalahan Mpesa Express,
+Account Balance Processing Error,Kesalahan Pemrosesan Saldo Akun,
+Please check your configuration and try again,Harap periksa konfigurasi Anda dan coba lagi,
+Mpesa Account Balance Processing Error,Kesalahan Pemrosesan Saldo Akun Mpesa,
+Balance Details,Rincian Saldo,
+Current Balance,Saldo saat ini,
+Available Balance,Saldo Tersedia,
+Reserved Balance,Saldo Cadangan,
+Uncleared Balance,Saldo Tidak Jelas,
+Payment related to {0} is not completed,Pembayaran yang terkait dengan {0} tidak selesai,
+Row #{}: Item Code: {} is not available under warehouse {}.,Baris # {}: Kode Item: {} tidak tersedia di gudang {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Baris # {}: Jumlah stok tidak cukup untuk Kode Barang: {} di bawah gudang {}. Kuantitas yang tersedia {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Baris # {}: Pilih nomor seri dan kelompokkan terhadap item: {} atau hapus untuk menyelesaikan transaksi.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Baris # {}: Tidak ada nomor seri yang dipilih terhadap item: {}. Pilih satu atau hapus untuk menyelesaikan transaksi.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Baris # {}: Tidak ada kelompok yang dipilih terhadap item: {}. Pilih kelompok atau hapus untuk menyelesaikan transaksi.,
+Payment amount cannot be less than or equal to 0,Jumlah pembayaran tidak boleh kurang dari atau sama dengan 0,
+Please enter the phone number first,Harap masukkan nomor telepon terlebih dahulu,
+Row #{}: {} {} does not exist.,Baris # {}: {} {} tidak ada.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Baris # {0}: {1} diperlukan untuk membuat Faktur {2} Pembukaan,
+You had {} errors while creating opening invoices. Check {} for more details,Anda mengalami {} kesalahan saat membuat pembukaan faktur. Periksa {} untuk detail selengkapnya,
+Error Occured,Terjadi kesalahan,
+Opening Invoice Creation In Progress,Pembukaan Pembuatan Faktur Sedang Berlangsung,
+Creating {} out of {} {},Membuat {} dari {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Nomor Seri: {0}) tidak dapat digunakan karena disimpan ulang untuk memenuhi Pesanan Penjualan {1}.,
+Item {0} {1},Item {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Transaksi Stok Terakhir untuk item {0} dalam gudang {1} adalah pada {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Transaksi Stok untuk Item {0} di bawah gudang {1} tidak dapat dikirim sebelum waktu ini.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Memposting transaksi saham di masa depan tidak diperbolehkan karena Immutable Ledger,
+A BOM with name {0} already exists for item {1}.,BOM dengan nama {0} sudah ada untuk item {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Apakah Anda mengganti nama item? Silakan hubungi Administrator / dukungan Teknis,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Di baris # {0}: id urutan {1} tidak boleh kurang dari id urutan baris sebelumnya {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) harus sama dengan {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, selesaikan operasi {1} sebelum operasi {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Tidak dapat memastikan pengiriman dengan Serial No karena Item {0} ditambahkan dengan dan tanpa Pastikan Pengiriman dengan Serial No.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Butir {0} tidak memiliki No. Seri. Hanya item serilialisasi yang dapat dikirimkan berdasarkan No. Seri,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Tidak ada BOM aktif yang ditemukan untuk item {0}. Pengiriman dengan Serial No tidak dapat dipastikan,
+No pending medication orders found for selected criteria,Tidak ada pesanan obat yang tertunda ditemukan untuk kriteria yang dipilih,
+From Date cannot be after the current date.,Dari Tanggal tidak boleh setelah tanggal sekarang.,
+To Date cannot be after the current date.,To Date tidak boleh setelah tanggal sekarang.,
+From Time cannot be after the current time.,Dari Waktu tidak boleh setelah waktu saat ini.,
+To Time cannot be after the current time.,Ke Waktu tidak bisa setelah waktu saat ini.,
+Stock Entry {0} created and ,Entri Saham {0} dibuat dan,
+Inpatient Medication Orders updated successfully,Perintah Pengobatan Rawat Inap berhasil diperbarui,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Baris {0}: Tidak dapat membuat Entri Obat Rawat Inap terhadap Pesanan Obat Rawat Inap yang dibatalkan {1},
+Row {0}: This Medication Order is already marked as completed,Baris {0}: Perintah Obat ini telah ditandai sebagai selesai,
+Quantity not available for {0} in warehouse {1},Kuantitas tidak tersedia untuk {0} di gudang {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Silakan aktifkan Izinkan Stok Negatif dalam Pengaturan Stok atau buat Entri Stok untuk melanjutkan.,
+No Inpatient Record found against patient {0},Tidak ada Catatan Rawat Inap yang ditemukan terhadap pasien {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Perintah Pengobatan Rawat Inap {0} terhadap Pertemuan Pasien {1} sudah ada.,
+Allow In Returns,Izinkan Pengembalian,
+Hide Unavailable Items,Sembunyikan Item yang Tidak Tersedia,
+Apply Discount on Discounted Rate,Terapkan Diskon untuk Tarif Diskon,
+Therapy Plan Template,Template Rencana Terapi,
+Fetching Template Details,Mengambil Detail Template,
+Linked Item Details,Detail Item Tertaut,
+Therapy Types,Jenis Terapi,
+Therapy Plan Template Detail,Detail Template Rencana Terapi,
+Non Conformance,Ketidaksesuaian,
+Process Owner,Pemilik Proses,
+Corrective Action,Tindakan perbaikan,
+Preventive Action,Aksi Pencegahan,
+Problem,Masalah,
+Responsible,Bertanggung jawab,
+Completion By,Penyelesaian Oleh,
+Process Owner Full Name,Nama Lengkap Pemilik Proses,
+Right Index,Indeks Kanan,
+Left Index,Indeks Kiri,
+Sub Procedure,Sub Prosedur,
+Passed,Lulus,
+Print Receipt,Cetak Kwitansi,
+Edit Receipt,Edit Tanda Terima,
+Focus on search input,Fokus pada input pencarian,
+Focus on Item Group filter,Fokus pada filter Grup Item,
+Checkout Order / Submit Order / New Order,Pesanan Checkout / Kirim Pesanan / Pesanan Baru,
+Add Order Discount,Tambahkan Diskon Pesanan,
+Item Code: {0} is not available under warehouse {1}.,Kode Barang: {0} tidak tersedia di gudang {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Nomor seri tidak tersedia untuk Item {0} di bawah gudang {1}. Silakan coba ganti gudang.,
+Fetched only {0} available serial numbers.,Mengambil hanya {0} nomor seri yang tersedia.,
+Switch Between Payment Modes,Beralih Antar Mode Pembayaran,
+Enter {0} amount.,Masukkan {0} jumlah.,
+You don't have enough points to redeem.,Anda tidak memiliki cukup poin untuk ditukarkan.,
+You can redeem upto {0}.,Anda dapat menebus hingga {0}.,
+Enter amount to be redeemed.,Masukkan jumlah yang akan ditebus.,
+You cannot redeem more than {0}.,Anda tidak dapat menebus lebih dari {0}.,
+Open Form View,Buka Tampilan Formulir,
+POS invoice {0} created succesfully,Faktur POS {0} berhasil dibuat,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Kuantitas stok tidak cukup untuk Kode Barang: {0} di bawah gudang {1}. Kuantitas yang tersedia {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Nomor Seri: {0} sudah ditransaksikan menjadi Faktur POS lain.,
+Balance Serial No,Balance Serial No,
+Warehouse: {0} does not belong to {1},Gudang: {0} bukan milik {1},
+Please select batches for batched item {0},Pilih kelompok untuk item kelompok {0},
+Please select quantity on row {0},Pilih jumlah di baris {0},
+Please enter serial numbers for serialized item {0},Silakan masukkan nomor seri untuk item serial {0},
+Batch {0} already selected.,Kelompok {0} sudah dipilih.,
+Please select a warehouse to get available quantities,Pilih gudang untuk mendapatkan jumlah yang tersedia,
+"For transfer from source, selected quantity cannot be greater than available quantity","Untuk transfer dari sumber, kuantitas yang dipilih tidak boleh lebih besar dari kuantitas yang tersedia",
+Cannot find Item with this Barcode,Tidak dapat menemukan Item dengan Barcode ini,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} adalah wajib. Mungkin catatan Penukaran Mata Uang tidak dibuat untuk {1} hingga {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} telah mengirimkan aset yang terkait dengannya. Anda perlu membatalkan aset untuk membuat pengembalian pembelian.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Tidak dapat membatalkan dokumen ini karena terkait dengan aset yang dikirim {0}. Harap batalkan untuk melanjutkan.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Baris # {}: No. Seri {} telah ditransaksikan menjadi Faktur POS lain. Pilih nomor seri yang valid.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Baris # {}: Nomor Seri. {} Telah ditransaksikan menjadi Faktur POS lain. Pilih nomor seri yang valid.,
+Item Unavailable,Item Tidak Tersedia,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Baris # {}: Nomor Seri {} tidak dapat dikembalikan karena tidak ditransaksikan dalam faktur asli {},
+Please set default Cash or Bank account in Mode of Payment {},Harap setel Rekening Tunai atau Bank default dalam Cara Pembayaran {},
+Please set default Cash or Bank account in Mode of Payments {},Harap setel rekening Tunai atau Bank default dalam Mode Pembayaran {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Harap pastikan akun {} adalah akun Neraca. Anda dapat mengubah akun induk menjadi akun Neraca atau memilih akun lain.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Harap pastikan akun {} adalah akun Hutang. Ubah jenis akun menjadi Hutang atau pilih akun lain.,
+Row {}: Expense Head changed to {} ,Baris {}: Expense Head diubah menjadi {},
+because account {} is not linked to warehouse {} ,karena akun {} tidak ditautkan ke gudang {},
+or it is not the default inventory account,atau bukan akun inventaris default,
+Expense Head Changed,Expense Head Berubah,
+because expense is booked against this account in Purchase Receipt {},karena biaya dibukukan ke akun ini di Tanda Terima Pembelian {},
+as no Purchase Receipt is created against Item {}. ,karena tidak ada Tanda Terima Pembelian yang dibuat untuk Item {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Ini dilakukan untuk menangani akuntansi untuk kasus-kasus ketika Tanda Terima Pembelian dibuat setelah Faktur Pembelian,
+Purchase Order Required for item {},Pesanan Pembelian Diperlukan untuk item {},
+To submit the invoice without purchase order please set {} ,"Untuk mengirimkan faktur tanpa pesanan pembelian, harap setel {}",
+as {} in {},seperti dalam {},
+Mandatory Purchase Order,Pesanan Pembelian Wajib,
+Purchase Receipt Required for item {},Tanda Terima Pembelian Diperlukan untuk item {},
+To submit the invoice without purchase receipt please set {} ,"Untuk mengirimkan faktur tanpa tanda terima pembelian, harap setel {}",
+Mandatory Purchase Receipt,Kwitansi Pembelian Wajib,
+POS Profile {} does not belongs to company {},Profil POS {} bukan milik perusahaan {},
+User {} is disabled. Please select valid user/cashier,Pengguna {} dinonaktifkan. Pilih pengguna / kasir yang valid,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Baris # {}: Faktur Asli {} dari faktur pengembalian {} adalah {}.,
+Original invoice should be consolidated before or along with the return invoice.,Faktur asli harus digabungkan sebelum atau bersama dengan faktur kembali.,
+You can add original invoice {} manually to proceed.,Anda bisa menambahkan faktur asli {} secara manual untuk melanjutkan.,
+Please ensure {} account is a Balance Sheet account. ,Harap pastikan akun {} adalah akun Neraca.,
+You can change the parent account to a Balance Sheet account or select a different account.,Anda dapat mengubah akun induk menjadi akun Neraca atau memilih akun lain.,
+Please ensure {} account is a Receivable account. ,Harap pastikan akun {} adalah akun Piutang.,
+Change the account type to Receivable or select a different account.,Ubah jenis akun menjadi Piutang atau pilih akun lain.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} tidak dapat dibatalkan karena Poin Loyalitas yang diperoleh telah ditukarkan. Pertama batalkan {} Tidak {},
+already exists,sudah ada,
+POS Closing Entry {} against {} between selected period,Entri Penutupan POS {} terhadap {} antara periode yang dipilih,
+POS Invoice is {},Faktur POS adalah {},
+POS Profile doesn't matches {},Profil POS tidak cocok {},
+POS Invoice is not {},Faktur POS bukan {},
+POS Invoice isn't created by user {},Faktur POS tidak dibuat oleh pengguna {},
+Row #{}: {},Baris # {}: {},
+Invalid POS Invoices,Faktur POS tidak valid,
+Please add the account to root level Company - {},Harap tambahkan akun ke Perusahaan tingkat akar - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Saat membuat akun untuk Perusahaan Anak {0}, akun induk {1} tidak ditemukan. Harap buat akun induk dengan COA yang sesuai",
+Account Not Found,Akun tidak ditemukan,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Saat membuat akun untuk Perusahaan Anak {0}, akun induk {1} ditemukan sebagai akun buku besar.",
+Please convert the parent account in corresponding child company to a group account.,Harap ubah akun induk di perusahaan anak yang sesuai menjadi akun grup.,
+Invalid Parent Account,Akun Induk Tidak Valid,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Mengganti nama hanya diperbolehkan melalui perusahaan induk {0}, untuk menghindari ketidakcocokan.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Jika Anda {0} {1} jumlah item {2}, skema {3} akan diterapkan pada item tersebut.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Jika Anda {0} {1} item bernilai {2}, skema {3} akan diterapkan pada item tersebut.",
+"As the field {0} is enabled, the field {1} is mandatory.","Saat bidang {0} diaktifkan, bidang {1} wajib diisi.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Saat bidang {0} diaktifkan, nilai bidang {1} harus lebih dari 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Tidak dapat mengirim Nomor Seri {0} item {1} karena dicadangkan untuk memenuhi Pesanan Penjualan {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Pesanan Penjualan {0} memiliki reservasi untuk item {1}, Anda hanya dapat mengirimkan reservasi {1} terhadap {0}.",
+{0} Serial No {1} cannot be delivered,{0} Serial No {1} tidak dapat dikirim,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Baris {0}: Item Subkontrak wajib untuk bahan mentah {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Karena ada bahan baku yang cukup, Permintaan Material tidak diperlukan untuk Gudang {0}.",
+" If you still want to proceed, please enable {0}.","Jika Anda masih ingin melanjutkan, aktifkan {0}.",
+The item referenced by {0} - {1} is already invoiced,Item yang direferensikan oleh {0} - {1} sudah ditagih,
+Therapy Session overlaps with {0},Sesi Terapi tumpang tindih dengan {0},
+Therapy Sessions Overlapping,Sesi Terapi Tumpang Tindih,
+Therapy Plans,Rencana Terapi,
+"Item Code, warehouse, quantity are required on row {0}","Kode Barang, gudang, kuantitas diperlukan di baris {0}",
+Get Items from Material Requests against this Supplier,Dapatkan Item dari Permintaan Material terhadap Pemasok ini,
+Enable European Access,Aktifkan Akses Eropa,
+Creating Purchase Order ...,Membuat Pesanan Pembelian ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Pilih Pemasok dari Pemasok Default item di bawah ini. Saat dipilih, Pesanan Pembelian akan dibuat terhadap barang-barang milik Pemasok terpilih saja.",
+Row #{}: You must select {} serial numbers for item {}.,Baris # {}: Anda harus memilih {} nomor seri untuk item {}.,
diff --git a/erpnext/translations/is.csv b/erpnext/translations/is.csv
index b7984c9..5f56aff 100644
--- a/erpnext/translations/is.csv
+++ b/erpnext/translations/is.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Raunveruleg gerð skattur getur ekki verið með í Liður hlutfall í röð {0},
Add,Bæta,
Add / Edit Prices,Bæta við / Breyta Verð,
-Add All Suppliers,Bæta við öllum birgjum,
Add Comment,Bæta við athugasemd,
Add Customers,Bæta við viðskiptavinum,
Add Employees,Bæta Starfsmenn,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Get ekki draga þegar flokkur er fyrir 'Verðmat' eða 'Vaulation og heildar',
"Cannot delete Serial No {0}, as it is used in stock transactions","Ekki hægt að eyða Serial Nei {0}, eins og það er notað í lager viðskiptum",
Cannot enroll more than {0} students for this student group.,Ekki er hægt að innritast meira en {0} nemendum fyrir þessum nemendahópi.,
-Cannot find Item with this barcode,Get ekki fundið hlut með þessum strikamerki,
Cannot find active Leave Period,Get ekki fundið virka skiladag,
Cannot produce more Item {0} than Sales Order quantity {1},Geta ekki framleitt meira ítarefni {0} en Sales Order Magn {1},
Cannot promote Employee with status Left,Get ekki kynnt starfsmanni með stöðu vinstri,
Cannot refer row number greater than or equal to current row number for this Charge type,Getur ekki átt línunúmeri meiri en eða jafnt og núverandi röð númer fyrir þessa Charge tegund,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Get ekki valið gjald tegund sem "On Fyrri Row Upphæð 'eða' Á fyrri röðinni Samtals 'fyrir fyrstu röðinni,
-Cannot set a received RFQ to No Quote,Ekki er hægt að stilla móttekið RFQ til neins vitna,
Cannot set as Lost as Sales Order is made.,Get ekki stillt eins Lost og Sales Order er gert.,
Cannot set authorization on basis of Discount for {0},Get ekki stillt leyfi á grundvelli afsláttur fyrir {0},
Cannot set multiple Item Defaults for a company.,Ekki er hægt að stilla mörg atriði sjálfgefna fyrir fyrirtæki.,
@@ -521,7 +518,6 @@
Chargeble,Gjaldtaka,
Charges are updated in Purchase Receipt against each item,Gjöld eru uppfærðar á kvittun við hvert atriði,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Gjöld verður dreift hlutfallslega miðað hlut Fjöldi eða magn, eins og á val þitt",
-Chart Of Accounts,Mynd reikninga,
Chart of Cost Centers,Mynd af stoðsviða,
Check all,Athugaðu alla,
Checkout,Athuga,
@@ -581,7 +577,6 @@
Compensatory Off,jöfnunaraðgerðir Off,
Compensatory leave request days not in valid holidays,Dagbætur vegna bótaábyrgðar ekki í gildum frídagum,
Complaint,Kvörtun,
-Completed Qty can not be greater than 'Qty to Manufacture',Lokið Magn má ekki vera meiri en 'Magn í Manufacture',
Completion Date,Verklok,
Computer,Tölva,
Condition,Ástand,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Búa til og stjórna daglega, vikulega og mánaðarlega email meltir.",
Create customer quotes,Búa viðskiptavina tilvitnanir,
Create rules to restrict transactions based on values.,Búa til reglur til að takmarka viðskipti sem byggjast á gildum.,
-Created By,Búið til af,
Created {0} scorecards for {1} between: ,Búið til {0} stigakort fyrir {1} á milli:,
Creating Company and Importing Chart of Accounts,Að stofna fyrirtæki og flytja inn reikningskort,
Creating Fees,Búa til gjöld,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Ekki er hægt að skila starfsmanni flytja fyrir flutningsdag,
Employee cannot report to himself.,Starfsmaður getur ekki skýrslu við sjálfan sig.,
Employee relieved on {0} must be set as 'Left',Starfsmaður létta á {0} skal stilla eins 'Vinstri',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,Ekki er hægt að stilla stöðu starfsmanna á „Vinstri“ þar sem eftirfarandi starfsmenn tilkynna þessa starfsmann sem stendur:,
Employee {0} already submited an apllication {1} for the payroll period {2},Starfsmaður {0} hefur nú þegar sent inn umsókn {1} fyrir launatímabilið {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Starfsmaður {0} hefur þegar sótt um {1} á milli {2} og {3}:,
Employee {0} has no maximum benefit amount,Starfsmaður {0} hefur ekki hámarksbætur,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Fyrir röð {0}: Sláðu inn skipulagt magn,
"For {0}, only credit accounts can be linked against another debit entry","Fyrir {0}, aðeins kredit reikninga er hægt að tengja við aðra gjaldfærslu",
"For {0}, only debit accounts can be linked against another credit entry","Fyrir {0}, aðeins debetkort reikninga er hægt að tengja við aðra tekjufærslu",
-Form View,Eyðublað,
Forum Activity,Forum Activity,
Free item code is not selected,Ókeypis hlutakóði er ekki valinn,
Freight and Forwarding Charges,Frakt og Áframsending Gjöld,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Leyfi ekki hægt að skipta áður en {0}, sem orlof jafnvægi hefur þegar verið fært sendar í framtíðinni leyfi úthlutun met {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Skildu ekki hægt að beita / aflýst áður {0}, sem orlof jafnvægi hefur þegar verið fært sendar í framtíðinni leyfi úthlutun met {1}",
Leave of type {0} cannot be longer than {1},Leyfi af gerð {0} má ekki vera lengri en {1},
-Leave the field empty to make purchase orders for all suppliers,Leyfa reitinn tóm til að gera kauppantanir fyrir alla birgja,
Leaves,Blöð,
Leaves Allocated Successfully for {0},Leaves Úthlutað Tókst fyrir {0},
Leaves has been granted sucessfully,Leaves hefur verið veitt með góðum árangri,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Engar Verk með Bill of Materials að Manufacture,
No Items with Bill of Materials.,Engir hlutir með efnisyfirlit.,
No Permission,Engin heimild,
-No Quote,Engin tilvitnun,
No Remarks,Engar athugasemdir,
No Result to submit,Engar niðurstöður til að senda inn,
No Salary Structure assigned for Employee {0} on given date {1},Nei Launastyrkur úthlutað fyrir starfsmann {0} á tilteknum degi {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Skarast skilyrði fundust milli:,
Owner,eigandi,
PAN,PAN,
-PO already created for all sales order items,Póstur er þegar búinn til fyrir allar vörur til sölu,
POS,POS,
POS Profile,POS Profile,
POS Profile is required to use Point-of-Sale,POS Profile er nauðsynlegt til að nota Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Vinsamlegast veldu Charge Tegund fyrst,
Please select Company,Vinsamlegast veldu Company,
Please select Company and Designation,Vinsamlegast veldu fyrirtæki og tilnefningu,
-Please select Company and Party Type first,Vinsamlegast veldu Company og Party Gerð fyrst,
Please select Company and Posting Date to getting entries,Vinsamlegast veldu félags og póstsetningu til að fá færslur,
Please select Company first,Vinsamlegast veldu Company fyrst,
Please select Completion Date for Completed Asset Maintenance Log,Vinsamlegast veldu Lokadagsetning fyrir lokaðan rekstrarskrá,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Row {0}: UOM viðskipta Factor er nauðsynlegur,
Row {0}: select the workstation against the operation {1},Rú {0}: veldu vinnustöðina gegn aðgerðinni {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Row {0}: {1} Raðnúmer er nauðsynlegt fyrir lið {2}. Þú hefur veitt {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Row {0}: {1} er nauðsynlegt til að búa til opnun {2} Reikningar,
Row {0}: {1} must be greater than 0,Rú {0}: {1} verður að vera meiri en 0,
Row {0}: {1} {2} does not match with {3},Row {0}: {1} {2} passar ekki við {3},
Row {0}:Start Date must be before End Date,Row {0}: Byrja Bætt verður fyrir lokadagsetningu,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Senda Grant Review Email,
Send Now,Senda Nú,
Send SMS,Senda SMS,
-Send Supplier Emails,Senda Birgir póst,
Send mass SMS to your contacts,Senda massa SMS til þinn snerting,
Sensitivity,Viðkvæmni,
Sent,sendir,
-Serial #,Serial #,
Serial No and Batch,Serial Nei og Batch,
Serial No is mandatory for Item {0},Serial Nei er nauðsynlegur fyrir lið {0},
Serial No {0} does not belong to Batch {1},Raðnúmer {0} tilheyrir ekki batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Nafn fyrirtækis þíns sem þú ert að setja upp þetta kerfi.,
The number of shares and the share numbers are inconsistent,Fjöldi hluta og hlutanúmer eru ósamræmi,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Greiðslugátt reikningsins í áætluninni {0} er frábrugðin greiðslugáttarkonto í þessari greiðslubeiðni,
-The request for quotation can be accessed by clicking on the following link,Beiðni um tilvitnun er hægt að nálgast með því að smella á eftirfarandi tengil,
The selected BOMs are not for the same item,Völdu BOMs eru ekki fyrir sama hlut,
The selected item cannot have Batch,Valið atriði getur ekki Hópur,
The seller and the buyer cannot be the same,Seljandi og kaupandi geta ekki verið þau sömu,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Heildarupphæð sveigjanlegs ávinningshluta {0} ætti ekki að vera minni en hámarksbætur {1},
Total hours: {0},Total hours: {0},
Total leaves allocated is mandatory for Leave Type {0},Heildarlaun úthlutað er nauðsynlegt fyrir Leyfi Type {0},
-Total weightage assigned should be 100%. It is {0},Alls weightage úthlutað ætti að vera 100%. Það er {0},
Total working hours should not be greater than max working hours {0},Samtals vinnutími ætti ekki að vera meiri en max vinnutíma {0},
Total {0} ({1}),Alls {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Alls {0} á öllum hlutum er núll, getur verið að þú ættir að breyta 'Úthluta Gjöld Byggt á'",
@@ -3316,7 +3299,6 @@
What do you need help with?,Hvað þarftu hjálp við?,
What does it do?,Hvað gerir það?,
Where manufacturing operations are carried.,Hvar framleiðslu aðgerðir eru gerðar.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Þegar stofnað var reikning fyrir barnafyrirtækið {0} fannst móðurreikningurinn {1} ekki. Vinsamlegast stofnaðu móðurreikninginn í samsvarandi COA,
White,White,
Wire Transfer,millifærsla,
WooCommerce Products,WooCommerce vörur,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} afbrigði búin til.,
{0} {1} created,{0} {1} búin,
{0} {1} does not exist,{0} {1} er ekki til,
-{0} {1} does not exist.,{0} {1} er ekki til.,
{0} {1} has been modified. Please refresh.,{0} {1} hefur verið breytt. Vinsamlegast hressa.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} hefur ekki verið send inn þannig að aðgerðin er ekki hægt að ljúka,
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1} tengist {2} en samningsreikningur er {3},
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} er ekki til,
{0}: {1} not found in Invoice Details table,{0}: {1} fannst ekki í Reikningsupplýsingar töflu,
{} of {},{} af {},
+Assigned To,Úthlutað til,
Chat,Spjallaðu,
Completed By,Lokið við,
Conditions,Skilyrði,
@@ -3506,7 +3488,9 @@
Merge with existing,Sameinast núverandi,
Office,Office,
Orientation,stefnumörkun,
+Parent,Parent,
Passive,Hlutlaus,
+Payment Failed,greiðsla mistókst,
Percent,prósent,
Permanent,Varanleg,
Personal,Starfsfólk,
@@ -3544,7 +3528,6 @@
Company field is required,Fyrirtækjasvið er krafist,
Creating Dimensions...,Býr til víddir ...,
Duplicate entry against the item code {0} and manufacturer {1},Afrit færslu gegn vörukóðanum {0} og framleiðanda {1},
-Import Chart Of Accounts from CSV / Excel files,Flytja inn reikningskort úr CSV / Excel skrám,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Ógilt GSTIN! Inntakið sem þú slóst inn passar ekki við GSTIN snið fyrir UIN handhafa eða OIDAR þjónustuaðila sem eru ekki búsettir,
Invoice Grand Total,Heildarfjárhæð reikninga,
Last carbon check date cannot be a future date,Síðasti dagsetning kolefnisrannsóknar getur ekki verið framtíðardagsetning,
@@ -3556,6 +3539,7 @@
Show {0},Sýna {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Sérstafir nema "-", "#", ".", "/", "{" Og "}" ekki leyfðar í nafngiftiröð",
Target Details,Upplýsingar um markmið,
+{0} already has a Parent Procedure {1}.,{0} er þegar með foreldraferli {1}.,
API,API,
Annual,Árleg,
Approved,samþykkt,
@@ -3572,6 +3556,8 @@
No data to export,Engin gögn til útflutnings,
Portrait,Andlitsmynd,
Print Heading,Print fyrirsögn,
+Scheduler Inactive,Tímaáætlun óvirk,
+Scheduler is inactive. Cannot import data.,Tímaáætlun er óvirk. Ekki hægt að flytja inn gögn.,
Show Document,Sýna skjal,
Show Traceback,Sýna Traceback,
Video,Myndband,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Búðu til gæðaskoðun fyrir hlutinn {0},
Creating Accounts...,Býr til reikninga ...,
Creating bank entries...,Býr til bankafærslur ...,
-Creating {0},Búa til {0},
Credit limit is already defined for the Company {0},Lánamörk eru þegar skilgreind fyrir fyrirtækið {0},
Ctrl + Enter to submit,Ctrl + Enter til að senda,
Ctrl+Enter to submit,Ctrl + Sláðu inn til að senda inn,
@@ -3921,7 +3906,6 @@
Plaid public token error,Villa við almenna táknið,
Plaid transactions sync error,Villa við samstillingu Plaid viðskipti,
Please check the error log for details about the import errors,Vinsamlegast athugaðu villubókina til að fá upplýsingar um innflutningsvillurnar,
-Please click on the following link to set your new password,Vinsamlegast smelltu á eftirfarandi tengil til að setja nýja lykilorðið þitt,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Vinsamlegast búðu til <b>DATEV stillingar</b> fyrir fyrirtæki <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Vinsamlegast stofnaðu færslu dagbókar fyrir upphæð {0},
Please do not create more than 500 items at a time,Vinsamlegast ekki búa til meira en 500 hluti í einu,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Útgáfudagur verður að vera í framtíðinni,
Relieving Date must be greater than or equal to Date of Joining,Slökunardagur verður að vera meiri en eða jafn og dagsetningardagur,
Rename,endurnefna,
+Rename Not Allowed,Endurnefna ekki leyfilegt,
Repayment Method is mandatory for term loans,Endurgreiðsluaðferð er skylda fyrir tíma lán,
Repayment Start Date is mandatory for term loans,Upphafsdagur endurgreiðslu er skylda vegna lánstíma,
Report Item,Tilkynna hlut,
@@ -4043,7 +4028,6 @@
Select All,Velja allt,
Select Difference Account,Veldu mismunareikning,
Select a Default Priority.,Veldu sjálfgefið forgang.,
-Select a Supplier from the Default Supplier List of the items below.,Veldu seljanda úr sjálfgefnum birgðalista yfir hlutina hér að neðan.,
Select a company,Veldu fyrirtæki,
Select finance book for the item {0} at row {1},Veldu fjármálabók fyrir hlutinn {0} í röð {1},
Select only one Priority as Default.,Veldu aðeins eitt forgang sem sjálfgefið.,
@@ -4247,7 +4231,6 @@
Actual ,Raunveruleg,
Add to cart,Bæta í körfu,
Budget,Budget,
-Chart Of Accounts Importer,Yfirlit yfir innflutning reikninga,
Chart of Accounts,Yfirlit yfir reikninga,
Customer database.,Viðskiptavinur Gagnagrunnur.,
Days Since Last order,Dagar frá síðustu Order,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Lokadagur getur ekki verið minna en upphafsdagur,
For Default Supplier (Optional),Fyrir Sjálfgefið Birgir (valfrjálst),
From date cannot be greater than To date,Frá Dagsetning má ekki vera meiri en Til Dagsetning,
-Get items from,Fá atriði úr,
Group by,Hópa eftir,
In stock,Á lager,
Item name,Item Name,
@@ -4532,32 +4514,22 @@
Accounts Settings,reikninga Stillingar,
Settings for Accounts,Stillingar fyrir reikninga,
Make Accounting Entry For Every Stock Movement,Gera Bókhald færslu fyrir hvert Stock Hreyfing,
-"If enabled, the system will post accounting entries for inventory automatically.","Ef þetta er virkt, mun kerfið birta bókhald færslur fyrir birgðum sjálfkrafa.",
-Accounts Frozen Upto,Reikninga Frozen uppí,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Bókhald færsla fryst upp til þessa dagsetningu, enginn getur gert / breyta færslu, nema hlutverki sem tilgreindur er hér.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Hlutverk leyft að setja á frysta reikninga & Sýsla Frozen færslur,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Notendur með þetta hlutverk er leyft að setja á frysta reikninga og búa til / breyta bókhaldsfærslum gegn frysta reikninga,
Determine Address Tax Category From,Ákveðið heimilisfang skattaflokks frá,
-Address used to determine Tax Category in transactions.,Heimilisfang notað til að ákvarða skattaflokk í viðskiptum.,
Over Billing Allowance (%),Yfir innheimtuheimild (%),
-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 for $110.,"Hlutfall sem þú hefur heimild til að innheimta meira gegn upphæðinni sem pantað er. Til dæmis: Ef pöntunargildið er $ 100 fyrir hlut og vikmörk eru stillt sem 10%, þá hefurðu heimild til að gjaldfæra $ 110.",
Credit Controller,Credit Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,Hlutverk sem er leyft að leggja viðskiptum sem fara lánamörk sett.,
Check Supplier Invoice Number Uniqueness,Athuga Birgir Reikningur númer Sérstöðu,
Make Payment via Journal Entry,Greiða í gegnum dagbókarfærslu,
Unlink Payment on Cancellation of Invoice,Aftengja greiðsla á niðurfellingar Invoice,
-Unlink Advance Payment on Cancelation of Order,Taktu úr sambandi fyrirframgreiðslu vegna niðurfellingar pöntunar,
Book Asset Depreciation Entry Automatically,Bókfært eignaaukning sjálfkrafa,
Automatically Add Taxes and Charges from Item Tax Template,Bættu sjálfkrafa við sköttum og gjöldum af sniðmáti hlutarskatta,
Automatically Fetch Payment Terms,Sæktu sjálfkrafa greiðsluskilmála,
-Show Inclusive Tax In Print,Sýna innifalið skatt í prenti,
Show Payment Schedule in Print,Sýna greiðsluáætlun í prenti,
Currency Exchange Settings,Valmöguleikar,
Allow Stale Exchange Rates,Leyfa óbreyttu gengi,
Stale Days,Gamall dagar,
Report Settings,Skýrslu Stillingar,
Use Custom Cash Flow Format,Notaðu Custom Cash Flow Format,
-Only select if you have setup Cash Flow Mapper documents,Veldu aðeins ef þú hefur sett upp Cash Flow Mapper skjöl,
Allowed To Transact With,Leyfilegt að eiga viðskipti við,
SWIFT number,SWIFT númer,
Branch Code,Útibúarkóði,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS viðskiptavinar Group,
POS Field,POS sviði,
POS Item Group,POS Item Group,
-[Select],[Veldu],
Company Address,Nafn fyrirtækis,
Update Stock,Uppfæra Stock,
Ignore Pricing Rule,Hunsa Verðlagning reglu,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Birgir Nafngift By,
Default Supplier Group,Sjálfgefið Birgir Group,
Default Buying Price List,Sjálfgefið Buying Verðskrá,
-Maintain same rate throughout purchase cycle,Halda sama hlutfall allan kaup hringrás,
-Allow Item to be added multiple times in a transaction,Leyfa Atriði til að bæta við mörgum sinnum í viðskiptum,
Backflush Raw Materials of Subcontract Based On,Backflush Raw Materials undirverktaka Byggt á,
Material Transferred for Subcontract,Efni flutt fyrir undirverktaka,
Over Transfer Allowance (%),Yfirfærsla vegna yfirfærslu (%),
@@ -5540,7 +5509,6 @@
Current Stock,Núverandi Stock,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Fyrir einstaka birgi,
-Supplier Detail,birgir Detail,
Link to Material Requests,Tengill á efnisbeiðnir,
Message for Supplier,Skilaboð til Birgir,
Request for Quotation Item,Beiðni um Tilvitnun Item,
@@ -6481,7 +6449,6 @@
Appraisal Template,Úttekt Snið,
For Employee Name,Fyrir Starfsmannafélag Nafn,
Goals,mörk,
-Calculate Total Score,Reikna aðaleinkunn,
Total Score (Out of 5),Total Score (af 5),
"Any other remarks, noteworthy effort that should go in the records.","Allar aðrar athugasemdir, athyglisvert áreynsla sem ætti að fara í skrám.",
Appraisal Goal,Úttekt Goal,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Ástæða til að fara,
Leave Encashed?,Leyfi Encashed?,
Encashment Date,Encashment Dagsetning,
-Exit Interview Details,Hætta Viðtal Upplýsingar,
-Held On,Hélt í,
-Reason for Resignation,Ástæðan fyrir úrsögn,
-Better Prospects,betri horfur,
-Health Concerns,Heilsa Áhyggjuefni,
New Workplace,ný Vinnustaðurinn,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Skilað upphæð,
@@ -6740,10 +6702,7 @@
Employee Settings,Employee Stillingar,
Retirement Age,starfslok Age,
Enter retirement age in years,Sláðu eftirlaunaaldur í ár,
-Employee Records to be created by,Starfskjör Records að vera búin með,
-Employee record is created using selected field. ,Starfsmaður færsla er búin til með völdu sviði.,
Stop Birthday Reminders,Stop afmælisáminningar,
-Don't send Employee Birthday Reminders,Ekki senda starfsmaður afmælisáminningar,
Expense Approver Mandatory In Expense Claim,Kostnaðarsamþykki Skylda á kostnaðarkröfu,
Payroll Settings,launaskrá Stillingar,
Leave,Farðu,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Leyfi samþykki skylt í leyfi umsókn,
Show Leaves Of All Department Members In Calendar,Sýna blöð allra deildarmanna í dagatalinu,
Auto Leave Encashment,Sjálfkrafa leyfi,
-Restrict Backdated Leave Application,Takmarka umsókn um dagsetning leyfis,
Hiring Settings,Ráðningarstillingar,
Check Vacancies On Job Offer Creation,Athugaðu laus störf við sköpun atvinnutilboða,
Identification Document Type,Skjalfestingartegund,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,framleiðsla Stillingar,
Raw Materials Consumption,Neyslu hráefna,
Allow Multiple Material Consumption,Leyfa mörgum efnisnotkun,
-Allow multiple Material Consumption against a Work Order,Leyfa mörgum efni neyslu gegn vinnu pöntunar,
Backflush Raw Materials Based On,Backflush Raw Materials miðað við,
Material Transferred for Manufacture,Efni flutt til Framleiðendur,
Capacity Planning,getu Planning,
Disable Capacity Planning,Slökkva á getu skipulags,
Allow Overtime,leyfa yfirvinnu,
-Plan time logs outside Workstation Working Hours.,Skipuleggja tíma logs utan Workstation vinnutíma.,
Allow Production on Holidays,Leyfa Framleiðsla á helgidögum,
Capacity Planning For (Days),Getu áætlanagerð fyrir (dagar),
-Try planning operations for X days in advance.,Prófaðu að skipuleggja starfsemi fyrir X daga fyrirvara.,
-Time Between Operations (in mins),Tími milli rekstrar (í mín),
-Default 10 mins,Default 10 mínútur,
Default Warehouses for Production,Sjálfgefin vöruhús til framleiðslu,
Default Work In Progress Warehouse,Sjálfgefið Work In Progress Warehouse,
Default Finished Goods Warehouse,Sjálfgefin fullunnum Warehouse,
Default Scrap Warehouse,Sjálfgefið ruslvörugeymsla,
-Over Production for Sales and Work Order,Yfirframleiðsla til sölu og vinnupöntunar,
Overproduction Percentage For Sales Order,Yfirvinnsla hlutfall fyrir sölu pöntunar,
Overproduction Percentage For Work Order,Yfirvinnsla hlutfall fyrir vinnu Order,
Other Settings,aðrar stillingar,
Update BOM Cost Automatically,Uppfæra BOM kostnað sjálfkrafa,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Uppfæra BOM kostnað sjálfkrafa með áætlun, byggt á nýjustu verðlagsgengi / verðskrárgengi / síðasta kaupgengi hráefna.",
Material Request Plan Item,Efnisyfirlit,
Material Request Type,Efni Beiðni Type,
Material Issue,efni Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Gæðamarkmið,
Monitoring Frequency,Vöktunartíðni,
Weekday,Vikudagur,
-January-April-July-October,Janúar-apríl-júlí-október,
-Revision and Revised On,Endurskoðun og endurskoðuð,
-Revision,Endurskoðun,
-Revised On,Endurskoðað þann,
Objectives,Markmið,
Quality Goal Objective,Gæðamarkmið,
Objective,Hlutlæg,
@@ -7619,7 +7566,6 @@
Processes,Ferli,
Quality Procedure Process,Gæðaferli,
Process Description,Aðferðalýsing,
-Child Procedure,Málsmeðferð barna,
Link existing Quality Procedure.,Tengdu núverandi gæðaferli.,
Additional Information,Viðbótarupplýsingar,
Quality Review Objective,Markmið gæðaúttektar,
@@ -7787,15 +7733,9 @@
Default Customer Group,Sjálfgefið Group Viðskiptavinur,
Default Territory,Sjálfgefið Territory,
Close Opportunity After Days,Loka Tækifæri Eftir daga,
-Auto close Opportunity after 15 days,Auto nálægt Tækifæri eftir 15 daga,
Default Quotation Validity Days,Sjálfgefið útboðsdagur,
Sales Update Frequency,Sala Uppfæra Tíðni,
-How often should project and company be updated based on Sales Transactions.,Hversu oft ætti verkefnið og fyrirtækið að uppfæra byggt á söluviðskiptum.,
Each Transaction,Hver viðskipti,
-Allow user to edit Price List Rate in transactions,Leyfa notanda að breyta gjaldskránni Rate í viðskiptum,
-Allow multiple Sales Orders against a Customer's Purchase Order,Leyfa mörgum sölu skipunum gegn Purchase Order viðskiptavinar,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Sannreyna söluverð lið gegn kaupgengi eða Verðmat Rate,
-Hide Customer's Tax Id from Sales Transactions,Fela Tax Auðkenni viðskiptavinar frá sölu viðskiptum,
SMS Center,SMS Center,
Send To,Senda til,
All Contact,Allt samband við,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Framleiðendur notað í liðum,
Limited to 12 characters,Takmarkast við 12 stafi,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Setja vöruhús,
-Sets 'For Warehouse' in each row of the Items table.,Stillir 'Fyrir vöruhús' í hverri röð hlutatöflunnar.,
-Requested For,Umbeðin Fyrir,
Partially Ordered,Að hluta til pantað,
Transferred,Flutt,
% Ordered,% Pantaði,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Sjálfgefið Stock UOM,
Sample Retention Warehouse,Sýnishorn vörugeymsla,
Default Valuation Method,Sjálfgefið Verðmatsaðferð,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Hlutfall sem þú ert leyft að taka á móti eða afhenda fleiri gegn pantað magn. Til dæmis: Ef þú hefur pantað 100 einingar. og barnabætur er 10% þá er leyft að taka á móti 110 einingar.,
-Action if Quality inspection is not submitted,Aðgerð ef gæðaskoðun er ekki lögð fram,
Show Barcode Field,Sýna Strikamerki Field,
Convert Item Description to Clean HTML,Breyta liður Lýsing til að hreinsa HTML,
-Auto insert Price List rate if missing,Auto innskotið Verðlisti hlutfall ef vantar,
Allow Negative Stock,Leyfa Neikvæð lager,
Automatically Set Serial Nos based on FIFO,Sjálfkrafa Setja Serial Nos miðað FIFO,
-Set Qty in Transactions based on Serial No Input,Setja magn í viðskiptum sem byggjast á raðnúmeri inntak,
Auto Material Request,Auto Efni Beiðni,
-Raise Material Request when stock reaches re-order level,Hækka Material Beiðni þegar birgðir nær aftur röð stigi,
-Notify by Email on creation of automatic Material Request,Tilkynna með tölvupósti á sköpun sjálfvirka Material Beiðni,
Inter Warehouse Transfer Settings,Stillingar millifærslu á vöruhúsi,
-Allow Material Transfer From Delivery Note and Sales Invoice,Leyfa flutning efnis frá afhendingarseðli og sölureikningi,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Leyfa efnisflutning frá innkaupakvittun og innkaupareikningi,
Freeze Stock Entries,Frysta lager Entries,
Stock Frozen Upto,Stock Frozen uppí,
-Freeze Stocks Older Than [Days],Frysta Stocks eldri en [Days],
-Role Allowed to edit frozen stock,Hlutverk Leyft að breyta fryst lager,
Batch Identification,Hópur auðkenni,
Use Naming Series,Notaðu nafngiftaröð,
Naming Series Prefix,Heiti forskeyti fyrir nöfn,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Kvittun Trends,
Purchase Register,kaup Register,
Quotation Trends,Tilvitnun Trends,
-Quoted Item Comparison,Vitnað Item Samanburður,
Received Items To Be Billed,Móttekin Items verður innheimt,
Qty to Order,Magn til að panta,
Requested Items To Be Transferred,Umbeðin Items til að flytja,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Veldu lager fyrir efnisbeiðnir,
Transfer Materials For Warehouse {0},Flytja efni fyrir lager {0},
Production Plan Material Request Warehouse,Vöruhús fyrir framleiðsluáætlun,
-Set From Warehouse,Sett frá vörugeymslu,
-Source Warehouse (Material Transfer),Upprunavöruhús (efnisflutningur),
Sets 'Source Warehouse' in each row of the items table.,Stillir 'Source Warehouse' í hverri röð hlutatöflunnar.,
Sets 'Target Warehouse' in each row of the items table.,Stillir 'Target Warehouse' í hverri röð hlutatöflunnar.,
Show Cancelled Entries,Sýna færslur sem falla niður,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Þjónusta móttekin en ekki innheimt,
Deferred Accounting Settings,Frestaðar bókhaldsstillingar,
Book Deferred Entries Based On,Bókaðu frestaðar færslur byggðar á,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",Ef „Mánuðir“ eru valdir þá verður föst upphæð bókuð sem frestaðar tekjur eða kostnaður fyrir hvern mánuð óháð fjölda daga í mánuði. Verður hlutfallstala ef frestaðar tekjur eða kostnaður er ekki bókfærður í heilan mánuð.,
Days,Dagar,
Months,Mánuðum,
Book Deferred Entries Via Journal Entry,Bókaðu frestaðar færslur í gegnum dagbókarfærslu,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,Ef þetta er ómerkt verða bein GL-færslur búnar til til að bóka frestaðar tekjur / gjöld,
Submit Journal Entries,Sendu dagbókarfærslur,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,Ef þetta er ekki merkt verða færslur dagbókar vistaðar í drögum og þarf að leggja þær fram handvirkt,
Enable Distributed Cost Center,Virkja dreifingarkostnaðarmiðstöð,
@@ -8901,8 +8823,6 @@
Is Inter State,Er Inter State,
Purchase Details,Upplýsingar um kaup,
Depreciation Posting Date,Dagsetning bókunar afskrifta,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Innkaupapöntun krafist við innkaupareikning og stofnun kvittana,
-Purchase Receipt Required for Purchase Invoice Creation,Innkaupakvittun krafist við stofnun innheimtuseðla,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",Sjálfgefið er að birgjaheiti sé stillt eins og nafn birgja sem slegið var inn. Ef þú vilt að birgjar séu nefndir af a,
choose the 'Naming Series' option.,veldu valkostinn 'Nafngiftaröð'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Stilltu sjálfgefna verðskrá þegar þú stofnar nýja kaupfærslu. Verð hlutar verður sótt í þessa verðskrá.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Er hluti tekjuskatts,
Component properties and references ,Hluti eiginleika og tilvísanir,
Additional Salary ,Viðbótarlaun,
-Condtion and formula,Leiðsla og uppskrift,
Unmarked days,Ómerktir dagar,
Absent Days,Fjarverandi dagar,
Conditions and Formula variable and example,Aðstæður og formúlubreytur og dæmi,
Feedback By,Endurgjöf frá,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.ÁÁÁ .-. MM .-. DD.-,
Manufacturing Section,Framleiðsluhluti,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Sölupöntun krafist fyrir sölureikning og stofnun afhendingarnótu,
-Delivery Note Required for Sales Invoice Creation,Afhendingarskýrsla krafist við stofnun sölureikninga,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",Sjálfgefið er að viðskiptavinanafnið sé stillt samkvæmt fullu nafni sem slegið er inn. Ef þú vilt að viðskiptavinir séu nefndir af a,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Stilla sjálfgefna verðskrá þegar ný sölufærsla er búin til. Verð hlutar verður sótt í þessa verðskrá.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",Ef þessi valkostur er stilltur 'Já' kemur ERPNext í veg fyrir að þú búir til sölureikning eða afhendingarseðil án þess að búa til sölupöntun fyrst. Hægt er að hnekkja þessari stillingu fyrir tiltekinn viðskiptavin með því að gera gátreitinn 'Leyfa stofnun sölureikninga án sölupöntunar' í viðskiptavinameistaranum.,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} hefur verið bætt við öll völdu efni með góðum árangri.,
Topics updated,Umræðuefni uppfært,
Academic Term and Program,Akademískt kjörtímabil og nám,
-Last Stock Transaction for item {0} was on {1}.,Síðasta birgðir viðskipti fyrir hlutinn {0} voru þann {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Ekki er hægt að bóka birgðir af vöru {0} fyrir þennan tíma.,
Please remove this item and try to submit again or update the posting time.,Vinsamlegast fjarlægðu þetta og reyndu að senda það aftur eða uppfæra pósttímann.,
Failed to Authenticate the API key.,Mistókst að auðkenna API lykilinn.,
Invalid Credentials,Ógild skilríki,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Vinsamlegast athugaðu auðkenni viðskiptavinar þíns og leynileg gildi,
Bank transaction creation error,Villa við að búa til bankaviðskipti,
Unit of Measurement,Mælieining,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Röð nr. {}: Sölugengi hlutar {} er lægra en {} þess. Söluhlutfall ætti að vera að minnsta kosti {},
Fiscal Year {0} Does Not Exist,Reikningsár {0} er ekki til,
Row # {0}: Returned Item {1} does not exist in {2} {3},Röð nr. {0}: Atriði sem skilað er {1} er ekki til í {2} {3},
Valuation type charges can not be marked as Inclusive,Ekki er hægt að merkja gjald fyrir verðmæti sem innifalið,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Svartími fyrir {0} forgang í röð {1} getur ekki verið meiri en Upplausnartími.,
{0} is not enabled in {1},{0} er ekki virkt í {1},
Group by Material Request,Flokkað eftir efnisbeiðni,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",Röð {0}: Fyrir birgjann {0} þarf netfang til að senda tölvupóst,
Email Sent to Supplier {0},Tölvupóstur sendur til birgja {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Aðgangur að beiðni um tilboð frá gátt er óvirkur. Til að leyfa aðgang, virkjaðu það í Portal Settings.",
Supplier Quotation {0} Created,Tilboð í birgja {0} búið til,
Valid till Date cannot be before Transaction Date,Gild til dagsetning getur ekki verið fyrir viðskiptadagsetningu,
+Unlink Advance Payment on Cancellation of Order,Aftengja fyrirframgreiðslu við afturköllun pöntunar,
+"Simple Python Expression, Example: territory != 'All Territories'","Einföld Python-tjáning, dæmi: territorium! = 'All Territories'",
+Sales Contributions and Incentives,Söluframlag og hvatning,
+Sourced by Supplier,Upprunnið af birgi,
+Total weightage assigned should be 100%.<br>It is {0},Heildarþyngd úthlutað ætti að vera 100%.<br> Það er {0},
+Account {0} exists in parent company {1}.,Reikningurinn {0} er til í móðurfélaginu {1}.,
+"To overrule this, enable '{0}' in company {1}",Til að ofsækja þetta skaltu virkja '{0}' í fyrirtæki {1},
+Invalid condition expression,Ógild ástandstjáning,
+Please Select a Company First,Vinsamlegast veldu fyrirtæki fyrst,
+Please Select Both Company and Party Type First,Vinsamlegast veldu bæði fyrirtæki og tegund aðila fyrst,
+Provide the invoice portion in percent,Gefðu upp reikningshlutann í prósentum,
+Give number of days according to prior selection,Gefðu upp fjölda daga samkvæmt forvali,
+Email Details,Upplýsingar um tölvupóst,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Veldu kveðju fyrir móttakara. Til dæmis herra, frú o.s.frv.",
+Preview Email,Forskoða tölvupóst,
+Please select a Supplier,Vinsamlegast veldu birgir,
+Supplier Lead Time (days),Leiðslutími birgja (dagar),
+"Home, Work, etc.","Heimili, vinna o.s.frv.",
+Exit Interview Held On,Útgönguviðtal haldið,
+Condition and formula,Ástand og uppskrift,
+Sets 'Target Warehouse' in each row of the Items table.,Stillir 'Target Warehouse' í hverri röð hlutatöflunnar.,
+Sets 'Source Warehouse' in each row of the Items table.,Stillir 'Source Warehouse' í hverri röð hlutatöflunnar.,
+POS Register,POS skrá,
+"Can not filter based on POS Profile, if grouped by POS Profile","Get ekki síað eftir POS prófíl, ef flokkað er eftir POS prófíl",
+"Can not filter based on Customer, if grouped by Customer","Get ekki síað eftir viðskiptavini, ef flokkað er eftir viðskiptavini",
+"Can not filter based on Cashier, if grouped by Cashier","Get ekki síað eftir gjaldkera, ef flokkað er eftir gjaldkera",
+Payment Method,Greiðslumáti,
+"Can not filter based on Payment Method, if grouped by Payment Method","Get ekki síað eftir greiðslumáta, ef það er flokkað eftir greiðslumáta",
+Supplier Quotation Comparison,Samanburður á tilboði birgja,
+Price per Unit (Stock UOM),Verð á hverja einingu (lager UOM),
+Group by Supplier,Flokkað eftir birgi,
+Group by Item,Flokkað eftir liðum,
+Remember to set {field_label}. It is required by {regulation}.,Mundu að setja {field_label}. Það er krafist af {reglugerð}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Innritunardagur getur ekki verið fyrir upphafsdag námsársins {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Innritunardagur getur ekki verið eftir lokadag námsársins {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Skráningardagur getur ekki verið fyrir upphafsdag námsársins {0},
+Future Posting Not Allowed,Framtíðarpóstur ekki leyfður,
+"To enable Capital Work in Progress Accounting, ","Til að virkja bókhald fjármagnsvinnu,",
+you must select Capital Work in Progress Account in accounts table,þú verður að velja Capital Work in Progress Account í reikningstöflu,
+You can also set default CWIP account in Company {},Þú getur einnig stillt sjálfgefinn CWIP reikning í fyrirtæki {},
+The Request for Quotation can be accessed by clicking on the following button,Beiðni um tilboð er hægt að nálgast með því að smella á eftirfarandi hnapp,
+Regards,Kveðja,
+Please click on the following button to set your new password,Vinsamlegast smelltu á eftirfarandi hnapp til að stilla nýja lykilorðið þitt,
+Update Password,Uppfærðu lykilorð,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Röð # {}: Sölugengi hlutar {} er lægra en {} þess. Sala {} ætti að vera að minnsta kosti {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Þú getur einnig slökkt á staðfestingu söluverðs í {} til að fara framhjá þessari löggildingu.,
+Invalid Selling Price,Ógilt söluverð,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Heimilisfang þarf að vera tengt fyrirtæki. Vinsamlegast bættu við röð fyrir fyrirtæki í tenglatöflunni.,
+Company Not Linked,Fyrirtæki ekki tengt,
+Import Chart of Accounts from CSV / Excel files,Flytja inn reikningskort úr CSV / Excel skrám,
+Completed Qty cannot be greater than 'Qty to Manufacture',Fullbúið magn getur ekki verið meira en „Magn til framleiðslu“,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",Röð {0}: Fyrir birgja {1} þarf netfang til að senda tölvupóst,
+"If enabled, the system will post accounting entries for inventory automatically",Ef það er virkt mun kerfið bókfæra bókhald fyrir birgðir sjálfkrafa,
+Accounts Frozen Till Date,Reikningar frosnir til dags,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Bókhaldsfærslur eru frystar fram að þessum degi. Enginn getur búið til eða breytt færslum nema notendur með hlutverkið sem tilgreint er hér að neðan,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Hlutverk leyft að setja frosna reikninga og breyta frosnum færslum,
+Address used to determine Tax Category in transactions,Heimilisfang notað til að ákvarða skattflokk í viðskiptum,
+"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 ","Hlutfallið sem þér er leyft að greiða meira á móti pöntuninni. Til dæmis, ef pöntunargildið er $ 100 fyrir hlut og umburðarlyndi er stillt sem 10%, þá er þér heimilt að skuldfæra allt að $ 110",
+This role is allowed to submit transactions that exceed credit limits,Þessu hlutverki er heimilt að leggja fram viðskipti sem fara yfir lánamörk,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",Ef valið er „Mánuðir“ verður föst upphæð bókuð sem frestaðar tekjur eða kostnaður fyrir hvern mánuð óháð fjölda daga í mánuði. Það verður hlutfallslegt ef frestaðar tekjur eða kostnaður er ekki bókfærður í heilan mánuð,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",Ef þetta er ekki hakað verða beinar GL-færslur búnar til til að bóka frestaðar tekjur eða kostnað,
+Show Inclusive Tax in Print,Sýnið skatta án aðgreiningar á prenti,
+Only select this if you have set up the Cash Flow Mapper documents,Veldu þetta aðeins ef þú hefur sett upp skjölin um sjóðstreymiskortagerð,
+Payment Channel,Greiðslurás,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Er innkaupapöntun krafist vegna innkaupareikninga og stofnun kvittana?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Er krafist kvittunar fyrir stofnun innheimtuseðla?,
+Maintain Same Rate Throughout the Purchase Cycle,Haltu sama hlutfalli allan kauphringinn,
+Allow Item To Be Added Multiple Times in a Transaction,Leyfa að bæta hlut við mörgum sinnum í viðskiptum,
+Suppliers,Birgjar,
+Send Emails to Suppliers,Sendu tölvupóst til birgja,
+Select a Supplier,Veldu birgir,
+Cannot mark attendance for future dates.,Get ekki merkt mætingu fyrir komandi dagsetningar.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Viltu uppfæra aðsókn?<br> Núverandi: {0}<br> Fjarverandi: {1},
+Mpesa Settings,Mpesa stillingar,
+Initiator Name,Nafn frumkvöðla,
+Till Number,Till Fjöldi,
+Sandbox,Sandkassi,
+ Online PassKey,Online PassKey,
+Security Credential,Öryggisskilríki,
+Get Account Balance,Fáðu reikningsjöfnuð,
+Please set the initiator name and the security credential,Vinsamlegast stilltu nafn frumkvöðla og öryggisskilríki,
+Inpatient Medication Entry,Lyfjagangur á legudeild,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Vörunúmer (eiturlyf),
+Medication Orders,Lyfjapantanir,
+Get Pending Medication Orders,Fáðu lyfjapantanir í bið,
+Inpatient Medication Orders,Lyfjapantanir á sjúkrahúsum,
+Medication Warehouse,Lyfjageymsla,
+Warehouse from where medication stock should be consumed,Vöruhús þaðan sem neyta ætti lyfjabirgða,
+Fetching Pending Medication Orders,Sækir lyfjapantanir í bið,
+Inpatient Medication Entry Detail,Upplýsingar um inngöngu lyfja á sjúkrahúsum,
+Medication Details,Upplýsingar um lyf,
+Drug Code,Lyfjakóði,
+Drug Name,Lyfjanafn,
+Against Inpatient Medication Order,Gegn lyfjapöntun á sjúkrahúsum,
+Against Inpatient Medication Order Entry,Gegn inngöngu í lyfjapöntun,
+Inpatient Medication Order,Lyfjapöntun á legudeild,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Samtals pantanir,
+Completed Orders,Lokið pantanir,
+Add Medication Orders,Bæta við lyfjapöntunum,
+Adding Order Entries,Bætir við pöntunarfærslum,
+{0} medication orders completed,{0} lyfjapöntunum lokið,
+{0} medication order completed,{0} lyfjapöntun lokið,
+Inpatient Medication Order Entry,Innlögn á pöntun á lyfjum,
+Is Order Completed,Er pöntun lokið,
+Employee Records to Be Created By,Starfsmannaskrár til að búa til,
+Employee records are created using the selected field,Skrár starfsmanna eru búnar til með því að nota valda reitinn,
+Don't send employee birthday reminders,Ekki senda starfsmanna afmælis áminningar,
+Restrict Backdated Leave Applications,Takmarka umsóknir um afturkölluð leyfi,
+Sequence ID,Raðauðkenni,
+Sequence Id,Raðkenni,
+Allow multiple material consumptions against a Work Order,Leyfa margs konar neyslu gegn vinnupöntun,
+Plan time logs outside Workstation working hours,Skipuleggðu tímaskrá utan vinnutíma vinnustöðvar,
+Plan operations X days in advance,Skipuleggðu aðgerðir X daga fyrirvara,
+Time Between Operations (Mins),Tími milli aðgerða (mín.),
+Default: 10 mins,Sjálfgefið: 10 mínútur,
+Overproduction for Sales and Work Order,Offramleiðsla fyrir sölu og vinnupöntun,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Uppfærðu BOM kostnað sjálfkrafa í gegnum tímaáætlun, byggt á nýjasta verðmatshlutfalli / verðskrá hlutfalli / síðasta kauphlutfalli hráefna",
+Purchase Order already created for all Sales Order items,Innkaupapöntun þegar búin til fyrir alla sölupöntunaratriði,
+Select Items,Veldu atriði,
+Against Default Supplier,Gegn vanefndum birgi,
+Auto close Opportunity after the no. of days mentioned above,Sjálfvirk lokun Tækifæri eftir nr. daga sem nefndir eru hér að ofan,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Er sölupöntun krafist vegna sölureiknings og stofnun afhendingarnótu?,
+Is Delivery Note Required for Sales Invoice Creation?,Er skilaboð krafist við stofnun sölureikninga?,
+How often should Project and Company be updated based on Sales Transactions?,Hversu oft ætti að uppfæra verkefni og fyrirtæki byggt á söluviðskiptum?,
+Allow User to Edit Price List Rate in Transactions,Leyfa notanda að breyta verðskrágengi í viðskiptum,
+Allow Item to Be Added Multiple Times in a Transaction,Leyfa að bæta hlut við mörgum sinnum í viðskiptum,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Leyfa margar sölupantanir gegn innkaupapöntun viðskiptavinar,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Staðfestu söluverð fyrir hlut á móti kauphlutfalli eða verðmatshlutfalli,
+Hide Customer's Tax ID from Sales Transactions,Fela skattaauðkenni viðskiptavinar frá söluviðskiptum,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Hlutfallið sem þú hefur leyfi til að fá eða afhenda meira á móti því magni sem pantað er. Til dæmis, ef þú hefur pantað 100 einingar, og heimildin þín er 10%, þá er þér heimilt að fá 110 einingar.",
+Action If Quality Inspection Is Not Submitted,Aðgerð ef gæðaskoðun er ekki lögð fram,
+Auto Insert Price List Rate If Missing,Setja sjálfkrafa inn verðskrá hlutfall ef það vantar,
+Automatically Set Serial Nos Based on FIFO,Stilltu sjálfkrafa raðnúmer byggt á FIFO,
+Set Qty in Transactions Based on Serial No Input,Stilltu magn í viðskiptum byggt á raðtölum án inntaks,
+Raise Material Request When Stock Reaches Re-order Level,Hækkaðu efnisbeiðni þegar birgðir ná endurpöntunarstigi,
+Notify by Email on Creation of Automatic Material Request,Tilkynntu með tölvupósti um stofnun sjálfvirkra efnisbeiðna,
+Allow Material Transfer from Delivery Note to Sales Invoice,Leyfa efnisflutning frá afhendingarnótu til sölureiknings,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Leyfa efnisflutning frá innkaupakvittun yfir á innkaupareikning,
+Freeze Stocks Older Than (Days),Frysta hlutabréf eldri en (dagar),
+Role Allowed to Edit Frozen Stock,Hlutverk leyft að breyta frosnum hlutabréfum,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Óúthlutað magn greiðslufærslu {0} er hærra en óskipt fjárhæð bankaviðskipta,
+Payment Received,Greiðsla móttekin,
+Attendance cannot be marked outside of Academic Year {0},Ekki er hægt að merkja mætingu utan námsársins {0},
+Student is already enrolled via Course Enrollment {0},Nemandi er þegar skráður með námskeiðsinnritun {0},
+Attendance cannot be marked for future dates.,Ekki er hægt að merkja mætingu fyrir dagsetningar í framtíðinni.,
+Please add programs to enable admission application.,Vinsamlegast bættu við forritum til að gera aðgangsumsókn kleift.,
+The following employees are currently still reporting to {0}:,Eftirfarandi starfsmenn eru ennþá að tilkynna til {0}:,
+Please make sure the employees above report to another Active employee.,Vinsamlegast vertu viss um að starfsmennirnir hér að ofan greini frá öðrum virkum starfsmanni.,
+Cannot Relieve Employee,Get ekki létt af starfsmanni,
+Please enter {0},Vinsamlegast sláðu inn {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Veldu annan greiðslumáta. Mpesa styður ekki viðskipti í gjaldmiðlinum '{0}',
+Transaction Error,Viðskiptavilla,
+Mpesa Express Transaction Error,Mpesa Express viðskiptavilla,
+"Issue detected with Mpesa configuration, check the error logs for more details","Vandamál greind með Mpesa stillingum, skoðaðu villuskráina til að fá frekari upplýsingar",
+Mpesa Express Error,Mpesa Express villa,
+Account Balance Processing Error,Villa við vinnslu reikningsjöfnuðar,
+Please check your configuration and try again,Vinsamlegast athugaðu stillingar þínar og reyndu aftur,
+Mpesa Account Balance Processing Error,Villa við úrvinnslu reiknings Mpesa,
+Balance Details,Upplýsingar um jafnvægi,
+Current Balance,Núverandi staða,
+Available Balance,Laus staða,
+Reserved Balance,Frátekið jafnvægi,
+Uncleared Balance,Ótæmt jafnvægi,
+Payment related to {0} is not completed,Greiðslu sem tengist {0} er ekki lokið,
+Row #{}: Item Code: {} is not available under warehouse {}.,Röð nr. {}: Vörukóði: {} er ekki fáanlegur undir lager {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Röð nr. {}: Magn birgða dugar ekki fyrir vörukóða: {} undir lager {}. Laus magn {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Röð nr. {}: Veldu raðnúmer og lotu á móti hlut: {} eða fjarlægðu það til að ljúka viðskiptum.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Röð nr. {}: Ekkert raðnúmer valið á móti hlut: {}. Veldu einn eða fjarlægðu hann til að ljúka viðskiptum.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Röð nr. {}: Engin lota valin á móti hlut: {}. Vinsamlegast veldu lotu eða fjarlægðu hana til að ljúka viðskiptum.,
+Payment amount cannot be less than or equal to 0,Greiðsluupphæð getur ekki verið lægri en eða 0,
+Please enter the phone number first,Vinsamlegast sláðu inn símanúmerið fyrst,
+Row #{}: {} {} does not exist.,Röð nr. {}: {} {} Er ekki til.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Röð nr. {0}: {1} er krafist til að stofna opnunar {2} reikninga,
+You had {} errors while creating opening invoices. Check {} for more details,Þú varst með {} villur þegar þú bjóst til upphafsreikninga. Athugaðu {} til að fá frekari upplýsingar,
+Error Occured,Villa kom upp,
+Opening Invoice Creation In Progress,Opnun reikningagerðar í vinnslu,
+Creating {} out of {} {},Býr til {} úr {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Raðnúmer: {0}) er ekki hægt að neyta þar sem það er áskilið til fullrar sölupöntunar {1}.,
+Item {0} {1},Atriði {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Síðasta birgðir viðskipti fyrir hlutinn {0} undir vöruhúsinu {1} voru þann {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Ekki er hægt að bóka birgðir fyrir hlut {0} undir vöruhúsi {1} fyrir þennan tíma.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Bókun framtíðar hlutabréfaviðskipta er ekki leyfð vegna Immutable Ledger,
+A BOM with name {0} already exists for item {1}.,BOM með nafninu {0} er þegar til fyrir hlutinn {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Endurnefndir þú hlutinn? Vinsamlegast hafðu samband við stjórnanda / tækniþjónustu,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Í línu nr. {0}: auðkenni raðarins {1} má ekki vera minna en fyrri línuröð auðkenni {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) verður að vera jöfn {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, ljúktu aðgerðinni {1} fyrir aðgerðina {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Get ekki tryggt afhendingu með raðnúmeri þar sem hlutur {0} er bætt við með og án þess að tryggja afhendingu með raðnúmer.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Vöru {0} er án raðnúmera. Aðeins serilialized hlutir geta fengið afhendingu byggt á raðnúmer,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Engin virk BOM fannst fyrir hlutinn {0}. Ekki er hægt að tryggja afhendingu með raðnúmeri,
+No pending medication orders found for selected criteria,Engar lyfjapantanir í bið fundust fyrir völdum forsendum,
+From Date cannot be after the current date.,Frá dagsetningu getur ekki verið eftir núverandi dagsetningu.,
+To Date cannot be after the current date.,Til dags getur ekki verið eftir núverandi dagsetningu.,
+From Time cannot be after the current time.,Frá tíma getur ekki verið eftir núverandi tíma.,
+To Time cannot be after the current time.,To Time getur ekki verið eftir núverandi tíma.,
+Stock Entry {0} created and ,Hlutafærsla {0} búin til og,
+Inpatient Medication Orders updated successfully,Lækningapantanir á legudeildum uppfærðar með góðum árangri,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Röð {0}: Get ekki búið til lyfjagjöf á legudeild gegn hætt við lyfjapöntun á legudeild {1},
+Row {0}: This Medication Order is already marked as completed,Röð {0}: Þessi lyfjapöntun er þegar merkt sem lokið,
+Quantity not available for {0} in warehouse {1},Magn ekki tiltækt fyrir {0} í lager {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Vinsamlegast virkjaðu Leyfa neikvæðan lager í lagerstillingum eða búðu til lagerfærslu til að halda áfram.,
+No Inpatient Record found against patient {0},Engin sjúkraskrá fannst gegn sjúklingi {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Lyfjapöntun á legudeild {0} gegn fundi sjúklinga {1} er þegar til.,
+Allow In Returns,Leyfa inn skil,
+Hide Unavailable Items,Fela hluti sem ekki eru tiltækir,
+Apply Discount on Discounted Rate,Sækja um afslátt á afsláttarverði,
+Therapy Plan Template,Sniðmát fyrir meðferðaráætlun,
+Fetching Template Details,Sækir upplýsingar um sniðmát,
+Linked Item Details,Upplýsingar um tengda hlut,
+Therapy Types,Meðferðartegundir,
+Therapy Plan Template Detail,Sniðmát fyrir meðferðaráætlun,
+Non Conformance,Ósamræmi,
+Process Owner,Ferli eigandi,
+Corrective Action,Úrbætur,
+Preventive Action,Fyrirbyggjandi aðgerð,
+Problem,Vandamál,
+Responsible,Ábyrg,
+Completion By,Lok frá,
+Process Owner Full Name,Fullt nafn eiganda ferils,
+Right Index,Hægri vísitala,
+Left Index,Vinstri vísitala,
+Sub Procedure,Undirferli,
+Passed,Samþykkt,
+Print Receipt,Prentakvittun,
+Edit Receipt,Breyta kvittun,
+Focus on search input,Einbeittu þér að leitarinntakinu,
+Focus on Item Group filter,Einbeittu þér að hlutahópasíu,
+Checkout Order / Submit Order / New Order,Afgreiðslupöntun / leggja fram pöntun / nýja pöntun,
+Add Order Discount,Bæta við pöntunarafslætti,
+Item Code: {0} is not available under warehouse {1}.,Vörukóði: {0} er ekki fáanlegur í vörugeymslu {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Raðnúmer eru ekki tiltæk fyrir vöru {0} undir vöruhúsi {1}. Vinsamlegast reyndu að skipta um lager.,
+Fetched only {0} available serial numbers.,Sótti aðeins {0} tiltækt raðnúmer.,
+Switch Between Payment Modes,Skiptu á milli greiðslumáta,
+Enter {0} amount.,Sláðu inn {0} upphæð.,
+You don't have enough points to redeem.,Þú hefur ekki nógu mörg stig til að innleysa.,
+You can redeem upto {0}.,Þú getur leyst allt að {0}.,
+Enter amount to be redeemed.,Sláðu inn upphæð sem á að innleysa.,
+You cannot redeem more than {0}.,Þú getur ekki innleyst meira en {0}.,
+Open Form View,Opnaðu skjámynd,
+POS invoice {0} created succesfully,POS reikningur {0} búinn til með góðum árangri,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Lagermagn dugar ekki fyrir vörukóða: {0} undir vöruhúsi {1}. Laus magn {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Raðnúmer: {0} hefur þegar verið flutt á annan POS reikning.,
+Balance Serial No,Jafnvægi raðnúmer,
+Warehouse: {0} does not belong to {1},Vöruhús: {0} tilheyrir ekki {1},
+Please select batches for batched item {0},Veldu lotur fyrir lotuhlut {0},
+Please select quantity on row {0},Veldu magn í línu {0},
+Please enter serial numbers for serialized item {0},Vinsamlegast sláðu inn raðnúmer fyrir raðnúmerið {0},
+Batch {0} already selected.,Hópur {0} þegar valinn.,
+Please select a warehouse to get available quantities,Vinsamlegast veldu vöruhús til að fá tiltækt magn,
+"For transfer from source, selected quantity cannot be greater than available quantity",Fyrir flutning frá uppruna getur valið magn ekki verið meira en tiltækt magn,
+Cannot find Item with this Barcode,Finnur ekki hlut með þessum strikamerki,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} er skylda. Kannski er gjaldeyrisskrá ekki búin til fyrir {1} til {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} hefur sent inn eignir sem tengjast henni. Þú þarft að hætta við eignirnar til að búa til kauprétt.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Ekki er hægt að hætta við þetta skjal þar sem það er tengt við innsendar eignir {0}. Vinsamlegast hætta við það til að halda áfram.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Röð nr. {}: Raðnúmer. {} Hefur þegar verið flutt á annan POS reikning. Vinsamlegast veldu gild raðnúmer.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Röð nr. {}: Raðnúmer. {} Hefur þegar verið flutt á annan POS reikning. Vinsamlegast veldu gild raðnúmer.,
+Item Unavailable,Atriði ekki tiltækt,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Röð nr. {}: Ekki er hægt að skila raðnúmeri {} þar sem það var ekki flutt á upphaflegum reikningi {},
+Please set default Cash or Bank account in Mode of Payment {},Vinsamlegast stilltu sjálfgefið reiðufé eða bankareikning í greiðslumáta {},
+Please set default Cash or Bank account in Mode of Payments {},Vinsamlegast stilltu sjálfgefið reiðufé eða bankareikning í greiðslumáta {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Gakktu úr skugga um að {} reikningurinn sé reikningur í efnahagsreikningi. Þú getur breytt móðurreikningi í efnahagsreikning eða valið annan reikning.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Gakktu úr skugga um að {} reikningurinn sé greiðslureikningur. Breyttu reikningsgerðinni í Greiðanleg eða veldu annan reikning.,
+Row {}: Expense Head changed to {} ,Röð {}: Kostnaðarhaus breytt í {},
+because account {} is not linked to warehouse {} ,vegna þess að reikningur {} er ekki tengdur við lager {},
+or it is not the default inventory account,eða það er ekki sjálfgefinn birgðareikningur,
+Expense Head Changed,Kostnaðarhaus breytt,
+because expense is booked against this account in Purchase Receipt {},vegna þess að kostnaður er bókfærður á þennan reikning í kvittun innkaupa {},
+as no Purchase Receipt is created against Item {}. ,þar sem engin innheimtukvittun er búin til gegn hlutnum {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Þetta er gert til að meðhöndla bókhald vegna tilvika þegar innkaupakvittun er búin til eftir innkaupareikning,
+Purchase Order Required for item {},Innkaupapöntun krafist fyrir hlutinn {},
+To submit the invoice without purchase order please set {} ,Til að leggja fram reikninginn án innkaupapöntunar skaltu stilla {},
+as {} in {},eins og í {},
+Mandatory Purchase Order,Lögboðin innkaupapöntun,
+Purchase Receipt Required for item {},Innkaupakvittunar krafist fyrir hlutinn {},
+To submit the invoice without purchase receipt please set {} ,Til að senda reikninginn án kvittunar skaltu stilla {},
+Mandatory Purchase Receipt,Skyldukaupakvittun,
+POS Profile {} does not belongs to company {},POS prófíll {} tilheyrir ekki fyrirtæki {},
+User {} is disabled. Please select valid user/cashier,Notandi {} er óvirkur. Vinsamlegast veldu gildan notanda / gjaldkera,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Röð nr.}}: Upprunalegur reikningur {} skilareiknings {} er {}.,
+Original invoice should be consolidated before or along with the return invoice.,Upprunalegur reikningur ætti að sameina fyrir eða ásamt skilareikningi.,
+You can add original invoice {} manually to proceed.,Þú getur bætt við upphaflegum reikningi {} handvirkt til að halda áfram.,
+Please ensure {} account is a Balance Sheet account. ,Gakktu úr skugga um að {} reikningurinn sé reikningur í efnahagsreikningi.,
+You can change the parent account to a Balance Sheet account or select a different account.,Þú getur breytt móðurreikningi í efnahagsreikning eða valið annan reikning.,
+Please ensure {} account is a Receivable account. ,Gakktu úr skugga um að {} reikningurinn sé viðtakanlegur reikningur.,
+Change the account type to Receivable or select a different account.,Breyttu reikningsgerðinni í Kröfur eða veldu annan reikning.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},Ekki er hægt að hætta við {} þar sem unnin vildarpunktar hafa verið innleystir. Hætta fyrst við {} Nei {},
+already exists,er þegar til,
+POS Closing Entry {} against {} between selected period,POS lokunarfærsla {} gegn {} milli valins tímabils,
+POS Invoice is {},POS reikningur er {},
+POS Profile doesn't matches {},POS prófíll passar ekki við {},
+POS Invoice is not {},POS-reikningur er ekki {},
+POS Invoice isn't created by user {},POS reikningur er ekki búinn til af notanda {},
+Row #{}: {},Röð nr. {}: {},
+Invalid POS Invoices,Ógildir POS-reikningar,
+Please add the account to root level Company - {},Vinsamlegast bættu reikningnum við rótarstig fyrirtækisins - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",Við stofnun reiknings fyrir Child Company {0} fannst móðurreikningur {1} ekki. Vinsamlegast stofnaðu móðurreikninginn í samsvarandi COA,
+Account Not Found,Reikningur fannst ekki,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",Við stofnun reiknings fyrir Child Company {0} fannst móðurreikningur {1} sem aðalbókareikningur.,
+Please convert the parent account in corresponding child company to a group account.,Vinsamlegast breyttu móðurreikningi í samsvarandi barnafyrirtæki í hópreikning.,
+Invalid Parent Account,Ógildur móðurreikningur,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Að endurnefna það er aðeins leyfilegt í gegnum móðurfélagið {0}, til að koma í veg fyrir misræmi.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",Ef þú {0} {1} magn hlutarins {2} verður kerfinu {3} beitt á hlutinn.,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",Ef þú {0} {1} virðir hlut {2} verður kerfinu {3} beitt á hlutinn.,
+"As the field {0} is enabled, the field {1} is mandatory.",Þar sem reiturinn {0} er virkur er reiturinn {1} skyldugur.,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Þar sem reiturinn {0} er virkur, ætti gildi reitsins {1} að vera meira en 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Get ekki afhent raðnúmer {0} hlutar {1} þar sem það er áskilið til fullrar sölupöntunar {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Sölupöntun {0} hefur fyrirvara fyrir hlutinn {1}, þú getur aðeins afhent frátekinn {1} á móti {0}.",
+{0} Serial No {1} cannot be delivered,Ekki er hægt að afhenda {0} raðnúmer {1},
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Röð {0}: Liður í undirverktöku er skyldur fyrir hráefnið {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",Þar sem nægilegt hráefni er til þarf ekki Efnisbeiðni fyrir Vöruhús {0}.,
+" If you still want to proceed, please enable {0}.",Ef þú vilt samt halda áfram skaltu virkja {0}.,
+The item referenced by {0} - {1} is already invoiced,Atriðið sem {0} - {1} vísar til er þegar reiknað,
+Therapy Session overlaps with {0},Meðferðarlotan skarast við {0},
+Therapy Sessions Overlapping,Meðferðarlotur skarast,
+Therapy Plans,Meðferðaráætlanir,
+"Item Code, warehouse, quantity are required on row {0}","Vörukóði, vöruhús, magn er krafist í línu {0}",
+Get Items from Material Requests against this Supplier,Fáðu hluti frá beiðnum um efni gagnvart þessum birgi,
+Enable European Access,Virkja evrópskan aðgang,
+Creating Purchase Order ...,Býr til innkaupapöntun ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",Veldu birgja frá sjálfgefnum birgjum hlutanna hér að neðan. Við val verður eingöngu gerð innkaupapöntun á hlutum sem tilheyra völdum birgi.,
+Row #{}: You must select {} serial numbers for item {}.,Röð nr. {}: Þú verður að velja {} raðnúmer fyrir hlut {}.,
diff --git a/erpnext/translations/it.csv b/erpnext/translations/it.csv
index 97bf2f1..3a1d73f 100644
--- a/erpnext/translations/it.csv
+++ b/erpnext/translations/it.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Il tipo di imposta / tassa non può essere inclusa nella tariffa della riga {0},
Add,Aggiungi,
Add / Edit Prices,Aggiungi / modifica prezzi,
-Add All Suppliers,Aggiungi tutti i fornitori,
Add Comment,Aggiungi un commento,
Add Customers,Aggiungi clienti,
Add Employees,Aggiungi dipendenti,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Non può dedurre quando categoria è per 'valutazione' o 'Vaulation e Total',
"Cannot delete Serial No {0}, as it is used in stock transactions","Impossibile eliminare N. di serie {0}, come si usa in transazioni di borsa",
Cannot enroll more than {0} students for this student group.,Non possono iscriversi più di {0} studenti per questo gruppo.,
-Cannot find Item with this barcode,Impossibile trovare l'oggetto con questo codice a barre,
Cannot find active Leave Period,Impossibile trovare il Periodo di congedo attivo,
Cannot produce more Item {0} than Sales Order quantity {1},Non può produrre più Voce {0} di Sales Order quantità {1},
Cannot promote Employee with status Left,Impossibile promuovere il Dipendente con stato Sinistro,
Cannot refer row number greater than or equal to current row number for this Charge type,Non può consultare numero di riga maggiore o uguale al numero di riga corrente per questo tipo di carica,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Non è possibile selezionare il tipo di carica come 'On Fila Indietro Importo ' o 'On Precedente totale riga ' per la prima fila,
-Cannot set a received RFQ to No Quote,Impossibile impostare una RFQ ricevuta al valore No Quote,
Cannot set as Lost as Sales Order is made.,Impossibile impostare come persa come è fatto Sales Order .,
Cannot set authorization on basis of Discount for {0},Impossibile impostare autorizzazione sulla base di Sconto per {0},
Cannot set multiple Item Defaults for a company.,Impossibile impostare più valori predefiniti oggetto per un'azienda.,
@@ -521,7 +518,6 @@
Chargeble,chargeble,
Charges are updated in Purchase Receipt against each item,Le tariffe sono aggiornati in acquisto ricevuta contro ogni voce,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Spese saranno distribuiti proporzionalmente basate su qty voce o importo, secondo la vostra selezione",
-Chart Of Accounts,Piano dei conti,
Chart of Cost Centers,Grafico Centro di Costo,
Check all,Seleziona tutto,
Checkout,Check-out,
@@ -581,7 +577,6 @@
Compensatory Off,compensativa Off,
Compensatory leave request days not in valid holidays,Giorni di congedo compensativo giorni non festivi validi,
Complaint,Denuncia,
-Completed Qty can not be greater than 'Qty to Manufacture',Completato Quantità non può essere maggiore di 'Quantità di Fabbricazione',
Completion Date,Data Completamento,
Computer,Computer,
Condition,Condizione,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Creare e gestire giornalieri , settimanali e mensili digerisce email .",
Create customer quotes,Creare le citazioni dei clienti,
Create rules to restrict transactions based on values.,Creare regole per limitare le transazioni in base ai valori .,
-Created By,Creato da,
Created {0} scorecards for {1} between: ,Creato {0} scorecard per {1} tra:,
Creating Company and Importing Chart of Accounts,Creazione di società e importazione del piano dei conti,
Creating Fees,Creazione di tariffe,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Il trasferimento del dipendente non può essere inoltrato prima della data di trasferimento,
Employee cannot report to himself.,Il dipendente non può riportare a se stesso.,
Employee relieved on {0} must be set as 'Left',Dipendente esonerato da {0} deve essere impostato come 'Congedato',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,Lo stato del dipendente non può essere impostato su "Sinistra" poiché i seguenti dipendenti stanno attualmente segnalando a questo dipendente:,
Employee {0} already submited an apllication {1} for the payroll period {2},Il dipendente {0} ha già inviato una richiesta {1} per il periodo di gestione stipendi {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Il Dipendente {0} ha già fatto domanda per {1} tra {2} e {3}:,
Employee {0} has no maximum benefit amount,Il dipendente {0} non ha l'importo massimo del beneficio,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Per la riga {0}: inserisci qtà pianificata,
"For {0}, only credit accounts can be linked against another debit entry","Per {0}, solo i conti di credito possono essere collegati contro un'altra voce di addebito",
"For {0}, only debit accounts can be linked against another credit entry","Per {0}, solo gli account di debito possono essere collegati contro un'altra voce di credito",
-Form View,Vista forma,
Forum Activity,Attività del forum,
Free item code is not selected,Il codice articolo gratuito non è selezionato,
Freight and Forwarding Charges,Freight Forwarding e spese,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Ferie non possono essere assegnati prima {0}, come equilibrio congedo è già stato inoltrato carry-in futuro record di assegnazione congedo {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Lasciare non può essere applicata / annullato prima {0}, come equilibrio congedo è già stato inoltrato carry-in futuro record di assegnazione congedo {1}",
Leave of type {0} cannot be longer than {1},Lascia di tipo {0} non può essere superiore a {1},
-Leave the field empty to make purchase orders for all suppliers,Lascia vuoto il campo per effettuare ordini di acquisto per tutti i fornitori,
Leaves,Le foglie,
Leaves Allocated Successfully for {0},Permessi allocati con successo per {0},
Leaves has been granted sucessfully,Le ferie sono state concesse con successo,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Non ci sono elementi con Bill of Materials per la produzione,
No Items with Bill of Materials.,Nessun articolo con distinta materiali.,
No Permission,Nessuna autorizzazione,
-No Quote,Nessuna cifra,
No Remarks,Nessun commento,
No Result to submit,Nessun risultato da presentare,
No Salary Structure assigned for Employee {0} on given date {1},Nessuna struttura retributiva assegnata al Dipendente {0} in data determinata {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Condizioni sovrapposti trovati tra :,
Owner,Proprietario,
PAN,PAN,
-PO already created for all sales order items,PO già creato per tutti gli articoli dell'ordine di vendita,
POS,POS,
POS Profile,POS Profilo,
POS Profile is required to use Point-of-Sale,Il profilo POS è richiesto per utilizzare Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Seleziona il tipo di carica prima,
Please select Company,Selezionare prego,
Please select Company and Designation,Si prega di selezionare Società e designazione,
-Please select Company and Party Type first,Per favore selezionare prima l'azienda e il tipo di Partner,
Please select Company and Posting Date to getting entries,Seleziona Società e Data di pubblicazione per ottenere le voci,
Please select Company first,Seleziona prima azienda,
Please select Completion Date for Completed Asset Maintenance Log,Selezionare la data di completamento per il registro di manutenzione delle attività completato,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Riga {0}: UOM fattore di conversione è obbligatoria,
Row {0}: select the workstation against the operation {1},Riga {0}: seleziona la workstation rispetto all'operazione {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Riga {0}: {1} Numeri di serie necessari per l'articolo {2}. Hai fornito {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Riga {0}: {1} è richiesta per creare le Fatture di apertura {2},
Row {0}: {1} must be greater than 0,Riga {0}: {1} deve essere maggiore di 0,
Row {0}: {1} {2} does not match with {3},Riga {0}: {1} {2} non corrisponde con {3},
Row {0}:Start Date must be before End Date,Riga {0} : Data di inizio deve essere precedente Data di fine,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Invia e-mail di revisione di Grant,
Send Now,Invia Ora,
Send SMS,Invia SMS,
-Send Supplier Emails,Inviare e-mail del fornitore,
Send mass SMS to your contacts,Invia SMS di massa ai tuoi contatti,
Sensitivity,sensibilità,
Sent,Inviati,
-Serial #,Serial #,
Serial No and Batch,N. di serie e batch,
Serial No is mandatory for Item {0},Numero d'ordine è obbligatorio per la voce {0},
Serial No {0} does not belong to Batch {1},Il numero di serie {0} non appartiene a Batch {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Il nome dell'azienda per la quale si sta configurando questo sistema.,
The number of shares and the share numbers are inconsistent,Il numero di condivisioni e i numeri di condivisione sono incoerenti,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,L'account del gateway di pagamento nel piano {0} è diverso dall'account del gateway di pagamento in questa richiesta di pagamento,
-The request for quotation can be accessed by clicking on the following link,Accedere alla richiesta di offerta cliccando sul seguente link,
The selected BOMs are not for the same item,Le distinte materiali selezionati non sono per la stessa voce,
The selected item cannot have Batch,La voce selezionata non può avere Batch,
The seller and the buyer cannot be the same,Il venditore e l'acquirente non possono essere uguali,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},L'importo della componente di benefit flessibile totale {0} non deve essere inferiore ai benefit massimi {1},
Total hours: {0},Ore totali: {0},
Total leaves allocated is mandatory for Leave Type {0},Le ferie totali assegnate sono obbligatorie per Tipo di uscita {0},
-Total weightage assigned should be 100%. It is {0},Weightage totale assegnato dovrebbe essere al 100% . E ' {0},
Total working hours should not be greater than max working hours {0},l'orario di lavoro totale non deve essere maggiore di ore di lavoro max {0},
Total {0} ({1}),Totale {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Totale {0} per tutti gli elementi è pari a zero, può essere che si dovrebbe cambiare 'distribuire oneri corrispondenti'",
@@ -3316,7 +3299,6 @@
What do you need help with?,Con cosa hai bisogno di aiuto?,
What does it do?,Che cosa fa ?,
Where manufacturing operations are carried.,Dove si svolgono le operazioni di fabbricazione.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Durante la creazione dell'account per la società figlio {0}, l'account padre {1} non è stato trovato. Crea l'account principale nel COA corrispondente",
White,Bianco,
Wire Transfer,Bonifico bancario,
WooCommerce Products,Prodotti WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} varianti create.,
{0} {1} created,{0} {1} creato,
{0} {1} does not exist,{0} {1} non esiste,
-{0} {1} does not exist.,{0} {1} non esiste.,
{0} {1} has been modified. Please refresh.,{0} {1} è stato modificato. Aggiornare prego.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} non è stato inviato perciò l'azione non può essere completata,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} è associato a {2}, ma il conto partito è {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} non esiste,
{0}: {1} not found in Invoice Details table,{0}: {1} non trovato in tabella Dettagli Fattura,
{} of {},{} di {},
+Assigned To,Assegnato a,
Chat,Chat,
Completed By,Completato da,
Conditions,condizioni,
@@ -3506,7 +3488,9 @@
Merge with existing,Unisci con esistente,
Office,Ufficio,
Orientation,Orientamento,
+Parent,Genitore,
Passive,Passivo,
+Payment Failed,Pagamento fallito,
Percent,Percentuale,
Permanent,Permanente,
Personal,Personale,
@@ -3544,7 +3528,6 @@
Company field is required,È richiesto il campo dell'azienda,
Creating Dimensions...,Creazione di quote ...,
Duplicate entry against the item code {0} and manufacturer {1},Voce duplicata rispetto al codice articolo {0} e al produttore {1},
-Import Chart Of Accounts from CSV / Excel files,Importa piano dei conti da file CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN non valido! L'input inserito non corrisponde al formato GSTIN per titolari UIN o provider di servizi OIDAR non residenti,
Invoice Grand Total,Totale totale fattura,
Last carbon check date cannot be a future date,La data dell'ultima verifica del carbonio non può essere una data futura,
@@ -3556,6 +3539,7 @@
Show {0},Mostra {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caratteri speciali tranne "-", "#", ".", "/", "{" E "}" non consentiti nelle serie di nomi",
Target Details,Dettagli target,
+{0} already has a Parent Procedure {1}.,{0} ha già una procedura padre {1}.,
API,API,
Annual,Annuale,
Approved,Approvato,
@@ -3572,6 +3556,8 @@
No data to export,Nessun dato da esportare,
Portrait,Ritratto,
Print Heading,Intestazione di stampa,
+Scheduler Inactive,Scheduler inattivo,
+Scheduler is inactive. Cannot import data.,Lo scheduler non è attivo. Impossibile importare i dati.,
Show Document,Mostra documento,
Show Traceback,Mostra traccia,
Video,video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Crea controllo di qualità per l'articolo {0},
Creating Accounts...,Creazione di account ...,
Creating bank entries...,Creazione di registrazioni bancarie ...,
-Creating {0},Creazione di {0},
Credit limit is already defined for the Company {0},Il limite di credito è già definito per la società {0},
Ctrl + Enter to submit,Ctrl + Invio per inviare,
Ctrl+Enter to submit,Ctrl + Invio per inviare,
@@ -3921,7 +3906,6 @@
Plaid public token error,Errore token pubblico plaid,
Plaid transactions sync error,Errore di sincronizzazione delle transazioni del plaid,
Please check the error log for details about the import errors,Controllare il registro degli errori per i dettagli sugli errori di importazione,
-Please click on the following link to set your new password,Cliccate sul link seguente per impostare la nuova password,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Crea le <b>impostazioni DATEV</b> per l'azienda <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Crea una registrazione prima nota di rettifica per l'importo {0},
Please do not create more than 500 items at a time,Non creare più di 500 elementi alla volta,
@@ -3997,6 +3981,7 @@
Release date must be in the future,La data di uscita deve essere in futuro,
Relieving Date must be greater than or equal to Date of Joining,La data di rilascio deve essere maggiore o uguale alla data di iscrizione,
Rename,Rinomina,
+Rename Not Allowed,Rinomina non consentita,
Repayment Method is mandatory for term loans,Il metodo di rimborso è obbligatorio per i prestiti a termine,
Repayment Start Date is mandatory for term loans,La data di inizio del rimborso è obbligatoria per i prestiti a termine,
Report Item,Segnala articolo,
@@ -4043,7 +4028,6 @@
Select All,Seleziona tutto,
Select Difference Account,Seleziona Conto differenze,
Select a Default Priority.,Seleziona una priorità predefinita.,
-Select a Supplier from the Default Supplier List of the items below.,Selezionare un fornitore dall'elenco fornitori predefinito degli articoli di seguito.,
Select a company,Seleziona un'azienda,
Select finance book for the item {0} at row {1},Seleziona il libro finanziario per l'articolo {0} alla riga {1},
Select only one Priority as Default.,Seleziona solo una priorità come predefinita.,
@@ -4247,7 +4231,6 @@
Actual ,Attuale,
Add to cart,Aggiungi al carrello,
Budget,Budget,
-Chart Of Accounts Importer,Importatore del piano dei conti,
Chart of Accounts,Piano dei conti,
Customer database.,Database clienti.,
Days Since Last order,Giorni dall'ultimo ordine,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Data di Fine non può essere inferiore a Data di inizio,
For Default Supplier (Optional),Per fornitore predefinito (facoltativo),
From date cannot be greater than To date,Dalla data non può essere maggiore di Alla data,
-Get items from,Ottenere elementi dal,
Group by,Raggruppa per,
In stock,disponibile,
Item name,Nome Articolo,
@@ -4532,32 +4514,22 @@
Accounts Settings,Impostazioni Conti,
Settings for Accounts,Impostazioni per gli account,
Make Accounting Entry For Every Stock Movement,Crea una voce contabile per ogni movimento di scorta,
-"If enabled, the system will post accounting entries for inventory automatically.","Se abilitato, il sistema pubblicherà le scritture contabili per l'inventario automatico.",
-Accounts Frozen Upto,Conti congelati fino al,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Registrazione contabile congelato fino a questa data, nessuno può / Modifica voce eccetto ruolo specificato di seguito.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Ruolo permesso di impostare conti congelati e modificare le voci congelati,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Gli utenti con questo ruolo sono autorizzati a impostare conti congelati e creare / modificare le voci contabili nei confronti di conti congelati,
Determine Address Tax Category From,Determinare la categoria di imposta indirizzo da,
-Address used to determine Tax Category in transactions.,Indirizzo utilizzato per determinare la categoria fiscale nelle transazioni.,
Over Billing Allowance (%),Indennità di fatturazione eccessiva (%),
-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 for $110.,"Percentuale che ti è consentita di fatturare di più rispetto all'importo ordinato. Ad esempio: se il valore dell'ordine è $ 100 per un articolo e la tolleranza è impostata sul 10%, è possibile fatturare $ 110.",
Credit Controller,Controllare Credito,
-Role that is allowed to submit transactions that exceed credit limits set.,Ruolo che è consentito di presentare le transazioni che superano i limiti di credito stabiliti.,
Check Supplier Invoice Number Uniqueness,Controllare l'unicità del numero fattura fornitore,
Make Payment via Journal Entry,Effettua il pagamento tramite Registrazione Contabile,
Unlink Payment on Cancellation of Invoice,Scollegare il pagamento per la cancellazione della fattura,
-Unlink Advance Payment on Cancelation of Order,Scollega pagamento anticipato in caso di annullamento dell'ordine,
Book Asset Depreciation Entry Automatically,Apprendere automaticamente l'ammortamento dell'attivo,
Automatically Add Taxes and Charges from Item Tax Template,Aggiungi automaticamente imposte e addebiti dal modello imposta articolo,
Automatically Fetch Payment Terms,Recupera automaticamente i termini di pagamento,
-Show Inclusive Tax In Print,Mostra imposta inclusiva nella stampa,
Show Payment Schedule in Print,Mostra programma pagamenti in stampa,
Currency Exchange Settings,Impostazioni di cambio valuta,
Allow Stale Exchange Rates,Consenti tariffe scadenti,
Stale Days,Giorni Stalli,
Report Settings,Segnala Impostazioni,
Use Custom Cash Flow Format,Usa il formato del flusso di cassa personalizzato,
-Only select if you have setup Cash Flow Mapper documents,Seleziona solo se hai impostato i documenti del Flow Flow Mapper,
Allowed To Transact With,Autorizzato a effettuare transazioni con,
SWIFT number,Numero rapido,
Branch Code,Codice della filiale,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Gruppi clienti,
POS Field,Campo POS,
POS Item Group,POS Gruppo Articolo,
-[Select],[Seleziona],
Company Address,indirizzo aziendale,
Update Stock,Aggiornare Giacenza,
Ignore Pricing Rule,Ignora regola tariffaria,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Creare il Nome Fornitore da,
Default Supplier Group,Gruppo di fornitori predefinito,
Default Buying Price List,Prezzo di acquisto predefinito,
-Maintain same rate throughout purchase cycle,Mantenere la stessa tariffa per l'intero ciclo di acquisto,
-Allow Item to be added multiple times in a transaction,Consenti di aggiungere lo stesso articolo più volte in una transazione,
Backflush Raw Materials of Subcontract Based On,Backflush Materie prime di subappalto basati su,
Material Transferred for Subcontract,Materiale trasferito per conto lavoro,
Over Transfer Allowance (%),Assegno di trasferimento eccessivo (%),
@@ -5540,7 +5509,6 @@
Current Stock,Giacenza Corrente,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Per singolo fornitore,
-Supplier Detail,Dettaglio del Fornitore,
Link to Material Requests,Collegamento alle richieste di materiale,
Message for Supplier,Messaggio per il Fornitore,
Request for Quotation Item,Articolo della richiesta di offerta,
@@ -5706,7 +5674,7 @@
Lost Quotation,Preventivo Perso,
Interested,Interessati,
Converted,Convertito,
-Do Not Contact,Non Contattaci,
+Do Not Contact,Non Contattarci,
From Customer,Da Cliente,
Campaign Name,Nome Campagna,
Follow Up,Seguito,
@@ -6481,7 +6449,6 @@
Appraisal Template,Modello valutazione,
For Employee Name,Per Nome Dipendente,
Goals,Obiettivi,
-Calculate Total Score,Calcola il punteggio totale,
Total Score (Out of 5),Punteggio totale (i 5),
"Any other remarks, noteworthy effort that should go in the records.","Eventuali altre osservazioni, sforzo degno di nota che dovrebbe andare nelle registrazioni.",
Appraisal Goal,Obiettivo di valutazione,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Motivo per Lasciare,
Leave Encashed?,Lascia non incassati?,
Encashment Date,Data Incasso,
-Exit Interview Details,Uscire Dettagli Intervista,
-Held On,Tenutasi il,
-Reason for Resignation,Motivo della Dimissioni,
-Better Prospects,Prospettive Migliori,
-Health Concerns,Preoccupazioni per la salute,
New Workplace,Nuovo posto di lavoro,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Importo restituito,
@@ -6740,10 +6702,7 @@
Employee Settings,Impostazioni dipendente,
Retirement Age,Età di pensionamento,
Enter retirement age in years,Inserire l'età pensionabile in anni,
-Employee Records to be created by,Informazioni del dipendenti da creare a cura di,
-Employee record is created using selected field. ,Record dipendente viene creato utilizzando campo selezionato.,
Stop Birthday Reminders,Arresto Compleanno Promemoria,
-Don't send Employee Birthday Reminders,Non inviare Dipendente Birthday Reminders,
Expense Approver Mandatory In Expense Claim,Approvazione dell'approvazione obbligatoria nel rimborso spese,
Payroll Settings,Impostazioni Payroll,
Leave,Partire,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Lascia l'Approvatore Obbligatorio In Congedo,
Show Leaves Of All Department Members In Calendar,Mostra le foglie di tutti i membri del dipartimento nel calendario,
Auto Leave Encashment,Abbandono automatico,
-Restrict Backdated Leave Application,Limita l'applicazione congedo retrodatata,
Hiring Settings,Impostazioni di assunzione,
Check Vacancies On Job Offer Creation,Controlla i posti vacanti sulla creazione di offerte di lavoro,
Identification Document Type,Tipo di documento di identificazione,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Impostazioni di Produzione,
Raw Materials Consumption,Consumo di materie prime,
Allow Multiple Material Consumption,Consenti il consumo di più materiali,
-Allow multiple Material Consumption against a Work Order,Consentire il consumo di più materiali rispetto a un ordine di lavoro,
Backflush Raw Materials Based On,Backflush Materie prime calcolate in base a,
Material Transferred for Manufacture,Materiale trasferito per Produzione,
Capacity Planning,Pianificazione Capacità,
Disable Capacity Planning,Disabilita pianificazione della capacità,
Allow Overtime,Consenti Straodinario,
-Plan time logs outside Workstation Working Hours.,Pianificare i registri di tempo al di fuori dell'orario di lavoro Workstation.,
Allow Production on Holidays,Consenti produzione su Vacanze,
Capacity Planning For (Days),Pianificazione Capacità per (giorni),
-Try planning operations for X days in advance.,Provare le operazioni per X giorni in programma in anticipo.,
-Time Between Operations (in mins),Tempo tra le operazioni (in minuti),
-Default 10 mins,Predefinito 10 minuti,
Default Warehouses for Production,Magazzini predefiniti per la produzione,
Default Work In Progress Warehouse,Deposito di default per Work In Progress,
Default Finished Goods Warehouse,Deposito beni ultimati,
Default Scrap Warehouse,Magazzino rottami predefinito,
-Over Production for Sales and Work Order,Oltre la produzione per le vendite e l'ordine di lavoro,
Overproduction Percentage For Sales Order,Percentuale di sovrapproduzione per ordine di vendita,
Overproduction Percentage For Work Order,Percentuale di sovrapproduzione per ordine di lavoro,
Other Settings,Altre impostazioni,
Update BOM Cost Automatically,Aggiorna automaticamente il costo della BOM,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","L'aggiornamento dei costi BOM avviene automaticamente via Scheduler, in base all'ultimo tasso di valutazione / prezzo di listino / ultimo tasso di acquisto di materie prime.",
Material Request Plan Item,Articolo piano di richiesta materiale,
Material Request Type,Tipo di richiesta materiale,
Material Issue,Fornitura materiale,
@@ -7603,10 +7554,6 @@
Quality Goal,Obiettivo di qualità,
Monitoring Frequency,Frequenza di monitoraggio,
Weekday,giorno feriale,
-January-April-July-October,Gennaio-Aprile-Luglio-Ottobre,
-Revision and Revised On,Revisione e revisione,
-Revision,Revisione,
-Revised On,Revisionato il,
Objectives,obiettivi,
Quality Goal Objective,Obiettivo obiettivo di qualità,
Objective,Obbiettivo,
@@ -7619,7 +7566,6 @@
Processes,Processi,
Quality Procedure Process,Processo di procedura di qualità,
Process Description,Descrizione del processo,
-Child Procedure,Procedura per bambini,
Link existing Quality Procedure.,Collegare la procedura di qualità esistente.,
Additional Information,Informazioni aggiuntive,
Quality Review Objective,Obiettivo della revisione della qualità,
@@ -7787,15 +7733,9 @@
Default Customer Group,Gruppo Clienti Predefinito,
Default Territory,Territorio Predefinito,
Close Opportunity After Days,Chiudi Opportunità dopo giorni,
-Auto close Opportunity after 15 days,Chiudi automaticamente Opportunità dopo 15 giorni,
Default Quotation Validity Days,Giorni di validità delle quotazioni predefinite,
Sales Update Frequency,Frequenza di aggiornamento delle vendite,
-How often should project and company be updated based on Sales Transactions.,Con quale frequenza il progetto e la società devono essere aggiornati in base alle transazioni di vendita.,
Each Transaction,Ogni transazione,
-Allow user to edit Price List Rate in transactions,Consenti all'utente di modificare il prezzo di Listino nelle transazioni,
-Allow multiple Sales Orders against a Customer's Purchase Order,Consentire più ordini di vendita da un singolo ordine di un cliente,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Convalida il prezzo di vendita dell'articolo dal prezzo di acquisto o dal tasso di valutazione,
-Hide Customer's Tax Id from Sales Transactions,Nascondere P. IVA / Cod. Fiscale dei clienti dai documenti di vendita,
SMS Center,Centro SMS,
Send To,Invia a,
All Contact,Tutti i contatti,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Produttori utilizzati in Articoli,
Limited to 12 characters,Limitato a 12 caratteri,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Imposta magazzino,
-Sets 'For Warehouse' in each row of the Items table.,Imposta "Per magazzino" in ogni riga della tabella Articoli.,
-Requested For,richiesto Per,
Partially Ordered,Ordinato parzialmente,
Transferred,trasferito,
% Ordered,% Ordinato,
@@ -8407,24 +8344,14 @@
Default Stock UOM,UdM predefinita per Giacenza,
Sample Retention Warehouse,Magazzino di conservazione dei campioni,
Default Valuation Method,Metodo di valorizzazione predefinito,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Percentuale si è permesso di ricevere o consegnare di più contro la quantità ordinata. Per esempio: Se avete ordinato 100 unità. e il vostro assegno è 10% poi si è permesso di ricevere 110 unità.,
-Action if Quality inspection is not submitted,Azione in caso di mancata presentazione del controllo di qualità,
Show Barcode Field,Mostra campo del codice a barre,
Convert Item Description to Clean HTML,Converti la descrizione dell'oggetto in Pulisci HTML,
-Auto insert Price List rate if missing,Inserimento automatico tasso Listino se mancante,
Allow Negative Stock,Permetti Scorte Negative,
Automatically Set Serial Nos based on FIFO,Imposta automaticamente seriale Nos sulla base FIFO,
-Set Qty in Transactions based on Serial No Input,Imposta Qtà in Transazioni basate su Nessun input seriale,
Auto Material Request,Richiesta Automatica Materiale,
-Raise Material Request when stock reaches re-order level,Crea un Richiesta Materiale quando la scorta raggiunge il livello di riordino,
-Notify by Email on creation of automatic Material Request,Notifica tramite e-mail sulla creazione di Richiesta automatica Materiale,
Inter Warehouse Transfer Settings,Impostazioni trasferimento tra magazzino,
-Allow Material Transfer From Delivery Note and Sales Invoice,Consenti trasferimento materiale dalla bolla di consegna e dalla fattura di vendita,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Consenti trasferimento materiale dalla ricevuta di acquisto e dalla fattura di acquisto,
Freeze Stock Entries,Congela scorta voci,
Stock Frozen Upto,Giacenza Bloccate Fino,
-Freeze Stocks Older Than [Days],Congelare Stocks Older Than [ giorni],
-Role Allowed to edit frozen stock,Ruolo ammessi da modificare stock congelato,
Batch Identification,Identificazione lotti,
Use Naming Series,Utilizzare le serie di denominazione,
Naming Series Prefix,Prefisso serie di denominazione,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Acquisto Tendenze Receipt,
Purchase Register,Registro Acquisti,
Quotation Trends,Tendenze di preventivo,
-Quoted Item Comparison,Articolo Citato Confronto,
Received Items To Be Billed,Oggetti ricevuti da fatturare,
Qty to Order,Qtà da Ordinare,
Requested Items To Be Transferred,Voci si chiede il trasferimento,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Seleziona il magazzino per le richieste di materiale,
Transfer Materials For Warehouse {0},Trasferisci materiali per magazzino {0},
Production Plan Material Request Warehouse,Magazzino richiesta materiale piano di produzione,
-Set From Warehouse,Impostato dal magazzino,
-Source Warehouse (Material Transfer),Magazzino di origine (trasferimento di materiale),
Sets 'Source Warehouse' in each row of the items table.,Imposta "Magazzino di origine" in ogni riga della tabella degli articoli.,
Sets 'Target Warehouse' in each row of the items table.,Imposta "Magazzino di destinazione" in ogni riga della tabella degli articoli.,
Show Cancelled Entries,Mostra voci annullate,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Servizio ricevuto ma non fatturato,
Deferred Accounting Settings,Impostazioni di contabilità differita,
Book Deferred Entries Based On,Registra voci differite basate su,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Se si seleziona "Mesi", l'importo fisso verrà registrato come entrate o spese differite per ogni mese indipendentemente dal numero di giorni in un mese. Sarà ripartito proporzionalmente se le entrate o le spese differite non vengono registrate per un intero mese.",
Days,Giorni,
Months,Mesi,
Book Deferred Entries Via Journal Entry,Registrare registrazioni differite tramite registrazione prima nota,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Se questa opzione è deselezionata, verranno create voci GL dirette per la registrazione di entrate / uscite differite",
Submit Journal Entries,Invia voci di diario,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Se questa opzione è deselezionata, le registrazioni a giornale verranno salvate in stato Bozza e dovranno essere inviate manualmente",
Enable Distributed Cost Center,Abilita centro di costo distribuito,
@@ -8901,8 +8823,6 @@
Is Inter State,È Inter State,
Purchase Details,Dettagli d'acquisto,
Depreciation Posting Date,Data di registrazione dell'ammortamento,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Ordine di acquisto richiesto per la creazione della fattura di acquisto e della ricevuta,
-Purchase Receipt Required for Purchase Invoice Creation,Ricevuta di acquisto richiesta per la creazione della fattura di acquisto,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Per impostazione predefinita, il nome del fornitore è impostato in base al nome del fornitore immesso. Se desideri che i fornitori siano nominati da un",
choose the 'Naming Series' option.,scegli l'opzione "Serie di nomi".,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Configurare il listino prezzi predefinito quando si crea una nuova transazione di acquisto. I prezzi degli articoli verranno recuperati da questo listino prezzi.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,È una componente dell'imposta sul reddito,
Component properties and references ,Proprietà e riferimenti dei componenti,
Additional Salary ,Stipendio aggiuntivo,
-Condtion and formula,Condizione e formula,
Unmarked days,Giorni non contrassegnati,
Absent Days,Giorni assenti,
Conditions and Formula variable and example,Condizioni e variabile di formula ed esempio,
Feedback By,Feedback di,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Sezione Produzione,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Ordine cliente richiesto per la creazione di fatture di vendita e bolle di consegna,
-Delivery Note Required for Sales Invoice Creation,Bolla di consegna richiesta per la creazione della fattura di vendita,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Per impostazione predefinita, il nome del cliente è impostato in base al nome completo inserito. Se desideri che i clienti siano nominati da un",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Configurare il listino prezzi predefinito quando si crea una nuova transazione di vendita. I prezzi degli articoli verranno recuperati da questo listino prezzi.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Se questa opzione è configurata "Sì", ERPNext ti impedirà di creare una fattura di vendita o una nota di consegna senza creare prima un ordine di vendita. Questa configurazione può essere sovrascritta per un particolare cliente abilitando la casella di spunta "Consenti creazione fattura di vendita senza ordine di vendita" nell'anagrafica cliente.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} è stato aggiunto correttamente a tutti gli argomenti selezionati.,
Topics updated,Argomenti aggiornati,
Academic Term and Program,Termine accademico e programma,
-Last Stock Transaction for item {0} was on {1}.,L'ultima transazione di magazzino per l'articolo {0} è avvenuta in data {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Le transazioni di magazzino per l'articolo {0} non possono essere registrate prima di questo orario.,
Please remove this item and try to submit again or update the posting time.,Rimuovi questo elemento e prova a inviarlo di nuovo o aggiorna l'orario di pubblicazione.,
Failed to Authenticate the API key.,Impossibile autenticare la chiave API.,
Invalid Credentials,Credenziali non valide,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Controlla l'ID del tuo cliente Plaid e i valori segreti,
Bank transaction creation error,Errore di creazione della transazione bancaria,
Unit of Measurement,Unità di misura,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Riga n. {}: La percentuale di vendita dell'articolo {} è inferiore alla relativa {}. Il tasso di vendita dovrebbe essere di almeno {},
Fiscal Year {0} Does Not Exist,L'anno fiscale {0} non esiste,
Row # {0}: Returned Item {1} does not exist in {2} {3},Riga n. {0}: l'articolo restituito {1} non esiste in {2} {3},
Valuation type charges can not be marked as Inclusive,Gli addebiti del tipo di valutazione non possono essere contrassegnati come inclusivi,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Il tempo di risposta per la {0} priorità nella riga {1} non può essere maggiore del tempo di risoluzione.,
{0} is not enabled in {1},{0} non è abilitato in {1},
Group by Material Request,Raggruppa per richiesta materiale,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Riga {0}: per il fornitore {0}, l'indirizzo e-mail è obbligatorio per inviare e-mail",
Email Sent to Supplier {0},Email inviata al fornitore {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","L'accesso alla richiesta di preventivo dal portale è disabilitato. Per consentire l'accesso, abilitalo nelle impostazioni del portale.",
Supplier Quotation {0} Created,Offerta fornitore {0} creata,
Valid till Date cannot be before Transaction Date,La data valida fino alla data non può essere precedente alla data della transazione,
+Unlink Advance Payment on Cancellation of Order,Scollegare il pagamento anticipato all'annullamento dell'ordine,
+"Simple Python Expression, Example: territory != 'All Territories'","Espressione Python semplice, esempio: territorio! = 'Tutti i territori'",
+Sales Contributions and Incentives,Contributi alle vendite e incentivi,
+Sourced by Supplier,Fornito dal fornitore,
+Total weightage assigned should be 100%.<br>It is {0},Il peso totale assegnato dovrebbe essere del 100%.<br> È {0},
+Account {0} exists in parent company {1}.,L'account {0} esiste nella società madre {1}.,
+"To overrule this, enable '{0}' in company {1}","Per annullare questa impostazione, abilita "{0}" nell'azienda {1}",
+Invalid condition expression,Espressione della condizione non valida,
+Please Select a Company First,Seleziona prima una società,
+Please Select Both Company and Party Type First,Seleziona prima sia la società che il tipo di partito,
+Provide the invoice portion in percent,Fornisci la parte della fattura in percentuale,
+Give number of days according to prior selection,Indicare il numero di giorni in base alla selezione precedente,
+Email Details,Dettagli email,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Seleziona un saluto per il destinatario. Ad esempio, signor, signora, ecc.",
+Preview Email,Anteprima email,
+Please select a Supplier,Seleziona un fornitore,
+Supplier Lead Time (days),Tempo di consegna del fornitore (giorni),
+"Home, Work, etc.","Casa, lavoro, ecc.",
+Exit Interview Held On,Esci Intervista trattenuta,
+Condition and formula,Condizione e formula,
+Sets 'Target Warehouse' in each row of the Items table.,Imposta "Magazzino di destinazione" in ogni riga della tabella Articoli.,
+Sets 'Source Warehouse' in each row of the Items table.,Imposta "Magazzino di origine" in ogni riga della tabella Articoli.,
+POS Register,Registro POS,
+"Can not filter based on POS Profile, if grouped by POS Profile","Impossibile filtrare in base al profilo POS, se raggruppato per profilo POS",
+"Can not filter based on Customer, if grouped by Customer","Non è possibile filtrare in base al cliente, se raggruppato per cliente",
+"Can not filter based on Cashier, if grouped by Cashier","Non è possibile filtrare in base alla Cassa, se raggruppata per Cassa",
+Payment Method,Metodo di pagamento,
+"Can not filter based on Payment Method, if grouped by Payment Method","Non è possibile filtrare in base al metodo di pagamento, se raggruppato per metodo di pagamento",
+Supplier Quotation Comparison,Confronto delle offerte dei fornitori,
+Price per Unit (Stock UOM),Prezzo per unità (Stock UM),
+Group by Supplier,Gruppo per fornitore,
+Group by Item,Raggruppa per articolo,
+Remember to set {field_label}. It is required by {regulation}.,Ricordati di impostare {field_label}. È richiesto dal {regolamento}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},La data di iscrizione non può essere antecedente alla data di inizio dell'anno accademico {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},La data di iscrizione non può essere successiva alla data di fine del periodo accademico {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},La data di iscrizione non può essere precedente alla data di inizio del periodo accademico {0},
+Future Posting Not Allowed,Pubblicazione futura non consentita,
+"To enable Capital Work in Progress Accounting, ","Per abilitare la contabilità dei lavori in corso,",
+you must select Capital Work in Progress Account in accounts table,è necessario selezionare Conto lavori in corso nella tabella dei conti,
+You can also set default CWIP account in Company {},Puoi anche impostare un account CWIP predefinito in Azienda {},
+The Request for Quotation can be accessed by clicking on the following button,È possibile accedere alla Richiesta di offerta facendo clic sul pulsante seguente,
+Regards,Saluti,
+Please click on the following button to set your new password,Fare clic sul pulsante seguente per impostare la nuova password,
+Update Password,Aggiorna password,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Riga n. {}: La percentuale di vendita dell'articolo {} è inferiore alla relativa {}. La vendita di {} dovrebbe essere almeno {},
+You can alternatively disable selling price validation in {} to bypass this validation.,"In alternativa, puoi disabilitare la convalida del prezzo di vendita in {} per ignorare questa convalida.",
+Invalid Selling Price,Prezzo di vendita non valido,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,L'indirizzo deve essere collegato a una società. Aggiungi una riga per Azienda nella tabella Collegamenti.,
+Company Not Linked,Società non collegata,
+Import Chart of Accounts from CSV / Excel files,Importa piano dei conti da file CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',La quantità completata non può essere maggiore di "Qtà da produrre",
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Riga {0}: per il fornitore {1}, l'indirizzo e-mail è richiesto per inviare un'e-mail",
+"If enabled, the system will post accounting entries for inventory automatically","Se abilitato, il sistema registrerà automaticamente le voci contabili per l'inventario",
+Accounts Frozen Till Date,Conti congelati fino alla data,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Le registrazioni contabili sono congelate fino a questa data. Nessuno può creare o modificare voci tranne gli utenti con il ruolo specificato di seguito,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Ruolo consentito per impostare account bloccati e modificare voci bloccate,
+Address used to determine Tax Category in transactions,Indirizzo utilizzato per determinare la categoria fiscale nelle transazioni,
+"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 ","La percentuale che puoi fatturare di più rispetto all'importo ordinato. Ad esempio, se il valore dell'ordine è $ 100 per un articolo e la tolleranza è impostata sul 10%, allora puoi fatturare fino a $ 110",
+This role is allowed to submit transactions that exceed credit limits,Questo ruolo è autorizzato a inviare transazioni che superano i limiti di credito,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Se si seleziona "Mesi", verrà registrato un importo fisso come spesa o ricavo differito per ogni mese indipendentemente dal numero di giorni in un mese. Verrà ripartito se le entrate o le spese differite non vengono registrate per un intero mese",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Se questa opzione è deselezionata, verranno create voci GL dirette per contabilizzare entrate o spese differite",
+Show Inclusive Tax in Print,Mostra IVA inclusiva in stampa,
+Only select this if you have set up the Cash Flow Mapper documents,Selezionalo solo se hai impostato i documenti Cash Flow Mapper,
+Payment Channel,Canale di pagamento,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,È necessario un ordine di acquisto per la creazione di fatture di acquisto e ricevute?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,È richiesta la ricevuta di acquisto per la creazione della fattura di acquisto?,
+Maintain Same Rate Throughout the Purchase Cycle,Mantieni la stessa tariffa per tutto il ciclo di acquisto,
+Allow Item To Be Added Multiple Times in a Transaction,Consenti all'elemento di essere aggiunto più volte in una transazione,
+Suppliers,Fornitori,
+Send Emails to Suppliers,Invia email ai fornitori,
+Select a Supplier,Seleziona un fornitore,
+Cannot mark attendance for future dates.,Impossibile contrassegnare la partecipazione per date future.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Vuoi aggiornare le presenze?<br> Presente: {0}<br> Assente: {1},
+Mpesa Settings,Impostazioni Mpesa,
+Initiator Name,Nome iniziatore,
+Till Number,Fino al numero,
+Sandbox,Sandbox,
+ Online PassKey,PassKey in linea,
+Security Credential,Credenziali di sicurezza,
+Get Account Balance,Ottieni il saldo del conto,
+Please set the initiator name and the security credential,Imposta il nome dell'iniziatore e le credenziali di sicurezza,
+Inpatient Medication Entry,Ingresso per farmaci ospedalieri,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Codice articolo (farmaco),
+Medication Orders,Ordini di farmaci,
+Get Pending Medication Orders,Ottieni ordini di farmaci in sospeso,
+Inpatient Medication Orders,Ordini di farmaci ospedalieri,
+Medication Warehouse,Magazzino dei farmaci,
+Warehouse from where medication stock should be consumed,Magazzino da cui consumare le scorte di farmaci,
+Fetching Pending Medication Orders,Recupero di ordini di farmaci in sospeso,
+Inpatient Medication Entry Detail,Dettagli immissione farmaci ospedalieri,
+Medication Details,Dettagli sui farmaci,
+Drug Code,Codice dei farmaci,
+Drug Name,Nome del farmaco,
+Against Inpatient Medication Order,Contro l'ordinanza di farmaci ospedalieri,
+Against Inpatient Medication Order Entry,Contro l'entrata dell'ordine di farmaci ospedalieri,
+Inpatient Medication Order,Ordine di farmaci ospedalieri,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Ordini totali,
+Completed Orders,Ordini completati,
+Add Medication Orders,Aggiungi ordini di farmaci,
+Adding Order Entries,Aggiunta di voci di ordine,
+{0} medication orders completed,{0} ordini di farmaci completati,
+{0} medication order completed,{0} ordine del farmaco completato,
+Inpatient Medication Order Entry,Inserimento ordine di farmaci ospedalieri,
+Is Order Completed,L'ordine è stato completato,
+Employee Records to Be Created By,Documenti dei dipendenti da creare,
+Employee records are created using the selected field,I record dei dipendenti vengono creati utilizzando il campo selezionato,
+Don't send employee birthday reminders,Non inviare promemoria di compleanno dei dipendenti,
+Restrict Backdated Leave Applications,Limita le domande di uscita retrodatate,
+Sequence ID,ID sequenza,
+Sequence Id,ID sequenza,
+Allow multiple material consumptions against a Work Order,Consenti più consumi di materiale rispetto a un ordine di lavoro,
+Plan time logs outside Workstation working hours,Pianifica i registri orari al di fuori dell'orario di lavoro della workstation,
+Plan operations X days in advance,Pianifica le operazioni con X giorni di anticipo,
+Time Between Operations (Mins),Tempo tra le operazioni (minuti),
+Default: 10 mins,Predefinito: 10 min,
+Overproduction for Sales and Work Order,Sovrapproduzione per vendita e ordine di lavoro,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Aggiorna automaticamente il costo della distinta base tramite il pianificatore, in base all'ultimo tasso di valutazione / tasso di listino / ultimo tasso di acquisto delle materie prime",
+Purchase Order already created for all Sales Order items,Ordine di acquisto già creato per tutti gli articoli dell'ordine di vendita,
+Select Items,Seleziona elementi,
+Against Default Supplier,Contro il fornitore predefinito,
+Auto close Opportunity after the no. of days mentioned above,Opportunità di chiusura automatica dopo il n. dei giorni sopra menzionati,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,L'ordine di vendita è necessario per la creazione di fatture di vendita e bolle di consegna?,
+Is Delivery Note Required for Sales Invoice Creation?,La bolla di consegna è necessaria per la creazione della fattura di vendita?,
+How often should Project and Company be updated based on Sales Transactions?,Con che frequenza è necessario aggiornare il progetto e la società in base alle transazioni di vendita?,
+Allow User to Edit Price List Rate in Transactions,Consenti all'utente di modificare il tasso di listino nelle transazioni,
+Allow Item to Be Added Multiple Times in a Transaction,Consenti all'elemento di essere aggiunto più volte in una transazione,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Consenti più ordini di vendita a fronte di un ordine di acquisto del cliente,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Convalida del prezzo di vendita dell'articolo rispetto al tasso di acquisto o al tasso di valutazione,
+Hide Customer's Tax ID from Sales Transactions,Nascondi l'ID fiscale del cliente dalle transazioni di vendita,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","La percentuale che ti è consentito ricevere o consegnare di più rispetto alla quantità ordinata. Ad esempio, se hai ordinato 100 unità e la tua indennità è del 10%, allora puoi ricevere 110 unità.",
+Action If Quality Inspection Is Not Submitted,Azione se l'ispezione di qualità non viene inviata,
+Auto Insert Price List Rate If Missing,Inserimento automatico del tasso di listino se mancante,
+Automatically Set Serial Nos Based on FIFO,Imposta automaticamente i numeri di serie in base a FIFO,
+Set Qty in Transactions Based on Serial No Input,Imposta la quantità nelle transazioni in base al numero di serie non immesso,
+Raise Material Request When Stock Reaches Re-order Level,Aumenta la richiesta di materiale quando lo stock raggiunge il livello di riordino,
+Notify by Email on Creation of Automatic Material Request,Notifica tramite e-mail alla creazione di una richiesta di materiale automatica,
+Allow Material Transfer from Delivery Note to Sales Invoice,Consenti trasferimento materiale dalla nota di consegna alla fattura di vendita,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Consenti trasferimento materiale dalla ricevuta d'acquisto alla fattura d'acquisto,
+Freeze Stocks Older Than (Days),Blocca scorte più vecchie di (giorni),
+Role Allowed to Edit Frozen Stock,Ruolo consentito per modificare stock congelati,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,L'importo non allocato della voce di pagamento {0} è maggiore dell'importo non allocato della transazione bancaria,
+Payment Received,Pagamento ricevuto,
+Attendance cannot be marked outside of Academic Year {0},La frequenza non può essere contrassegnata al di fuori dell'anno accademico {0},
+Student is already enrolled via Course Enrollment {0},Lo studente è già iscritto tramite l'iscrizione al corso {0},
+Attendance cannot be marked for future dates.,La partecipazione non può essere contrassegnata per date future.,
+Please add programs to enable admission application.,Si prega di aggiungere programmi per abilitare la domanda di ammissione.,
+The following employees are currently still reporting to {0}:,I seguenti dipendenti attualmente stanno ancora segnalando a {0}:,
+Please make sure the employees above report to another Active employee.,Assicurati che i dipendenti di cui sopra riferiscano a un altro dipendente attivo.,
+Cannot Relieve Employee,Non posso alleviare il dipendente,
+Please enter {0},Inserisci {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Seleziona un altro metodo di pagamento. Mpesa non supporta le transazioni nella valuta "{0}",
+Transaction Error,Errore di transazione,
+Mpesa Express Transaction Error,Errore di transazione Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Problema rilevato con la configurazione di Mpesa, controlla i log degli errori per maggiori dettagli",
+Mpesa Express Error,Errore di Mpesa Express,
+Account Balance Processing Error,Errore di elaborazione del saldo del conto,
+Please check your configuration and try again,Controlla la configurazione e riprova,
+Mpesa Account Balance Processing Error,Errore di elaborazione del saldo del conto Mpesa,
+Balance Details,Dettagli del saldo,
+Current Balance,Bilancio corrente,
+Available Balance,saldo disponibile,
+Reserved Balance,Saldo riservato,
+Uncleared Balance,Equilibrio non chiarito,
+Payment related to {0} is not completed,Il pagamento relativo a {0} non è stato completato,
+Row #{}: Item Code: {} is not available under warehouse {}.,Riga n. {}: Codice articolo: {} non è disponibile in magazzino {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Riga n. {}: Quantità di stock non sufficiente per il codice articolo: {} in magazzino {}. Quantità disponibile {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Riga # {}: selezionare un numero di serie e un batch rispetto all'articolo: {} o rimuoverlo per completare la transazione.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Riga # {}: nessun numero di serie selezionato per l'articolo: {}. Seleziona uno o rimuovilo per completare la transazione.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Riga n. {}: Nessun batch selezionato per l'elemento: {}. Seleziona un batch o rimuovilo per completare la transazione.,
+Payment amount cannot be less than or equal to 0,L'importo del pagamento non può essere inferiore o uguale a 0,
+Please enter the phone number first,Si prega di inserire prima il numero di telefono,
+Row #{}: {} {} does not exist.,Riga # {}: {} {} non esiste.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Riga n. {0}: {1} è richiesta per creare le {2} fatture di apertura,
+You had {} errors while creating opening invoices. Check {} for more details,Hai avuto {} errori durante la creazione delle fatture di apertura. Controlla {} per maggiori dettagli,
+Error Occured,C'è stato un'errore,
+Opening Invoice Creation In Progress,Creazione fattura di apertura in corso,
+Creating {} out of {} {},Creazione di {} su {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Numero di serie: {0}) non può essere utilizzato poiché è riservato per completare l'ordine di vendita {1}.,
+Item {0} {1},Articolo {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,L'ultima transazione di magazzino per l'articolo {0} in magazzino {1} è stata in data {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Le transazioni di magazzino per l'articolo {0} in magazzino {1} non possono essere registrate prima di questo orario.,
+Posting future stock transactions are not allowed due to Immutable Ledger,La registrazione di transazioni di stock future non è consentita a causa di Immutable Ledger,
+A BOM with name {0} already exists for item {1}.,Esiste già una distinta base con il nome {0} per l'articolo {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Hai rinominato l'elemento? Si prega di contattare l'amministratore / supporto tecnico,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Alla riga # {0}: l'ID sequenza {1} non può essere inferiore all'ID sequenza di righe precedente {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) deve essere uguale a {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, completa l'operazione {1} prima dell'operazione {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Non è possibile garantire la consegna tramite numero di serie poiché l'articolo {0} viene aggiunto con e senza garantire la consegna tramite numero di serie,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,L'articolo {0} non ha un numero di serie. Solo gli articoli con numero di serie possono avere la consegna basata sul numero di serie,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Nessuna distinta base attiva trovata per l'articolo {0}. La consegna tramite numero di serie non può essere garantita,
+No pending medication orders found for selected criteria,Nessun ordine di farmaci in sospeso trovato per i criteri selezionati,
+From Date cannot be after the current date.,Dalla data non può essere successiva alla data corrente.,
+To Date cannot be after the current date.,Alla data non può essere successiva alla data corrente.,
+From Time cannot be after the current time.,Dall'ora non può essere successivo all'ora corrente.,
+To Time cannot be after the current time.,L'ora non può essere successiva all'ora corrente.,
+Stock Entry {0} created and ,Stock Entry {0} creato e,
+Inpatient Medication Orders updated successfully,Ordini di farmaci ospedalieri aggiornati correttamente,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Riga {0}: impossibile creare una voce di farmaco ospedaliero a fronte di un ordine di farmaci ospedalieri annullato {1},
+Row {0}: This Medication Order is already marked as completed,Riga {0}: questo ordine di farmaci è già contrassegnato come completato,
+Quantity not available for {0} in warehouse {1},Quantità non disponibile per {0} in magazzino {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Abilita Consenti stock negativo in Impostazioni scorte o crea immissione scorte per procedere.,
+No Inpatient Record found against patient {0},Nessun record di degenza trovato per il paziente {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Esiste già un ordine per farmaci ospedalieri {0} contro l'incontro con il paziente {1}.,
+Allow In Returns,Consenti resi,
+Hide Unavailable Items,Nascondi elementi non disponibili,
+Apply Discount on Discounted Rate,Applica lo sconto sulla tariffa scontata,
+Therapy Plan Template,Modello di piano terapeutico,
+Fetching Template Details,Recupero dei dettagli del modello,
+Linked Item Details,Dettagli articolo collegato,
+Therapy Types,Tipi di terapia,
+Therapy Plan Template Detail,Dettaglio del modello del piano terapeutico,
+Non Conformance,Non conformità,
+Process Owner,Proprietario del processo,
+Corrective Action,Azione correttiva,
+Preventive Action,Azione preventiva,
+Problem,Problema,
+Responsible,Responsabile,
+Completion By,Completamento da,
+Process Owner Full Name,Nome completo del proprietario del processo,
+Right Index,Indice destro,
+Left Index,Indice sinistro,
+Sub Procedure,Procedura secondaria,
+Passed,Passato,
+Print Receipt,Stampa ricevuta,
+Edit Receipt,Modifica ricevuta,
+Focus on search input,Concentrati sull'input di ricerca,
+Focus on Item Group filter,Focus sul filtro Gruppo di articoli,
+Checkout Order / Submit Order / New Order,Ordine di pagamento / Invia ordine / Nuovo ordine,
+Add Order Discount,Aggiungi sconto ordine,
+Item Code: {0} is not available under warehouse {1}.,Codice articolo: {0} non è disponibile in magazzino {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Numeri di serie non disponibili per l'articolo {0} in magazzino {1}. Prova a cambiare magazzino.,
+Fetched only {0} available serial numbers.,Sono stati recuperati solo {0} numeri di serie disponibili.,
+Switch Between Payment Modes,Passa da una modalità di pagamento all'altra,
+Enter {0} amount.,Inserisci {0} importo.,
+You don't have enough points to redeem.,Non hai abbastanza punti da riscattare.,
+You can redeem upto {0}.,Puoi riscattare fino a {0}.,
+Enter amount to be redeemed.,Inserisci l'importo da riscattare.,
+You cannot redeem more than {0}.,Non puoi riscattare più di {0}.,
+Open Form View,Apri la visualizzazione modulo,
+POS invoice {0} created succesfully,Fattura POS {0} creata con successo,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Quantità in stock non sufficiente per Codice articolo: {0} in magazzino {1}. Quantità disponibile {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Numero di serie: {0} è già stato trasferito in un'altra fattura POS.,
+Balance Serial No,Numero di serie della bilancia,
+Warehouse: {0} does not belong to {1},Magazzino: {0} non appartiene a {1},
+Please select batches for batched item {0},Seleziona batch per articolo in batch {0},
+Please select quantity on row {0},Seleziona la quantità nella riga {0},
+Please enter serial numbers for serialized item {0},Inserisci i numeri di serie per l'articolo con numero di serie {0},
+Batch {0} already selected.,Batch {0} già selezionato.,
+Please select a warehouse to get available quantities,Seleziona un magazzino per ottenere le quantità disponibili,
+"For transfer from source, selected quantity cannot be greater than available quantity","Per il trasferimento dall'origine, la quantità selezionata non può essere maggiore della quantità disponibile",
+Cannot find Item with this Barcode,Impossibile trovare l'articolo con questo codice a barre,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} è obbligatorio. Forse il record di cambio valuta non è stato creato da {1} a {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} ha inviato risorse ad esso collegate. È necessario annullare le risorse per creare un reso di acquisto.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Impossibile annullare questo documento poiché è collegato alla risorsa inviata {0}. Annullalo per continuare.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Riga # {}: il numero di serie {} è già stato trasferito in un'altra fattura POS. Selezionare un numero di serie valido,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Riga n. {}: I numeri di serie {} sono già stati trasferiti in un'altra fattura POS. Selezionare un numero di serie valido,
+Item Unavailable,Articolo non disponibile,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Riga n. {}: Il numero di serie {} non può essere restituito poiché non è stato oggetto di transazione nella fattura originale {},
+Please set default Cash or Bank account in Mode of Payment {},Imposta il conto corrente o il conto bancario predefinito in Modalità di pagamento {},
+Please set default Cash or Bank account in Mode of Payments {},Imposta il conto corrente o il conto bancario predefinito in Modalità di pagamento {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Assicurati che il conto {} sia un conto di bilancio. È possibile modificare il conto principale in un conto di bilancio o selezionare un conto diverso.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Assicurati che il conto {} sia un conto pagabile. Cambia il tipo di conto in Pagabile o seleziona un conto diverso.,
+Row {}: Expense Head changed to {} ,Riga {}: Intestazione spese modificata in {},
+because account {} is not linked to warehouse {} ,perché l'account {} non è collegato al magazzino {},
+or it is not the default inventory account,oppure non è l'account inventario predefinito,
+Expense Head Changed,Testa di spesa modificata,
+because expense is booked against this account in Purchase Receipt {},perché la spesa è registrata a fronte di questo account nella ricevuta di acquisto {},
+as no Purchase Receipt is created against Item {}. ,poiché non viene creata alcuna ricevuta di acquisto per l'articolo {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Questa operazione viene eseguita per gestire la contabilità dei casi quando la ricevuta di acquisto viene creata dopo la fattura di acquisto,
+Purchase Order Required for item {},Ordine di acquisto richiesto per l'articolo {},
+To submit the invoice without purchase order please set {} ,"Per inviare la fattura senza ordine di acquisto, impostare {}",
+as {} in {},come in {},
+Mandatory Purchase Order,Ordine di acquisto obbligatorio,
+Purchase Receipt Required for item {},Ricevuta di acquisto richiesta per articolo {},
+To submit the invoice without purchase receipt please set {} ,"Per inviare la fattura senza ricevuta di acquisto, impostare {}",
+Mandatory Purchase Receipt,Ricevuta d'acquisto obbligatoria,
+POS Profile {} does not belongs to company {},Il profilo POS {} non appartiene all'azienda {},
+User {} is disabled. Please select valid user/cashier,L'utente {} è disabilitato. Seleziona un utente / cassiere valido,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Riga n. {}: La fattura originale {} della fattura di reso {} è {}.,
+Original invoice should be consolidated before or along with the return invoice.,La fattura originale deve essere consolidata prima o insieme alla fattura di reso.,
+You can add original invoice {} manually to proceed.,Puoi aggiungere manualmente la fattura originale {} per procedere.,
+Please ensure {} account is a Balance Sheet account. ,Assicurati che il conto {} sia un conto di bilancio.,
+You can change the parent account to a Balance Sheet account or select a different account.,È possibile modificare il conto principale in un conto di bilancio o selezionare un conto diverso.,
+Please ensure {} account is a Receivable account. ,Assicurati che il conto {} sia un conto clienti.,
+Change the account type to Receivable or select a different account.,Modificare il tipo di conto in Crediti o selezionare un conto diverso.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} non può essere annullato poiché i punti fedeltà guadagnati sono stati riscattati. Per prima cosa annulla il {} No {},
+already exists,esiste già,
+POS Closing Entry {} against {} between selected period,Voce di chiusura POS {} contro {} tra il periodo selezionato,
+POS Invoice is {},La fattura POS è {},
+POS Profile doesn't matches {},Il profilo POS non corrisponde a {},
+POS Invoice is not {},La fattura POS non è {},
+POS Invoice isn't created by user {},La fattura POS non è stata creata dall'utente {},
+Row #{}: {},Riga n. {}: {},
+Invalid POS Invoices,Fatture POS non valide,
+Please add the account to root level Company - {},Aggiungi l'account all'Azienda di livello root - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Durante la creazione dell'account per l'azienda figlia {0}, account genitore {1} non trovato. Si prega di creare l'account genitore nel corrispondente COA",
+Account Not Found,Account non trovato,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Durante la creazione dell'account per la società figlia {0}, l'account principale {1} è stato trovato come conto contabile.",
+Please convert the parent account in corresponding child company to a group account.,Converti l'account genitore nella corrispondente azienda figlia in un account di gruppo.,
+Invalid Parent Account,Account genitore non valido,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Rinominarlo è consentito solo tramite la società madre {0}, per evitare mancate corrispondenze.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Se si {0} {1} la quantità dell'articolo {2}, lo schema {3} verrà applicato all'articolo.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Se {0} {1} vali un articolo {2}, lo schema {3} verrà applicato all'elemento.",
+"As the field {0} is enabled, the field {1} is mandatory.","Poiché il campo {0} è abilitato, il campo {1} è obbligatorio.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Poiché il campo {0} è abilitato, il valore del campo {1} dovrebbe essere maggiore di 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Impossibile consegnare il numero di serie {0} dell'articolo {1} poiché è riservato per completare l'ordine di vendita {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","L'ordine di vendita {0} ha una prenotazione per l'articolo {1}, puoi solo consegnare prenotato {1} contro {0}.",
+{0} Serial No {1} cannot be delivered,{0} Numero di serie {1} non può essere consegnato,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Riga {0}: l'articolo in conto lavoro è obbligatorio per la materia prima {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Poiché sono disponibili materie prime sufficienti, la richiesta di materiale non è richiesta per il magazzino {0}.",
+" If you still want to proceed, please enable {0}.","Se desideri comunque procedere, abilita {0}.",
+The item referenced by {0} - {1} is already invoiced,L'articolo a cui fa riferimento {0} - {1} è già fatturato,
+Therapy Session overlaps with {0},La sessione di terapia si sovrappone a {0},
+Therapy Sessions Overlapping,Sessioni di terapia sovrapposte,
+Therapy Plans,Piani terapeutici,
+"Item Code, warehouse, quantity are required on row {0}","Codice articolo, magazzino e quantità sono obbligatori nella riga {0}",
+Get Items from Material Requests against this Supplier,Ottieni articoli da richieste di materiale contro questo fornitore,
+Enable European Access,Consentire l'accesso europeo,
+Creating Purchase Order ...,Creazione dell'ordine di acquisto ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Seleziona un fornitore dai fornitori predefiniti degli articoli seguenti. Alla selezione, verrà effettuato un Ordine di acquisto solo per gli articoli appartenenti al Fornitore selezionato.",
+Row #{}: You must select {} serial numbers for item {}.,Riga # {}: è necessario selezionare i {} numeri di serie per l'articolo {}.,
diff --git a/erpnext/translations/ja.csv b/erpnext/translations/ja.csv
index b2e6b75..6e2eaae 100644
--- a/erpnext/translations/ja.csv
+++ b/erpnext/translations/ja.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},「実際」タイプの税は行{0}内のアイテム額に含めることはできません,
Add,追加,
Add / Edit Prices,価格の追加/編集,
-Add All Suppliers,すべてのサプライヤーを追加,
Add Comment,コメント追加,
Add Customers,顧客を追加する,
Add Employees,従業員追加,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',カテゴリが「評価」または「Vaulationと合計」のためのものであるときに控除することはできません。,
"Cannot delete Serial No {0}, as it is used in stock transactions",在庫取引で使用されているため、シリアル番号{0}を削除することはできません,
Cannot enroll more than {0} students for this student group.,この生徒グループには {0} 以上の生徒を登録することはできません,
-Cannot find Item with this barcode,このバーコードの商品が見つかりません,
Cannot find active Leave Period,有効期間を見つけることができません,
Cannot produce more Item {0} than Sales Order quantity {1},受注数{1}より多くのアイテム{0}を製造することはできません,
Cannot promote Employee with status Left,ステータスが「左」の従業員を昇格できません,
Cannot refer row number greater than or equal to current row number for this Charge type,この請求タイプの行数以上の行番号を参照することはできません,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,最初の行には、「前行の数量」「前行の合計」などの料金タイプを選択することはできません,
-Cannot set a received RFQ to No Quote,受信RFQをいいえ引用符に設定できません,
Cannot set as Lost as Sales Order is made.,受注が作成されているため、失注にできません,
Cannot set authorization on basis of Discount for {0},{0}の割引に基づく承認を設定することはできません,
Cannot set multiple Item Defaults for a company.,ある企業に対して複数の項目デフォルトを設定することはできません。,
@@ -521,7 +518,6 @@
Chargeble,有料,
Charges are updated in Purchase Receipt against each item,料金は、各アイテムに対して、領収書上で更新されます,
"Charges will be distributed proportionately based on item qty or amount, as per your selection",料金は、選択によって、アイテムの数量または量に基づいて均等に分割されます,
-Chart Of Accounts,勘定科目表,
Chart of Cost Centers,コストセンターの表,
Check all,すべてチェック,
Checkout,チェックアウト,
@@ -581,7 +577,6 @@
Compensatory Off,代償オフ,
Compensatory leave request days not in valid holidays,有効休暇ではない補償休暇申請日,
Complaint,苦情,
-Completed Qty can not be greater than 'Qty to Manufacture',完成した数量は「製造数量」より大きくすることはできません,
Completion Date,完了日,
Computer,コンピュータ,
Condition,条件,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.",日次・週次・月次のメールダイジェストを作成・管理,
Create customer quotes,顧客の引用符を作成します。,
Create rules to restrict transactions based on values.,値に基づいて取引を制限するルールを作成,
-Created By,によって作成された,
Created {0} scorecards for {1} between: ,{1}の間に{0}スコアカードが作成されました:,
Creating Company and Importing Chart of Accounts,会社の作成と勘定コード表のインポート,
Creating Fees,手数料の作成,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,従業員譲渡は譲渡日前に提出することはできません。,
Employee cannot report to himself.,従業員は自分自身に報告することはできません。,
Employee relieved on {0} must be set as 'Left',{0}から取り除かれた従業員は「退職」に設定されなければなりません,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,次の従業員が現在この従業員に報告しているため、従業員のステータスを「左」に設定することはできません。,
Employee {0} already submited an apllication {1} for the payroll period {2},給与計算期間{2}の従業員{0}はすでに申請{1}を提出しています,
Employee {0} has already applied for {1} between {2} and {3} : ,従業員{0}は{2}から{3}の間で既に{1}を申請しています:,
Employee {0} has no maximum benefit amount,従業員{0}には最大給付額はありません,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,行{0}の場合:計画数量を入力してください,
"For {0}, only credit accounts can be linked against another debit entry",{0}には、別の借方エントリに対する貸方勘定のみリンクすることができます,
"For {0}, only debit accounts can be linked against another credit entry",{0}には、別の貸方エントリに対する借方勘定のみリンクすることができます,
-Form View,フォームビュー,
Forum Activity,フォーラム活動,
Free item code is not selected,無料商品コードが選択されていません,
Freight and Forwarding Charges,運送・転送料金,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",残休暇が先の日付の休暇割当レコード{1}に割り当てられているため、{0}以前の休暇を割り当てることができません,
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",残休暇が先の日付の休暇割当レコード{1}に持ち越されているため、{0}以前の休暇を適用/キャンセルすることができません。,
Leave of type {0} cannot be longer than {1},休暇タイプ{0}は、{1}よりも長くすることはできません,
-Leave the field empty to make purchase orders for all suppliers,すべての仕入先の購買発注を行うには、項目を空のままにします。,
Leaves,葉,
Leaves Allocated Successfully for {0},休暇は{0}に正常に割り当てられました,
Leaves has been granted sucessfully,葉がうまく与えられた,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,製造する部品表(BOM)を持つアイテムはありません,
No Items with Bill of Materials.,部品表のある品目はありません。,
No Permission,権限がありませんん,
-No Quote,いいえ,
No Remarks,備考がありません,
No Result to submit,提出する結果がありません,
No Salary Structure assigned for Employee {0} on given date {1},指定された日付{1}に従業員{0}に割り当てられた給与構造がありません,
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,次の条件が重複しています:,
Owner,所有者,
PAN,PAN,
-PO already created for all sales order items,POはすべての受注伝票に対してすでに登録されています,
POS,POS,
POS Profile,POSプロフィール,
POS Profile is required to use Point-of-Sale,POSプロファイルはPoint-of-Saleを使用する必要があります,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,請求タイプを最初に選択してください,
Please select Company,会社を選択してください,
Please select Company and Designation,会社と指定を選択してください,
-Please select Company and Party Type first,最初の会社と当事者タイプを選択してください,
Please select Company and Posting Date to getting entries,エントリを取得するには、会社と転記日付を選択してください,
Please select Company first,会社を選択してください,
Please select Completion Date for Completed Asset Maintenance Log,完了した資産管理ログの完了日を選択してください,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,行{0}:数量単位(UOM)換算係数は必須です,
Row {0}: select the workstation against the operation {1},行{0}:操作{1}に対するワークステーションを選択します。,
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,行{0}:{1}アイテム{2}に必要なシリアル番号。あなたは{3}を提供しました。,
-Row {0}: {1} is required to create the Opening {2} Invoices,行{0}:開始{2}請求書を登録するには{1}が必要です,
Row {0}: {1} must be greater than 0,行{0}:{1}は0より大きくなければなりません,
Row {0}: {1} {2} does not match with {3},行{0}:{1} {2} は {3}と一致しません,
Row {0}:Start Date must be before End Date,行{0}:開始日は終了日より前でなければなりません,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,助成金レビューメールを送る,
Send Now,今すぐ送信,
Send SMS,SMSを送信,
-Send Supplier Emails,サプライヤーメールを送信,
Send mass SMS to your contacts,連絡先にまとめてSMSを送信,
Sensitivity,感度,
Sent,送信済,
-Serial #,シリアル番号,
Serial No and Batch,シリアル番号とバッチ,
Serial No is mandatory for Item {0},アイテム{0}にはシリアル番号が必須です,
Serial No {0} does not belong to Batch {1},シリアル番号{0}はバッチ{1}に属していません,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,このシステムを設定する会社の名前,
The number of shares and the share numbers are inconsistent,株式数と株式数が矛盾している,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,プラン{0}の支払ゲートウェイ口座が、この支払依頼の支払ゲートウェイ口座と異なる,
-The request for quotation can be accessed by clicking on the following link,見積依頼は、以下のリンクをクリックすることによってアクセスすることができます,
The selected BOMs are not for the same item,選択されたBOMはアイテムと同一ではありません,
The selected item cannot have Batch,選択した項目はバッチを持てません,
The seller and the buyer cannot be the same,売り手と買い手は同じではありません,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},フレキシブル給付金の総額{0}は、最大給付額{1}より少なくてはいけません,
Total hours: {0},合計時間:{0},
Total leaves allocated is mandatory for Leave Type {0},割り当てられたリーフの種類は{0},
-Total weightage assigned should be 100%. It is {0},割り当てられた重みづけの合計は100%でなければなりません。{0}になっています。,
Total working hours should not be greater than max working hours {0},総労働時間は最大労働時間よりも大きくてはいけません{0},
Total {0} ({1}),合計{0}({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'",合計{0}のすべての項目がゼロになっています。「支払案分基準」を変更する必要があるかもしれません,
@@ -3316,7 +3299,6 @@
What do you need help with?,お手伝いしましょうか?,
What does it do?,これは何?,
Where manufacturing operations are carried.,製造作業が行なわれる場所,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",子会社{0}のアカウントを作成中に、親アカウント{1}が見つかりませんでした。対応するCOAで親口座を作成してください,
White,ホワイト,
Wire Transfer,電信振込,
WooCommerce Products,WooCommerce製品,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0}バリアントが作成されました。,
{0} {1} created,{0} {1} 作成済,
{0} {1} does not exist,{0} {1}が存在しません,
-{0} {1} does not exist.,{0} {1}は存在しません。,
{0} {1} has been modified. Please refresh.,{0} {1}が変更されています。画面を更新してください。,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} が送信されていないためアクションが完了できません,
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1}は{2}に関連付けられていますが、当事者アカウントは{3}に関連付けられています,
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}:{1}は存在しません,
{0}: {1} not found in Invoice Details table,{0}:{1}は請求書詳細テーブルに存在しません,
{} of {},{} / {},
+Assigned To,割当先,
Chat,チャット,
Completed By,完了者,
Conditions,条件,
@@ -3506,7 +3488,9 @@
Merge with existing,既存のものとマージ,
Office,事務所,
Orientation,オリエンテーション,
+Parent,親,
Passive,消極的,
+Payment Failed,支払いできませんでした,
Percent,割合(%),
Permanent,恒久的な,
Personal,個人情報,
@@ -3544,7 +3528,6 @@
Company field is required,会社フィールドは必須です,
Creating Dimensions...,ディメンションを作成しています...,
Duplicate entry against the item code {0} and manufacturer {1},商品コード{0}と製造元{1}に対する重複エントリ,
-Import Chart Of Accounts from CSV / Excel files,CSV / Excelファイルから勘定科目表のインポート,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTINが無効です。入力した入力が、UIN保有者または非居住者用OIDARサービスプロバイダのGSTIN形式と一致しません,
Invoice Grand Total,請求書の合計,
Last carbon check date cannot be a future date,最後のカーボンチェック日を未来の日にすることはできません,
@@ -3556,6 +3539,7 @@
Show {0},{0}を表示,
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series"," - "、 "#"、 "。"、 "/"、 "{"、および "}"以外の特殊文字は、一連の名前付けでは使用できません,
Target Details,ターゲット詳細,
+{0} already has a Parent Procedure {1}.,{0}にはすでに親プロシージャー{1}があります。,
API,API,
Annual,年次,
Approved,承認済,
@@ -3572,6 +3556,8 @@
No data to export,エクスポートするデータがありません,
Portrait,ポートレート,
Print Heading,印刷見出し,
+Scheduler Inactive,スケジューラー非アクティブ,
+Scheduler is inactive. Cannot import data.,スケジューラは非アクティブです。データをインポートできません。,
Show Document,ドキュメントを表示,
Show Traceback,トレースバックを表示,
Video,ビデオ,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},商品{0}の品質検査を作成,
Creating Accounts...,アカウントを作成しています...,
Creating bank entries...,銀行口座を作成しています...,
-Creating {0},{0}の作成,
Credit limit is already defined for the Company {0},会社{0}の与信限度はすでに定義されています,
Ctrl + Enter to submit,送信するにはCtrl + Enter,
Ctrl+Enter to submit,送信するCtrl + Enter,
@@ -3921,7 +3906,6 @@
Plaid public token error,プレイドパブリックトークンエラー,
Plaid transactions sync error,格子縞のトランザクション同期エラー,
Please check the error log for details about the import errors,インポートエラーの詳細についてはエラーログを確認してください。,
-Please click on the following link to set your new password,新しいパスワードを設定するには、次のリンクをクリックしてください,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,会社<b>{}の</b> <b>DATEV設定</b>を作成してください。,
Please create adjustment Journal Entry for amount {0} ,金額{0}の調整仕訳を作成してください,
Please do not create more than 500 items at a time,一度に500個を超えるアイテムを作成しないでください,
@@ -3997,6 +3981,7 @@
Release date must be in the future,発売日は未来でなければなりません,
Relieving Date must be greater than or equal to Date of Joining,免除日は参加日以上でなければなりません,
Rename,名称変更,
+Rename Not Allowed,許可されていない名前の変更,
Repayment Method is mandatory for term loans,タームローンには返済方法が必須,
Repayment Start Date is mandatory for term loans,定期ローンの返済開始日は必須です,
Report Item,レポートアイテム,
@@ -4043,7 +4028,6 @@
Select All,すべて選択,
Select Difference Account,差額勘定を選択,
Select a Default Priority.,デフォルトの優先順位を選択します。,
-Select a Supplier from the Default Supplier List of the items below.,以下のアイテムのデフォルトのサプライヤーリストからサプライヤーを選択します。,
Select a company,会社を選択,
Select finance book for the item {0} at row {1},行{1}のアイテム{0}のファイナンスブックを選択してください,
Select only one Priority as Default.,デフォルトとして優先度を1つだけ選択します。,
@@ -4247,7 +4231,6 @@
Actual ,実際,
Add to cart,カートに追加,
Budget,予算,
-Chart Of Accounts Importer,アカウントインポーターのチャート,
Chart of Accounts,勘定科目一覧表,
Customer database.,顧客データベース,
Days Since Last order,最新注文からの日数,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,終了日は開始日より短くすることはできません,
For Default Supplier (Optional),デフォルトサプライヤ(オプション),
From date cannot be greater than To date,開始日を終了日より大きくすることはできません,
-Get items from,アイテム取得元,
Group by,グループ化,
In stock,在庫あり,
Item name,アイテム名,
@@ -4532,32 +4514,22 @@
Accounts Settings,アカウント設定,
Settings for Accounts,アカウント設定,
Make Accounting Entry For Every Stock Movement,各在庫の動きを会計処理のエントリとして作成,
-"If enabled, the system will post accounting entries for inventory automatically.",有効にすると、システムは自動的に在庫の会計エントリーを投稿します,
-Accounts Frozen Upto,凍結口座上限,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",会計エントリーはこの日から凍結され、以下の役割を除いて実行/変更できません。,
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,アカウントの凍結と凍結エントリの編集が許可された役割,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,この役割を持つユーザーは、口座の凍結と、凍結口座に対しての会計エントリーの作成/修正が許可されています,
Determine Address Tax Category From,住所税カテゴリの決定元,
-Address used to determine Tax Category in transactions.,取引で課税カテゴリを決定するために使用される住所。,
Over Billing Allowance (%),超過手当(%),
-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 for $110.,あなたが注文した金額に対してもっと請求することを許可されている割合。たとえば、注文の金額が100ドルで、許容範囲が10%に設定されている場合、110ドルの請求が許可されます。,
Credit Controller,与信管理,
-Role that is allowed to submit transactions that exceed credit limits set.,設定された与信限度額を超えた取引を提出することが許可されている役割,
Check Supplier Invoice Number Uniqueness,サプライヤー請求番号が一意であることを確認,
Make Payment via Journal Entry,仕訳を経由して支払いを行います,
Unlink Payment on Cancellation of Invoice,請求書のキャンセルにお支払いのリンクを解除,
-Unlink Advance Payment on Cancelation of Order,注文のキャンセルに関する前払いのリンクの解除,
Book Asset Depreciation Entry Automatically,資産償却エントリを自動的に記帳,
Automatically Add Taxes and Charges from Item Tax Template,アイテム税テンプレートから自動的に税金と請求を追加,
Automatically Fetch Payment Terms,支払い条件を自動的に取得する,
-Show Inclusive Tax In Print,印刷時に税込で表示,
Show Payment Schedule in Print,印刷時に支払スケジュールを表示,
Currency Exchange Settings,通貨交換の設定,
Allow Stale Exchange Rates,失効した為替レートを許可する,
Stale Days,有効期限,
Report Settings,レポートの設定,
Use Custom Cash Flow Format,カスタムキャッシュフローフォーマットの使用,
-Only select if you have setup Cash Flow Mapper documents,キャッシュフローマッパー文書を設定している場合のみ選択してください,
Allowed To Transact With,処理を許可する,
SWIFT number,SWIFT番号,
Branch Code,支店コード,
@@ -4940,7 +4912,6 @@
POS Customer Group,POSの顧客グループ,
POS Field,POSフィールド,
POS Item Group,POSアイテムのグループ,
-[Select],[選択],
Company Address,会社住所,
Update Stock,在庫更新,
Ignore Pricing Rule,価格設定ルールを無視,
@@ -5495,8 +5466,6 @@
Supplier Naming By,サプライヤー通称,
Default Supplier Group,デフォルトサプライヤグループ,
Default Buying Price List,デフォルト購入価格表,
-Maintain same rate throughout purchase cycle,仕入サイクル全体で同じレートを維持,
-Allow Item to be added multiple times in a transaction,取引内でのアイテムの複数回追加を許可,
Backflush Raw Materials of Subcontract Based On,バックグラウンドの原材料,
Material Transferred for Subcontract,外注先に転送される品目,
Over Transfer Allowance (%),超過手当(%),
@@ -5540,7 +5509,6 @@
Current Stock,現在の在庫,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,個々のサプライヤーのため,
-Supplier Detail,サプライヤー詳細,
Link to Material Requests,マテリアルリクエストへのリンク,
Message for Supplier,サプライヤーへのメッセージ,
Request for Quotation Item,見積明細依頼,
@@ -6481,7 +6449,6 @@
Appraisal Template,査定テンプレート,
For Employee Name,従業員名用,
Goals,ゴール,
-Calculate Total Score,合計スコアを計算,
Total Score (Out of 5),総得点(5点満点),
"Any other remarks, noteworthy effort that should go in the records.",記録内で注目に値する特記事項,
Appraisal Goal,査定目標,
@@ -6599,11 +6566,6 @@
Reason for Leaving,退職理由,
Leave Encashed?,現金化された休暇?,
Encashment Date,現金化日,
-Exit Interview Details,インタビュー詳細を終了,
-Held On,開催,
-Reason for Resignation,退職理由,
-Better Prospects,良い見通し,
-Health Concerns,健康への懸念,
New Workplace,新しい職場,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,返金額,
@@ -6740,10 +6702,7 @@
Employee Settings,従業員の設定,
Retirement Age,定年,
Enter retirement age in years,年間で退職年齢を入力してください,
-Employee Records to be created by,従業員レコード作成元,
-Employee record is created using selected field. ,従業員レコードは選択されたフィールドを使用して作成されます。,
Stop Birthday Reminders,誕生日リマインダを停止,
-Don't send Employee Birthday Reminders,従業員の誕生日リマインダを送信しないでください,
Expense Approver Mandatory In Expense Claim,経費請求者に必須の経費承認者,
Payroll Settings,給与計算の設定,
Leave,去る,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,休暇申請時に承認者を必須のままにする,
Show Leaves Of All Department Members In Calendar,カレンダーのすべての部署メンバーの葉を表示する,
Auto Leave Encashment,自動脱退,
-Restrict Backdated Leave Application,バックデート休暇申請の制限,
Hiring Settings,雇用設定,
Check Vacancies On Job Offer Creation,求人の作成時に空室をチェックする,
Identification Document Type,識別文書タイプ,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,製造設定,
Raw Materials Consumption,原材料の消費,
Allow Multiple Material Consumption,複数の品目消費を許可する,
-Allow multiple Material Consumption against a Work Order,作業指示に対して複数の品目消費を許可する,
Backflush Raw Materials Based On,原材料のバックフラッシュ基準,
Material Transferred for Manufacture,製造用移送資材,
Capacity Planning,キャパシティプランニング,
Disable Capacity Planning,キャパシティプランニングを無効にする,
Allow Overtime,残業を許可,
-Plan time logs outside Workstation Working Hours.,ワークステーションの労働時間外のタイムログを計画します。,
Allow Production on Holidays,休日に製造を許可,
Capacity Planning For (Days),キャパシティプランニング(日数),
-Try planning operations for X days in advance.,事前にX日の業務を計画してみてください,
-Time Between Operations (in mins),操作の間の時間(分単位),
-Default 10 mins,デフォルト 10分,
Default Warehouses for Production,本番用のデフォルト倉庫,
Default Work In Progress Warehouse,デフォルト作業中倉庫,
Default Finished Goods Warehouse,デフォルト完成品倉庫,
Default Scrap Warehouse,デフォルトのスクラップ倉庫,
-Over Production for Sales and Work Order,販売および作業指示書の過剰生産,
Overproduction Percentage For Sales Order,受注の生産過剰率,
Overproduction Percentage For Work Order,作業オーダーの生産過剰率,
Other Settings,その他設定,
Update BOM Cost Automatically,BOMコストの自動更新,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",最新の評価レート/価格リストレート/原材料の最終購入レートに基づいて、スケジューラを使用してBOM原価を自動的に更新します。,
Material Request Plan Item,品目計画項目,
Material Request Type,資材要求タイプ,
Material Issue,資材課題,
@@ -7603,10 +7554,6 @@
Quality Goal,品質目標,
Monitoring Frequency,モニタリング頻度,
Weekday,平日,
-January-April-July-October,1月 - 4月 - 7月 - 10月,
-Revision and Revised On,改訂および改訂日,
-Revision,リビジョン,
-Revised On,改訂日,
Objectives,目的,
Quality Goal Objective,品質目標,
Objective,目的,
@@ -7619,7 +7566,6 @@
Processes,プロセス,
Quality Procedure Process,品質管理プロセス,
Process Description,過程説明,
-Child Procedure,子供の手順,
Link existing Quality Procedure.,既存の品質管理手順をリンクする。,
Additional Information,追加情報,
Quality Review Objective,品質レビューの目的,
@@ -7787,15 +7733,9 @@
Default Customer Group,デフォルトの顧客グループ,
Default Territory,デフォルト地域,
Close Opportunity After Days,日後に閉じるの機会,
-Auto close Opportunity after 15 days,機会を15日後に自動的にクローズ,
Default Quotation Validity Days,デフォルト見積り有効日数,
Sales Update Frequency,販売更新頻度,
-How often should project and company be updated based on Sales Transactions.,販売取引に基づいてプロジェクトや会社を更新する頻度。,
Each Transaction,各取引,
-Allow user to edit Price List Rate in transactions,ユーザーに取引の価格表単価の編集を許可,
-Allow multiple Sales Orders against a Customer's Purchase Order,顧客の発注に対する複数の受注を許可,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,購入料金や評価レートに対するアイテムの販売価格を検証します,
-Hide Customer's Tax Id from Sales Transactions,販売取引内での顧客の税IDを非表示,
SMS Center,SMSセンター,
Send To,送信先,
All Contact,全ての連絡先,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,アイテムに使用されるメーカー,
Limited to 12 characters,12文字に制限されています,
MAT-MR-.YYYY.-,MAT-MR- .YYYY.-,
-Set Warehouse,倉庫を設定する,
-Sets 'For Warehouse' in each row of the Items table.,Itemsテーブルの各行に「ForWarehouse」を設定します。,
-Requested For,要求対象,
Partially Ordered,半順序,
Transferred,転送された,
% Ordered,%注文済,
@@ -8407,24 +8344,14 @@
Default Stock UOM,デフォルト在庫数量単位,
Sample Retention Warehouse,サンプル保持倉庫,
Default Valuation Method,デフォルト評価方法,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,注文数に対して受領または提供が許可されている割合。例:100単位の注文を持っている状態で、割当が10%だった場合、110単位の受領を許可されます。,
-Action if Quality inspection is not submitted,品質検査が提出されていない場合の対処,
Show Barcode Field,バーコードフィールド表示,
Convert Item Description to Clean HTML,アイテム説明をHTMLに変換する,
-Auto insert Price List rate if missing,空の場合価格表の単価を自動挿入,
Allow Negative Stock,マイナス在庫を許可,
Automatically Set Serial Nos based on FIFO,先入先出法(FIFO)によりシリアル番号を自動的に設定,
-Set Qty in Transactions based on Serial No Input,シリアルナンバーに基づいて取引で数量を設定する,
Auto Material Request,自動資材要求,
-Raise Material Request when stock reaches re-order level,在庫が再注文レベルに達したときに原材料要求を挙げる,
-Notify by Email on creation of automatic Material Request,自動的な資材要求の作成時にメールで通知,
Inter Warehouse Transfer Settings,倉庫間転送設定,
-Allow Material Transfer From Delivery Note and Sales Invoice,納品書および売上請求書からの資材転送を許可する,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,購入領収書と購入請求書からの資材転送を許可する,
Freeze Stock Entries,凍結在庫エントリー,
Stock Frozen Upto,在庫凍結,
-Freeze Stocks Older Than [Days],[日]より古い在庫を凍結,
-Role Allowed to edit frozen stock,凍結在庫の編集が許可された役割,
Batch Identification,バッチ識別,
Use Naming Series,命名シリーズを使用する,
Naming Series Prefix,命名シリーズ接頭辞,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,領収書傾向,
Purchase Register,仕入帳,
Quotation Trends,見積傾向,
-Quoted Item Comparison,引用符で囲まれた項目の比較,
Received Items To Be Billed,支払予定受領アイテム,
Qty to Order,注文数,
Requested Items To Be Transferred,移転予定の要求アイテム,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,資材依頼用の倉庫を選択,
Transfer Materials For Warehouse {0},倉庫{0}の転送資材,
Production Plan Material Request Warehouse,生産計画資材依頼倉庫,
-Set From Warehouse,倉庫から設定,
-Source Warehouse (Material Transfer),ソースウェアハウス(資材転送),
Sets 'Source Warehouse' in each row of the items table.,itemsテーブルの各行に「SourceWarehouse」を設定します。,
Sets 'Target Warehouse' in each row of the items table.,itemsテーブルの各行に「TargetWarehouse」を設定します。,
Show Cancelled Entries,キャンセルされたエントリを表示する,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,サービスを受けたが請求されていない,
Deferred Accounting Settings,据え置き会計設定,
Book Deferred Entries Based On,に基づいて延期されたエントリを予約する,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",「月」を選択した場合、月の日数に関係なく、毎月の繰延収益または費用として固定金額が計上されます。繰延収益または費用が1か月間予約されていない場合は、日割り計算されます。,
Days,日々,
Months,月,
Book Deferred Entries Via Journal Entry,仕訳入力による繰延入力の予約,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,これがチェックされていない場合、直接GLエントリが作成され、繰延収益/費用が予約されます。,
Submit Journal Entries,仕訳の提出,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,これがチェックされていない場合、仕訳入力はドラフト状態で保存され、手動で送信する必要があります,
Enable Distributed Cost Center,分散コストセンターを有効にする,
@@ -8901,8 +8823,6 @@
Is Inter State,州間,
Purchase Details,購入の詳細,
Depreciation Posting Date,減価償却転記日,
-Purchase Order Required for Purchase Invoice & Receipt Creation,発注書と領収書の作成に必要な発注書,
-Purchase Receipt Required for Purchase Invoice Creation,購入請求書の作成に必要な購入領収書,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",デフォルトでは、サプライヤー名は入力されたサプライヤー名に従って設定されます。サプライヤーに名前を付けたい場合,
choose the 'Naming Series' option.,「ネーミングシリーズ」オプションを選択します。,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,新しい購入トランザクションを作成するときに、デフォルトの価格表を構成します。アイテムの価格は、この価格表から取得されます。,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,所得税の要素ですか,
Component properties and references ,コンポーネントのプロパティと参照,
Additional Salary ,追加給与,
-Condtion and formula,条件と式,
Unmarked days,マークされていない日,
Absent Days,不在日,
Conditions and Formula variable and example,条件と式の変数と例,
Feedback By,フィードバック,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-。MM .-。DD.-,
Manufacturing Section,製造部門,
-Sales Order Required for Sales Invoice & Delivery Note Creation,売上請求書と納品書の作成に必要な受注,
-Delivery Note Required for Sales Invoice Creation,売上請求書の作成に必要な納品書,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",デフォルトでは、顧客名は入力されたフルネームに従って設定されます。顧客に名前を付けたい場合,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,新しい販売トランザクションを作成するときに、デフォルトの価格表を構成します。アイテムの価格は、この価格表から取得されます。,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",このオプションが「はい」に設定されている場合、ERPNextは、最初に販売注文を作成せずに販売請求書または納品書を作成することを防ぎます。この構成は、顧客マスターで[販売注文なしで販売請求書の作成を許可する]チェックボックスを有効にすることで、特定の顧客に対して上書きできます。,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1}が選択したすべてのトピックに正常に追加されました。,
Topics updated,トピックが更新されました,
Academic Term and Program,学期とプログラム,
-Last Stock Transaction for item {0} was on {1}.,アイテム{0}の最後の在庫トランザクションは{1}にありました。,
-Stock Transactions for Item {0} cannot be posted before this time.,アイテム{0}の在庫トランザクションは、この時間より前に転記することはできません。,
Please remove this item and try to submit again or update the posting time.,このアイテムを削除して、もう一度送信するか、投稿時間を更新してください。,
Failed to Authenticate the API key.,APIキーの認証に失敗しました。,
Invalid Credentials,無効な資格情報,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,チェック柄のクライアントIDとシークレット値を確認してください,
Bank transaction creation error,銀行取引作成エラー,
Unit of Measurement,測定の単位,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},行#{}:アイテム{}の販売率はその{}よりも低くなっています。販売率は少なくとも{}でなければなりません,
Fiscal Year {0} Does Not Exist,会計年度{0}は存在しません,
Row # {0}: Returned Item {1} does not exist in {2} {3},行番号{0}:返品されたアイテム{1}は{2} {3}に存在しません,
Valuation type charges can not be marked as Inclusive,評価タイプの料金を包括的としてマークすることはできません,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,行{1}の{0}優先度の応答時間は解決時間より長くすることはできません。,
{0} is not enabled in {1},{0}は{1}で有効になっていません,
Group by Material Request,マテリアルリクエストによるグループ化,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",行{0}:サプライヤー{0}の場合、Eメールを送信するにはEメールアドレスが必要です,
Email Sent to Supplier {0},サプライヤーに送信された電子メール{0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",ポータルからの見積依頼へのアクセスが無効になっています。アクセスを許可するには、ポータル設定で有効にします。,
Supplier Quotation {0} Created,サプライヤー見積もり{0}が作成されました,
Valid till Date cannot be before Transaction Date,有効期限は取引日より前にすることはできません,
+Unlink Advance Payment on Cancellation of Order,注文のキャンセル時に前払いのリンクを解除する,
+"Simple Python Expression, Example: territory != 'All Territories'",単純なPython式、例:territory!= 'すべてのテリトリー',
+Sales Contributions and Incentives,売上への貢献とインセンティブ,
+Sourced by Supplier,サプライヤーによる供給,
+Total weightage assigned should be 100%.<br>It is {0},割り当てられる総重みは100%である必要があります。<br> {0}です,
+Account {0} exists in parent company {1}.,アカウント{0}は親会社{1}に存在します。,
+"To overrule this, enable '{0}' in company {1}",これを無効にするには、会社{1}で「{0}」を有効にします,
+Invalid condition expression,無効な条件式,
+Please Select a Company First,最初に会社を選択してください,
+Please Select Both Company and Party Type First,最初に会社とパーティーの両方のタイプを選択してください,
+Provide the invoice portion in percent,請求書の部分をパーセントで入力します,
+Give number of days according to prior selection,事前の選択に従って日数を与える,
+Email Details,メールの詳細,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.",受信者の挨拶を選択します。例:Mr.、Ms。など,
+Preview Email,プレビューメール,
+Please select a Supplier,サプライヤーを選択してください,
+Supplier Lead Time (days),サプライヤーのリードタイム(日),
+"Home, Work, etc.",自宅、職場など,
+Exit Interview Held On,面接終了,
+Condition and formula,条件と式,
+Sets 'Target Warehouse' in each row of the Items table.,Itemsテーブルの各行に「TargetWarehouse」を設定します。,
+Sets 'Source Warehouse' in each row of the Items table.,Itemsテーブルの各行に「SourceWarehouse」を設定します。,
+POS Register,POSレジスタ,
+"Can not filter based on POS Profile, if grouped by POS Profile",POSプロファイルでグループ化されている場合、POSプロファイルに基づいてフィルタリングすることはできません,
+"Can not filter based on Customer, if grouped by Customer",顧客ごとにグループ化されている場合、顧客に基づいてフィルタリングすることはできません,
+"Can not filter based on Cashier, if grouped by Cashier",キャッシャーでグループ化されている場合、キャッシャーに基づいてフィルタリングすることはできません,
+Payment Method,支払方法,
+"Can not filter based on Payment Method, if grouped by Payment Method",支払い方法でグループ化されている場合、支払い方法に基づいてフィルタリングすることはできません,
+Supplier Quotation Comparison,サプライヤーの見積もりの比較,
+Price per Unit (Stock UOM),ユニットあたりの価格(ストック単位),
+Group by Supplier,サプライヤー別グループ,
+Group by Item,アイテムでグループ化,
+Remember to set {field_label}. It is required by {regulation}.,{field_label}を設定することを忘れないでください。 {規制}で義務付けられています。,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},登録日は、学年度の開始日より前にすることはできません{0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},登録日は、学期の終了日より後にすることはできません{0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},登録日は、学期の開始日より前にすることはできません{0},
+Future Posting Not Allowed,今後の投稿は許可されません,
+"To enable Capital Work in Progress Accounting, ",資本仕掛品会計を有効にするには、,
+you must select Capital Work in Progress Account in accounts table,勘定科目テーブルで資本仕掛品勘定科目を選択する必要があります,
+You can also set default CWIP account in Company {},会社{}でデフォルトのCWIPアカウントを設定することもできます,
+The Request for Quotation can be accessed by clicking on the following button,見積依頼には、次のボタンをクリックしてアクセスできます。,
+Regards,よろしく,
+Please click on the following button to set your new password,次のボタンをクリックして、新しいパスワードを設定してください,
+Update Password,パスワードの更新,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},行#{}:アイテム{}の販売率はその{}よりも低くなっています。 {}の販売は少なくとも{}である必要があります,
+You can alternatively disable selling price validation in {} to bypass this validation.,または、{}で販売価格の検証を無効にして、この検証をバイパスすることもできます。,
+Invalid Selling Price,無効な販売価格,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,住所は会社にリンクする必要があります。リンクテーブルに会社の行を追加してください。,
+Company Not Linked,リンクされていない会社,
+Import Chart of Accounts from CSV / Excel files,CSV / Excelファイルから勘定科目表をインポートする,
+Completed Qty cannot be greater than 'Qty to Manufacture',完了数量は「製造数量」を超えることはできません,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",行{0}:サプライヤー{1}の場合、Eメールを送信するにはEメールアドレスが必要です,
+"If enabled, the system will post accounting entries for inventory automatically",有効にすると、システムは在庫の会計仕訳を自動的に転記します,
+Accounts Frozen Till Date,日付まで凍結されたアカウント,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,アカウンティングエントリは、この日付まで凍結されています。以下に指定された役割を持つユーザーを除いて、誰もエントリを作成または変更できません,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,凍結されたアカウントの設定と凍結されたエントリの編集を許可された役割,
+Address used to determine Tax Category in transactions,トランザクションの税カテゴリを決定するために使用されるアドレス,
+"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 ",注文した金額に対してさらに請求できる割合。たとえば、アイテムの注文額が$ 100で、許容範囲が10%に設定されている場合、最大$ 110まで請求できます。,
+This role is allowed to submit transactions that exceed credit limits,このロールは、与信限度額を超えるトランザクションを送信できます,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",「月」を選択した場合、月の日数に関係なく、毎月の繰延収益または費用として固定金額が計上されます。繰延収益または費用が1か月間予約されていない場合は、比例配分されます。,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",これがチェックされていない場合、繰延収益または費用を計上するために直接総勘定元帳エントリが作成されます,
+Show Inclusive Tax in Print,包括税を印刷物で表示,
+Only select this if you have set up the Cash Flow Mapper documents,キャッシュフローマッパードキュメントを設定した場合にのみ、これを選択してください,
+Payment Channel,支払いチャネル,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,発注書と領収書の作成には発注書が必要ですか?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,購入請求書の作成には購入領収書が必要ですか?,
+Maintain Same Rate Throughout the Purchase Cycle,購入サイクル全体を通じて同じレートを維持する,
+Allow Item To Be Added Multiple Times in a Transaction,トランザクションでアイテムを複数回追加できるようにする,
+Suppliers,サプライヤー,
+Send Emails to Suppliers,サプライヤーにメールを送信する,
+Select a Supplier,サプライヤーを選択する,
+Cannot mark attendance for future dates.,将来の日付の出席をマークすることはできません。,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},出席を更新しますか?<br>現在:{0}<br>不在:{1},
+Mpesa Settings,Mpesa設定,
+Initiator Name,イニシエーター名,
+Till Number,番号まで,
+Sandbox,サンドボックス,
+ Online PassKey,オンラインパスキー,
+Security Credential,セキュリティ資格情報,
+Get Account Balance,アカウントの残高を取得する,
+Please set the initiator name and the security credential,イニシエーター名とセキュリティ資格情報を設定してください,
+Inpatient Medication Entry,入院薬のエントリー,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),商品コード(薬剤),
+Medication Orders,薬の注文,
+Get Pending Medication Orders,保留中の薬の注文を取得する,
+Inpatient Medication Orders,入院薬の注文,
+Medication Warehouse,薬の倉庫,
+Warehouse from where medication stock should be consumed,医薬品在庫を消費する倉庫,
+Fetching Pending Medication Orders,保留中の投薬注文の取得,
+Inpatient Medication Entry Detail,入院薬エントリーの詳細,
+Medication Details,薬の詳細,
+Drug Code,薬物コード,
+Drug Name,薬名,
+Against Inpatient Medication Order,入院薬の注文に対して,
+Against Inpatient Medication Order Entry,入院薬の注文入力に対して,
+Inpatient Medication Order,入院薬の注文,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,総注文数,
+Completed Orders,完了した注文,
+Add Medication Orders,薬の注文を追加する,
+Adding Order Entries,注文エントリの追加,
+{0} medication orders completed,{0}薬の注文が完了しました,
+{0} medication order completed,{0}薬の注文が完了しました,
+Inpatient Medication Order Entry,入院薬の注文入力,
+Is Order Completed,注文は完了しました,
+Employee Records to Be Created By,作成される従業員レコード,
+Employee records are created using the selected field,従業員レコードは、選択したフィールドを使用して作成されます,
+Don't send employee birthday reminders,従業員の誕生日のリマインダーを送信しないでください,
+Restrict Backdated Leave Applications,過去の休暇申請を制限する,
+Sequence ID,シーケンスID,
+Sequence Id,シーケンスID,
+Allow multiple material consumptions against a Work Order,作業指示に対して複数の材料の消費を許可する,
+Plan time logs outside Workstation working hours,ワークステーションの稼働時間外に時間ログを計画する,
+Plan operations X days in advance,X日前に運用を計画する,
+Time Between Operations (Mins),操作間の時間(分),
+Default: 10 mins,デフォルト:10分,
+Overproduction for Sales and Work Order,販売および作業指示の過剰生産,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",原材料の最新の評価率/価格表率/最終購入率に基づいて、スケジューラを介してBOMコストを自動的に更新します,
+Purchase Order already created for all Sales Order items,すべての販売注文アイテムに対してすでに作成されている注文書,
+Select Items,アイテムを選択,
+Against Default Supplier,デフォルトのサプライヤーに対して,
+Auto close Opportunity after the no. of days mentioned above,いいえの後に機会を自動で閉じます。上記の日数,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,売上請求書と納品書の作成には受注が必要ですか?,
+Is Delivery Note Required for Sales Invoice Creation?,売上請求書の作成には納品書が必要ですか?,
+How often should Project and Company be updated based on Sales Transactions?,プロジェクトと会社は、販売取引に基づいてどのくらいの頻度で更新する必要がありますか?,
+Allow User to Edit Price List Rate in Transactions,ユーザーがトランザクションで価格表レートを編集できるようにする,
+Allow Item to Be Added Multiple Times in a Transaction,トランザクションでアイテムを複数回追加できるようにする,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,顧客の注文書に対して複数の販売注文を許可する,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,購入率または評価率に対してアイテムの販売価格を検証する,
+Hide Customer's Tax ID from Sales Transactions,販売取引から顧客の納税者番号を非表示にする,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.",注文数量に対して、より多くの受け取りまたは配達が許可されているパーセンテージ。たとえば、100ユニットを注文し、アローワンスが10%の場合、110ユニットを受け取ることができます。,
+Action If Quality Inspection Is Not Submitted,品質検査が提出されない場合のアクション,
+Auto Insert Price List Rate If Missing,欠落している場合の自動挿入価格表レート,
+Automatically Set Serial Nos Based on FIFO,FIFOに基づいてシリアル番号を自動的に設定,
+Set Qty in Transactions Based on Serial No Input,シリアル入力なしに基づくトランザクションの数量を設定する,
+Raise Material Request When Stock Reaches Re-order Level,在庫が再注文レベルに達したときに資材要求を上げる,
+Notify by Email on Creation of Automatic Material Request,自動マテリアルリクエストの作成についてメールで通知する,
+Allow Material Transfer from Delivery Note to Sales Invoice,納品書から売上請求書への資材転送を許可する,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,購入領収書から購入請求書への資材の転送を許可する,
+Freeze Stocks Older Than (Days),(日)より古い在庫を凍結する,
+Role Allowed to Edit Frozen Stock,冷凍ストックの編集を許可された役割,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,支払いエントリ{0}の未割り当て金額が、銀行取引の未割り当て金額よりも大きい,
+Payment Received,お支払い頂いた,
+Attendance cannot be marked outside of Academic Year {0},学年外に出席をマークすることはできません{0},
+Student is already enrolled via Course Enrollment {0},学生はすでにコース登録{0}を介して登録されています,
+Attendance cannot be marked for future dates.,出席は将来の日付のためにマークすることはできません。,
+Please add programs to enable admission application.,入学願書を有効にするプログラムを追加してください。,
+The following employees are currently still reporting to {0}:,次の従業員は現在も{0}に報告しています。,
+Please make sure the employees above report to another Active employee.,上記の従業員が別のアクティブな従業員に報告していることを確認してください。,
+Cannot Relieve Employee,従業員を救うことはできません,
+Please enter {0},{0}を入力してください,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',別のお支払い方法を選択してください。 Mpesaは通貨「{0}」でのトランザクションをサポートしていません,
+Transaction Error,トランザクションエラー,
+Mpesa Express Transaction Error,MpesaExpressトランザクションエラー,
+"Issue detected with Mpesa configuration, check the error logs for more details",Mpesa構成で問題が検出されました。詳細については、エラーログを確認してください,
+Mpesa Express Error,MpesaExpressエラー,
+Account Balance Processing Error,口座残高処理エラー,
+Please check your configuration and try again,構成を確認して、再試行してください,
+Mpesa Account Balance Processing Error,Mpesaアカウント残高処理エラー,
+Balance Details,残高の詳細,
+Current Balance,経常収支,
+Available Balance,利用可能残高,
+Reserved Balance,予約残高,
+Uncleared Balance,未決済残高,
+Payment related to {0} is not completed,{0}に関連する支払いが完了していません,
+Row #{}: Item Code: {} is not available under warehouse {}.,行#{}:アイテムコード:{}はウェアハウス{}では使用できません。,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,行#{}:在庫数がアイテムコードに十分ではありません:{}倉庫{}の下。利用可能な数量{}。,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,行#{}:シリアル番号とアイテムに対するバッチを選択してください:{}またはそれを削除してトランザクションを完了してください。,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,行#{}:アイテムに対してシリアル番号が選択されていません:{}。トランザクションを完了するには、1つを選択するか、削除してください。,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,行#{}:アイテムに対してバッチが選択されていません:{}。バッチを選択するか、削除してトランザクションを完了してください。,
+Payment amount cannot be less than or equal to 0,お支払い金額は0以下にすることはできません,
+Please enter the phone number first,最初に電話番号を入力してください,
+Row #{}: {} {} does not exist.,行#{}:{} {}は存在しません。,
+Row #{0}: {1} is required to create the Opening {2} Invoices,行#{0}:開始{2}請求書を作成するには{1}が必要です,
+You had {} errors while creating opening invoices. Check {} for more details,開始請求書の作成中に{}エラーが発生しました。詳細については{}を確認してください,
+Error Occured,エラーが発生しました,
+Opening Invoice Creation In Progress,進行中の請求書作成を開く,
+Creating {} out of {} {},{} {}から{}を作成する,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(シリアル番号:{0})は、販売注文{1}を履行するために予約されているため、消費できません。,
+Item {0} {1},アイテム{0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,倉庫{1}の下のアイテム{0}の最後の在庫取引は{2}でした。,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,倉庫{1}の下の明細{0}の在庫取引は、この時間より前に転記することはできません。,
+Posting future stock transactions are not allowed due to Immutable Ledger,不変元帳のため、先物株式取引の転記は許可されていません,
+A BOM with name {0} already exists for item {1}.,アイテム{1}には、名前{0}のBOMがすでに存在します。,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1}アイテムの名前を変更しましたか?管理者/テクニカルサポートに連絡してください,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},行#{0}:シーケンスID {1}は前の行シーケンスID {2}より小さくすることはできません,
+The {0} ({1}) must be equal to {2} ({3}),{0}({1})は{2}({3})と等しくなければなりません,
+"{0}, complete the operation {1} before the operation {2}.",{0}、操作{2}の前に操作{1}を完了します。,
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,アイテム{0}がシリアル番号による配達の確認の有無にかかわらず追加されるため、シリアル番号による配達を保証できません。,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,アイテム{0}にはシリアル番号がありません。シリアル番号に基づいて配送できるのは、シリアル化されたアイテムのみです。,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,アイテム{0}のアクティブなBOMが見つかりません。シリアル番号による配送は保証できません,
+No pending medication orders found for selected criteria,選択した基準で保留中の投薬注文が見つかりません,
+From Date cannot be after the current date.,開始日を現在の日付より後にすることはできません。,
+To Date cannot be after the current date.,To Dateは、現在の日付より後にすることはできません。,
+From Time cannot be after the current time.,From Timeは、現在の時刻より後にすることはできません。,
+To Time cannot be after the current time.,To Timeは、現在の時刻より後にすることはできません。,
+Stock Entry {0} created and ,在庫エントリ{0}が作成され、,
+Inpatient Medication Orders updated successfully,入院薬の注文が正常に更新されました,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},行{0}:キャンセルされた入院薬注文に対して入院薬エントリを作成できません{1},
+Row {0}: This Medication Order is already marked as completed,行{0}:この投薬注文はすでに完了としてマークされています,
+Quantity not available for {0} in warehouse {1},倉庫{1}の{0}で利用できない数量,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,続行するには、[在庫設定で負の在庫を許可する]を有効にするか、在庫入力を作成してください。,
+No Inpatient Record found against patient {0},患者{0}に対する入院記録が見つかりません,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,患者との遭遇{1}に対する入院薬の注文{0}はすでに存在します。,
+Allow In Returns,返品を許可する,
+Hide Unavailable Items,利用できないアイテムを隠す,
+Apply Discount on Discounted Rate,割引率に割引を適用する,
+Therapy Plan Template,治療計画テンプレート,
+Fetching Template Details,テンプレートの詳細を取得する,
+Linked Item Details,リンクされたアイテムの詳細,
+Therapy Types,治療の種類,
+Therapy Plan Template Detail,治療計画テンプレートの詳細,
+Non Conformance,不適合,
+Process Owner,プロセスオーナー,
+Corrective Action,是正処置,
+Preventive Action,予防処置,
+Problem,問題,
+Responsible,責任者,
+Completion By,完了者,
+Process Owner Full Name,プロセス所有者のフルネーム,
+Right Index,右手の人差し指,
+Left Index,左インデックス,
+Sub Procedure,サブプロシージャ,
+Passed,合格しました,
+Print Receipt,領収書を印刷する,
+Edit Receipt,領収書の編集,
+Focus on search input,検索入力に焦点を当てる,
+Focus on Item Group filter,アイテムグループフィルターに焦点を当てる,
+Checkout Order / Submit Order / New Order,チェックアウト注文/送信注文/新規注文,
+Add Order Discount,注文割引を追加,
+Item Code: {0} is not available under warehouse {1}.,商品コード:{0}は倉庫{1}ではご利用いただけません。,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,倉庫{1}の下のアイテム{0}のシリアル番号は使用できません。倉庫を変えてみてください。,
+Fetched only {0} available serial numbers.,{0}の使用可能なシリアル番号のみを取得しました。,
+Switch Between Payment Modes,支払いモードの切り替え,
+Enter {0} amount.,{0}金額を入力します。,
+You don't have enough points to redeem.,引き換えるのに十分なポイントがありません。,
+You can redeem upto {0}.,{0}までご利用いただけます。,
+Enter amount to be redeemed.,引き換える金額を入力します。,
+You cannot redeem more than {0}.,{0}を超えて利用することはできません。,
+Open Form View,フォームビューを開く,
+POS invoice {0} created succesfully,POS請求書{0}が正常に作成されました,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,在庫数がアイテムコードに十分ではありません:倉庫{1}の下の{0}。利用可能な数量{2}。,
+Serial No: {0} has already been transacted into another POS Invoice.,シリアル番号:{0}はすでに別のPOS請求書に処理されています。,
+Balance Serial No,バランスシリアル番号,
+Warehouse: {0} does not belong to {1},倉庫:{0}は{1}に属していません,
+Please select batches for batched item {0},バッチアイテム{0}のバッチを選択してください,
+Please select quantity on row {0},行{0}で数量を選択してください,
+Please enter serial numbers for serialized item {0},シリアル化されたアイテム{0}のシリアル番号を入力してください,
+Batch {0} already selected.,バッチ{0}はすでに選択されています。,
+Please select a warehouse to get available quantities,利用可能な数量を取得するには、倉庫を選択してください,
+"For transfer from source, selected quantity cannot be greater than available quantity",ソースからの転送の場合、選択した数量は利用可能な数量を超えることはできません,
+Cannot find Item with this Barcode,このバーコードのアイテムが見つかりません,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0}は必須です。 {1}から{2}の外貨両替レコードが作成されていない可能性があります,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{}はそれにリンクされたアセットを送信しました。購入返品を作成するには、アセットをキャンセルする必要があります。,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,送信されたアセット{0}にリンクされているため、このドキュメントをキャンセルできません。続行するにはキャンセルしてください。,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,行#{}:シリアル番号{}はすでに別のPOS請求書に処理されています。有効なシリアル番号を選択してください。,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,行#{}:シリアル番号{}はすでに別のPOS請求書に処理されています。有効なシリアル番号を選択してください。,
+Item Unavailable,アイテムは利用できません,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},行#{}:シリアル番号{}は、元の請求書{}で取引されていないため、返品できません。,
+Please set default Cash or Bank account in Mode of Payment {},お支払い方法でデフォルトの現金または銀行口座を設定してください{},
+Please set default Cash or Bank account in Mode of Payments {},お支払い方法でデフォルトの現金または銀行口座を設定してください{},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,{}アカウントが貸借対照表アカウントであることを確認してください。親アカウントを貸借対照表アカウントに変更するか、別のアカウントを選択できます。,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,{}アカウントが買掛金アカウントであることを確認してください。アカウントタイプをPayableに変更するか、別のアカウントを選択します。,
+Row {}: Expense Head changed to {} ,行{}:経費の頭が{}に変更されました,
+because account {} is not linked to warehouse {} ,アカウント{}は倉庫{}にリンクされていないため,
+or it is not the default inventory account,または、デフォルトの在庫アカウントではありません,
+Expense Head Changed,経費ヘッドが変更されました,
+because expense is booked against this account in Purchase Receipt {},費用は購入領収書{}でこのアカウントに対して予約されているためです。,
+as no Purchase Receipt is created against Item {}. ,アイテム{}に対して購入領収書が作成されないため。,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,これは、購入請求書の後に購入領収書が作成された場合の会計処理を処理するために行われます。,
+Purchase Order Required for item {},アイテムに必要な注文書{},
+To submit the invoice without purchase order please set {} ,注文書なしで請求書を送信するには、{}を設定してください,
+as {} in {},{}の{}として,
+Mandatory Purchase Order,必須の発注書,
+Purchase Receipt Required for item {},アイテム{}に必要な購入領収書,
+To submit the invoice without purchase receipt please set {} ,領収書なしで請求書を提出するには、{}を設定してください,
+Mandatory Purchase Receipt,必須の購入領収書,
+POS Profile {} does not belongs to company {},POSプロファイル{}は会社{}に属していません,
+User {} is disabled. Please select valid user/cashier,ユーザー{}は無効になっています。有効なユーザー/キャッシャーを選択してください,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,行#{}:返品請求書{}の元の請求書{}は{}です。,
+Original invoice should be consolidated before or along with the return invoice.,元の請求書は、返品請求書の前または一緒に統合する必要があります。,
+You can add original invoice {} manually to proceed.,元の請求書{}を手動で追加して続行できます。,
+Please ensure {} account is a Balance Sheet account. ,{}アカウントが貸借対照表アカウントであることを確認してください。,
+You can change the parent account to a Balance Sheet account or select a different account.,親アカウントを貸借対照表アカウントに変更するか、別のアカウントを選択できます。,
+Please ensure {} account is a Receivable account. ,{}アカウントが売掛金アカウントであることを確認してください。,
+Change the account type to Receivable or select a different account.,売掛金タイプを売掛金に変更するか、別のアカウントを選択します。,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},獲得したポイントは引き換えられているため、{}をキャンセルすることはできません。最初に{}いいえ{}をキャンセルします,
+already exists,もう存在している,
+POS Closing Entry {} against {} between selected period,選択した期間の{}に対するPOSクロージングエントリ{},
+POS Invoice is {},POS請求書は{},
+POS Profile doesn't matches {},POSプロファイルが{}と一致しません,
+POS Invoice is not {},POS請求書は{}ではありません,
+POS Invoice isn't created by user {},POS請求書はユーザーによって作成されていません{},
+Row #{}: {},行#{}:{},
+Invalid POS Invoices,無効なPOS請求書,
+Please add the account to root level Company - {},アカウントをルートレベルの会社に追加してください-{},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",子会社{0}のアカウントを作成しているときに、親アカウント{1}が見つかりません。対応するCOAで親アカウントを作成してください,
+Account Not Found,アカウントが見つかりません,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",子会社{0}のアカウントを作成しているときに、親アカウント{1}が元帳アカウントとして見つかりました。,
+Please convert the parent account in corresponding child company to a group account.,対応する子会社の親アカウントをグループアカウントに変換してください。,
+Invalid Parent Account,無効な親アカウント,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",名前の変更は、不一致を避けるために、親会社{0}を介してのみ許可されます。,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",アイテム{2}の数量が{0} {1}の場合、スキーム{3}がアイテムに適用されます。,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",アイテム{2}の価値がある{0} {1}の場合、スキーム{3}がアイテムに適用されます。,
+"As the field {0} is enabled, the field {1} is mandatory.",フィールド{0}が有効になっているため、フィールド{1}は必須です。,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",フィールド{0}が有効になっているため、フィールド{1}の値は1より大きくする必要があります。,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},販売注文を履行するために予約されているため、アイテム{1}のシリアル番号{0}を配信できません{2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",受注{0}にはアイテム{1}の予約があり、予約済みの{1}は{0}に対してのみ配信できます。,
+{0} Serial No {1} cannot be delivered,{0}シリアル番号{1}は配信できません,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},行{0}:下請け品目は原材料に必須です{1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",十分な原材料があるため、倉庫{0}には資材要求は必要ありません。,
+" If you still want to proceed, please enable {0}.",それでも続行する場合は、{0}を有効にしてください。,
+The item referenced by {0} - {1} is already invoiced,{0}-{1}で参照されているアイテムはすでに請求されています,
+Therapy Session overlaps with {0},セラピーセッションが{0}と重複しています,
+Therapy Sessions Overlapping,重複する治療セッション,
+Therapy Plans,治療計画,
+"Item Code, warehouse, quantity are required on row {0}",行{0}にはアイテムコード、倉庫、数量が必要です,
+Get Items from Material Requests against this Supplier,このサプライヤーに対する重要な要求からアイテムを取得する,
+Enable European Access,ヨーロッパへのアクセスを有効にする,
+Creating Purchase Order ...,注文書の作成..。,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",以下の項目のデフォルトサプライヤーからサプライヤーを選択します。選択時に、選択したサプライヤーに属するアイテムに対してのみ発注書が作成されます。,
+Row #{}: You must select {} serial numbers for item {}.,行#{}:アイテム{}の{}シリアル番号を選択する必要があります。,
diff --git a/erpnext/translations/km.csv b/erpnext/translations/km.csv
index d08acb3..e2a528c 100644
--- a/erpnext/translations/km.csv
+++ b/erpnext/translations/km.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},ពន្ធលើប្រភេទពិតប្រាកដមិនអាចត្រូវបានរួមបញ្ចូលនៅក្នុងអត្រាធាតុនៅក្នុងជួរដេក {0},
Add,បន្ថែម,
Add / Edit Prices,បន្ថែម / កែសម្រួលតម្លៃទំនិញ,
-Add All Suppliers,បន្ថែមអ្នកផ្គត់ផ្គង់ទាំងអស់,
Add Comment,បន្ថែមសេចក្តីអធិប្បាយ,
Add Customers,បន្ថែមអតិថិជន,
Add Employees,បន្ថែម បុគ្គលិក,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',មិនអាចកាត់ពេលដែលប្រភេទគឺសម្រាប់ 'វាយតម្លៃ' ឬ 'Vaulation និងសរុប,
"Cannot delete Serial No {0}, as it is used in stock transactions","មិនអាចលុបសៀរៀលគ្មាន {0}, ដូចដែលវាត្រូវបានគេប្រើនៅក្នុងប្រតិបត្តិការភាគហ៊ុន",
Cannot enroll more than {0} students for this student group.,មិនអាចចុះឈ្មោះចូលរៀនច្រើនជាង {0} សិស្សសម្រាប់ក្រុមនិស្សិតនេះ។,
-Cannot find Item with this barcode,មិនអាចរកឃើញធាតុជាមួយលេខកូដនេះទេ។,
Cannot find active Leave Period,មិនអាចរកកំនត់ឈប់កំនត់សកម្ម,
Cannot produce more Item {0} than Sales Order quantity {1},មិនអាចបង្កើតធាតុជាច្រើនទៀត {0} ជាងបរិមាណលំដាប់លក់ {1},
Cannot promote Employee with status Left,មិនអាចលើកកម្ពស់និយោជិកដោយមានស្ថានភាពនៅសល់,
Cannot refer row number greater than or equal to current row number for this Charge type,មិនអាចយោងលេខជួរដេកធំជាងឬស្មើទៅនឹងចំនួនជួរដេកបច្ចុប្បន្នសម្រាប់ប្រភេទការចោទប្រកាន់នេះ,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,មិនអាចជ្រើសប្រភេទការចោទប្រកាន់ថាជា "នៅលើចំនួនជួរដេកមុន 'ឬ' នៅលើជួរដេកសរុបមុន" សម្រាប់ជួរដេកដំបូង,
-Cannot set a received RFQ to No Quote,មិនអាចកំណត់ RFQ ដែលបានទទួលដើម្បីគ្មានសម្រង់,
Cannot set as Lost as Sales Order is made.,មិនអាចបាត់បង់ដូចដែលបានកំណត់ជាលំដាប់ត្រូវបានធ្វើឱ្យការលក់រថយន្ត។,
Cannot set authorization on basis of Discount for {0},មិនអាចកំណត់ការអនុញ្ញាតនៅលើមូលដ្ឋាននៃការបញ្ចុះតម្លៃសម្រាប់ {0},
Cannot set multiple Item Defaults for a company.,មិនអាចកំណត់លំនាំដើមធាតុច្រើនសម្រាប់ក្រុមហ៊ុន។,
@@ -521,7 +518,6 @@
Chargeble,អាចសាកបាន។,
Charges are updated in Purchase Receipt against each item,ការចោទប្រកាន់ត្រូវបានធ្វើបច្ចុប្បន្នភាពនៅបង្កាន់ដៃទិញប្រឆាំងនឹងធាតុគ្នា,
"Charges will be distributed proportionately based on item qty or amount, as per your selection",បទចោទប្រកាន់នឹងត្រូវបានចែកដោយផ្អែកលើធាតុ qty សមាមាត្រឬបរិមាណជាមួយជម្រើសរបស់អ្នក,
-Chart Of Accounts,គំនូសតាងគណនី,
Chart of Cost Centers,គំនូសតាងនៃមជ្ឈមណ្ឌលការចំណាយ,
Check all,សូមពិនិត្យមើលទាំងអស់,
Checkout,ពិនិត្យមុនពេលចេញ,
@@ -581,7 +577,6 @@
Compensatory Off,ទូទាត់បិទ,
Compensatory leave request days not in valid holidays,ថ្ងៃស្នើសុំការឈប់សម្រាកមិនមានថ្ងៃឈប់សម្រាកត្រឹមត្រូវ,
Complaint,បណ្តឹង,
-Completed Qty can not be greater than 'Qty to Manufacture',Qty បានបញ្ចប់មិនអាចជាធំជាង Qty ដើម្បីផលិត ",
Completion Date,កាលបរិច្ឆេទបញ្ចប់,
Computer,កុំព្យូទ័រ,
Condition,លក្ខខណ្ឌ,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.",បង្កើតនិងគ្រប់គ្រងការរំលាយអាហារបានអ៊ីម៉ែលជារៀងរាល់ថ្ងៃប្រចាំសប្តាហ៍និងប្រចាំខែ។,
Create customer quotes,បង្កើតសម្រង់អតិថិជន,
Create rules to restrict transactions based on values.,បង្កើតច្បាប់ដើម្បីរឹតបន្តឹងការធ្វើប្រតិបត្តិការដោយផ្អែកលើតម្លៃ។,
-Created By,បានបង្កើតដោយ,
Created {0} scorecards for {1} between: ,បានបង្កើត {0} សន្លឹកបៀសម្រាប់ {1} រវាង:,
Creating Company and Importing Chart of Accounts,បង្កើតក្រុមហ៊ុននិងនាំចូលតារាងគណនី។,
Creating Fees,បង្កើតកម្រៃ,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,ការផ្ទេរបុគ្គលិកមិនអាចបញ្ជូនបានទេមុនពេលផ្ទេរ,
Employee cannot report to himself.,បុគ្គលិកមិនអាចរាយការណ៍ទៅខ្លួនឯង។,
Employee relieved on {0} must be set as 'Left',បុគ្គលិកធូរស្រាលនៅលើ {0} ត្រូវតែត្រូវបានកំណត់ជា "ឆ្វេង",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,ស្ថានភាពនិយោជិកមិនអាចត្រូវបានកំណត់ទៅខាងឆ្វេងទេព្រោះនិយោជិកខាងក្រោមកំពុងរាយការណ៍ទៅនិយោជិកនេះ៖,
Employee {0} already submited an apllication {1} for the payroll period {2},និយោជិក {0} បានដាក់ពាក្យសុំ {1} រួចហើយសម្រាប់រយៈពេលបង់ប្រាក់ {2},
Employee {0} has already applied for {1} between {2} and {3} : ,និយោជិក {0} បានអនុវត្តរួចហើយសម្រាប់ {1} រវាង {2} និង {3}:,
Employee {0} has no maximum benefit amount,និយោជិក {0} មិនមានអត្ថប្រយោជន៍អតិបរមាទេ,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,សម្រាប់ជួរដេក {0}: បញ្ចូល Qty ដែលបានគ្រោងទុក,
"For {0}, only credit accounts can be linked against another debit entry",{0} មានតែគណនីឥណទានអាចត្រូវបានតភ្ជាប់ប្រឆាំងនឹងធាតុឥណពន្ធផ្សេងទៀត,
"For {0}, only debit accounts can be linked against another credit entry",{0} មានតែគណនីឥណពន្ធអាចត្រូវបានតភ្ជាប់ប្រឆាំងនឹងធាតុឥណទានផ្សេងទៀត,
-Form View,ទិដ្ឋភាពទម្រង់,
Forum Activity,សកម្មភាពវេទិកា,
Free item code is not selected,លេខកូដធាតុឥតគិតថ្លៃមិនត្រូវបានជ្រើសរើសទេ។,
Freight and Forwarding Charges,ការចោទប្រកាន់ការដឹកជញ្ជូននិងការបញ្ជូនបន្ត,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ទុកឱ្យមិនអាចត្រូវបានបម្រុងទុកមុន {0}, ដែលជាតុល្យភាពការឈប់សម្រាកបានជាទំនិញ-បានបញ្ជូនបន្តនៅក្នុងកំណត់ត្រាការបែងចែកការឈប់សម្រាកនាពេលអនាគតរួចទៅហើយ {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ទុកឱ្យមិនអាចត្រូវបានអនុវត្ត / លុបចោលមុនពេល {0}, ដែលជាតុល្យភាពការឈប់សម្រាកបានជាទំនិញ-បានបញ្ជូនបន្តនៅក្នុងកំណត់ត្រាការបែងចែកការឈប់សម្រាកនាពេលអនាគតរួចទៅហើយ {1}",
Leave of type {0} cannot be longer than {1},ការឈប់សម្រាកនៃប្រភេទ {0} មិនអាចមានយូរជាង {1},
-Leave the field empty to make purchase orders for all suppliers,ទុកវាលទទេដើម្បីធ្វើការបញ្ជាទិញសម្រាប់អ្នកផ្គត់ផ្គង់ទាំងអស់,
Leaves,ស្លឹកឈើ។,
Leaves Allocated Successfully for {0},ទុកបម្រុងទុកដោយជោគជ័យសម្រាប់ {0},
Leaves has been granted sucessfully,ស្លឹកត្រូវបានផ្តល់ដោយជោគជ័យ,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,គ្មានធាតុជាមួយលោក Bill នៃសម្ភារៈដើម្បីផលិត,
No Items with Bill of Materials.,គ្មានរបស់របរដែលមានវិក្កយបត្រសំភារៈ។,
No Permission,គ្មានសិទ្ធិ,
-No Quote,គ្មានសម្រង់,
No Remarks,គ្មានសុន្ទរកថា,
No Result to submit,គ្មានលទ្ធផលដើម្បីដាក់ស្នើ,
No Salary Structure assigned for Employee {0} on given date {1},គ្មានរចនាសម្ព័ន្ធប្រាក់ខែត្រូវបានគេកំណត់សម្រាប់និយោជិក {0} នៅថ្ងៃដែលបានផ្តល់ឱ្យ {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,លក្ខខណ្ឌត្រួតស៊ីគ្នាបានរកឃើញរវាង:,
Owner,ម្ចាស់,
PAN,PAN,
-PO already created for all sales order items,PO បានបង្កើតរួចហើយសំរាប់ធាតុបញ្ជាទិញទាំងអស់,
POS,ម៉ាស៊ីនឆូតកាត,
POS Profile,ទម្រង់ ម៉ាស៊ីនឆូតកាត,
POS Profile is required to use Point-of-Sale,ព័ត៌មានអំពីម៉ាស៊ីនឆូតកាតត្រូវបានតម្រូវឱ្យប្រើ Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,សូមជ្រើសប្រភេទទទួលបន្ទុកជាលើកដំបូង,
Please select Company,សូមជ្រើសរើសក្រុមហ៊ុន,
Please select Company and Designation,សូមជ្រើសរើសក្រុមហ៊ុននិងការកំណត់,
-Please select Company and Party Type first,សូមជ្រើសប្រភេទក្រុមហ៊ុននិងបក្សទីមួយ,
Please select Company and Posting Date to getting entries,សូមជ្រើសរើសក្រុមហ៊ុននិងកាលបរិច្ឆេទប្រកាសដើម្បីទទួលបានធាតុ,
Please select Company first,សូមជ្រើសរើសក្រុមហ៊ុនដំបូង,
Please select Completion Date for Completed Asset Maintenance Log,សូមជ្រើសកាលបរិច្ឆេទបញ្ចប់សម្រាប់កំណត់ហេតុថែរក្សាទ្រព្យសម្បត្តិរួចរាល់,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,ជួរដេក {0}: UOM ការប្រែចិត្តជឿកត្តាគឺជាការចាំបាច់,
Row {0}: select the workstation against the operation {1},ជួរដេក {0}: ជ្រើសកន្លែងធ្វើការប្រឆាំងនឹងប្រតិបត្តិការ {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,ជួរដេក {0}: {1} លេខរៀងដែលទាមទារសម្រាប់ធាតុ {2} ។ អ្នកបានផ្តល់ {3} ។,
-Row {0}: {1} is required to create the Opening {2} Invoices,ជួរដេក {0}: {1} ត្រូវបានទាមទារដើម្បីបង្កើតវិក័យប័ត្រ {2} បើក,
Row {0}: {1} must be greater than 0,ជួរដេក {0}: {1} ត្រូវតែធំជាង 0,
Row {0}: {1} {2} does not match with {3},ជួរដេក {0}: {1} {2} មិនផ្គូផ្គងនឹង {3},
Row {0}:Start Date must be before End Date,ជួរដេក {0}: ចាប់ផ្តើមកាលបរិច្ឆេទត្រូវតែមុនពេលដែលកាលបរិច្ឆេទបញ្ចប់,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,សូមផ្ញើអ៊ីម៉ែលពិនិត្យជំនួយ,
Send Now,ផ្ញើឥឡូវ,
Send SMS,ផ្ញើសារជាអក្សរ,
-Send Supplier Emails,ផ្ញើអ៊ីម៉ែលផ្គត់ផ្គង់,
Send mass SMS to your contacts,ផ្ញើសារជាអក្សរដ៏ធំមួយដើម្បីទំនាក់ទំនងរបស់អ្នក,
Sensitivity,ភាពប្រែប្រួល,
Sent,ដែលបានផ្ញើ,
-Serial #,# សៀរៀល,
Serial No and Batch,សៀរៀលទេនិងបាច់ & ‧;,
Serial No is mandatory for Item {0},គ្មានស៊េរីគឺជាការចាំបាច់សម្រាប់ធាតុ {0},
Serial No {0} does not belong to Batch {1},ស៊េរីលេខ {0} មិនមែនជារបស់ {1} បាច់ទេ,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,ឈ្មោះរបស់ក្រុមហ៊ុនរបស់អ្នកដែលអ្នកកំពុងបង្កើតប្រព័ន្ធនេះ។,
The number of shares and the share numbers are inconsistent,ចំនួនភាគហ៊ុននិងលេខភាគហ៊ុនមិនសមស្រប,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,គណនីច្រកទូទាត់នៅក្នុងគម្រោង {0} គឺខុសពីគណនីទូទាត់ប្រាក់នៅក្នុងការបង់ប្រាក់នេះ,
-The request for quotation can be accessed by clicking on the following link,សំណើរសម្រាប់សម្រង់នេះអាចត្រូវបានចូលដំណើរការដោយចុចលើតំណខាងក្រោម,
The selected BOMs are not for the same item,នេះ BOMs បានជ្រើសរើសគឺមិនមែនសម្រាប់ធាតុដូចគ្នា,
The selected item cannot have Batch,ធាតុដែលបានជ្រើសមិនអាចមានជំនាន់ទី,
The seller and the buyer cannot be the same,អ្នកលក់និងអ្នកទិញមិនអាចមានលក្ខណៈដូចគ្នាទេ,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},ចំនួនសរុបនៃផលប្រយោជន៏ដែលអាចបត់បែនបាន {0} មិនគួរតិចជាងអត្ថប្រយោជន៍ច្រើនបំផុត {1},
Total hours: {0},ម៉ោងសរុប: {0},
Total leaves allocated is mandatory for Leave Type {0},ចំនួនស្លឹកដែលបានបម្រុងទុកគឺចាំបាច់សម្រាប់ការចាកចេញពីប្រភេទ {0},
-Total weightage assigned should be 100%. It is {0},weightage សរុបដែលបានផ្ដល់គួរតែទទួលបាន 100% ។ វាគឺជា {0},
Total working hours should not be greater than max working hours {0},ម៉ោងធ្វើការសរុបមិនគួរត្រូវបានធំជាងម៉ោងធ្វើការអតិបរមា {0},
Total {0} ({1}),សរុប {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","សរុប {0} សម្រាប់ធាតុទាំងអស់គឺសូន្យ, អាចជាអ្នកគួរផ្លាស់ប្តូរ "ចែកបទចោទប្រកាន់ដោយផ្អែកលើ",
@@ -3316,7 +3299,6 @@
What do you need help with?,តើអ្នកត្រូវការអ្វីខ្លះជួយជាមួយនឹង?,
What does it do?,តើធ្វើដូចម្ដេច?,
Where manufacturing operations are carried.,ដែលជាកន្លែងដែលប្រតិបត្ដិការផលិតត្រូវបានអនុវត្ត។,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","នៅពេលបង្កើតគណនីសម្រាប់ក្រុមហ៊ុនកុមារ {0}, រកមិនឃើញ {1} ពត៌មានពីមាតាឬបិតា។ សូមបង្កើតគណនីមេនៅក្នុង COA ដែលត្រូវគ្នា",
White,សេត,
Wire Transfer,ការផ្ទេរខ្សែ,
WooCommerce Products,ផលិតផលវ៉ាយហ្វាយ។,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} បានបង្កើតវ៉ារ្យ៉ង់។,
{0} {1} created,{0} {1} បានបង្កើត,
{0} {1} does not exist,{0} {1} មិនមាន,
-{0} {1} does not exist.,{0} {1} មិនមានទេ។,
{0} {1} has been modified. Please refresh.,{0} {1} បានកែប្រែទេ។ សូមផ្ទុកឡើងវិញ។,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} មិនត្រូវបានដាក់ស្នើដូច្នេះសកម្មភាពនេះមិនអាចត្រូវបានបញ្ចប់,
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1} ត្រូវបានភ្ជាប់ជាមួយនឹង {2} ប៉ុន្តែគណនីបក្សគឺ {3},
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0} {1} មិនមាន,
{0}: {1} not found in Invoice Details table,{0}: {1} មិនត្រូវបានរកឃើញនៅក្នុងតារាងវិក្កយបត្ររាយលំអិត,
{} of {},{} នៃ {},
+Assigned To,បានផ្ដល់តម្លៃទៅ,
Chat,ការជជែកកំសាន្ត,
Completed By,បានបញ្ចប់ដោយ,
Conditions,លក្ខខណ្ឌ,
@@ -3506,7 +3488,9 @@
Merge with existing,បញ្ចូលចូលគ្នាជាមួយនឹងការដែលមានស្រាប់,
Office,ការិយាល័យ,
Orientation,ការតំរង់ទិស,
+Parent,មាតាឬបិតា,
Passive,អកម្ម,
+Payment Failed,ការទូទាត់បរាជ័យ,
Percent,ភាគរយ,
Permanent,អចិន្រ្តៃយ៍,
Personal,ផ្ទាល់ខ្លួន,
@@ -3544,7 +3528,6 @@
Company field is required,វាលក្រុមហ៊ុនត្រូវបានទាមទារ។,
Creating Dimensions...,កំពុងបង្កើតវិមាត្រ ...,
Duplicate entry against the item code {0} and manufacturer {1},ស្ទួនធាតុប្រឆាំងនឹងកូដធាតុ {0} និងក្រុមហ៊ុនផលិត {1},
-Import Chart Of Accounts from CSV / Excel files,នាំចូលតារាងតម្លៃគណនីពីឯកសារស៊ីអេសអេស / អេហ្វអេស។,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN មិនត្រឹមត្រូវ! ការបញ្ចូលដែលអ្នកបានបញ្ចូលមិនត្រូវគ្នានឹងទំរង់ GSTIN សំរាប់អ្នកកាន់ UIN រឺអ្នកផ្តល់សេវាកម្ម OIDAR មិនមែនអ្នកស្នាក់នៅ។,
Invoice Grand Total,វិក្ក័យបត្រសរុប។,
Last carbon check date cannot be a future date,កាលបរិច្ឆេទពិនិត្យកាបូនចុងក្រោយមិនអាចជាកាលបរិច្ឆេទនាពេលអនាគតទេ។,
@@ -3556,6 +3539,7 @@
Show {0},បង្ហាញ {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","តួអក្សរពិសេសលើកលែងតែ "-", "#", "។ ", "/", "{" និង "}" មិនត្រូវបានអនុញ្ញាតក្នុងស៊េរីដាក់ឈ្មោះ",
Target Details,ព័ត៌មានលម្អិតគោលដៅ។,
+{0} already has a Parent Procedure {1}.,{0} មាននីតិវិធីឪពុកម្តាយរួចហើយ {1} ។,
API,API,
Annual,ប្រចាំឆ្នាំ,
Approved,បានអនុម័ត,
@@ -3572,6 +3556,8 @@
No data to export,គ្មានទិន្នន័យត្រូវនាំចេញ។,
Portrait,បញ្ឈរ។,
Print Heading,បោះពុម្ពក្បាល,
+Scheduler Inactive,ឧបករណ៍កំណត់ពេលវេលាអសកម្ម។,
+Scheduler is inactive. Cannot import data.,ឧបករណ៍កំណត់ពេលវេលាគឺអសកម្ម។ មិនអាចនាំចូលទិន្នន័យ។,
Show Document,បង្ហាញឯកសារ។,
Show Traceback,បង្ហាញ Traceback ។,
Video,វីដេអូ។,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},បង្កើតការត្រួតពិនិត្យគុណភាពសម្រាប់ធាតុ {0},
Creating Accounts...,កំពុងបង្កើតគណនី ...,
Creating bank entries...,បង្កើតធាតុបញ្ចូលធនាគារ ...,
-Creating {0},បង្កើត {0},
Credit limit is already defined for the Company {0},ដែនកំណត់ឥណទានត្រូវបានកំណត់រួចហើយសម្រាប់ក្រុមហ៊ុន {0},
Ctrl + Enter to submit,បញ្ជា (Ctrl) + បញ្ចូល (Enter) ដើម្បីដាក់ស្នើ។,
Ctrl+Enter to submit,បញ្ជា (Ctrl) + បញ្ចូល (Enter) ដើម្បីដាក់ស្នើ,
@@ -3921,7 +3906,6 @@
Plaid public token error,កំហុសនិមិត្តសញ្ញាសាធារណៈរបស់ Plaid ។,
Plaid transactions sync error,កំហុសក្នុងការធ្វើសមកាលកម្មប្រតិបត្តិការ Plaid ។,
Please check the error log for details about the import errors,សូមពិនិត្យកំណត់ហេតុកំហុសសម្រាប់ព័ត៌មានលម្អិតអំពីកំហុសនាំចូល។,
-Please click on the following link to set your new password,សូមចុចលើតំណខាងក្រោមដើម្បីកំណត់ពាក្យសម្ងាត់ថ្មីរបស់អ្នក,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,សូមបង្កើត <b>ការកំណត់ DATEV</b> សម្រាប់ក្រុមហ៊ុន <b>{}</b> ។,
Please create adjustment Journal Entry for amount {0} ,សូមបង្កើតការកែសម្រួលទិនានុប្បវត្តិធាតុសម្រាប់ចំនួន {0},
Please do not create more than 500 items at a time,សូមកុំបង្កើតរបស់របរច្រើនជាង ៥០០ ក្នុងពេលតែមួយ។,
@@ -3997,6 +3981,7 @@
Release date must be in the future,កាលបរិច្ឆេទនៃការចេញផ្សាយត្រូវតែមាននាពេលអនាគត។,
Relieving Date must be greater than or equal to Date of Joining,កាលបរិច្ឆេទដែលទុកចិត្តត្រូវតែធំជាងឬស្មើកាលបរិច្ឆេទនៃការចូលរួម,
Rename,ប្តូរឈ្មោះ,
+Rename Not Allowed,មិនប្តូរឈ្មោះមិនអនុញ្ញាត។,
Repayment Method is mandatory for term loans,វិធីសាស្រ្តទូទាត់សងគឺចាំបាច់សម្រាប់ប្រាក់កម្ចីរយៈពេល,
Repayment Start Date is mandatory for term loans,កាលបរិច្ឆេទចាប់ផ្តើមសងគឺចាំបាច់សម្រាប់ប្រាក់កម្ចីមានកាលកំណត់,
Report Item,រាយការណ៍អំពីធាតុ។,
@@ -4043,7 +4028,6 @@
Select All,ជ្រើសទាំងអស់,
Select Difference Account,ជ្រើសរើសគណនីខុសគ្នា។,
Select a Default Priority.,ជ្រើសអាទិភាពលំនាំដើម។,
-Select a Supplier from the Default Supplier List of the items below.,ជ្រើសរើសអ្នកផ្គត់ផ្គង់ពីបញ្ជីអ្នកផ្គត់ផ្គង់លំនាំដើមនៃធាតុខាងក្រោម។,
Select a company,ជ្រើសរើសក្រុមហ៊ុន។,
Select finance book for the item {0} at row {1},ជ្រើសរើសសៀវភៅហិរញ្ញវត្ថុសម្រាប់ធាតុ {០} នៅជួរ {១},
Select only one Priority as Default.,ជ្រើសអាទិភាពមួយជាលំនាំដើម។,
@@ -4247,7 +4231,6 @@
Actual ,ពិតប្រាកដ,
Add to cart,បញ្ចូលទៅក្នុងរទេះ,
Budget,ថវិការ,
-Chart Of Accounts Importer,តារាងនាំចូលគណនី។,
Chart of Accounts,តារាងគណនី,
Customer database.,មូលដ្ឋានទិន្នន័យអតិថិជន។,
Days Since Last order,ថ្ងៃចាប់ពីលំដាប់ចុងក្រោយ,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,កាលបរិច្ឆេទបញ្ចប់មិនអាចតិចជាងកាលបរិច្ឆេទចាប់ផ្ដើមទេ,
For Default Supplier (Optional),សម្រាប់អ្នកផ្គត់ផ្គង់លំនាំដើម (ស្រេចចិត្ត),
From date cannot be greater than To date,ពីកាលបរិច្ឆេទមិនអាចមានចំនួនច្រើនជាងកាលបរិច្ឆេទ,
-Get items from,ទទួលបានមុខទំនិញពី,
Group by,ក្រុមតាម,
In stock,នៅក្នុងស្តុក,
Item name,ឈ្មោះធាតុ,
@@ -4532,32 +4514,22 @@
Accounts Settings,ការកំណត់គណនី,
Settings for Accounts,ការកំណត់សម្រាប់គណនី,
Make Accounting Entry For Every Stock Movement,ធ្វើឱ្យធាតុគណនេយ្យសម្រាប់គ្រប់ចលនាហ៊ុន,
-"If enabled, the system will post accounting entries for inventory automatically.",បើអនុញ្ញាតប្រព័ន្ធនេះនឹងផ្តល់ការបញ្ចូលគណនីសម្រាប់ការដោយស្វ័យប្រវត្តិ។,
-Accounts Frozen Upto,រីករាយជាមួយនឹងទឹកកកគណនី,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",ធាតុគណនេយ្យកករហូតដល់កាលបរិច្ឆេទនេះគ្មាននរណាម្នាក់អាចធ្វើ / កែប្រែធាតុមួយលើកលែងតែជាតួនាទីដែលបានបញ្ជាក់ខាងក្រោម។,
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,តួនាទីដែលត្រូវបានអនុញ្ញាតឱ្យកំណត់គណនីទឹកកកកែសម្រួលធាតុទឹកកក,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,អ្នកប្រើដែលមានតួនាទីនេះត្រូវបានអនុញ្ញាតឱ្យកំណត់គណនីរបស់ទឹកកកនិងបង្កើត / កែប្រែធាតុគណនេយ្យប្រឆាំងនឹងគណនីជាទឹកកក,
Determine Address Tax Category From,កំណត់ប្រភេទពន្ធអាសយដ្ឋានពី។,
-Address used to determine Tax Category in transactions.,អាសយដ្ឋានត្រូវបានប្រើដើម្បីកំណត់ប្រភេទពន្ធនៅក្នុងប្រតិបត្តិការ។,
Over Billing Allowance (%),ប្រាក់លើសវិក្កយបត្រ (គិតជាភាគរយ),
-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 for $110.,ភាគរយដែលអ្នកត្រូវបានអនុញ្ញាតឱ្យចេញវិក្កយបត្រច្រើនជាងចំនួនដែលបានបញ្ជា។ ឧទាហរណ៍ៈប្រសិនបើតម្លៃបញ្ជាទិញគឺ ១០០ ដុល្លារសម្រាប់ទំនិញមួយហើយការអត់អោនត្រូវបានកំណត់ ១០ ភាគរយនោះអ្នកត្រូវបានអនុញ្ញាតឱ្យចេញវិក្កយបត្រក្នុងតម្លៃ ១១០ ដុល្លារ។,
Credit Controller,ឧបករណ៍ត្រួតពិនិត្យឥណទាន,
-Role that is allowed to submit transactions that exceed credit limits set.,តួនាទីដែលត្រូវបានអនុញ្ញាតឱ្យដាក់ស្នើតិបត្តិការដែលលើសពីដែនកំណត់ឥណទានបានកំណត់។,
Check Supplier Invoice Number Uniqueness,ពិនិត្យហាងទំនិញវិក័យប័ត្រលេខពិសេស,
Make Payment via Journal Entry,ធ្វើឱ្យសេវាទូទាត់តាមរយៈ Journal Entry,
Unlink Payment on Cancellation of Invoice,ដោះតំណទូទាត់វិក័យប័ត្រនៅលើការលុបចោល,
-Unlink Advance Payment on Cancelation of Order,ដកការបង់ប្រាក់ជាមុនលើការលុបចោលការបញ្ជាទិញ។,
Book Asset Depreciation Entry Automatically,សៀវភៅរំលស់ទ្រព្យសម្បត្តិចូលដោយស្វ័យប្រវត្តិ,
Automatically Add Taxes and Charges from Item Tax Template,បន្ថែមពន្ធនិងការគិតថ្លៃដោយស្វ័យប្រវត្តិពីគំរូពន្ធលើទំនិញ។,
Automatically Fetch Payment Terms,ប្រមូលយកលក្ខខណ្ឌទូទាត់ដោយស្វ័យប្រវត្តិ។,
-Show Inclusive Tax In Print,បង្ហាញពន្ធបញ្ចូលគ្នាក្នុងការបោះពុម្ព,
Show Payment Schedule in Print,បង្ហាញតារាងទូទាត់ប្រាក់នៅក្នុងការបោះពុម្ព,
Currency Exchange Settings,ការកំណត់ប្តូររូបិយប័ណ្ណ,
Allow Stale Exchange Rates,អនុញ្ញាតឱ្យមានអត្រាប្តូរប្រាក់ថេរ,
Stale Days,Stale Days,
Report Settings,កំណត់របាយការណ៍,
Use Custom Cash Flow Format,ប្រើទំរង់លំហូរសាច់ប្រាក់ផ្ទាល់ខ្លួន,
-Only select if you have setup Cash Flow Mapper documents,ជ្រើសរើសតែអ្នកប្រសិនបើអ្នកបានរៀបចំឯកសារ Cash Flow Mapper,
Allowed To Transact With,បានអនុញ្ញាតឱ្យធ្វើការជាមួយ,
SWIFT number,លេខ SWIFT,
Branch Code,លេខកូដសាខា,
@@ -4940,7 +4912,6 @@
POS Customer Group,ក្រុមផ្ទាល់ខ្លួនម៉ាស៊ីនឆូតកាត,
POS Field,វាលម៉ាស៊ីនឆូតកាត,
POS Item Group,គ្រុបធាតុម៉ាស៊ីនឆូតកាត,
-[Select],[ជ្រើសរើស],
Company Address,អាសយដ្ឋានរបស់ក្រុមហ៊ុន,
Update Stock,ធ្វើឱ្យទាន់សម័យហ៊ុន,
Ignore Pricing Rule,មិនអើពើវិធានតម្លៃ,
@@ -5495,8 +5466,6 @@
Supplier Naming By,ដាក់ឈ្មោះអ្នកផ្គត់ផ្គង់ដោយ,
Default Supplier Group,ក្រុមអ្នកផ្គត់ផ្គង់លំនាំដើម,
Default Buying Price List,តារាងតម្លៃទិញលំនាំដើម & ‧;,
-Maintain same rate throughout purchase cycle,រក្សាអត្រាការប្រាក់ដូចគ្នាពេញមួយវដ្តនៃការទិញ,
-Allow Item to be added multiple times in a transaction,អនុញ្ញាតឱ្យធាតុនឹងត្រូវបានបន្ថែមជាច្រើនដងនៅក្នុងប្រតិបត្តិការ,
Backflush Raw Materials of Subcontract Based On,Backflush វត្ថុធាតុដើមនៃកិច្ចសន្យាដែលមានមូលដ្ឋានលើ,
Material Transferred for Subcontract,សម្ភារៈបានផ្ទេរសម្រាប់កិច្ចសន្យាម៉ៅការ,
Over Transfer Allowance (%),ប្រាក់ឧបត្ថម្ភផ្ទេរលើស (%),
@@ -5540,7 +5509,6 @@
Current Stock,ហ៊ុននាពេលបច្ចុប្បន្ន,
PUR-RFQ-.YYYY.-,PUR-RFQ-yYYYY.-,
For individual supplier,សម្រាប់ផ្គត់ផ្គង់បុគ្គល,
-Supplier Detail,ក្រុមហ៊ុនផ្គត់ផ្គង់លំអិត,
Link to Material Requests,ភ្ជាប់ទៅនឹងតម្រូវការសម្ភារៈ,
Message for Supplier,សារសម្រាប់ផ្គត់ផ្គង់,
Request for Quotation Item,ស្នើសុំសម្រាប់ធាតុសម្រង់,
@@ -6481,7 +6449,6 @@
Appraisal Template,ការវាយតម្លៃទំព័រគំរូ,
For Employee Name,សម្រាប់ឈ្មោះបុគ្គលិក,
Goals,គ្រាប់បាល់បញ្ចូលទី,
-Calculate Total Score,គណនាពិន្ទុសរុប,
Total Score (Out of 5),ពិន្ទុសរុប (ក្នុងចំណោម 5),
"Any other remarks, noteworthy effort that should go in the records.","ការកត់សម្គាល់ណាមួយផ្សេងទៀត, ការខិតខំប្រឹងប្រែងគួរឱ្យកត់សម្គាល់ដែលគួរតែចូលទៅក្នុងរបាយការណ៍។",
Appraisal Goal,គោលដៅវាយតម្លៃ,
@@ -6599,11 +6566,6 @@
Reason for Leaving,ហេតុផលសម្រាប់ការចាកចេញ,
Leave Encashed?,ទុកឱ្យ Encashed?,
Encashment Date,Encashment កាលបរិច្ឆេទ,
-Exit Interview Details,ពត៌មានលំអិតចេញពីការសម្ភាសន៍,
-Held On,ប្រារព្ធឡើងនៅថ្ងៃទី,
-Reason for Resignation,ហេតុផលសម្រាប់ការលាលែងពីតំណែង,
-Better Prospects,ទស្សនវិស័យល្អប្រសើរជាងមុន,
-Health Concerns,ការព្រួយបារម្ភសុខភាព,
New Workplace,ញូការងារ,
HR-EAD-.YYYY.-,HR-EAD -YYYY.-,
Returned Amount,ចំនួនទឹកប្រាក់ត្រឡប់មកវិញ,
@@ -6740,10 +6702,7 @@
Employee Settings,ការកំណត់បុគ្គលិក,
Retirement Age,អាយុចូលនិវត្តន៍,
Enter retirement age in years,បញ្ចូលអាយុចូលនិវត្តន៍នៅក្នុងប៉ុន្មានឆ្នាំ,
-Employee Records to be created by,កំណត់ត្រាបុគ្គលិកដែលនឹងត្រូវបានបង្កើតឡើងដោយ,
-Employee record is created using selected field. ,កំណត់ត្រាបុគ្គលិកត្រូវបានបង្កើតដោយប្រើវាលដែលបានជ្រើស។,
Stop Birthday Reminders,បញ្ឈប់ការរំលឹកខួបកំណើត,
-Don't send Employee Birthday Reminders,កុំផ្ញើបុគ្គលិករំលឹកខួបកំណើត,
Expense Approver Mandatory In Expense Claim,អ្នកអនុម័តប្រាក់ចំណាយចាំបាច់ក្នុងការទាមទារសំណង,
Payroll Settings,ការកំណត់បើកប្រាក់បៀវត្ស,
Leave,ចាកចេញ,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,ទុកអ្នកអនុម័តជាចាំបាច់ក្នុងការចាកចេញពីកម្មវិធី,
Show Leaves Of All Department Members In Calendar,បង្ហាញស្លឹករបស់សមាជិកនាយកដ្ឋានទាំងអស់នៅក្នុងប្រតិទិន,
Auto Leave Encashment,ការចាកចេញពីរថយន្តដោយស្វ័យប្រវត្តិ។,
-Restrict Backdated Leave Application,ដាក់កម្រិតពាក្យសុំឈប់សម្រាកហួសសម័យ,
Hiring Settings,ជួលការកំណត់។,
Check Vacancies On Job Offer Creation,ពិនិត្យមើលភាពទំនេរលើការបង្កើតការផ្តល់ជូនការងារ។,
Identification Document Type,ប្រភេទឯកសារអត្តសញ្ញាណ,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,ការកំណត់កម្មន្តសាល,
Raw Materials Consumption,ការប្រើប្រាស់វត្ថុធាតុដើម,
Allow Multiple Material Consumption,អនុញ្ញាតឱ្យមានការប្រើប្រាស់សម្ភារៈច្រើន,
-Allow multiple Material Consumption against a Work Order,អនុញ្ញាតិអោយការប្រើប្រាស់វត្ថុធាតុដើមជាច្រើនប្រឆាំងនឹងស្នាដៃការងារ,
Backflush Raw Materials Based On,Backflush វត្ថុធាតុដើមដែលមានមូលដ្ឋាននៅលើ,
Material Transferred for Manufacture,សម្ភារៈផ្ទេរសម្រាប់ការផលិត,
Capacity Planning,ផែនការការកសាងសមត្ថភាព,
Disable Capacity Planning,បិទផែនការសមត្ថភាព,
Allow Overtime,អនុញ្ញាតឱ្យបន្ថែមម៉ោង,
-Plan time logs outside Workstation Working Hours.,គម្រោងការកំណត់ហេតុពេលវេលាដែលនៅក្រៅម៉ោងស្ថានីយការងារការងារ។,
Allow Production on Holidays,ផលិតកម្មនៅលើថ្ងៃឈប់សម្រាកអនុញ្ញាតឱ្យ,
Capacity Planning For (Days),ផែនការការកសាងសមត្ថភាពសម្រាប់ (ថ្ងៃ),
-Try planning operations for X days in advance.,ការធ្វើផែនការប្រតិបត្ដិការសម្រាប់ការព្យាយាមរបស់ X នៅមុនថ្ងៃ។,
-Time Between Operations (in mins),ពេលវេលារវាងការប្រតិបត្តិការ (នៅក្នុងនាទី),
-Default 10 mins,10 នាទីលំនាំដើម,
Default Warehouses for Production,ឃ្លាំងលំនាំដើមសម្រាប់ផលិតកម្ម,
Default Work In Progress Warehouse,ការងារលំនាំដើមនៅក្នុងឃ្លាំងវឌ្ឍនភាព,
Default Finished Goods Warehouse,ឃ្លាំងទំនិញលំនាំដើមបានបញ្ចប់,
Default Scrap Warehouse,ឃ្លាំងអេតចាយលំនាំដើម,
-Over Production for Sales and Work Order,លើសផលិតកម្មសម្រាប់ការលក់និងសណ្តាប់ធ្នាប់ការងារ,
Overproduction Percentage For Sales Order,ភាគរយលើសផលិតកម្មសម្រាប់លំដាប់លក់,
Overproduction Percentage For Work Order,ភាគរយលើសផលិតកម្មសម្រាប់ស្នាដៃការងារ,
Other Settings,ការកំណត់ផ្សេងទៀត,
Update BOM Cost Automatically,ធ្វើបច្ចុប្បន្នភាពថ្លៃចំណាយរបស់ក្រុមហ៊ុនដោយស្វ័យប្រវត្តិ,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",បន្ទាន់សម័យ BOM ចំណាយដោយស្វ័យប្រវត្តិតាមរយៈកម្មវិធីកំណត់ពេលដោយផ្អែកលើអត្រាតំលៃចុងក្រោយ / អត្រាតំលៃបញ្ជី / អត្រាទិញចុងក្រោយនៃវត្ថុធាតុដើម។,
Material Request Plan Item,សម្ភារៈផែនការគម្រោង,
Material Request Type,ប្រភេទស្នើសុំសម្ភារៈ,
Material Issue,សម្ភារៈបញ្ហា,
@@ -7603,10 +7554,6 @@
Quality Goal,គោលដៅគុណភាព។,
Monitoring Frequency,ភាពញឹកញាប់នៃការត្រួតពិនិត្យ។,
Weekday,ថ្ងៃធ្វើការ។,
-January-April-July-October,មករា - មេសា - កក្កដា - តុលា។,
-Revision and Revised On,ការពិនិត្យឡើងវិញនិងកែលម្អឡើងវិញ។,
-Revision,ការពិនិត្យឡើងវិញ,
-Revised On,បានកែសំរួលនៅថ្ងៃទី។,
Objectives,គោលបំណង។,
Quality Goal Objective,គោលបំណងគោលដៅគុណភាព។,
Objective,គោលបំណង។,
@@ -7619,7 +7566,6 @@
Processes,ដំណើរការ។,
Quality Procedure Process,ដំណើរការនីតិវិធីគុណភាព។,
Process Description,ការពិពណ៌នាអំពីដំណើរការ។,
-Child Procedure,នីតិវិធីកុមារ,
Link existing Quality Procedure.,ភ្ជាប់នីតិវិធីគុណភាពដែលមានស្រាប់។,
Additional Information,ព័ត៍មានបន្ថែម,
Quality Review Objective,គោលបំណងពិនិត្យគុណភាព។,
@@ -7787,15 +7733,9 @@
Default Customer Group,លំនាំដើមគ្រុបអតិថិជន,
Default Territory,ដែនដីលំនាំដើម,
Close Opportunity After Days,ឱកាសការងារបន្ទាប់ពីថ្ងៃបិទ,
-Auto close Opportunity after 15 days,ដោយស្វ័យប្រវត្តិបន្ទាប់ពីឱកាសយ៉ាងជិតស្និទ្ធ 15 ថ្ងៃ,
Default Quotation Validity Days,សុពលភាពតំលៃថ្ងៃខែ,
Sales Update Frequency,ភាពញឹកញាប់នៃការធ្វើបច្ចុប្បន្នភាព,
-How often should project and company be updated based on Sales Transactions.,តើគួរធ្វើបច្ចុប្បន្នភាពគម្រោងនិងក្រុមហ៊ុនដោយផ្អែកលើប្រតិបត្ដិការលក់ជាញឹកញាប់។,
Each Transaction,កិច្ចការនីមួយៗ,
-Allow user to edit Price List Rate in transactions,អនុញ្ញាតឱ្យអ្នកប្រើដើម្បីកែសម្រួលអត្រាតំលៃបញ្ជីនៅក្នុងប្រតិបត្តិការ,
-Allow multiple Sales Orders against a Customer's Purchase Order,អនុញ្ញាតឱ្យមានការបញ្ជាទិញការលក់ការទិញសណ្តាប់ធ្នាប់ជាច្រើនប្រឆាំងនឹងអតិថិជនរបស់មួយ,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,ធ្វើឱ្យមានសុពលភាពសម្រាប់ធាតុលក់តម្លៃអត្រាការទិញឬការប្រឆាំងនឹងការវាយតម្លៃអត្រាការប្រាក់,
-Hide Customer's Tax Id from Sales Transactions,លាក់លេខសម្គាល់របស់អតិថិជនពន្ធពីការលក់,
SMS Center,ផ្ញើសារជាអក្សរមជ្ឈមណ្ឌល,
Send To,បញ្ជូនទៅ,
All Contact,ទំនាក់ទំនងទាំងអស់,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,ក្រុមហ៊ុនផលិតដែលត្រូវបានប្រើនៅក្នុងធាតុ,
Limited to 12 characters,កំណត់ទៅជា 12 តួអក្សរ,
MAT-MR-.YYYY.-,MAT-MR-YYYY.-,
-Set Warehouse,កំណត់ឃ្លាំង,
-Sets 'For Warehouse' in each row of the Items table.,កំណត់ 'សម្រាប់ឃ្លាំង' នៅក្នុងជួរនីមួយៗនៃតារាងធាតុ។,
-Requested For,ស្នើសម្រាប់,
Partially Ordered,បានបញ្ជាទិញដោយផ្នែក,
Transferred,ផ្ទេរ,
% Ordered,% បានបញ្ជា(ទិញឬលក់),
@@ -8407,24 +8344,14 @@
Default Stock UOM,លំនាំដើមហ៊ុន UOM,
Sample Retention Warehouse,ឃ្លាំងស្តុកគំរូ,
Default Valuation Method,វិធីសាស្រ្តវាយតម្លៃលំនាំដើម,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,ចំនួនភាគរយដែលអ្នកត្រូវបានអនុញ្ញាតឱ្យទទួលបានច្រើនជាងការប្រឆាំងនឹងឬផ្តល់នូវបរិមាណបញ្ជាឱ្យ។ ឧទាហរណ៍: ប្រសិនបើអ្នកបានបញ្ជាឱ្យបាន 100 គ្រឿង។ និងអនុញ្ញាតឱ្យរបស់អ្នកគឺ 10% បន្ទាប់មកលោកអ្នកត្រូវបានអនុញ្ញាតឱ្យទទួលបាន 110 គ្រឿង។,
-Action if Quality inspection is not submitted,សកម្មភាពប្រសិនបើការត្រួតពិនិត្យគុណភាពមិនត្រូវបានដាក់ស្នើ។,
Show Barcode Field,បង្ហាញវាលលេខកូដ,
Convert Item Description to Clean HTML,បម្លែងពិពណ៌នាធាតុទៅស្អាត HTML,
-Auto insert Price List rate if missing,បញ្ចូលដោយស្វ័យប្រវត្តិប្រសិនបើអ្នកមានអត្រាតារាងតម្លៃបាត់ខ្លួន,
Allow Negative Stock,អនុញ្ញាតឱ្យមានស្តុកអវិជ្ជមាន,
Automatically Set Serial Nos based on FIFO,កំណត់សម្គាល់ Nos ដោយស្វ័យប្រវត្តិដោយផ្អែកលើ FIFO & ‧;,
-Set Qty in Transactions based on Serial No Input,កំណត់ Qty នៅក្នុងប្រតិបត្តិការដែលមានមូលដ្ឋានលើលេខស៊េរី,
Auto Material Request,សម្ភារៈស្នើសុំដោយស្វ័យប្រវត្តិ,
-Raise Material Request when stock reaches re-order level,ចូរលើកសំណើសុំនៅពេលដែលភាគហ៊ុនសម្ភារៈឈានដល់កម្រិតបញ្ជាទិញឡើងវិញ,
-Notify by Email on creation of automatic Material Request,ជូនដំណឹងដោយអ៊ីមែលនៅលើការបង្កើតសម្ភារៈស្នើសុំដោយស្វ័យប្រវត្តិ,
Inter Warehouse Transfer Settings,កំណត់ការផ្ទេរប្រាក់អន្តរឃ្លាំង,
-Allow Material Transfer From Delivery Note and Sales Invoice,អនុញ្ញាតឱ្យផ្ទេរសម្ភារៈពីកំណត់ត្រាចែកចាយនិងវិក័យប័ត្រលក់,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,អនុញ្ញាតឱ្យផ្ទេរសម្ភារៈពីវិក័យប័ត្រទិញនិងវិក័យប័ត្រទិញ,
Freeze Stock Entries,ធាតុបង្កហ៊ុន,
Stock Frozen Upto,រីករាយជាមួយនឹងផ្សារភាគហ៊ុនទឹកកក,
-Freeze Stocks Older Than [Days],ភាគហ៊ុនបង្កកចាស់ជាង [ថ្ងៃ],
-Role Allowed to edit frozen stock,តួនាទីដែលត្រូវបានអនុញ្ញាតឱ្យកែសម្រួលភាគហ៊ុនទឹកកក,
Batch Identification,លេខសម្គាល់,
Use Naming Series,ប្រើស៊ុមឈ្មោះ,
Naming Series Prefix,ដាក់ឈ្មោះបុព្វបទស៊េរី,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,និន្នាការបង្កាន់ដៃទិញ,
Purchase Register,ទិញចុះឈ្មោះ,
Quotation Trends,សម្រង់និន្នាការ,
-Quoted Item Comparison,ធាតុដកស្រង់សម្តីប្រៀបធៀប,
Received Items To Be Billed,ទទួលបានធាតុដែលនឹងត្រូវបានផ្សព្វផ្សាយ,
Qty to Order,qty ម៉ង់ទិញ,
Requested Items To Be Transferred,ធាតុដែលបានស្នើសុំឱ្យគេបញ្ជូន,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,ជ្រើសរើសឃ្លាំងសម្រាប់ការស្នើសុំសម្ភារៈ,
Transfer Materials For Warehouse {0},ផ្ទេរសម្ភារៈសម្រាប់ឃ្លាំង {0},
Production Plan Material Request Warehouse,សម្ភារៈស្នើសុំផែនការផលិតកម្មឃ្លាំង,
-Set From Warehouse,កំណត់ពីឃ្លាំង,
-Source Warehouse (Material Transfer),ឃ្លាំងប្រភព (ផ្ទេរសម្ភារៈ),
Sets 'Source Warehouse' in each row of the items table.,កំណត់ 'ឃ្លាំងប្រភព' នៅក្នុងជួរនីមួយៗនៃតារាងធាតុ។,
Sets 'Target Warehouse' in each row of the items table.,កំណត់ 'ឃ្លាំងគោលដៅ' នៅក្នុងជួរនីមួយៗនៃតារាងធាតុ។,
Show Cancelled Entries,បង្ហាញធាតុដែលបានបោះបង់,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,សេវាកម្មបានទទួលប៉ុន្តែមិនបានគិតប្រាក់ទេ,
Deferred Accounting Settings,ការកំណត់គណនីពនរ,
Book Deferred Entries Based On,ធាតុពនរសៀវភៅដែលមានមូលដ្ឋានលើ,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",ប្រសិនបើ "ខែ" ត្រូវបានជ្រើសរើសនោះចំនួនទឹកប្រាក់ថេរនឹងត្រូវបានកក់ទុកជាចំណូលដែលបានពន្យារឬចំណាយសម្រាប់ខែនីមួយៗដោយមិនគិតពីចំនួនថ្ងៃក្នុងមួយខែ។ នឹងត្រូវបានកំណត់ប្រសិនបើប្រាក់ចំណូលឬការចំណាយមិនត្រូវបានរក្សាទុកពេញមួយខែ។,
Days,ថ្ងៃ,
Months,ខែ,
Book Deferred Entries Via Journal Entry,ធាតុសៀវភៅពត៌មានតាមរយៈធាតុទិនានុប្បវត្តិ,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,ប្រសិនបើនេះមិនត្រូវបានធីកដោយផ្ទាល់ក្រុមហ៊ុន GL នឹងត្រូវបានបង្កើតឡើងដើម្បីកក់ចំណូល / ចំណាយដែលបានពនរ,
Submit Journal Entries,បញ្ជូនធាតុទិនានុប្បវត្តិ,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,ប្រសិនបើនេះមិនត្រូវបានធីកធាតុទិនានុប្បវត្តិនឹងត្រូវបានរក្សាទុកក្នុងស្ថានភាពព្រាងហើយនឹងត្រូវដាក់ស្នើដោយដៃ,
Enable Distributed Cost Center,បើកដំណើរការមជ្ឈមណ្ឌលចំណាយចែកចាយ,
@@ -8901,8 +8823,6 @@
Is Inter State,គឺរដ្ឋអន្តររដ្ឋ,
Purchase Details,ព័ត៌មានលម្អិតការទិញ,
Depreciation Posting Date,កាលបរិច្ឆេទប្រកាសរំលោះរំលោះ,
-Purchase Order Required for Purchase Invoice & Receipt Creation,ការបញ្ជាទិញដែលត្រូវការសម្រាប់ការទិញវិក័យប័ត្រនិងការបង្កើតបង្កាន់ដៃ,
-Purchase Receipt Required for Purchase Invoice Creation,វិក័យប័ត្រទិញត្រូវការសម្រាប់ការបង្កើតវិក័យប័ត្រទិញ,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",តាមលំនាំដើមឈ្មោះអ្នកផ្គត់ផ្គង់ត្រូវបានកំណត់តាមឈ្មោះអ្នកផ្គត់ផ្គង់ដែលបានបញ្ចូល។ ប្រសិនបើអ្នកចង់ឱ្យអ្នកផ្គត់ផ្គង់ត្រូវបានដាក់ឈ្មោះដោយក,
choose the 'Naming Series' option.,ជ្រើសរើសជំរើស“ ការដាក់ឈ្មោះស៊េរី” ។,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,កំណត់បញ្ជីតម្លៃលំនាំដើមនៅពេលបង្កើតប្រតិបត្តិការទិញថ្មី។ តម្លៃទំនិញនឹងត្រូវបានទាញយកពីបញ្ជីតម្លៃនេះ។,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,គឺជាសមាសធាតុពន្ធលើប្រាក់ចំណូល,
Component properties and references ,លក្ខណៈសម្បត្តិនិងឯកសារយោង,
Additional Salary ,ប្រាក់ខែបន្ថែម,
-Condtion and formula,លក្ខខណ្ឌនិងរូបមន្ត,
Unmarked days,ថ្ងៃដែលមិនបានសម្គាល់,
Absent Days,ថ្ងៃអវត្តមាន,
Conditions and Formula variable and example,លក្ខខណ្ឌនិងអថេររូបមន្តនិងឧទាហរណ៍,
Feedback By,មតិដោយ,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .- ។ MM .- DD.-,
Manufacturing Section,ផ្នែកផលិត,
-Sales Order Required for Sales Invoice & Delivery Note Creation,ការបញ្ជាទិញដែលត្រូវការសម្រាប់វិក័យប័ត្រលក់និងការបង្កើតកំណត់ត្រាចែកចាយ,
-Delivery Note Required for Sales Invoice Creation,កំណត់ចំណាំការដឹកជញ្ជូនត្រូវការសម្រាប់ការបង្កើតវិក័យប័ត្រលក់,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",តាមលំនាំដើមឈ្មោះអតិថិជនត្រូវបានកំណត់ដូចឈ្មោះពេញដែលបានបញ្ចូល។ ប្រសិនបើអ្នកចង់អោយអតិថិជនដាក់ឈ្មោះដោយក,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,កំណត់បញ្ជីតម្លៃលំនាំដើមនៅពេលបង្កើតប្រតិបត្តិការលក់ថ្មី។ តម្លៃទំនិញនឹងត្រូវបានទាញយកពីបញ្ជីតម្លៃនេះ។,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",ប្រសិនបើជម្រើសនេះត្រូវបានកំណត់រចនាសម្ព័ន្ធ 'បាទ / ចាស' នោះ ERP បន្ទាប់នឹងរារាំងអ្នកពីការបង្កើតវិក្កយបត្រលក់ឬកំណត់ត្រាចែកចាយដោយមិនចាំបាច់បង្កើតការបញ្ជាទិញជាមុនទេ។ ការកំណត់រចនាសម្ព័ន្ធនេះអាចត្រូវបានបដិសេធចំពោះអតិថិជនពិសេសដោយបើកប្រអប់ធីក 'អនុញ្ញាតការបង្កើតវិក័យប័ត្រលក់ដោយគ្មានការបញ្ជាទិញ' នៅក្នុងម៉ាស្ទ័រអតិថិជន។,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} ត្រូវបានបន្ថែមទៅគ្រប់ប្រធានបទដែលបានជ្រើសរើសដោយជោគជ័យ។,
Topics updated,ប្រធានបទត្រូវបានធ្វើបច្ចុប្បន្នភាព,
Academic Term and Program,រយៈពេលសិក្សានិងកម្មវិធី,
-Last Stock Transaction for item {0} was on {1}.,ប្រតិបត្តិការភាគហ៊ុនចុងក្រោយសម្រាប់ធាតុ {0} គឺនៅលើ {1} ។,
-Stock Transactions for Item {0} cannot be posted before this time.,ប្រតិបត្តិការភាគហ៊ុនសម្រាប់ធាតុ {0} មិនអាចត្រូវបានប្រកាសមុនពេលនេះទេ។,
Please remove this item and try to submit again or update the posting time.,សូមយកធាតុនេះចេញហើយព្យាយាមដាក់ស្នើម្តងទៀតឬធ្វើបច្ចុប្បន្នភាពពេលវេលាប្រកាស។,
Failed to Authenticate the API key.,បានបរាជ័យក្នុងការផ្ទៀងផ្ទាត់លេខកូដ API ។,
Invalid Credentials,លិខិតសម្គាល់មិនត្រឹមត្រូវ,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,សូមពិនិត្យលេខសម្គាល់អតិថិជន Plaid និងតម្លៃសំងាត់,
Bank transaction creation error,កំហុសក្នុងការបង្កើតប្រតិបត្តិការធនាគារ,
Unit of Measurement,ឯកតារង្វាស់,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},ជួរដេក # {}៖ អត្រាលក់របស់ធាតុ {} ទាបជាង {} របស់វា។ អត្រាលក់គួរតែមានភាពអន់បំផុត {},
Fiscal Year {0} Does Not Exist,ឆ្នាំសារពើពន្ធ {០} មិនមានទេ,
Row # {0}: Returned Item {1} does not exist in {2} {3},ជួរដេក # {០}៖ ធាតុដែលបានត្រឡប់ {១} មិនមាននៅក្នុង {២} {៣},
Valuation type charges can not be marked as Inclusive,ការចោទប្រកាន់ប្រភេទតម្លៃមិនអាចត្រូវបានសម្គាល់ថារាប់បញ្ចូលនោះទេ,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,ពេលវេលាឆ្លើយតបសម្រាប់ {0} អាទិភាពក្នុងជួរដេក {1} មិនអាចធំជាងពេលវេលាដោះស្រាយបានទេ។,
{0} is not enabled in {1},{0} មិនត្រូវបានបើកនៅក្នុង {1},
Group by Material Request,ដាក់ជាក្រុមតាមសំណើសម្ភារៈ,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",ជួរដេក {0}៖ សម្រាប់អ្នកផ្គត់ផ្គង់ {0} អាស័យដ្ឋានអ៊ីម៉ែលគឺត្រូវការផ្ញើអ៊ីមែល,
Email Sent to Supplier {0},អ៊ីមែលបានផ្ញើទៅអ្នកផ្គត់ផ្គង់ {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",សិទ្ធិទទួលបានការស្នើសុំដកស្រង់ពីវិបផតថលត្រូវបានបិទ។ ដើម្បីអនុញ្ញាតការចូលប្រើបើកវានៅក្នុងការកំណត់វិបផតថល។,
Supplier Quotation {0} Created,សម្រង់អ្នកផ្គត់ផ្គង់ {០} បង្កើត,
Valid till Date cannot be before Transaction Date,សុពលភាពរហូតដល់កាលបរិច្ឆេទមិនអាចមុនកាលបរិច្ឆេទប្រតិបត្តិការ,
+Unlink Advance Payment on Cancellation of Order,ដកការបង់ប្រាក់ជាមុនលើការលុបចោលការបញ្ជាទិញ,
+"Simple Python Expression, Example: territory != 'All Territories'",កន្សោមពស់ថ្លាន់សាមញ្ញឧទាហរណ៍៖ ទឹកដី! = 'ដែនដីទាំងអស់',
+Sales Contributions and Incentives,វិភាគទានការលក់និងការលើកទឹកចិត្ត,
+Sourced by Supplier,ប្រភពដោយអ្នកផ្គត់ផ្គង់,
+Total weightage assigned should be 100%.<br>It is {0},ទំងន់សរុបដែលបានកំណត់គួរមាន 100% ។<br> វាគឺ {0},
+Account {0} exists in parent company {1}.,គណនី {0} មាននៅក្នុងក្រុមហ៊ុនមេ {1} ។,
+"To overrule this, enable '{0}' in company {1}",ដើម្បីបដិសេធរឿងនេះបើកដំណើរការ '{0}' នៅក្នុងក្រុមហ៊ុន {1},
+Invalid condition expression,ការបង្ហាញលក្ខខណ្ឌមិនត្រឹមត្រូវ,
+Please Select a Company First,សូមជ្រើសរើសក្រុមហ៊ុនជាមុនសិន,
+Please Select Both Company and Party Type First,សូមជ្រើសរើសទាំងក្រុមហ៊ុននិងប្រភេទគណបក្សជាមុនសិន,
+Provide the invoice portion in percent,ផ្តល់ចំណែកវិក័យប័ត្រគិតជាភាគរយ,
+Give number of days according to prior selection,ផ្តល់ចំនួនថ្ងៃយោងទៅតាមការជ្រើសរើសមុន,
+Email Details,ព័ត៌មានលម្អិតអ៊ីមែល,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","ជ្រើសរើសការស្វាគមន៍សម្រាប់អ្នកទទួល។ ឧ។ លោក, លោកស្រី, ល។",
+Preview Email,មើលអ៊ីមែលជាមុន,
+Please select a Supplier,សូមជ្រើសរើសអ្នកផ្គត់ផ្គង់,
+Supplier Lead Time (days),ពេលវេលានាំមុខអ្នកផ្គត់ផ្គង់ (ថ្ងៃ),
+"Home, Work, etc.",ផ្ទះកន្លែងធ្វើការ។ ល។,
+Exit Interview Held On,ការសំភាសន៍ចាកចេញបានធ្វើឡើង,
+Condition and formula,លក្ខខណ្ឌនិងរូបមន្ត,
+Sets 'Target Warehouse' in each row of the Items table.,កំណត់ 'ឃ្លាំងគោលដៅ' នៅក្នុងជួរនីមួយៗនៃតារាងធាតុ។,
+Sets 'Source Warehouse' in each row of the Items table.,កំណត់ 'ឃ្លាំងប្រភព' នៅក្នុងជួរនីមួយៗនៃតារាងធាតុ។,
+POS Register,ចុះឈ្មោះម៉ាស៊ីនឆូតកាត,
+"Can not filter based on POS Profile, if grouped by POS Profile",មិនអាចច្រោះដោយផ្អែកលើ POS Profile ទេប្រសិនបើត្រូវបានដាក់ជាក្រុមដោយ POS Profile,
+"Can not filter based on Customer, if grouped by Customer",មិនអាចច្រោះដោយផ្អែកលើអតិថិជនប្រសិនបើដាក់ជាក្រុមដោយអតិថិជន,
+"Can not filter based on Cashier, if grouped by Cashier",មិនអាចច្រោះដោយផ្អែកលើបេឡាករបានទេប្រសិនបើដាក់ជាក្រុមដោយបេឡាករ,
+Payment Method,វិធីសាស្រ្តទូទាត់,
+"Can not filter based on Payment Method, if grouped by Payment Method",មិនអាចច្រោះដោយផ្អែកលើវិធីបង់ប្រាក់ប្រសិនបើដាក់ជាក្រុមដោយវិធីបង់ប្រាក់,
+Supplier Quotation Comparison,ការប្រៀបធៀបសម្រង់អ្នកផ្គត់ផ្គង់,
+Price per Unit (Stock UOM),តម្លៃក្នុងមួយឯកតា (ស្តុក UOM),
+Group by Supplier,ដាក់ជាក្រុមដោយអ្នកផ្គត់ផ្គង់,
+Group by Item,ដាក់ជាក្រុមតាមធាតុ,
+Remember to set {field_label}. It is required by {regulation}.,កុំភ្លេចកំណត់ {វាល - ស្លាក} ។ វាត្រូវបានទាមទារដោយ {បទប្បញ្ញត្តិ} ។,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},កាលបរិច្ឆេទចុះឈ្មោះចូលរៀនមិនអាចនៅមុនកាលបរិច្ឆេទចាប់ផ្តើមនៃឆ្នាំសិក្សា {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},កាលបរិច្ឆេទចុះឈ្មោះចូលរៀនមិនអាចនៅក្រោយកាលបរិច្ឆេទបញ្ចប់នៃរយៈពេលសិក្សា {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},កាលបរិច្ឆេទចុះឈ្មោះចូលរៀនមិនអាចនៅមុនកាលបរិច្ឆេទចាប់ផ្ដើមនៃរយៈពេលសិក្សា {០},
+Future Posting Not Allowed,ការបិទផ្សាយអនាគតមិនត្រូវបានអនុញ្ញាតទេ,
+"To enable Capital Work in Progress Accounting, ",ដើម្បីបើកដំណើរការគណនេយ្យនៅក្នុងវឌ្ឍនភាពគណនេយ្យ,
+you must select Capital Work in Progress Account in accounts table,អ្នកត្រូវជ្រើសរើសគណនីដើមទុនក្នុងដំណើរការវឌ្ឍនភាពនៅក្នុងតារាងគណនី,
+You can also set default CWIP account in Company {},អ្នកក៏អាចកំណត់គណនី CWIP លំនាំដើមនៅក្នុងក្រុមហ៊ុន {},
+The Request for Quotation can be accessed by clicking on the following button,ការស្នើសុំដកស្រង់អាចចូលបានដោយចុចលើប៊ូតុងខាងក្រោម,
+Regards,ដោយក្តីគោរព,
+Please click on the following button to set your new password,សូមចុចលើប៊ូតុងខាងក្រោមដើម្បីកំណត់លេខសំងាត់ថ្មីរបស់អ្នក,
+Update Password,ពាក្យសម្ងាត់ធ្វើបច្ចុប្បន្នភាព,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},ជួរដេក # {}៖ អត្រាលក់របស់ធាតុ {} ទាបជាង {} របស់វា។ ការលក់ {} គួរតែមានភាពអន់បំផុត {},
+You can alternatively disable selling price validation in {} to bypass this validation.,អ្នកអាចជំនួសការលក់សុពលភាពតម្លៃនៅក្នុង {} ដើម្បីចៀសវៀងសុពលភាពនេះ។,
+Invalid Selling Price,តំលៃលក់មិនត្រឹមត្រូវ,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,អាសយដ្ឋានត្រូវភ្ជាប់ទៅក្រុមហ៊ុន។ សូមបន្ថែមជួរសម្រាប់ក្រុមហ៊ុននៅក្នុងតារាងតំណ។,
+Company Not Linked,ក្រុមហ៊ុនមិនភ្ជាប់,
+Import Chart of Accounts from CSV / Excel files,នាំចូលតារាងតម្លៃគណនីពីឯកសារស៊ីអេសអេស / អេហ្វអេស,
+Completed Qty cannot be greater than 'Qty to Manufacture',Qty ដែលបានបញ្ចប់មិនអាចធំជាង“ Qty to Manufacturing” ទេ។,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",ជួរដេក {0}៖ សម្រាប់អ្នកផ្គត់ផ្គង់ {1} អាស័យដ្ឋានអ៊ីមែលត្រូវបានទាមទារដើម្បីផ្ញើអ៊ីមែល,
+"If enabled, the system will post accounting entries for inventory automatically",ប្រសិនបើបានបើកដំណើរការប្រព័ន្ធនឹងប្រកាសធាតុគណនេយ្យសម្រាប់សារពើភ័ណ្ឌដោយស្វ័យប្រវត្តិ,
+Accounts Frozen Till Date,គណនីជាប់គាំងរហូតដល់កាលបរិច្ឆេទ,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,ធាតុគណនេយ្យត្រូវបានជាប់គាំងរហូតដល់កាលបរិច្ឆេទនេះ។ គ្មាននរណាម្នាក់អាចបង្កើតឬកែប្រែធាតុបានទេលើកលែងតែអ្នកប្រើប្រាស់ដែលមានតួនាទីដូចបានបញ្ជាក់ខាងក្រោម,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,តួនាទីត្រូវបានអនុញ្ញាតឱ្យកំណត់គណនីកកនិងកែសម្រួលធាតុដែលបង្កក,
+Address used to determine Tax Category in transactions,អាសយដ្ឋានត្រូវបានប្រើដើម្បីកំណត់ប្រភេទពន្ធនៅក្នុងប្រតិបត្តិការ,
+"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 ",ភាគរយដែលអ្នកត្រូវបានអនុញ្ញាតឱ្យចេញវិក្កយបត្រច្រើនជាងចំនួនដែលបានបញ្ជា។ ឧទាហរណ៍ប្រសិនបើតម្លៃបញ្ជាទិញគឺ ១០០ ដុល្លារសម្រាប់ទំនិញហើយការអត់អោនត្រូវបានកំណត់ ១០ ភាគរយនោះអ្នកត្រូវបានអនុញ្ញាតឱ្យចេញវិក្កយបត្ររហូតដល់ ១១០ ដុល្លារ,
+This role is allowed to submit transactions that exceed credit limits,តួនាទីនេះត្រូវបានអនុញ្ញាតឱ្យដាក់ប្រតិបត្តិការដែលលើសពីដែនកំណត់ឥណទាន,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",ប្រសិនបើ "ខែ" ត្រូវបានជ្រើសរើសចំនួនថេរនឹងត្រូវបានកក់ទុកជាចំណូលដែលបានពន្យារឬចំណាយសម្រាប់ខែនីមួយៗដោយមិនគិតពីចំនួនថ្ងៃក្នុងមួយខែ។ វានឹងត្រូវបានបញ្ជាក់ប្រសិនបើប្រាក់ចំណូលពន្យាឬការចំណាយមិនត្រូវបានគេកក់អស់រយៈពេលមួយខែ,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",ប្រសិនបើវាមិនត្រូវបានត្រួតពិនិត្យទេធាតុ GL ផ្ទាល់នឹងត្រូវបានបង្កើតឡើងដើម្បីកក់ចំណូលឬចំណាយដែលពន្យា,
+Show Inclusive Tax in Print,បង្ហាញពន្ធបញ្ចូលក្នុងការបោះពុម្ព,
+Only select this if you have set up the Cash Flow Mapper documents,ជ្រើសរើសវាប្រសិនបើអ្នកបានរៀបចំឯកសារលំហូរសាច់ប្រាក់,
+Payment Channel,ឆានែលទូទាត់,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,តើការបញ្ជាទិញត្រូវបានទាមទារសម្រាប់ការទិញវិក័យប័ត្រនិងការបង្កើតបង្កាន់ដៃ?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,តើវិក័យប័ត្រទិញត្រូវបានទាមទារសម្រាប់ការបង្កើតវិក័យប័ត្រទិញមែនទេ?,
+Maintain Same Rate Throughout the Purchase Cycle,រក្សាអត្រាដដែលនៅទូទាំងវដ្តនៃការទិញ,
+Allow Item To Be Added Multiple Times in a Transaction,អនុញ្ញាតឱ្យបន្ថែមធាតុជាច្រើនដងក្នុងប្រតិបត្តិការ,
+Suppliers,អ្នកផ្គត់ផ្គង់,
+Send Emails to Suppliers,ផ្ញើអ៊ីមែលទៅអ្នកផ្គត់ផ្គង់,
+Select a Supplier,ជ្រើសរើសអ្នកផ្គត់ផ្គង់,
+Cannot mark attendance for future dates.,មិនអាចសម្គាល់ការចូលរួមសម្រាប់កាលបរិច្ឆេទនាពេលអនាគតបានទេ។,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},តើអ្នកចង់ធ្វើបច្ចុប្បន្នភាពការចូលរួមទេ?<br> បច្ចុប្បន្ន៖ {០}<br> អវត្តមាន៖ {១},
+Mpesa Settings,ការកំណត់ម៉ាល់ប៉ា,
+Initiator Name,ឈ្មោះអ្នកផ្ដើមគំនិត,
+Till Number,លេខរហូតដល់,
+Sandbox,Sandbox,
+ Online PassKey,លើបណ្តាញ PassKey,
+Security Credential,លិខិតសម្គាល់សុវត្ថិភាព,
+Get Account Balance,ទទួលបានសមតុល្យគណនី,
+Please set the initiator name and the security credential,សូមកំណត់ឈ្មោះអ្នកផ្តួចផ្តើមនិងលិខិតសម្គាល់សុវត្ថិភាព,
+Inpatient Medication Entry,ការចូលប្រើថ្នាំព្យាបាលអ្នកជំងឺ,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),លេខកូដធាតុ (គ្រឿងញៀន),
+Medication Orders,ការបញ្ជាទិញឱសថ,
+Get Pending Medication Orders,ទទួលការបញ្ជាទិញឱសថដែលមិនទាន់សម្រេច,
+Inpatient Medication Orders,ការបញ្ជាទិញថ្នាំព្យាបាលអ្នកជំងឺ,
+Medication Warehouse,ឃ្លាំងឱសថ,
+Warehouse from where medication stock should be consumed,ឃ្លាំងពីកន្លែងស្តុកថ្នាំគួរតែត្រូវបានប្រើប្រាស់,
+Fetching Pending Medication Orders,ទទួលយកការបញ្ជាទិញឱសថដែលមិនទាន់សម្រេច,
+Inpatient Medication Entry Detail,ពត៌មានលំអិតអំពីការប្រើថ្នាំសំរាប់អ្នកជំងឺ,
+Medication Details,ព័ត៌មានលម្អិតអំពីថ្នាំ,
+Drug Code,ក្រមគ្រឿងញៀន,
+Drug Name,ឈ្មោះថ្នាំ,
+Against Inpatient Medication Order,ប្រឆាំងនឹងបទបញ្ជាថ្នាំសំរាប់អ្នកជម្ងឺ,
+Against Inpatient Medication Order Entry,ការប្រឆាំងនឹងការបញ្ជាទិញថ្នាំចូលអ្នកជំងឺ,
+Inpatient Medication Order,ការបញ្ជាទិញឱសថព្យាបាលអ្នកជំងឺ,
+HLC-IMO-.YYYY.-,HLC-IMO -YYYY.-,
+Total Orders,ការបញ្ជាទិញសរុប,
+Completed Orders,ការបញ្ជាទិញដែលបានបញ្ចប់,
+Add Medication Orders,បន្ថែមការបញ្ជាទិញឱសថ,
+Adding Order Entries,បន្ថែមធាតុលំដាប់,
+{0} medication orders completed,{0} ការបញ្ជាទិញថ្នាំបានបញ្ចប់,
+{0} medication order completed,{0} ការបញ្ជាទិញថ្នាំបានបញ្ចប់,
+Inpatient Medication Order Entry,ការបញ្ជាទិញការព្យាបាលដោយថ្នាំចូល,
+Is Order Completed,ត្រូវបានបញ្ចប់ការបញ្ជាទិញ,
+Employee Records to Be Created By,កំណត់ត្រានិយោជិកដែលត្រូវបង្កើតដោយ,
+Employee records are created using the selected field,កំណត់ត្រានិយោជិកត្រូវបានបង្កើតដោយប្រើវាលដែលបានជ្រើសរើស,
+Don't send employee birthday reminders,កុំផ្ញើការរំលឹកថ្ងៃកំណើតរបស់និយោជិក,
+Restrict Backdated Leave Applications,ដាក់កម្រិតពាក្យសុំឈប់សម្រាកហួសសម័យ,
+Sequence ID,លេខសម្គាល់លំដាប់,
+Sequence Id,លេខសម្គាល់លំដាប់,
+Allow multiple material consumptions against a Work Order,អនុញ្ញាតឱ្យមានការសន្មតសម្ភារៈជាច្រើនប្រឆាំងនឹងបទបញ្ជាការងារ,
+Plan time logs outside Workstation working hours,រៀបចំផែនការកំណត់ហេតុនៅខាងក្រៅម៉ោងធ្វើការ,
+Plan operations X days in advance,គំរោងប្រតិបត្តិការ X ថ្ងៃមុន,
+Time Between Operations (Mins),ពេលវេលារវាងប្រតិបត្តិការ (មីន),
+Default: 10 mins,លំនាំដើម៖ ១០ នាទី,
+Overproduction for Sales and Work Order,ការផលិតហួសកំរិតសម្រាប់ការលក់និងសណ្តាប់ធ្នាប់ការងារ,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",ធ្វើបច្ចុប្បន្នភាពការចំណាយ BOM ដោយស្វ័យប្រវត្តិតាមរយៈកម្មវិធីកំណត់ពេលដោយផ្អែកលើអត្រាវាយតម្លៃចុងក្រោយ / អត្រាបញ្ជីតម្លៃ / អត្រាទិញវត្ថុធាតុដើមចុងក្រោយ,
+Purchase Order already created for all Sales Order items,ការបញ្ជាទិញដែលបានបង្កើតរួចហើយសម្រាប់រាល់ការបញ្ជាទិញការលក់,
+Select Items,ជ្រើសរើសធាតុ,
+Against Default Supplier,ប្រឆាំងនឹងអ្នកផ្គត់ផ្គង់លំនាំដើម,
+Auto close Opportunity after the no. of days mentioned above,ឱកាសបិទដោយស្វ័យប្រវត្តិបន្ទាប់ពីលេខ។ នៃថ្ងៃដែលបានរៀបរាប់ខាងលើ,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,តើការបញ្ជាទិញត្រូវបានទាមទារសម្រាប់ការលក់វិក័យប័ត្រនិងការបង្កើតកំណត់ចំណាំនៃការចែកចាយដែរឬទេ?,
+Is Delivery Note Required for Sales Invoice Creation?,តើកំណត់ចំណាំនៃការដឹកជញ្ជូនត្រូវការសម្រាប់ការបង្កើតវិក្កយបត្រលក់ដែរឬទេ?,
+How often should Project and Company be updated based on Sales Transactions?,តើគម្រោងនិងក្រុមហ៊ុនគួរតែត្រូវបានធ្វើបច្ចុប្បន្នភាពញឹកញាប់ប៉ុណ្ណាដោយផ្អែកលើប្រតិបត្តិការលក់?,
+Allow User to Edit Price List Rate in Transactions,អនុញ្ញាតឱ្យអ្នកប្រើប្រាស់កែសម្រួលអត្រាបញ្ជីតម្លៃក្នុងប្រតិបត្តិការ,
+Allow Item to Be Added Multiple Times in a Transaction,អនុញ្ញាតឱ្យបន្ថែមធាតុជាច្រើនដងក្នុងប្រតិបត្តិការ,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,អនុញ្ញាតឱ្យមានការបញ្ជាទិញការលក់ច្រើនដងប្រឆាំងនឹងការបញ្ជាទិញរបស់អតិថិជន,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,ធ្វើឱ្យតម្លៃលក់មានសុពលភាពសម្រាប់ធាតុធៀបនឹងអត្រាទិញឬអត្រាវាយតម្លៃ,
+Hide Customer's Tax ID from Sales Transactions,លាក់អត្តសញ្ញាណពន្ធរបស់អតិថិជនពីប្រតិបត្តិការលក់,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.",ភាគរយដែលអ្នកត្រូវបានអនុញ្ញាតឱ្យទទួលឬចែកចាយច្រើនជាងចំនួនដែលបានបញ្ជា។ ឧទាហរណ៍ប្រសិនបើអ្នកបានបញ្ជាទិញចំនួន 100 គ្រឿងហើយប្រាក់ឧបត្ថម្ភរបស់អ្នកគឺ 10% បន្ទាប់មកអ្នកត្រូវបានអនុញ្ញាតឱ្យទទួលបាន 110 គ្រឿង។,
+Action If Quality Inspection Is Not Submitted,សកម្មភាពប្រសិនបើការត្រួតពិនិត្យគុណភាពមិនត្រូវបានដាក់ស្នើ,
+Auto Insert Price List Rate If Missing,អត្រាបញ្ចូលតារាងតម្លៃដោយស្វ័យប្រវត្តិប្រសិនបើបាត់,
+Automatically Set Serial Nos Based on FIFO,កំណត់លេខស៊េរីស្វ័យប្រវត្តិដោយផ្អែកលើកូណូអេ,
+Set Qty in Transactions Based on Serial No Input,កំណត់ Qty ក្នុងប្រតិបត្តិការដោយផ្អែកលើសៀរៀលគ្មានធាតុចូល,
+Raise Material Request When Stock Reaches Re-order Level,បង្កើនសំណើសម្ភារៈនៅពេលស្តុកឈានដល់កម្រិតនៃការបញ្ជាទិញឡើងវិញ,
+Notify by Email on Creation of Automatic Material Request,ជូនដំណឹងតាមអ៊ីម៉ែលស្តីពីការបង្កើតសំណើសម្ភារៈស្វ័យប្រវត្តិ,
+Allow Material Transfer from Delivery Note to Sales Invoice,អនុញ្ញាតឱ្យផ្ទេរសម្ភារៈពីកំណត់ត្រាដឹកជញ្ជូនទៅវិក័យប័ត្រលក់,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,អនុញ្ញាតឱ្យផ្ទេរសម្ភារៈពីបង្កាន់ដៃទិញទៅវិក័យប័ត្រទិញ,
+Freeze Stocks Older Than (Days),ត្រជាក់ស្តុកចាស់ជាង (ថ្ងៃ),
+Role Allowed to Edit Frozen Stock,តួនាទីត្រូវបានអនុញ្ញាតឱ្យកែសម្រួលស្តុកកក,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,ចំនួនទឹកប្រាក់ដែលមិនបានផ្ទេរចូលនៃការទូទាត់ប្រាក់ {0} គឺធំជាងចំនួនទឹកប្រាក់ដែលមិនបានផ្ទេរតាមប្រតិបត្តិការរបស់ធនាគារ,
+Payment Received,បានទទួលការទូទាត់,
+Attendance cannot be marked outside of Academic Year {0},ការចូលរួមមិនអាចត្រូវបានសម្គាល់ក្រៅពីឆ្នាំសិក្សា {០},
+Student is already enrolled via Course Enrollment {0},និស្សិតត្រូវបានចុះឈ្មោះរួចហើយតាមរយៈការចុះឈ្មោះវគ្គសិក្សា {0},
+Attendance cannot be marked for future dates.,ការចូលរួមមិនអាចត្រូវបានសម្គាល់សម្រាប់កាលបរិច្ឆេទនាពេលអនាគតឡើយ។,
+Please add programs to enable admission application.,សូមបន្ថែមកម្មវិធីដើម្បីបើកពាក្យសុំចូលរៀន។,
+The following employees are currently still reporting to {0}:,និយោជិកខាងក្រោមកំពុងរាយការណ៍ទៅ {0}៖,
+Please make sure the employees above report to another Active employee.,សូមប្រាកដថានិយោជិកខាងលើរាយការណ៍ទៅនិយោជិកសកម្មផ្សេងទៀត។,
+Cannot Relieve Employee,មិនអាចជួយនិយោជិកបានទេ,
+Please enter {0},សូមបញ្ចូល {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',សូមជ្រើសរើសវិធីទូទាត់ប្រាក់ផ្សេងទៀត។ Mpesa មិនគាំទ្រប្រតិបត្តិការជារូបិយប័ណ្ណ '{0}',
+Transaction Error,កំហុសប្រតិបត្តិការ,
+Mpesa Express Transaction Error,កំហុសប្រតិបត្តិការប្រេសអ៊ិចប្រេស,
+"Issue detected with Mpesa configuration, check the error logs for more details",បញ្ហាត្រូវបានរកឃើញជាមួយការកំណត់រចនាសម្ព័ន្ធ Mpesa ពិនិត្យមើលកំណត់ហេតុកំហុសសម្រាប់ព័ត៌មានលំអិត,
+Mpesa Express Error,កំហុស Mpesa Express,
+Account Balance Processing Error,កំហុសក្នុងដំណើរការសមតុល្យគណនី,
+Please check your configuration and try again,សូមពិនិត្យការកំណត់របស់អ្នកហើយព្យាយាមម្តងទៀត,
+Mpesa Account Balance Processing Error,កំហុសដំណើរការសមតុល្យគណនី Mpesa,
+Balance Details,ព័ត៌មានលម្អិតអំពីតុល្យភាព,
+Current Balance,តុល្យភាពបច្ចុប្បន្ន,
+Available Balance,សមតុល្យដែលមាន,
+Reserved Balance,សមតុល្យបម្រុង,
+Uncleared Balance,តុល្យភាពមិនស្អាត,
+Payment related to {0} is not completed,ការទូទាត់ទាក់ទងនឹង {0} មិនត្រូវបានបញ្ចប់ទេ,
+Row #{}: Item Code: {} is not available under warehouse {}.,ជួរដេក # {}៖ លេខកូដៈ {} មិនមាននៅក្រោមឃ្លាំង {} ទេ។,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,ជួរដេក # {}៖ បរិមាណស្តុកមិនគ្រប់គ្រាន់សម្រាប់លេខកូដទំនិញ៖ {} នៅក្រោមឃ្លាំង {} ។ បរិមាណដែលមាន {} ។,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,ជួរទី # {}៖ សូមជ្រើសរើសសៀរៀលនិងបាច់ប្រឆាំងនឹងធាតុ៖ {} ឬយកវាចេញដើម្បីបញ្ចប់ប្រតិបត្តិការ។,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,ជួរដេក # {}៖ គ្មានលេខស៊េរីត្រូវបានជ្រើសរើសប្រឆាំងនឹងធាតុ៖ {} ។ សូមជ្រើសយកមួយឬយកវាចេញដើម្បីបញ្ចប់ប្រតិបត្តិការ។,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,ជួរដេក # {}៖ គ្មានបាច់ដែលបានជ្រើសប្រឆាំងនឹងធាតុ៖ {} ។ សូមជ្រើសរើសយកបាច់ឬយកវាចេញដើម្បីបញ្ចប់ប្រតិបត្តិការ។,
+Payment amount cannot be less than or equal to 0,ចំនួនទឹកប្រាក់ទូទាត់មិនតិចជាងឬស្មើ ០ ទេ,
+Please enter the phone number first,សូមបញ្ចូលលេខទូរស័ព្ទជាមុន,
+Row #{}: {} {} does not exist.,ជួរដេក # {}: {} {} មិនមានទេ។,
+Row #{0}: {1} is required to create the Opening {2} Invoices,ជួរដេក # {០}៖ {១} ត្រូវបង្កើតវិក្កយបត្របើក {២},
+You had {} errors while creating opening invoices. Check {} for more details,អ្នកមានកំហុស {} ពេលបង្កើតវិក្កយបត្របើក។ ពិនិត្យ {} សម្រាប់ព័ត៌មានលម្អិត,
+Error Occured,កំហុសកើតឡើង,
+Opening Invoice Creation In Progress,ការបើកការបង្កើតវិក្កយបត្រកំពុងដំណើរការ,
+Creating {} out of {} {},ការបង្កើត {} ចេញពី {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(សៀរៀលលេខ៖ {០}) មិនអាចប្រើប្រាស់បានទេព្រោះវាជាការផ្លាស់ប្តូរទៅនឹងការបញ្ជាទិញលក់ពេញលេញ {១} ។,
+Item {0} {1},ធាតុ {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,ប្រតិបត្តិការភាគហ៊ុនចុងក្រោយសំរាប់ទំនិញ {០} ក្រោមឃ្លាំង {១} គឺនៅលើ {២} ។,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,ប្រតិបត្តិការភាគហ៊ុនសម្រាប់ធាតុ {0} នៅក្រោមឃ្លាំង {1} មិនអាចត្រូវបានប្រកាសមុនពេលនេះទេ។,
+Posting future stock transactions are not allowed due to Immutable Ledger,ការបិទផ្សាយនូវប្រតិបត្តិការភាគហ៊ុននាពេលអនាគតមិនត្រូវបានអនុញ្ញាតទេដោយសារតែមិនអាចកែប្រែបាន,
+A BOM with name {0} already exists for item {1}.,BOM ដែលមានឈ្មោះ {0} មានរួចហើយសម្រាប់ធាតុ {1} ។,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} តើអ្នកបានប្តូរឈ្មោះធាតុទេ? សូមទាក់ទងរដ្ឋបាល / ជំនួយផ្នែកបច្ចេកទេស,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},នៅជួរទី # {0}៖ លេខសម្គាល់លេខរៀង {១} មិនអាចតិចជាងលេខសម្គាល់ជួរដេកពីមុនទេ {២},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) ត្រូវតែស្មើនឹង {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, បញ្ចប់ប្រតិបត្តិការ {1} មុនពេលប្រតិបត្តិការ {2} ។",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,មិនអាចធានាបានថាការដឹកជញ្ជូនតាមលេខមិនមែនជាធាតុ {0} ត្រូវបានបន្ថែមដោយនិងមិនធានាថាការដឹកជញ្ជូនតាមស៊េរីទេ។,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,ធាតុ {0} មិនមានលេខស៊េរីទេមានតែវត្ថុដែលមានសេរ៊ីលីតប៉ុណ្ណោះដែលអាចមានការដឹកជញ្ជូនដោយផ្អែកលើសៀរៀល,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,រកមិនឃើញ BOM សកម្មសម្រាប់ធាតុ {0} ។ ការដឹកជញ្ជូនតាមស៊េរីមិនអាចត្រូវបានធានាទេ,
+No pending medication orders found for selected criteria,គ្មានការបញ្ជាទិញថ្នាំដែលមិនទាន់សម្រេចត្រូវបានរកឃើញសម្រាប់លក្ខណៈវិនិច្ឆ័យដែលបានជ្រើសរើស,
+From Date cannot be after the current date.,ពីកាលបរិច្ឆេទមិនអាចបន្ទាប់ពីកាលបរិច្ឆេទបច្ចុប្បន្ន។,
+To Date cannot be after the current date.,កាលបរិច្ឆេទមិនអាចនៅក្រោយកាលបរិច្ឆេទបច្ចុប្បន្ន។,
+From Time cannot be after the current time.,ពីពេលវេលាមិនអាចបន្ទាប់ពីពេលបច្ចុប្បន្ន។,
+To Time cannot be after the current time.,ដល់ពេលវេលាមិនអាចជាពេលបច្ចុប្បន្ន។,
+Stock Entry {0} created and ,ធាតុចូល {0} បានបង្កើតនិង,
+Inpatient Medication Orders updated successfully,ការបញ្ជាទិញថ្នាំព្យាបាលអ្នកជំងឺបានធ្វើបច្ចុប្បន្នភាពដោយជោគជ័យ,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},ជួរដេក {0}៖ មិនអាចបង្កើតការបញ្ចូលថ្នាំចូលអ្នកជំងឺប្រឆាំងនឹងការបញ្ជាទិញថ្នាំសំរាប់អ្នកជម្ងឺដែលត្រូវបានលុបចោល {1},
+Row {0}: This Medication Order is already marked as completed,ជួរដេក {0}៖ ការបញ្ជាទិញថ្នាំនេះត្រូវបានសម្គាល់រួចហើយថាបានបញ្ចប់,
+Quantity not available for {0} in warehouse {1},បរិមាណមិនមានសម្រាប់ {0} នៅក្នុងឃ្លាំង {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,សូមអនុញ្ញាតអនុញ្ញាតភាគហ៊ុនអវិជ្ជមាននៅក្នុងការកំណត់ភាគហ៊ុនឬបង្កើតធាតុចូលដើម្បីដំណើរការបន្ត។,
+No Inpatient Record found against patient {0},គ្មានកំណត់ត្រាអ្នកជំងឺដែលរកឃើញប្រឆាំងនឹងអ្នកជំងឺ {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,ការបញ្ជាទិញថ្នាំព្យាបាលដោយអ្នកជម្ងឺ {0} ប្រឆាំងនឹងអ្នកជួបប្រទះអ្នកជម្ងឺ {1} មានរួចហើយ។,
+Allow In Returns,អនុញ្ញាតឱ្យត្រឡប់មកវិញ,
+Hide Unavailable Items,លាក់ធាតុដែលមិនមាន,
+Apply Discount on Discounted Rate,អនុវត្តការបញ្ចុះតម្លៃលើអត្រាបញ្ចុះតម្លៃ,
+Therapy Plan Template,គំរូផែនការព្យាបាល,
+Fetching Template Details,ការទាញយកព័ត៌មានលំអិតនៃគំរូ,
+Linked Item Details,ព័ត៌មានលំអិតទាក់ទងនឹងធាតុ,
+Therapy Types,ប្រភេទនៃការព្យាបាល,
+Therapy Plan Template Detail,ទំព័រគំរូលំអិតនៃផែនការព្យាបាល,
+Non Conformance,ការមិនអនុលោម,
+Process Owner,ម្ចាស់ដំណើរការ,
+Corrective Action,សកម្មភាពកែតម្រូវ,
+Preventive Action,សកម្មភាពការពារ,
+Problem,បញ្ហា,
+Responsible,ទទួលខុសត្រូវ,
+Completion By,បញ្ចប់ដោយ,
+Process Owner Full Name,ម្ចាស់ឈ្មោះដំណើរការពេញ,
+Right Index,សន្ទស្សន៍ត្រឹមត្រូវ,
+Left Index,សន្ទស្សន៍ខាងឆ្វេង,
+Sub Procedure,នីតិវិធីរង,
+Passed,បានឆ្លងកាត់,
+Print Receipt,បង្កាន់ដៃបោះពុម្ព,
+Edit Receipt,កែសម្រួលបង្កាន់ដៃ,
+Focus on search input,ផ្តោតលើការបញ្ចូលការស្វែងរក,
+Focus on Item Group filter,ផ្តោតលើតម្រងក្រុមធាតុ,
+Checkout Order / Submit Order / New Order,Checkout បញ្ជាទិញ / ដាក់បញ្ជាទិញ / បញ្ជាទិញថ្មី,
+Add Order Discount,បន្ថែមការបញ្ចុះតម្លៃតាមលំដាប់,
+Item Code: {0} is not available under warehouse {1}.,លេខកូដធាតុ៖ {០} មិនមាននៅក្រោមឃ្លាំង {១} ទេ។,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,លេខស៊េរីមិនអាចប្រើបានសម្រាប់ធាតុ {0} នៅក្រោមឃ្លាំង {1} ។ សូមព្យាយាមផ្លាស់ប្តូរឃ្លាំង។,
+Fetched only {0} available serial numbers.,ទទួលបានតែលេខ {0} ប៉ុណ្ណោះ។,
+Switch Between Payment Modes,ប្តូររវាងរបៀបបង់ប្រាក់,
+Enter {0} amount.,បញ្ចូលចំនួន {0} ។,
+You don't have enough points to redeem.,អ្នកមិនមានពិន្ទុគ្រប់គ្រាន់ដើម្បីលោះទេ។,
+You can redeem upto {0}.,អ្នកអាចផ្តោះប្តូរប្រាក់បានដល់លេខ {០} ។,
+Enter amount to be redeemed.,បញ្ចូលចំនួនទឹកប្រាក់ដែលត្រូវបង់រំលោះ។,
+You cannot redeem more than {0}.,អ្នកមិនអាចលោះច្រើនជាង {0} ទេ។,
+Open Form View,បើកទិដ្ឋភាពទម្រង់,
+POS invoice {0} created succesfully,វិក័យប័ត្រម៉ាស៊ីនឆូតកាត {០} បានបង្កើតដោយជោគជ័យ,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,បរិមាណស្តុកមិនគ្រប់គ្រាន់សម្រាប់លេខកូដទំនិញ៖ {០} ក្រោមឃ្លាំង {១} ។ បរិមាណដែលអាចរកបាន {2} ។,
+Serial No: {0} has already been transacted into another POS Invoice.,លេខស៊េរី៖ {០} ត្រូវបានប្តូរទៅជាវិក្កយបត្រម៉ាស៊ីនឆូតកាតផ្សេងទៀត។,
+Balance Serial No,លេខសៀរៀលគ្មាន,
+Warehouse: {0} does not belong to {1},ឃ្លាំង: {០} មិនមែនជាកម្មសិទ្ធិរបស់ {១} ទេ,
+Please select batches for batched item {0},សូមជ្រើសរើសបាច់សម្រាប់វត្ថុដែលមានឆ្នូតៗ {0},
+Please select quantity on row {0},សូមជ្រើសរើសបរិមាណនៅជួរ {0},
+Please enter serial numbers for serialized item {0},សូមបញ្ចូលលេខស៊េរីសម្រាប់ធាតុសៀរៀល {0},
+Batch {0} already selected.,បាច់ {0} ដែលបានជ្រើសរើសរួចហើយ។,
+Please select a warehouse to get available quantities,សូមជ្រើសរើសឃ្លាំងមួយដើម្បីទទួលបានបរិមាណដែលមាន,
+"For transfer from source, selected quantity cannot be greater than available quantity",សម្រាប់ការផ្ទេរពីប្រភពបរិមាណដែលបានជ្រើសរើសមិនអាចធំជាងបរិមាណដែលមានទេ,
+Cannot find Item with this Barcode,មិនអាចរកឃើញធាតុជាមួយលេខកូដនេះទេ,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} គឺចាំបាច់។ ប្រហែលជាកំណត់ត្រាការផ្លាស់ប្តូររូបិយប័ណ្ណមិនត្រូវបានបង្កើតឡើងសម្រាប់ {១} ដល់ {២},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} បានបញ្ជូនទ្រព្យសម្បត្តិដែលភ្ជាប់ទៅវា។ អ្នកត្រូវបោះបង់ទ្រព្យសម្បត្តិដើម្បីបង្កើតការទិញត្រឡប់មកវិញ។,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,មិនអាចលុបចោលឯកសារនេះទេព្រោះវាត្រូវបានភ្ជាប់ជាមួយទ្រព្យសម្បត្តិដែលបានដាក់ស្នើ {0} ។ សូមបោះបង់វាដើម្បីបន្ត។,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,ជួរទី # {}៖ លេខស៊េរី {} ត្រូវបានប្តូរទៅជាវិក្កយបត្រម៉ាស៊ីនឆូតកាតផ្សេងទៀត។ សូមជ្រើសរើសសៀរៀលត្រឹមត្រូវ។,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,ជួរទី # {}៖ សៀរៀលសៀរៀល។ {} បានប្តូរទៅជាវិក្កយបត្រម៉ាស៊ីនឆូតកាតផ្សេងទៀត។ សូមជ្រើសរើសសៀរៀលត្រឹមត្រូវ។,
+Item Unavailable,មិនមានធាតុ,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},ជួរទី # {}៖ លេខស៊េរី {} មិនអាចត្រលប់មកវិញទេពីព្រោះវាមិនត្រូវបានប្តូរទៅជាវិក័យប័ត្រដើម {},
+Please set default Cash or Bank account in Mode of Payment {},សូមកំណត់គណនីសាច់ប្រាក់ឬគណនីធនាគារលំនាំដើមក្នុងរបៀបបង់ប្រាក់ {},
+Please set default Cash or Bank account in Mode of Payments {},សូមកំណត់គណនីសាច់ប្រាក់ឬគណនីធនាគារក្នុងរបៀបបង់ប្រាក់ {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,សូមប្រាកដថា {} គណនីគឺជាគណនីសន្លឹកសមតុល្យ។ អ្នកអាចប្តូរគណនីមេទៅគណនីសន្លឹកសមតុល្យឬជ្រើសរើសគណនីផ្សេង។,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,សូមប្រាកដថា {} គណនីគឺជាគណនីដែលត្រូវបង់។ ផ្លាស់ប្តូរប្រភេទគណនីទៅជាការទូទាត់ឬជ្រើសរើសគណនីផ្សេងទៀត។,
+Row {}: Expense Head changed to {} ,ជួរដេក {}៖ ក្បាលចំណាយបានប្តូរទៅ {},
+because account {} is not linked to warehouse {} ,ពីព្រោះគណនី {} មិនត្រូវបានភ្ជាប់ទៅនឹងឃ្លាំង {},
+or it is not the default inventory account,ឬវាមិនមែនជាគណនីសារពើភ័ណ្ឌលំនាំដើម,
+Expense Head Changed,ប្តូរក្បាល,
+because expense is booked against this account in Purchase Receipt {},ពីព្រោះការចំណាយត្រូវបានកក់ទុកសម្រាប់គណនីនេះក្នុងវិក័យប័ត្រទិញ {},
+as no Purchase Receipt is created against Item {}. ,ដោយសារគ្មានវិក័យប័ត្រទិញត្រូវបានបង្កើតឡើងប្រឆាំងនឹងធាតុ {} ។,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,នេះត្រូវបានធ្វើដើម្បីដោះស្រាយគណនេយ្យករណីនៅពេលបង្កាន់ដៃទិញត្រូវបានបង្កើតបន្ទាប់ពីវិក័យប័ត្រទិញ,
+Purchase Order Required for item {},ការបញ្ជាទិញដែលត្រូវការសម្រាប់ធាតុ {},
+To submit the invoice without purchase order please set {} ,ដើម្បីដាក់វិក័យប័ត្រដោយគ្មានការបញ្ជាទិញសូមកំណត់ {},
+as {} in {},ដូចជានៅក្នុង {},
+Mandatory Purchase Order,ការបញ្ជាទិញចាំបាច់,
+Purchase Receipt Required for item {},វិក័យប័ត្រទិញត្រូវការសម្រាប់ធាតុ {},
+To submit the invoice without purchase receipt please set {} ,ដើម្បីផ្ញើវិក័យប័ត្រដោយគ្មានបង្កាន់ដៃទិញសូមកំណត់ {},
+Mandatory Purchase Receipt,បង្កាន់ដៃទិញចាំបាច់,
+POS Profile {} does not belongs to company {},ពត៌មានរបស់ម៉ាស៊ីនឆូតកាត {} មិនមែនជារបស់ក្រុមហ៊ុន {},
+User {} is disabled. Please select valid user/cashier,អ្នកប្រើ {} ត្រូវបានបិទ។ សូមជ្រើសរើសអ្នកប្រើប្រាស់ / បេឡាករត្រឹមត្រូវ,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,ជួរដេក # {}៖ វិក័យប័ត្រដើម {} នៃវិក័យប័ត្រត្រឡប់មកវិញ {} គឺ {} ។,
+Original invoice should be consolidated before or along with the return invoice.,វិក័យប័ត្រដើមគួរតែត្រូវបានបង្រួបបង្រួមមុនឬរួមជាមួយវិក័យប័ត្រត្រឡប់មកវិញ។,
+You can add original invoice {} manually to proceed.,អ្នកអាចបន្ថែមវិក័យប័ត្រដើម {} ដោយដៃដើម្បីបន្ត។,
+Please ensure {} account is a Balance Sheet account. ,សូមប្រាកដថា {} គណនីគឺជាគណនីសន្លឹកសមតុល្យ។,
+You can change the parent account to a Balance Sheet account or select a different account.,អ្នកអាចប្តូរគណនីមេទៅគណនីសន្លឹកសមតុល្យឬជ្រើសរើសគណនីផ្សេង។,
+Please ensure {} account is a Receivable account. ,សូមប្រាកដថា {} គណនីគឺជាគណនីដែលអាចទទួលយកបាន។,
+Change the account type to Receivable or select a different account.,ផ្លាស់ប្តូរប្រភេទគណនីទៅជាអ្នកទទួលឬជ្រើសរើសគណនីផ្សេងទៀត។,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} មិនអាចត្រូវបានលុបចោលទេចាប់តាំងពីចំនុចស្មោះត្រង់ដែលរកបានត្រូវបានលោះ។ ដំបូងលុបចោល {} ទេ {},
+already exists,ធ្លាប់មានរួចហើយ,
+POS Closing Entry {} against {} between selected period,ការបិទម៉ាស៊ីនឆូតកាត {} ប្រឆាំងនឹង {} រវាងរយៈពេលដែលបានជ្រើសរើស,
+POS Invoice is {},វិក្កយបត្រម៉ាស៊ីនឆូតកាតគឺ {},
+POS Profile doesn't matches {},ទម្រង់ម៉ាស៊ីនឆូតកាតមិនត្រូវគ្នាទេ {},
+POS Invoice is not {},វិក្កយបត្រម៉ាស៊ីនឆូតកាតមិនមែន {},
+POS Invoice isn't created by user {},វិក្កយបត្រម៉ាស៊ីនឆូតកាតមិនត្រូវបានបង្កើតដោយអ្នកប្រើ {},
+Row #{}: {},ជួរដេក # {}៖ {},
+Invalid POS Invoices,វិក្កយបត្រម៉ាស៊ីនឆូតកាតមិនត្រឹមត្រូវ,
+Please add the account to root level Company - {},សូមបន្ថែមគណនីទៅក្រុមហ៊ុនកម្រិត root - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",ពេលកំពុងបង្កើតគណនីសម្រាប់ក្រុមហ៊ុនកុមារ {០} គណនីមេ {១} រកមិនឃើញទេ។ សូមបង្កើតគណនីមេនៅក្នុង COA ដែលត្រូវគ្នា,
+Account Not Found,រកមិនឃើញគណនី,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",នៅពេលបង្កើតគណនីសម្រាប់ក្រុមហ៊ុនកុមារ {០} គណនីមេ {១} ត្រូវបានរកឃើញថាជាគណនីយួរដៃ។,
+Please convert the parent account in corresponding child company to a group account.,សូមប្តូរគណនីមេនៅក្នុងក្រុមហ៊ុនកុមារដែលត្រូវគ្នាទៅនឹងគណនីក្រុម។,
+Invalid Parent Account,គណនីមេមិនត្រឹមត្រូវ,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",ការប្តូរឈ្មោះវាត្រូវបានអនុញ្ញាតិតែតាមរយៈក្រុមហ៊ុនមេ {0} ដើម្បីចៀសវាងភាពមិនស៊ីចង្វាក់គ្នា។,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",ប្រសិនបើអ្នក {0} {1} បរិមាណនៃធាតុ {2} គ្រោងការណ៍ {3} នឹងត្រូវបានអនុវត្តលើធាតុ។,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",ប្រសិនបើអ្នក {0} {1} វត្ថុមានតម្លៃ {2} គ្រោងការណ៍ {3} នឹងត្រូវបានអនុវត្តលើធាតុ។,
+"As the field {0} is enabled, the field {1} is mandatory.",នៅពេលដែលវាល {0} ត្រូវបានបើកនោះវាល {1} គឺចាំបាច់។,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",នៅពេលដែលវាល {0} ត្រូវបានបើកតម្លៃនៃវាល {1} គួរតែលើសពី 1 ។,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},មិនអាចចែកចាយសៀរៀលលេខ {០} នៃធាតុ {១} បានទេព្រោះវាត្រូវបានបម្រុងទុកសម្រាប់ការបញ្ជាទិញការលក់ពេញលេញ {២},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",ការបញ្ជាទិញការលក់ {0} មានការកក់ទុកសម្រាប់ធាតុ {1} អ្នកអាចចែកចាយបានតែតូប {1} ទល់នឹង {0} ប៉ុណ្ណោះ។,
+{0} Serial No {1} cannot be delivered,{0} ស៊េរីលេខ {1} មិនអាចត្រូវបានបញ្ជូនទេ,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},ជួរដេក {0}៖ ធាតុដែលបានចុះកិច្ចសន្យាត្រូវបានតំរូវអោយជាវត្ថុធាតុដើម {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",ដោយសារមានវត្ថុធាតុដើមគ្រប់គ្រាន់ការស្នើសុំសម្ភារៈមិនចាំបាច់សម្រាប់ឃ្លាំង {0} ទេ។,
+" If you still want to proceed, please enable {0}.",ប្រសិនបើអ្នកនៅតែចង់បន្តសូមបើក {0} ។,
+The item referenced by {0} - {1} is already invoiced,ធាតុដែលយោងដោយ {០} - {១} បានចេញវិក្កយបត្ររួចហើយ,
+Therapy Session overlaps with {0},វគ្គនៃការព្យាបាលត្រួតគ្នាជាមួយ {0},
+Therapy Sessions Overlapping,ការព្យាបាលដោយការត្រួតគ្នា,
+Therapy Plans,ផែនការព្យាបាល,
+"Item Code, warehouse, quantity are required on row {0}",លេខកូដទំនិញឃ្លាំងបរិមាណត្រូវបានទាមទារនៅជួរ {0},
+Get Items from Material Requests against this Supplier,ទទួលបានវត្ថុពីសំណើសម្ភារៈប្រឆាំងនឹងអ្នកផ្គត់ផ្គង់នេះ,
+Enable European Access,បើកដំណើរការចូលអឺរ៉ុប,
+Creating Purchase Order ...,កំពុងបង្កើតការបញ្ជាទិញ ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",ជ្រើសរើសអ្នកផ្គត់ផ្គង់ពីអ្នកផ្គត់ផ្គង់លំនាំដើមនៃធាតុខាងក្រោម។ នៅពេលជ្រើសរើសការបញ្ជាទិញនឹងត្រូវធ្វើឡើងប្រឆាំងនឹងរបស់របរដែលជាកម្មសិទ្ធិរបស់អ្នកផ្គត់ផ្គង់ដែលបានជ្រើសរើសតែប៉ុណ្ណោះ។,
+Row #{}: You must select {} serial numbers for item {}.,ជួរទី # {}៖ អ្នកត្រូវតែជ្រើសរើស {} លេខស៊េរីសម្រាប់ធាតុ {} ។,
diff --git a/erpnext/translations/kn.csv b/erpnext/translations/kn.csv
index 7dfbb5c..4a9173d 100644
--- a/erpnext/translations/kn.csv
+++ b/erpnext/translations/kn.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},ನಿಜವಾದ ರೀತಿಯ ತೆರಿಗೆ ಸತತವಾಗಿ ಐಟಂ ದರದಲ್ಲಿ ಸೇರಿಸಲಾಗಿದೆ ಸಾಧ್ಯವಿಲ್ಲ {0},
Add,ಸೇರಿಸು,
Add / Edit Prices,/ ಸಂಪಾದಿಸಿ ಬೆಲೆಗಳು ಸೇರಿಸಿ,
-Add All Suppliers,ಎಲ್ಲಾ ಪೂರೈಕೆದಾರರನ್ನು ಸೇರಿಸಿ,
Add Comment,ಕಾಮೆಂಟ್ ಸೇರಿಸಿ,
Add Customers,ಗ್ರಾಹಕರು ಸೇರಿಸಿ,
Add Employees,ನೌಕರರು ಸೇರಿಸಿ,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',ವರ್ಗದಲ್ಲಿ 'ಮೌಲ್ಯಾಂಕನ' ಅಥವಾ 'Vaulation ಮತ್ತು ಒಟ್ಟು' ಆಗಿದೆ ಮಾಡಿದಾಗ ಕಡಿತಗೊಳಿಸದಿರುವುದರ ಸಾಧ್ಯವಿಲ್ಲ,
"Cannot delete Serial No {0}, as it is used in stock transactions","ಅಳಿಸಿಹಾಕಲಾಗದು ಸೀರಿಯಲ್ ಯಾವುದೇ {0}, ಇದು ಸ್ಟಾಕ್ ವ್ಯವಹಾರಗಳಲ್ಲಿ ಬಳಸಲಾಗುತ್ತದೆ",
Cannot enroll more than {0} students for this student group.,{0} ಈ ವಿದ್ಯಾರ್ಥಿ ಗುಂಪು ವಿದ್ಯಾರ್ಥಿಗಳನ್ನು ಹೆಚ್ಚು ದಾಖಲಿಸಲಾಗುವುದಿಲ್ಲ.,
-Cannot find Item with this barcode,ಈ ಬಾರ್ಕೋಡ್ನೊಂದಿಗೆ ಐಟಂ ಅನ್ನು ಕಂಡುಹಿಡಿಯಲಾಗುವುದಿಲ್ಲ,
Cannot find active Leave Period,ಸಕ್ರಿಯ ಬಿಡಿ ಅವಧಿಯನ್ನು ಕಂಡುಹಿಡಿಯಲಾಗಲಿಲ್ಲ,
Cannot produce more Item {0} than Sales Order quantity {1},ಹೆಚ್ಚು ಐಟಂ ಉತ್ಪಾದಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ {0} ಹೆಚ್ಚು ಮಾರಾಟದ ಆರ್ಡರ್ ಪ್ರಮಾಣ {1},
Cannot promote Employee with status Left,ನೌಕರರು ಸ್ಥಿತಿಯನ್ನು ಎಡಕ್ಕೆ ಪ್ರಚಾರ ಮಾಡಲಾಗುವುದಿಲ್ಲ,
Cannot refer row number greater than or equal to current row number for this Charge type,ಈ ಬ್ಯಾಚ್ ಮಾದರಿ ಸಾಲು ಸಂಖ್ಯೆ ಹೆಚ್ಚಿನ ಅಥವಾ ಪ್ರಸ್ತುತ ಸಾಲಿನ ಸಂಖ್ಯೆ ಸಮಾನವಾಗಿರುತ್ತದೆ ಸೂಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,ಮೊದಲ ಸಾಲಿನ ' ಹಿಂದಿನ ರೋ ಒಟ್ಟು ರಂದು ' ' ಹಿಂದಿನ ಸಾಲಿನಲ್ಲಿ ಪ್ರಮಾಣ ' ಅಥವಾ ಒಂದು ಬ್ಯಾಚ್ ರೀತಿಯ ಆಯ್ಕೆ ಮಾಡಬಹುದು,
-Cannot set a received RFQ to No Quote,ಯಾವುದೇ ಉಲ್ಲೇಖಕ್ಕೆ ಸ್ವೀಕರಿಸಿದ RFQ ಅನ್ನು ಹೊಂದಿಸಲಾಗುವುದಿಲ್ಲ,
Cannot set as Lost as Sales Order is made.,ಮಾರಾಟದ ಆರ್ಡರ್ ಮಾಡಿದ ಎಂದು ಕಳೆದು ಹೊಂದಿಸಲು ಸಾಧ್ಯವಾಗಿಲ್ಲ .,
Cannot set authorization on basis of Discount for {0},ರಿಯಾಯಿತಿ ಆಧಾರದ ಮೇಲೆ ಅಧಿಕಾರ ಹೊಂದಿಸಲು ಸಾಧ್ಯವಾಗಿಲ್ಲ {0},
Cannot set multiple Item Defaults for a company.,ಕಂಪೆನಿಗಾಗಿ ಬಹು ಐಟಂ ಡೀಫಾಲ್ಟ್ಗಳನ್ನು ಹೊಂದಿಸಲಾಗುವುದಿಲ್ಲ.,
@@ -521,7 +518,6 @@
Chargeble,ಚಾರ್ಜ್ ಮಾಡಬಹುದಾದ,
Charges are updated in Purchase Receipt against each item,ಆರೋಪಗಳನ್ನು ಪ್ರತಿ ಐಟಂ ವಿರುದ್ಧ ಖರೀದಿ ರಿಸೀಟ್ನ್ನು ನವೀಕರಿಸಲಾಗುವುದು,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","ಆರೋಪಗಳನ್ನು ಸೂಕ್ತ ಪ್ರಮಾಣದಲ್ಲಿ ನಿಮ್ಮ ಆಯ್ಕೆಯ ಪ್ರಕಾರ, ಐಟಂ ಪ್ರಮಾಣ ಅಥವಾ ಪ್ರಮಾಣವನ್ನು ಆಧರಿಸಿ ಹಂಚಲಾಗುತ್ತದೆ",
-Chart Of Accounts,ಖಾತೆಗಳ ಚಾರ್ಟ್,
Chart of Cost Centers,ವೆಚ್ಚ ಸೆಂಟರ್ಸ್ ಚಾರ್ಟ್,
Check all,ಎಲ್ಲಾ ಪರಿಶೀಲಿಸಿ,
Checkout,ಚೆಕ್ಔಟ್,
@@ -581,7 +577,6 @@
Compensatory Off,ಪರಿಹಾರ ಆಫ್,
Compensatory leave request days not in valid holidays,ಕಾಂಪೆನ್ಸೇಟರಿ ರಜೆ ವಿನಂತಿಯ ದಿನಗಳು ಮಾನ್ಯ ರಜಾದಿನಗಳಲ್ಲಿಲ್ಲ,
Complaint,ದೂರು,
-Completed Qty can not be greater than 'Qty to Manufacture',ಹೆಚ್ಚು 'ಪ್ರಮಾಣ ತಯಾರಿಸಲು' ಮುಗಿದಿದೆ ಪ್ರಮಾಣ ಹೆಚ್ಚಾಗಿರುವುದು ಸಾಧ್ಯವಿಲ್ಲ,
Completion Date,ಪೂರ್ಣಗೊಳ್ಳುವ ದಿನಾಂಕ,
Computer,ಗಣಕಯಂತ್ರ,
Condition,ಪರಿಸ್ಥಿತಿ,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","ರಚಿಸಿ ಮತ್ತು , ದೈನಂದಿನ ಸಾಪ್ತಾಹಿಕ ಮತ್ತು ಮಾಸಿಕ ಇಮೇಲ್ ಡೈಜೆಸ್ಟ್ ನಿರ್ವಹಿಸಿ .",
Create customer quotes,ಗ್ರಾಹಕ ಉಲ್ಲೇಖಗಳು ರಚಿಸಿ,
Create rules to restrict transactions based on values.,ಮೌಲ್ಯಗಳ ಆಧಾರದ ವ್ಯವಹಾರ ನಿರ್ಬಂಧಿಸಲು ನಿಯಮಗಳನ್ನು ರಚಿಸಿ .,
-Created By,ದಾಖಲಿಸಿದವರು,
Created {0} scorecards for {1} between: ,ನಡುವೆ {1 for ಗೆ {0} ಸ್ಕೋರ್ಕಾರ್ಡ್ಗಳನ್ನು ರಚಿಸಲಾಗಿದೆ:,
Creating Company and Importing Chart of Accounts,ಕಂಪನಿಯನ್ನು ರಚಿಸುವುದು ಮತ್ತು ಖಾತೆಗಳ ಚಾರ್ಟ್ ಅನ್ನು ಆಮದು ಮಾಡಿಕೊಳ್ಳುವುದು,
Creating Fees,ಶುಲ್ಕಗಳು ರಚಿಸಲಾಗುತ್ತಿದೆ,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,ವರ್ಗಾವಣೆ ದಿನಾಂಕದ ಮೊದಲು ಉದ್ಯೋಗಿ ವರ್ಗಾವಣೆ ಸಲ್ಲಿಸಲಾಗುವುದಿಲ್ಲ,
Employee cannot report to himself.,ನೌಕರರ ಸ್ವತಃ ವರದಿ ಸಾಧ್ಯವಿಲ್ಲ.,
Employee relieved on {0} must be set as 'Left',{0} ಮೇಲೆ ಬಿಡುಗಡೆ ನೌಕರರ ' ಎಡ ' ಹೊಂದಿಸಿ,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,ಈ ಕೆಳಗಿನ ಉದ್ಯೋಗಿಗಳು ಪ್ರಸ್ತುತ ಈ ಉದ್ಯೋಗಿಗೆ ವರದಿ ಮಾಡುತ್ತಿರುವುದರಿಂದ ನೌಕರರ ಸ್ಥಿತಿಯನ್ನು 'ಎಡ'ಕ್ಕೆ ಹೊಂದಿಸಲಾಗುವುದಿಲ್ಲ:,
Employee {0} already submited an apllication {1} for the payroll period {2},ಉದ್ಯೋಗಿ {0} ಈಗಾಗಲೇ ವೇತನದಾರರ ಅವಧಿಗೆ {1} ಒಂದು ಪ್ರಸ್ತಾಪವನ್ನು {1} ಸಲ್ಲಿಸಿರುತ್ತಾನೆ.,
Employee {0} has already applied for {1} between {2} and {3} : ,ನೌಕರ {0} {2} ಮತ್ತು {3} ನಡುವಿನ {1} ಗೆ ಈಗಾಗಲೇ ಅರ್ಜಿ ಸಲ್ಲಿಸಿದ್ದಾರೆ:,
Employee {0} has no maximum benefit amount,ಉದ್ಯೋಗಿ {0} ಗರಿಷ್ಠ ಲಾಭದ ಮೊತ್ತವನ್ನು ಹೊಂದಿಲ್ಲ,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,ಸಾಲು {0}: ಯೋಜಿತ Qty ಯನ್ನು ನಮೂದಿಸಿ,
"For {0}, only credit accounts can be linked against another debit entry","{0}, ಮಾತ್ರ ಕ್ರೆಡಿಟ್ ಖಾತೆಗಳನ್ನು ಮತ್ತೊಂದು ಡೆಬಿಟ್ ಪ್ರವೇಶ ವಿರುದ್ಧ ಲಿಂಕ್ ಮಾಡಬಹುದು ಫಾರ್",
"For {0}, only debit accounts can be linked against another credit entry","{0}, ಮಾತ್ರ ಡೆಬಿಟ್ ಖಾತೆಗಳನ್ನು ಇನ್ನೊಂದು ಕ್ರೆಡಿಟ್ ಪ್ರವೇಶ ವಿರುದ್ಧ ಲಿಂಕ್ ಮಾಡಬಹುದು ಫಾರ್",
-Form View,ಫಾರ್ಮ್ ವೀಕ್ಷಿಸಿ,
Forum Activity,ವೇದಿಕೆ ಚಟುವಟಿಕೆ,
Free item code is not selected,ಉಚಿತ ಐಟಂ ಕೋಡ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿಲ್ಲ,
Freight and Forwarding Charges,ಸರಕು ಮತ್ತು ಸಾಗಣೆಯನ್ನು ಚಾರ್ಜಸ್,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ಮೊದಲು ಹಂಚಿಕೆ ಸಾಧ್ಯವಿಲ್ಲ ಬಿಡಿ {0}, ರಜೆ ಸಮತೋಲನ ಈಗಾಗಲೇ ಕ್ಯಾರಿ ಫಾರ್ವರ್ಡ್ ಭವಿಷ್ಯದ ರಜೆ ಹಂಚಿಕೆ ದಾಖಲೆಯಲ್ಲಿ ಬಂದಿದೆ {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ರಜೆ ಸಮತೋಲನ ಈಗಾಗಲೇ ಕ್ಯಾರಿ ಫಾರ್ವರ್ಡ್ ಭವಿಷ್ಯದ ರಜೆ ಹಂಚಿಕೆ ದಾಖಲೆಯಲ್ಲಿ ಬಂದಿದೆ, ಮೊದಲು {0} ರದ್ದು / ಅನ್ವಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ ಬಿಡಿ {1}",
Leave of type {0} cannot be longer than {1},ರೀತಿಯ ಲೀವ್ {0} ಹೆಚ್ಚು ಸಾಧ್ಯವಿಲ್ಲ {1},
-Leave the field empty to make purchase orders for all suppliers,ಎಲ್ಲಾ ಸರಬರಾಜುದಾರರಿಗೆ ಖರೀದಿ ಆದೇಶಗಳನ್ನು ಮಾಡಲು ಖಾಲಿ ಜಾಗವನ್ನು ಬಿಡಿ,
Leaves,ಎಲೆಗಳು,
Leaves Allocated Successfully for {0},ಎಲೆಗಳು ಯಶಸ್ವಿಯಾಗಿ ನಿಗದಿ {0},
Leaves has been granted sucessfully,ಎಲೆಗಳನ್ನು ಯಶಸ್ವಿಯಾಗಿ ನೀಡಲಾಗಿದೆ,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,ಮೆಟೀರಿಯಲ್ಸ್ ಬಿಲ್ ಯಾವುದೇ ವಸ್ತುಗಳು ತಯಾರಿಸಲು,
No Items with Bill of Materials.,ಮೆಟೀರಿಯಲ್ಗಳ ಬಿಲ್ನೊಂದಿಗೆ ಯಾವುದೇ ಐಟಂಗಳಿಲ್ಲ.,
No Permission,ಯಾವುದೇ ಅನುಮತಿ,
-No Quote,ಯಾವುದೇ ಉದ್ಧರಣ,
No Remarks,ಯಾವುದೇ ಟೀಕೆಗಳನ್ನು,
No Result to submit,ಸಲ್ಲಿಸಲು ಯಾವುದೇ ಫಲಿತಾಂಶವಿಲ್ಲ,
No Salary Structure assigned for Employee {0} on given date {1},ನಿರ್ದಿಷ್ಟ ದಿನಾಂಕ {1 on ರಂದು ನೌಕರ {0 for ಗೆ ಯಾವುದೇ ಸಂಬಳ ರಚನೆಯನ್ನು ನಿಗದಿಪಡಿಸಲಾಗಿಲ್ಲ,
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,ನಡುವೆ ಕಂಡುಬರುವ ಅತಿಕ್ರಮಿಸುವ ಪರಿಸ್ಥಿತಿಗಳು :,
Owner,ಒಡೆಯ,
PAN,ಪ್ಯಾನ್,
-PO already created for all sales order items,ಎಲ್ಲಾ ಮಾರಾಟ ಆದೇಶದ ಐಟಂಗಳಿಗಾಗಿ ಪಿಒ ಈಗಾಗಲೇ ರಚಿಸಲಾಗಿದೆ,
POS,ಪಿಓಎಸ್,
POS Profile,ಪಿಓಎಸ್ ವಿವರ,
POS Profile is required to use Point-of-Sale,ಪಿಓಎಸ್ ಪ್ರೊಫೈಲ್ ಪಾಯಿಂಟ್-ಆಫ್-ಮಾರಾಟವನ್ನು ಬಳಸಬೇಕಾಗುತ್ತದೆ,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,ಮೊದಲ ಬ್ಯಾಚ್ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ,
Please select Company,ಕಂಪನಿ ಆಯ್ಕೆಮಾಡಿ,
Please select Company and Designation,ಕಂಪನಿ ಮತ್ತು ಸ್ಥಾನೀಕರಣವನ್ನು ಆಯ್ಕೆಮಾಡಿ,
-Please select Company and Party Type first,ಮೊದಲ ಕಂಪನಿ ಮತ್ತು ಪಕ್ಷದ ಕೌಟುಂಬಿಕತೆ ಆಯ್ಕೆ ಮಾಡಿ,
Please select Company and Posting Date to getting entries,ನಮೂದುಗಳನ್ನು ಪಡೆಯಲು ಕಂಪನಿ ಮತ್ತು ಪೋಸ್ಟಿಂಗ್ ದಿನಾಂಕವನ್ನು ಆಯ್ಕೆಮಾಡಿ,
Please select Company first,ಮೊದಲ ಕಂಪನಿ ಆಯ್ಕೆ ಮಾಡಿ,
Please select Completion Date for Completed Asset Maintenance Log,ದಯವಿಟ್ಟು ಪೂರ್ಣಗೊಂಡ ಆಸ್ತಿ ನಿರ್ವಹಣೆ ಲಾಗ್ಗಾಗಿ ಪೂರ್ಣಗೊಂಡ ದಿನಾಂಕವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,ಸಾಲು {0}: ಮೈಸೂರು ವಿಶ್ವವಿದ್ಯಾನಿಲದ ಪರಿವರ್ತನಾ ಕಾರಕ ಕಡ್ಡಾಯ,
Row {0}: select the workstation against the operation {1},ಸಾಲು {0}: ಕಾರ್ಯಾಚರಣೆ ವಿರುದ್ಧ ಕಾರ್ಯಕ್ಷೇತ್ರವನ್ನು ಆಯ್ಕೆಮಾಡಿ {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,ಸಾಲು {0}: {1} ಐಟಂಗೆ ಸೀರಿಯಲ್ ಸಂಖ್ಯೆಗಳು ಅಗತ್ಯವಿದೆ {2}. ನೀವು {3} ಒದಗಿಸಿದ್ದೀರಿ.,
-Row {0}: {1} is required to create the Opening {2} Invoices,ಆರಂಭಿಕ {2} ಇನ್ವಾಯ್ಸ್ಗಳನ್ನು ರಚಿಸಲು ಸಾಲು {0}: {1} ಅಗತ್ಯವಿದೆ,
Row {0}: {1} must be greater than 0,ಸಾಲು {0}: {1} 0 ಗಿಂತಲೂ ದೊಡ್ಡದಾಗಿರಬೇಕು,
Row {0}: {1} {2} does not match with {3},ಸಾಲು {0}: {1} {2} ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ {3},
Row {0}:Start Date must be before End Date,ರೋ {0} : ಪ್ರಾರಂಭ ದಿನಾಂಕ ಎಂಡ್ ದಿನಾಂಕದ ಮೊದಲು,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,ಗ್ರಾಂಟ್ ರಿವ್ಯೂ ಇಮೇಲ್ ಕಳುಹಿಸಿ,
Send Now,ಈಗ ಕಳುಹಿಸಿ,
Send SMS,ಎಸ್ಎಂಎಸ್ ಕಳುಹಿಸಿ,
-Send Supplier Emails,ಸರಬರಾಜುದಾರ ಇಮೇಲ್ಗಳನ್ನು ಕಳುಹಿಸಿ,
Send mass SMS to your contacts,ನಿಮ್ಮ ಸಂಪರ್ಕಗಳಿಗೆ ಸಾಮೂಹಿಕ SMS ಕಳುಹಿಸಿ,
Sensitivity,ಸೂಕ್ಷ್ಮತೆ,
Sent,ಕಳುಹಿಸಲಾಗಿದೆ,
-Serial #,ಸರಣಿ #,
Serial No and Batch,ಸೀರಿಯಲ್ ಯಾವುದೇ ಮತ್ತು ಬ್ಯಾಚ್,
Serial No is mandatory for Item {0},ಅನುಕ್ರಮ ಸಂಖ್ಯೆ ಐಟಂ ಕಡ್ಡಾಯ {0},
Serial No {0} does not belong to Batch {1},ಸರಣಿ ಇಲ್ಲ {0} ಬ್ಯಾಚ್ಗೆ ಸೇರಿಲ್ಲ {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,ನೀವು ಈ ಗಣಕವನ್ನು ಹೊಂದಿಸುವ ಇದು ನಿಮ್ಮ ಕಂಪನಿ ಹೆಸರು .,
The number of shares and the share numbers are inconsistent,ಷೇರುಗಳ ಸಂಖ್ಯೆ ಮತ್ತು ಷೇರು ಸಂಖ್ಯೆಗಳು ಅಸಮಂಜಸವಾಗಿದೆ,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,{0} ಯೋಜನೆಯಲ್ಲಿ ಪಾವತಿ ಗೇಟ್ವೇ ಖಾತೆ ಈ ಪಾವತಿ ವಿನಂತಿಯಲ್ಲಿ ಪಾವತಿ ಗೇಟ್ವೇ ಖಾತೆಯಿಂದ ಭಿನ್ನವಾಗಿದೆ,
-The request for quotation can be accessed by clicking on the following link,ಉದ್ಧರಣ ವಿನಂತಿಯನ್ನು ಕೆಳಗಿನ ಲಿಂಕ್ ಕ್ಲಿಕ್ಕಿಸಿ ನಿಲುಕಿಸಿಕೊಳ್ಳಬಹುದು,
The selected BOMs are not for the same item,ಆಯ್ಕೆ BOMs ಒಂದೇ ಐಟಂ ಅಲ್ಲ,
The selected item cannot have Batch,ಆಯ್ದುಕೊಂಡ ಬ್ಯಾಚ್ ಹೊಂದುವಂತಿಲ್ಲ,
The seller and the buyer cannot be the same,ಮಾರಾಟಗಾರ ಮತ್ತು ಖರೀದಿದಾರರು ಒಂದೇ ಆಗಿರುವುದಿಲ್ಲ,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},ಒಟ್ಟು ಹೊಂದಿಕೊಳ್ಳುವ ಲಾಭಾಂಶದ ಮೊತ್ತವು {0} ಗರಿಷ್ಠ ಪ್ರಯೋಜನಗಳಿಗಿಂತ ಕಡಿಮೆ ಇರಬಾರದು {1},
Total hours: {0},ಒಟ್ಟು ಗಂಟೆಗಳ: {0},
Total leaves allocated is mandatory for Leave Type {0},ನಿಯೋಜಿಸಲಾದ ಒಟ್ಟು ಎಲೆಗಳು ಲೀವ್ ಟೈಪ್ {0} ಗೆ ಕಡ್ಡಾಯವಾಗಿದೆ.,
-Total weightage assigned should be 100%. It is {0},ನಿಯೋಜಿಸಲಾಗಿದೆ ಒಟ್ಟು ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು 100% ಇರಬೇಕು. ಇದು {0},
Total working hours should not be greater than max working hours {0},ಒಟ್ಟು ಕೆಲಸದ ಗರಿಷ್ಠ ಕೆಲಸದ ಹೆಚ್ಚು ಮಾಡಬಾರದು {0},
Total {0} ({1}),ಒಟ್ಟು {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","ಒಟ್ಟು {0} ಎಲ್ಲಾ ಐಟಂಗಳನ್ನು, ಶೂನ್ಯವಾಗಿರುತ್ತದೆ ನೀವು ರಂದು ಆಧರಿಸಿ ಚಾರ್ಜಸ್ ವಿತರಿಸಿ 'ಬದಲಿಸಬೇಕಾಗುತ್ತದೆ ಇರಬಹುದು",
@@ -3316,7 +3299,6 @@
What do you need help with?,ನೀವು ಸಹಾಯ ಬೇಕು?,
What does it do?,ಇದು ಏನು ಮಾಡುತ್ತದೆ?,
Where manufacturing operations are carried.,ಉತ್ಪಾದನಾ ಕಾರ್ಯಗಳ ಅಲ್ಲಿ ನಿರ್ವಹಿಸುತ್ತಾರೆ.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","ಮಗುವಿನ ಕಂಪನಿ {0} ಖಾತೆ ರಚಿಸುವಾಗ, ಮೂಲ ಖಾತೆ {1} ಕಂಡುಬಂದಿಲ್ಲ. ದಯವಿಟ್ಟು ಸಂಬಂಧಿಸಿದ COA ನಲ್ಲಿ ಪೋಷಕ ಖಾತೆಯನ್ನು ರಚಿಸಿ",
White,ಬಿಳಿ,
Wire Transfer,ವೈರ್ ಟ್ರಾನ್ಸ್ಫರ್,
WooCommerce Products,WooCommerce ಉತ್ಪನ್ನಗಳು,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} ರೂಪಾಂತರಗಳು ರಚಿಸಲಾಗಿದೆ.,
{0} {1} created,{0} {1} ದಾಖಲಿಸಿದವರು,
{0} {1} does not exist,{0} {1} ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ,
-{0} {1} does not exist.,{0} {1} ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ.,
{0} {1} has been modified. Please refresh.,{0} {1} ಮಾರ್ಪಡಿಸಲಾಗಿದೆ. ರಿಫ್ರೆಶ್ ಮಾಡಿ.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} ಸಲ್ಲಿಸಲಾಗಿಲ್ಲ ಕ್ರಮ ಪೂರ್ಣಗೊಳಿಸಲಾಗಲಿಲ್ಲ ಆದ್ದರಿಂದ,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} {2} ನೊಂದಿಗೆ ಸಂಬಂಧಿಸಿದೆ, ಆದರೆ ಪಾರ್ಟಿ ಖಾತೆ {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} ಮಾಡುವುದಿಲ್ಲ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ,
{0}: {1} not found in Invoice Details table,{0}: {1} ಸರಕುಪಟ್ಟಿ ವಿವರಗಳು ಟೇಬಲ್ ಕಂಡುಬಂದಿಲ್ಲ,
{} of {},{} ಆಫ್ {},
+Assigned To,ನಿಯೋಜಿಸಲಾಗಿದೆ,
Chat,ಚಾಟಿಂಗ್,
Completed By,ಪೂರ್ಣಗೊಂಡಿದೆ,
Conditions,ನಿಯಮಗಳು,
@@ -3506,7 +3488,9 @@
Merge with existing,ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ವಿಲೀನಗೊಳ್ಳಲು,
Office,ಕಚೇರಿ,
Orientation,ದೃಷ್ಟಿಕೋನ,
+Parent,ಪೋಷಕ,
Passive,ನಿಷ್ಕ್ರಿಯ,
+Payment Failed,ಪಾವತಿ ವಿಫಲವಾಗಿದೆ,
Percent,ಪರ್ಸೆಂಟ್,
Permanent,ಶಾಶ್ವತ,
Personal,ದೊಣ್ಣೆ,
@@ -3544,7 +3528,6 @@
Company field is required,ಕಂಪನಿ ಕ್ಷೇತ್ರದ ಅಗತ್ಯವಿದೆ,
Creating Dimensions...,ಆಯಾಮಗಳನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ ...,
Duplicate entry against the item code {0} and manufacturer {1},ಐಟಂ ಕೋಡ್ {0} ಮತ್ತು ತಯಾರಕ {1} ವಿರುದ್ಧ ನಕಲು ಪ್ರವೇಶ,
-Import Chart Of Accounts from CSV / Excel files,CSV / Excel ಫೈಲ್ಗಳಿಂದ ಖಾತೆಗಳ ಚಾರ್ಟ್ ಅನ್ನು ಆಮದು ಮಾಡಿ,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,ಅಮಾನ್ಯ GSTIN! ನೀವು ನಮೂದಿಸಿದ ಇನ್ಪುಟ್ ಯುಐಎನ್ ಹೊಂದಿರುವವರು ಅಥವಾ ಅನಿವಾಸಿ ಒಐಡಿಎಆರ್ ಸೇವಾ ಪೂರೈಕೆದಾರರಿಗೆ ಜಿಎಸ್ಟಿಎನ್ ಸ್ವರೂಪಕ್ಕೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ,
Invoice Grand Total,ಸರಕುಪಟ್ಟಿ ಗ್ರ್ಯಾಂಡ್ ಒಟ್ಟು,
Last carbon check date cannot be a future date,ಕೊನೆಯ ಇಂಗಾಲದ ಪರಿಶೀಲನಾ ದಿನಾಂಕ ಭವಿಷ್ಯದ ದಿನಾಂಕವಾಗಿರಬಾರದು,
@@ -3556,6 +3539,7 @@
Show {0},{0} ತೋರಿಸು,
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" ಮತ್ತು "}" ಹೊರತುಪಡಿಸಿ ವಿಶೇಷ ಅಕ್ಷರಗಳನ್ನು ಹೆಸರಿಸುವ ಸರಣಿಯಲ್ಲಿ ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ",
Target Details,ಗುರಿ ವಿವರಗಳು,
+{0} already has a Parent Procedure {1}.,{0} ಈಗಾಗಲೇ ಪೋಷಕ ವಿಧಾನವನ್ನು ಹೊಂದಿದೆ {1}.,
API,API,
Annual,ವಾರ್ಷಿಕ,
Approved,Approved,
@@ -3572,6 +3556,8 @@
No data to export,ರಫ್ತು ಮಾಡಲು ಡೇಟಾ ಇಲ್ಲ,
Portrait,ಭಾವಚಿತ್ರ,
Print Heading,ಪ್ರಿಂಟ್ ಶಿರೋನಾಮೆ,
+Scheduler Inactive,ವೇಳಾಪಟ್ಟಿ ನಿಷ್ಕ್ರಿಯ,
+Scheduler is inactive. Cannot import data.,ವೇಳಾಪಟ್ಟಿ ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ. ಡೇಟಾವನ್ನು ಆಮದು ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ.,
Show Document,ಡಾಕ್ಯುಮೆಂಟ್ ತೋರಿಸಿ,
Show Traceback,ಟ್ರೇಸ್ಬ್ಯಾಕ್ ತೋರಿಸಿ,
Video,ವೀಡಿಯೊ,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},ಐಟಂ {0 for ಗಾಗಿ ಗುಣಮಟ್ಟದ ತಪಾಸಣೆ ರಚಿಸಿ,
Creating Accounts...,ಖಾತೆಗಳನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ ...,
Creating bank entries...,ಬ್ಯಾಂಕ್ ನಮೂದುಗಳನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ ...,
-Creating {0},{0} ರಚಿಸಲಾಗುತ್ತಿದೆ,
Credit limit is already defined for the Company {0},ಕ್ರೆಡಿಟ್ ಮಿತಿಯನ್ನು ಈಗಾಗಲೇ ಕಂಪನಿಗೆ ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿದೆ {0},
Ctrl + Enter to submit,ಸಲ್ಲಿಸಲು Ctrl + ನಮೂದಿಸಿ,
Ctrl+Enter to submit,ಸಲ್ಲಿಸಲು Ctrl + Enter,
@@ -3921,7 +3906,6 @@
Plaid public token error,ಸಾರ್ವಜನಿಕ ಟೋಕನ್ ದೋಷ,
Plaid transactions sync error,ಪ್ಲೈಡ್ ವಹಿವಾಟುಗಳು ಸಿಂಕ್ ದೋಷ,
Please check the error log for details about the import errors,ಆಮದು ದೋಷಗಳ ವಿವರಗಳಿಗಾಗಿ ದಯವಿಟ್ಟು ದೋಷ ಲಾಗ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ,
-Please click on the following link to set your new password,ನಿಮ್ಮ ಹೊಸ ಗುಪ್ತಪದವನ್ನು ಕೆಳಗಿನ ಲಿಂಕ್ ಅನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,ದಯವಿಟ್ಟು ಕಂಪೆನಿಗೆ <b>DATEV ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು</b> <b>{ರಚಿಸಲು}.</b>,
Please create adjustment Journal Entry for amount {0} ,ದಯವಿಟ್ಟು value 0 ಮೊತ್ತಕ್ಕೆ ಹೊಂದಾಣಿಕೆ ಜರ್ನಲ್ ನಮೂದನ್ನು ರಚಿಸಿ,
Please do not create more than 500 items at a time,ದಯವಿಟ್ಟು ಒಂದು ಸಮಯದಲ್ಲಿ 500 ಕ್ಕೂ ಹೆಚ್ಚು ವಸ್ತುಗಳನ್ನು ರಚಿಸಬೇಡಿ,
@@ -3997,6 +3981,7 @@
Release date must be in the future,ಬಿಡುಗಡೆ ದಿನಾಂಕ ಭವಿಷ್ಯದಲ್ಲಿರಬೇಕು,
Relieving Date must be greater than or equal to Date of Joining,ಪರಿಹಾರ ದಿನಾಂಕವು ಸೇರುವ ದಿನಾಂಕಕ್ಕಿಂತ ದೊಡ್ಡದಾಗಿರಬೇಕು ಅಥವಾ ಸಮನಾಗಿರಬೇಕು,
Rename,ಹೊಸ ಹೆಸರಿಡು,
+Rename Not Allowed,ಮರುಹೆಸರಿಸಲು ಅನುಮತಿಸಲಾಗಿಲ್ಲ,
Repayment Method is mandatory for term loans,ಟರ್ಮ್ ಸಾಲಗಳಿಗೆ ಮರುಪಾವತಿ ವಿಧಾನ ಕಡ್ಡಾಯವಾಗಿದೆ,
Repayment Start Date is mandatory for term loans,ಅವಧಿ ಸಾಲಗಳಿಗೆ ಮರುಪಾವತಿ ಪ್ರಾರಂಭ ದಿನಾಂಕ ಕಡ್ಡಾಯವಾಗಿದೆ,
Report Item,ಐಟಂ ವರದಿ ಮಾಡಿ,
@@ -4043,7 +4028,6 @@
Select All,ಎಲ್ಲಾ ಆಯ್ಕೆಮಾಡಿ,
Select Difference Account,ವ್ಯತ್ಯಾಸ ಖಾತೆ ಆಯ್ಕೆಮಾಡಿ,
Select a Default Priority.,ಡೀಫಾಲ್ಟ್ ಆದ್ಯತೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ.,
-Select a Supplier from the Default Supplier List of the items below.,ಕೆಳಗಿನ ಐಟಂಗಳ ಡೀಫಾಲ್ಟ್ ಸರಬರಾಜುದಾರರ ಪಟ್ಟಿಯಿಂದ ಸರಬರಾಜುದಾರರನ್ನು ಆಯ್ಕೆಮಾಡಿ.,
Select a company,ಕಂಪನಿಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿ,
Select finance book for the item {0} at row {1},{1 row ಸಾಲಿನಲ್ಲಿ {0 item ಐಟಂಗೆ ಹಣಕಾಸು ಪುಸ್ತಕವನ್ನು ಆಯ್ಕೆಮಾಡಿ,
Select only one Priority as Default.,ಡೀಫಾಲ್ಟ್ ಆಗಿ ಕೇವಲ ಒಂದು ಆದ್ಯತೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ.,
@@ -4247,7 +4231,6 @@
Actual ,ವಾಸ್ತವಿಕ,
Add to cart,ಕಾರ್ಟ್ ಸೇರಿಸಿ,
Budget,ಮುಂಗಡಪತ್ರ,
-Chart Of Accounts Importer,ಖಾತೆಗಳ ಆಮದುದಾರರ ಚಾರ್ಟ್,
Chart of Accounts,ಖಾತೆಗಳ ಚಾರ್ಟ್,
Customer database.,ಗ್ರಾಹಕ ಡೇಟಾಬೇಸ್.,
Days Since Last order,ದಿನಗಳಿಂದಲೂ ಕೊನೆಯ ಆರ್ಡರ್,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,ಅಂತಿಮ ದಿನಾಂಕ ಪ್ರಾರಂಭ ದಿನಾಂಕಕ್ಕಿಂತ ಕಡಿಮೆ ಇರುವಂತಿಲ್ಲ,
For Default Supplier (Optional),ಡೀಫಾಲ್ಟ್ ಪೂರೈಕೆದಾರರಿಗಾಗಿ (ಐಚ್ಛಿಕ),
From date cannot be greater than To date,ದಿನಾಂಕದಿಂದ ದಿನಾಂಕಕ್ಕಿಂತಲೂ ಹೆಚ್ಚಿನದಾಗಿರುವಂತಿಲ್ಲ,
-Get items from,ಐಟಂಗಳನ್ನು ಪಡೆಯಿರಿ,
Group by,ಗುಂಪಿನ,
In stock,ಉಪಲಬ್ದವಿದೆ,
Item name,ಐಟಂ ಹೆಸರು,
@@ -4532,32 +4514,22 @@
Accounts Settings,ಸೆಟ್ಟಿಂಗ್ಗಳು ಖಾತೆಗಳು,
Settings for Accounts,ಖಾತೆಗಳಿಗೆ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Make Accounting Entry For Every Stock Movement,ಪ್ರತಿ ಸ್ಟಾಕ್ ಚಳುವಳಿ ಲೆಕ್ಕಪರಿಶೋಧಕ ಎಂಟ್ರಿ ಮಾಡಿ,
-"If enabled, the system will post accounting entries for inventory automatically.","ಶಕ್ತಗೊಂಡಿದ್ದಲ್ಲಿ , ಗಣಕವು ದಾಸ್ತಾನು ಲೆಕ್ಕಪರಿಶೋಧಕ ನಮೂದುಗಳನ್ನು ಪೋಸ್ಟ್ ಕಾಣಿಸುತ್ತದೆ .",
-Accounts Frozen Upto,ಘನೀಕೃತ ವರೆಗೆ ಖಾತೆಗಳು,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","ಲೆಕ್ಕಪರಿಶೋಧಕ ಪ್ರವೇಶ ಈ ದಿನಾಂಕ ಫ್ರೀಜ್ , ಯಾರೂ / ಕೆಳಗೆ ಸೂಚಿಸಲಾದ ಪಾತ್ರವನ್ನು ಹೊರತುಪಡಿಸಿ ಪ್ರವೇಶ ಮಾರ್ಪಡಿಸಲು ಮಾಡಬಹುದು .",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,ಪಾತ್ರವನ್ನು ಘನೀಕೃತ ಖಾತೆಗಳು & ಸಂಪಾದಿಸಿ ಘನೀಕೃತ ನಮೂದುಗಳು ಹೊಂದಿಸಲು ಅನುಮತಿಸಲಾದ,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,ಈ ಪಾತ್ರವನ್ನು ಬಳಕೆದಾರರು ಹೆಪ್ಪುಗಟ್ಟಿದ ಖಾತೆಗಳ ವಿರುದ್ಧ ಲೆಕ್ಕಪರಿಶೋಧಕ ನಮೂದುಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು / ಹೆಪ್ಪುಗಟ್ಟಿದ ಖಾತೆಗಳನ್ನು ಸೆಟ್ ಮತ್ತು ರಚಿಸಲು ಅವಕಾಶ,
Determine Address Tax Category From,ವಿಳಾಸ ತೆರಿಗೆ ವರ್ಗವನ್ನು ನಿರ್ಧರಿಸುವುದು,
-Address used to determine Tax Category in transactions.,ವಹಿವಾಟಿನಲ್ಲಿ ತೆರಿಗೆ ವರ್ಗವನ್ನು ನಿರ್ಧರಿಸಲು ಬಳಸುವ ವಿಳಾಸ.,
Over Billing Allowance (%),ಓವರ್ ಬಿಲ್ಲಿಂಗ್ ಭತ್ಯೆ (%),
-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 for $110.,ಆದೇಶಿಸಿದ ಮೊತ್ತದ ವಿರುದ್ಧ ಹೆಚ್ಚು ಬಿಲ್ ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸಲಾದ ಶೇಕಡಾವಾರು. ಉದಾಹರಣೆಗೆ: ಐಟಂಗೆ ಆರ್ಡರ್ ಮೌಲ್ಯವು $ 100 ಮತ್ತು ಸಹಿಷ್ಣುತೆಯನ್ನು 10% ಎಂದು ಹೊಂದಿಸಿದ್ದರೆ ನಿಮಗೆ bill 110 ಗೆ ಬಿಲ್ ಮಾಡಲು ಅನುಮತಿಸಲಾಗುತ್ತದೆ.,
Credit Controller,ಕ್ರೆಡಿಟ್ ನಿಯಂತ್ರಕ,
-Role that is allowed to submit transactions that exceed credit limits set.,ಪಾತ್ರ ವ್ಯವಹಾರ ಸೆಟ್ ಕ್ರೆಡಿಟ್ ಮಿತಿಯನ್ನು ಮಾಡಲಿಲ್ಲ ಸಲ್ಲಿಸಲು ಅವಕಾಶ ನೀಡಲಿಲ್ಲ .,
Check Supplier Invoice Number Uniqueness,ಚೆಕ್ ಸರಬರಾಜುದಾರ ಸರಕುಪಟ್ಟಿ ಸಂಖ್ಯೆ ವೈಶಿಷ್ಟ್ಯ,
Make Payment via Journal Entry,ಜರ್ನಲ್ ಎಂಟ್ರಿ ಮೂಲಕ ಪಾವತಿ ಮಾಡಲು,
Unlink Payment on Cancellation of Invoice,ಸರಕುಪಟ್ಟಿ ರದ್ದು ಮೇಲೆ ಪಾವತಿ ಅನ್ಲಿಂಕ್,
-Unlink Advance Payment on Cancelation of Order,ಆದೇಶವನ್ನು ರದ್ದುಗೊಳಿಸುವ ಕುರಿತು ಮುಂಗಡ ಪಾವತಿಯನ್ನು ಅನ್ಲಿಂಕ್ ಮಾಡಿ,
Book Asset Depreciation Entry Automatically,ಪುಸ್ತಕ ಸ್ವತ್ತು ಸವಕಳಿ ಎಂಟ್ರಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ,
Automatically Add Taxes and Charges from Item Tax Template,ಐಟಂ ತೆರಿಗೆ ಟೆಂಪ್ಲೇಟ್ನಿಂದ ತೆರಿಗೆಗಳು ಮತ್ತು ಶುಲ್ಕಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸೇರಿಸಿ,
Automatically Fetch Payment Terms,ಪಾವತಿ ನಿಯಮಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಪಡೆದುಕೊಳ್ಳಿ,
-Show Inclusive Tax In Print,ಮುದ್ರಣದಲ್ಲಿ ಅಂತರ್ಗತ ತೆರಿಗೆ ತೋರಿಸಿ,
Show Payment Schedule in Print,ಮುದ್ರಣದಲ್ಲಿ ಪಾವತಿ ವೇಳಾಪಟ್ಟಿ ತೋರಿಸಿ,
Currency Exchange Settings,ಕರೆನ್ಸಿ ವಿನಿಮಯ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Allow Stale Exchange Rates,ಸ್ಟಾಲ್ ಎಕ್ಸ್ಚೇಂಜ್ ದರಗಳನ್ನು ಅನುಮತಿಸಿ,
Stale Days,ಸ್ಟಾಲ್ ಡೇಸ್,
Report Settings,ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವರದಿ ಮಾಡಿ,
Use Custom Cash Flow Format,ಕಸ್ಟಮ್ ಕ್ಯಾಶ್ ಫ್ಲೋ ಫಾರ್ಮ್ಯಾಟ್ ಬಳಸಿ,
-Only select if you have setup Cash Flow Mapper documents,ಕ್ಯಾಶ್ ಫ್ಲೋ ಮ್ಯಾಪರ್ ಡಾಕ್ಯುಮೆಂಟ್ಗಳನ್ನು ನೀವು ಹೊಂದಿದ್ದಲ್ಲಿ ಮಾತ್ರ ಆಯ್ಕೆಮಾಡಿ,
Allowed To Transact With,ವ್ಯವಹರಿಸಲು ಅನುಮತಿಸಲಾಗಿದೆ,
SWIFT number,SWIFT ಸಂಖ್ಯೆ,
Branch Code,ಶಾಖೆ ಕೋಡ್,
@@ -4940,7 +4912,6 @@
POS Customer Group,ಪಿಓಎಸ್ ಗ್ರಾಹಕ ಗುಂಪಿನ,
POS Field,ಪಿಒಎಸ್ ಕ್ಷೇತ್ರ,
POS Item Group,ಪಿಓಎಸ್ ಐಟಂ ಗ್ರೂಪ್,
-[Select],[ ಆರಿಸಿರಿ ],
Company Address,ಕಂಪೆನಿ ವಿಳಾಸ,
Update Stock,ಸ್ಟಾಕ್ ನವೀಕರಿಸಲು,
Ignore Pricing Rule,ಬೆಲೆ ರೂಲ್ ನಿರ್ಲಕ್ಷಿಸು,
@@ -5495,8 +5466,6 @@
Supplier Naming By,ಸರಬರಾಜುದಾರ ಹೆಸರಿಸುವ ಮೂಲಕ,
Default Supplier Group,ಡೀಫಾಲ್ಟ್ ಪೂರೈಕೆದಾರ ಗುಂಪು,
Default Buying Price List,ಡೀಫಾಲ್ಟ್ ಬೆಲೆ ಪಟ್ಟಿ ಖರೀದಿ,
-Maintain same rate throughout purchase cycle,ಖರೀದಿ ಪ್ರಕ್ರಿಯೆಯ ಉದ್ದಕ್ಕೂ ಅದೇ ದರವನ್ನು ಕಾಯ್ದುಕೊಳ್ಳಲು,
-Allow Item to be added multiple times in a transaction,ಐಟಂ ಒಂದು ವ್ಯವಹಾರದಲ್ಲಿ ಅನೇಕ ಬಾರಿ ಸೇರಿಸಬೇಕಾಗಿದೆ,
Backflush Raw Materials of Subcontract Based On,ಸಬ್ ಕಾಂಟ್ರಾಕ್ಟ್ ಆಧಾರದ ಮೇಲೆ ಬ್ಯಾಕ್ ಫ್ಲೂಶ್ ರಾ ಮೆಟೀರಿಯಲ್ಸ್,
Material Transferred for Subcontract,ಸಬ್ ಕಾಂಟ್ರಾಕ್ಟ್ಗೆ ಮೆಟೀರಿಯಲ್ ಟ್ರಾನ್ಸ್ಫರ್ಡ್,
Over Transfer Allowance (%),ಓವರ್ ಟ್ರಾನ್ಸ್ಫರ್ ಭತ್ಯೆ (%),
@@ -5540,7 +5509,6 @@
Current Stock,ಪ್ರಸ್ತುತ ಸ್ಟಾಕ್,
PUR-RFQ-.YYYY.-,ಪುರ್- ಆರ್ಎಫ್ಕ್ಯು - .YYYY.-,
For individual supplier,ವೈಯಕ್ತಿಕ ಸರಬರಾಜುದಾರನ,
-Supplier Detail,ಸರಬರಾಜುದಾರ ವಿವರ,
Link to Material Requests,ವಸ್ತು ವಿನಂತಿಗಳಿಗೆ ಲಿಂಕ್ ಮಾಡಿ,
Message for Supplier,ಸರಬರಾಜುದಾರ ಸಂದೇಶ,
Request for Quotation Item,ಉದ್ಧರಣ ಐಟಂ ವಿನಂತಿ,
@@ -6481,7 +6449,6 @@
Appraisal Template,ಅಪ್ರೇಸಲ್ ಟೆಂಪ್ಲೇಟು,
For Employee Name,ನೌಕರರ ಹೆಸರು,
Goals,ಗುರಿಗಳು,
-Calculate Total Score,ಒಟ್ಟು ಸ್ಕೋರ್ ಲೆಕ್ಕ,
Total Score (Out of 5),ಒಟ್ಟು ಸ್ಕೋರ್ ( 5),
"Any other remarks, noteworthy effort that should go in the records.","ಯಾವುದೇ ಟೀಕೆಗಳನ್ನು, ದಾಖಲೆಗಳಲ್ಲಿ ಹೋಗಬೇಕು ಎಂದು ವಿವರಣೆಯಾಗಿದೆ ಪ್ರಯತ್ನ.",
Appraisal Goal,ಅಪ್ರೇಸಲ್ ಗೋಲ್,
@@ -6599,11 +6566,6 @@
Reason for Leaving,ಲೀವಿಂಗ್ ಕಾರಣ,
Leave Encashed?,Encashed ಬಿಡಿ ?,
Encashment Date,ನಗದೀಕರಣ ದಿನಾಂಕ,
-Exit Interview Details,ಎಕ್ಸಿಟ್ ಸಂದರ್ಶನ ವಿವರಗಳು,
-Held On,ನಡೆದ,
-Reason for Resignation,ರಾಜೀನಾಮೆಗೆ ಕಾರಣ,
-Better Prospects,ಉತ್ತಮ ಜೀವನ,
-Health Concerns,ಆರೋಗ್ಯ ಕಾಳಜಿ,
New Workplace,ಹೊಸ ಕೆಲಸದ,
HR-EAD-.YYYY.-,HR-EAD-YYYY.-,
Returned Amount,ಹಿಂತಿರುಗಿದ ಮೊತ್ತ,
@@ -6740,10 +6702,7 @@
Employee Settings,ನೌಕರರ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Retirement Age,ನಿವೃತ್ತಿ ವಯಸ್ಸು,
Enter retirement age in years,ವರ್ಷಗಳಲ್ಲಿ ನಿವೃತ್ತಿ ವಯಸ್ಸು ನಮೂದಿಸಿ,
-Employee Records to be created by,ನೌಕರರ ದಾಖಲೆಗಳು ದಾಖಲಿಸಿದವರು,
-Employee record is created using selected field. ,,
Stop Birthday Reminders,ನಿಲ್ಲಿಸಿ ಜನ್ಮದಿನ ಜ್ಞಾಪನೆಗಳು,
-Don't send Employee Birthday Reminders,ನೌಕರರ ಜನ್ಮದಿನ ಜ್ಞಾಪನೆಗಳನ್ನು ಕಳುಹಿಸಬೇಡಿ,
Expense Approver Mandatory In Expense Claim,ಖರ್ಚು ಕ್ಲೈಮ್ನಲ್ಲಿ ಕಡ್ಡಾಯವಾಗಿ ಖರ್ಚು ಮಾಡುವಿಕೆ,
Payroll Settings,ವೇತನದಾರರ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Leave,ಬಿಡಿ,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,ಲೀವ್ ಅಪ್ಲಿಕೇಶನ್ನಲ್ಲಿ ಕಡ್ಡಾಯವಾಗಿ ಅನುಮೋದನೆಯನ್ನು ಬಿಡಿ,
Show Leaves Of All Department Members In Calendar,ಕ್ಯಾಲೆಂಡರ್ನಲ್ಲಿ ಎಲ್ಲಾ ಇಲಾಖೆಯ ಸದಸ್ಯರ ಎಲೆಗಳನ್ನು ತೋರಿಸಿ,
Auto Leave Encashment,ಸ್ವಯಂ ರಜೆ ಎನ್ಕ್ಯಾಶ್ಮೆಂಟ್,
-Restrict Backdated Leave Application,ಬ್ಯಾಕ್ಡೇಟೆಡ್ ರಜೆ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಿ,
Hiring Settings,ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ನೇಮಿಸಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ,
Check Vacancies On Job Offer Creation,ಜಾಬ್ ಆಫರ್ ಸೃಷ್ಟಿಯಲ್ಲಿ ಖಾಲಿ ಹುದ್ದೆಗಳನ್ನು ಪರಿಶೀಲಿಸಿ,
Identification Document Type,ಗುರುತಿನ ಡಾಕ್ಯುಮೆಂಟ್ ಪ್ರಕಾರ,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,ಉತ್ಪಾದನಾ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Raw Materials Consumption,ಕಚ್ಚಾ ವಸ್ತುಗಳ ಬಳಕೆ,
Allow Multiple Material Consumption,ಬಹು ಮೆಟೀರಿಯಲ್ ಬಳಕೆಗೆ ಅನುಮತಿಸಿ,
-Allow multiple Material Consumption against a Work Order,ವರ್ಕ್ ಆರ್ಡರ್ ವಿರುದ್ಧ ಅನೇಕ ಮೆಟೀರಿಯಲ್ ಸೇವನೆಯನ್ನು ಅನುಮತಿಸಿ,
Backflush Raw Materials Based On,Backflush ಕಚ್ಚಾ ವಸ್ತುಗಳ ಆಧರಿಸಿದ,
Material Transferred for Manufacture,ವಸ್ತು ತಯಾರಿಕೆಗೆ ವರ್ಗಾಯಿಸಲಾಯಿತು,
Capacity Planning,ಸಾಮರ್ಥ್ಯವನ್ನು ಯೋಜನೆ,
Disable Capacity Planning,ಸಾಮರ್ಥ್ಯ ಯೋಜನೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ,
Allow Overtime,ಓವರ್ಟೈಮ್ ಅವಕಾಶ,
-Plan time logs outside Workstation Working Hours.,ವರ್ಕ್ಸ್ಟೇಷನ್ ಕೆಲಸ ಅವಧಿಗಳನ್ನು ಹೊರತುಪಡಿಸಿ ಸಮಯ ದಾಖಲೆಗಳು ಯೋಜನೆ.,
Allow Production on Holidays,ರಜಾ ದಿನಗಳಲ್ಲಿ ಪ್ರೊಡಕ್ಷನ್ ಅವಕಾಶ,
Capacity Planning For (Days),(ದಿನಗಳು) ಸಾಮರ್ಥ್ಯವನ್ನು ಯೋಜನೆ,
-Try planning operations for X days in advance.,ಮುಂಚಿತವಾಗಿ ಎಕ್ಸ್ ದಿನಗಳ ಕಾರ್ಯಾಚರಣೆ ಯೋಜನೆ ಪ್ರಯತ್ನಿಸಿ.,
-Time Between Operations (in mins),(ನಿಮಿಷಗಳು) ಕಾರ್ಯಾಚರಣೆ ನಡುವೆ ಸಮಯ,
-Default 10 mins,10 ನಿಮಿಷಗಳು ಡೀಫಾಲ್ಟ್,
Default Warehouses for Production,ಉತ್ಪಾದನೆಗಾಗಿ ಡೀಫಾಲ್ಟ್ ಗೋದಾಮುಗಳು,
Default Work In Progress Warehouse,ಪ್ರೋಗ್ರೆಸ್ ಉಗ್ರಾಣದಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಕೆಲಸ,
Default Finished Goods Warehouse,ಡೀಫಾಲ್ಟ್ ತಯಾರಾದ ಸರಕುಗಳು ವೇರ್ಹೌಸ್,
Default Scrap Warehouse,ಡೀಫಾಲ್ಟ್ ಸ್ಕ್ರ್ಯಾಪ್ ಗೋದಾಮು,
-Over Production for Sales and Work Order,ಮಾರಾಟ ಮತ್ತು ಕೆಲಸದ ಆದೇಶಕ್ಕಾಗಿ ಹೆಚ್ಚಿನ ಉತ್ಪಾದನೆ,
Overproduction Percentage For Sales Order,ಮಾರಾಟದ ಆದೇಶಕ್ಕಾಗಿ ಉತ್ಪಾದನೆ ಶೇಕಡಾವಾರು,
Overproduction Percentage For Work Order,ಕೆಲಸದ ಆದೇಶಕ್ಕಾಗಿ ಉತ್ಪಾದನೆ ಶೇಕಡಾವಾರು,
Other Settings,ಇತರೆ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Update BOM Cost Automatically,ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನವೀಕರಿಸಿ BOM ವೆಚ್ಚ,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",ಕಚ್ಚಾ ವಸ್ತುಗಳ ಇತ್ತೀಚಿನ ಮೌಲ್ಯಮಾಪನ ದರ / ಬೆಲೆ ಪಟ್ಟಿ ದರ / ಕೊನೆಯ ಖರೀದಿಯ ದರವನ್ನು ಆಧರಿಸಿ ವೇಳಾಪಟ್ಟಿ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನವೀಕರಿಸಿ BOM ವೆಚ್ಚ.,
Material Request Plan Item,ವಸ್ತು ವಿನಂತಿ ಯೋಜನೆ ಐಟಂ,
Material Request Type,ಮೆಟೀರಿಯಲ್ RequestType,
Material Issue,ಮೆಟೀರಿಯಲ್ ಸಂಚಿಕೆ,
@@ -7603,10 +7554,6 @@
Quality Goal,ಗುಣಮಟ್ಟದ ಗುರಿ,
Monitoring Frequency,ಮಾನಿಟರಿಂಗ್ ಆವರ್ತನ,
Weekday,ವಾರದ ದಿನ,
-January-April-July-October,ಜನವರಿ-ಏಪ್ರಿಲ್-ಜುಲೈ-ಅಕ್ಟೋಬರ್,
-Revision and Revised On,ಪರಿಷ್ಕರಣೆ ಮತ್ತು ಪರಿಷ್ಕೃತ ಆನ್,
-Revision,ಪರಿಷ್ಕರಣೆ,
-Revised On,ಪರಿಷ್ಕರಿಸಲಾಗಿದೆ,
Objectives,ಉದ್ದೇಶಗಳು,
Quality Goal Objective,ಗುಣಮಟ್ಟದ ಗುರಿ ಉದ್ದೇಶ,
Objective,ಉದ್ದೇಶ,
@@ -7619,7 +7566,6 @@
Processes,ಪ್ರಕ್ರಿಯೆಗಳು,
Quality Procedure Process,ಗುಣಮಟ್ಟದ ಕಾರ್ಯವಿಧಾನ ಪ್ರಕ್ರಿಯೆ,
Process Description,ಪ್ರಕ್ರಿಯೆಯ ವಿವರಣೆ,
-Child Procedure,ಮಕ್ಕಳ ವಿಧಾನ,
Link existing Quality Procedure.,ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಗುಣಮಟ್ಟದ ಕಾರ್ಯವಿಧಾನವನ್ನು ಲಿಂಕ್ ಮಾಡಿ.,
Additional Information,ಹೆಚ್ಚುವರಿ ಮಾಹಿತಿ,
Quality Review Objective,ಗುಣಮಟ್ಟದ ವಿಮರ್ಶೆ ಉದ್ದೇಶ,
@@ -7787,15 +7733,9 @@
Default Customer Group,ಡೀಫಾಲ್ಟ್ ಗ್ರಾಹಕ ಗುಂಪಿನ,
Default Territory,ಡೀಫಾಲ್ಟ್ ಪ್ರದೇಶ,
Close Opportunity After Days,ದಿನಗಳ ಅವಕಾಶ ಮುಚ್ಚಿ,
-Auto close Opportunity after 15 days,15 ದಿನಗಳ ನಂತರ ಆಟೋ ನಿಕಟ ಅವಕಾಶ,
Default Quotation Validity Days,ಡೀಫಾಲ್ಟ್ ಕೊಟೇಶನ್ ವಾಲಿಡಿಟಿ ಡೇಸ್,
Sales Update Frequency,ಮಾರಾಟದ ನವೀಕರಣ ಆವರ್ತನ,
-How often should project and company be updated based on Sales Transactions.,ಮಾರಾಟದ ವಹಿವಾಟುಗಳನ್ನು ಆಧರಿಸಿ ಎಷ್ಟು ಬಾರಿ ಯೋಜನೆ ಮತ್ತು ಕಂಪನಿ ನವೀಕರಿಸಬೇಕು.,
Each Transaction,ಪ್ರತಿ ವಹಿವಾಟು,
-Allow user to edit Price List Rate in transactions,ಬಳಕೆದಾರ ವ್ಯವಹಾರಗಳಲ್ಲಿ ಬೆಲೆ ಪಟ್ಟಿ ದರ ಸಂಪಾದಿಸಲು ಅನುಮತಿಸಿ,
-Allow multiple Sales Orders against a Customer's Purchase Order,ಗ್ರಾಹಕರ ಖರೀದಿ ಆದೇಶದ ವಿರುದ್ಧ ಅನೇಕ ಮಾರಾಟ ಆದೇಶಗಳಿಗೆ ಅವಕಾಶ,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,ವಿರುದ್ಧ ಖರೀದಿ ದರ ಅಥವಾ ಮೌಲ್ಯಾಂಕನ ದರ ಐಟಂ ಮಾರಾಟದ ಬೆಲೆ ಮೌಲ್ಯೀಕರಿಸಲು,
-Hide Customer's Tax Id from Sales Transactions,ಮಾರಾಟದ ಟ್ರಾನ್ಸಾಕ್ಷನ್ಸ್ ನಿಂದ ಗ್ರಾಹಕರ ತೆರಿಗೆ Id ಮರೆಮಾಡಿ,
SMS Center,ಸಂಚಿಕೆ ಸೆಂಟರ್,
Send To,ಕಳಿಸಿ,
All Contact,ಎಲ್ಲಾ ಸಂಪರ್ಕಿಸಿ,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,ವಸ್ತುಗಳ ತಯಾರಿಕೆಯಲ್ಲಿ ತಯಾರಕರು,
Limited to 12 characters,"12 ಪಾತ್ರಗಳು,",
MAT-MR-.YYYY.-,MAT-MR-YYYY.-,
-Set Warehouse,ಗೋದಾಮು ಹೊಂದಿಸಿ,
-Sets 'For Warehouse' in each row of the Items table.,ಐಟಂಗಳ ಕೋಷ್ಟಕದ ಪ್ರತಿಯೊಂದು ಸಾಲಿನಲ್ಲಿ 'ಗೋದಾಮಿಗಾಗಿ' ಹೊಂದಿಸುತ್ತದೆ.,
-Requested For,ಮನವಿ,
Partially Ordered,ಭಾಗಶಃ ಆದೇಶಿಸಲಾಗಿದೆ,
Transferred,ವರ್ಗಾಯಿಸಲ್ಪಟ್ಟ,
% Ordered,% ಆದೇಶ,
@@ -8407,24 +8344,14 @@
Default Stock UOM,ಡೀಫಾಲ್ಟ್ ಸ್ಟಾಕ್ UOM,
Sample Retention Warehouse,ಮಾದರಿ ಧಾರಣ ವೇರ್ಹೌಸ್,
Default Valuation Method,ಡೀಫಾಲ್ಟ್ ಮೌಲ್ಯಮಾಪನ ವಿಧಾನ,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,ನೀವು ಪ್ರಮಾಣ ವಿರುದ್ಧ ಹೆಚ್ಚು ಸ್ವೀಕರಿಸಲು ಅಥವಾ ತಲುಪಿಸಲು ಅವಕಾಶ ಶೇಕಡಾವಾರು ಆದೇಶ . ಉದಾಹರಣೆಗೆ : ನೀವು 100 ಘಟಕಗಳು ಆದೇಶ ಇದ್ದರೆ . ನಿಮ್ಮ ಸೇವನೆ ನೀವು 110 ಘಟಕಗಳು ಸ್ವೀಕರಿಸಲು 10% ಅವಕಾಶವಿರುತ್ತದೆ ಇದೆ .,
-Action if Quality inspection is not submitted,ಗುಣಮಟ್ಟದ ತಪಾಸಣೆ ಸಲ್ಲಿಸದಿದ್ದರೆ ಕ್ರಮ,
Show Barcode Field,ಶೋ ಬಾರ್ಕೋಡ್ ಫೀಲ್ಡ್,
Convert Item Description to Clean HTML,HTML ಅನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಲು ಐಟಂ ವಿವರಣೆಯನ್ನು ಪರಿವರ್ತಿಸಿ,
-Auto insert Price List rate if missing,ಆಟೋ ಇನ್ಸರ್ಟ್ ದರ ಪಟ್ಟಿ ದರ ಕಾಣೆಯಾಗಿದೆ ವೇಳೆ,
Allow Negative Stock,ನಕಾರಾತ್ಮಕ ಸ್ಟಾಕ್ ಅನುಮತಿಸಿ,
Automatically Set Serial Nos based on FIFO,ಸ್ವಯಂಚಾಲಿತವಾಗಿ FIFO ಆಧರಿಸಿ ನಾವು ಸೀರಿಯಲ್ ಹೊಂದಿಸಿ,
-Set Qty in Transactions based on Serial No Input,ಸೀರಿಯಲ್ ನೋ ಇನ್ಪುಟ್ ಆಧರಿಸಿ ಟ್ರಾನ್ಸಾಕ್ಷನ್ಸ್ನಲ್ಲಿ ಹೊಂದಿಸಿ,
Auto Material Request,ಆಟೋ ಉತ್ಪನ್ನ ವಿನಂತಿ,
-Raise Material Request when stock reaches re-order level,ಸ್ಟಾಕ್ ಮತ್ತೆ ಸಲುವಾಗಿ ಮಟ್ಟ ತಲುಪಿದಾಗ ವಸ್ತು ವಿನಂತಿಗಳನ್ನು ರೈಸ್,
-Notify by Email on creation of automatic Material Request,ಸ್ವಯಂಚಾಲಿತ ವಸ್ತು ವಿನಂತಿಯನ್ನು ಸೃಷ್ಟಿ ಮೇಲೆ ಈಮೇಲ್ ಸೂಚಿಸಿ,
Inter Warehouse Transfer Settings,ಇಂಟರ್ ವೇರ್ಹೌಸ್ ವರ್ಗಾವಣೆ ಸೆಟ್ಟಿಂಗ್ಗಳು,
-Allow Material Transfer From Delivery Note and Sales Invoice,ವಿತರಣಾ ಟಿಪ್ಪಣಿ ಮತ್ತು ಮಾರಾಟ ಸರಕುಪಟ್ಟಿಗಳಿಂದ ವಸ್ತು ವರ್ಗಾವಣೆಯನ್ನು ಅನುಮತಿಸಿ,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,ಖರೀದಿ ರಶೀದಿ ಮತ್ತು ಖರೀದಿ ಸರಕುಪಟ್ಟಿಗಳಿಂದ ವಸ್ತು ವರ್ಗಾವಣೆಯನ್ನು ಅನುಮತಿಸಿ,
Freeze Stock Entries,ಫ್ರೀಜ್ ಸ್ಟಾಕ್ ನಮೂದುಗಳು,
Stock Frozen Upto,ಸ್ಟಾಕ್ ಘನೀಕೃತ ವರೆಗೆ,
-Freeze Stocks Older Than [Days],ಫ್ರೀಜ್ ಸ್ಟಾಕ್ಗಳು ಹಳೆಯದಾಗಿರುವ [ ಡೇಸ್ ],
-Role Allowed to edit frozen stock,ಪಾತ್ರ ಹೆಪ್ಪುಗಟ್ಟಿದ ಸ್ಟಾಕ್ ಸಂಪಾದಿಸಲು ಅನುಮತಿಸಲಾಗಿದೆ,
Batch Identification,ಬ್ಯಾಚ್ ಗುರುತಿಸುವಿಕೆ,
Use Naming Series,ನಾಮಕರಣ ಸರಣಿ ಬಳಸಿ,
Naming Series Prefix,ನಾಮಕರಣ ಸರಣಿ ಪೂರ್ವಪ್ರತ್ಯಯ,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,ಖರೀದಿ ರಸೀತಿ ಟ್ರೆಂಡ್ಸ್,
Purchase Register,ಖರೀದಿ ನೋಂದಣಿ,
Quotation Trends,ನುಡಿಮುತ್ತುಗಳು ಟ್ರೆಂಡ್ಸ್,
-Quoted Item Comparison,ಉಲ್ಲೇಖಿಸಿದ ಐಟಂ ಹೋಲಿಕೆ,
Received Items To Be Billed,ಪಾವತಿಸಬೇಕಾಗುತ್ತದೆ ಸ್ವೀಕರಿಸಿದ ಐಟಂಗಳು,
Qty to Order,ಪ್ರಮಾಣ ಆರ್ಡರ್,
Requested Items To Be Transferred,ಬದಲಾಯಿಸಿಕೊಳ್ಳುವಂತೆ ವಿನಂತಿಸಲಾಗಿದೆ ಐಟಂಗಳು,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,ವಸ್ತು ವಿನಂತಿಗಳಿಗಾಗಿ ಗೋದಾಮು ಆಯ್ಕೆಮಾಡಿ,
Transfer Materials For Warehouse {0},ಗೋದಾಮಿನ ಸಾಮಗ್ರಿಗಳನ್ನು ವರ್ಗಾಯಿಸಿ {0},
Production Plan Material Request Warehouse,ಉತ್ಪಾದನಾ ಯೋಜನೆ ವಸ್ತು ವಿನಂತಿ ಗೋದಾಮು,
-Set From Warehouse,ಗೋದಾಮಿನಿಂದ ಹೊಂದಿಸಿ,
-Source Warehouse (Material Transfer),ಮೂಲ ಗೋದಾಮು (ವಸ್ತು ವರ್ಗಾವಣೆ),
Sets 'Source Warehouse' in each row of the items table.,ಐಟಂಗಳ ಟೇಬಲ್ನ ಪ್ರತಿಯೊಂದು ಸಾಲಿನಲ್ಲಿ 'ಮೂಲ ಗೋದಾಮು' ಹೊಂದಿಸುತ್ತದೆ.,
Sets 'Target Warehouse' in each row of the items table.,ಐಟಂಗಳ ಟೇಬಲ್ನ ಪ್ರತಿಯೊಂದು ಸಾಲಿನಲ್ಲಿ 'ಟಾರ್ಗೆಟ್ ವೇರ್ಹೌಸ್' ಅನ್ನು ಹೊಂದಿಸುತ್ತದೆ.,
Show Cancelled Entries,ರದ್ದಾದ ನಮೂದುಗಳನ್ನು ತೋರಿಸಿ,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,ಸೇವೆಯನ್ನು ಸ್ವೀಕರಿಸಲಾಗಿದೆ ಆದರೆ ಬಿಲ್ ಮಾಡಲಾಗಿಲ್ಲ,
Deferred Accounting Settings,ಮುಂದೂಡಲ್ಪಟ್ಟ ಲೆಕ್ಕಪರಿಶೋಧಕ ಸೆಟ್ಟಿಂಗ್ಗಳು,
Book Deferred Entries Based On,ಪುಸ್ತಕ ಮುಂದೂಡಲ್ಪಟ್ಟ ನಮೂದುಗಳನ್ನು ಆಧರಿಸಿ,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",""ತಿಂಗಳುಗಳು" ಆಯ್ಕೆಮಾಡಿದರೆ, ಒಂದು ತಿಂಗಳಲ್ಲಿ ಎಷ್ಟು ದಿನಗಳ ಲೆಕ್ಕಿಸದೆ ನಿಗದಿತ ಮೊತ್ತವನ್ನು ಪ್ರತಿ ತಿಂಗಳು ಮುಂದೂಡಲ್ಪಟ್ಟ ಆದಾಯ ಅಥವಾ ವೆಚ್ಚವಾಗಿ ಕಾಯ್ದಿರಿಸಲಾಗುತ್ತದೆ. ಮುಂದೂಡಲ್ಪಟ್ಟ ಆದಾಯ ಅಥವಾ ವೆಚ್ಚವನ್ನು ಇಡೀ ತಿಂಗಳು ಕಾಯ್ದಿರಿಸದಿದ್ದರೆ ಅದನ್ನು ಸಾಬೀತುಪಡಿಸಲಾಗುತ್ತದೆ.",
Days,ದಿನಗಳು,
Months,ತಿಂಗಳುಗಳು,
Book Deferred Entries Via Journal Entry,ಜರ್ನಲ್ ಎಂಟ್ರಿ ಮೂಲಕ ಪುಸ್ತಕ ಮುಂದೂಡಲ್ಪಟ್ಟ ನಮೂದುಗಳು,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,ಇದನ್ನು ಪರಿಶೀಲಿಸದಿದ್ದರೆ ಮುಂದೂಡಲ್ಪಟ್ಟ ಆದಾಯ / ವೆಚ್ಚವನ್ನು ಕಾಯ್ದಿರಿಸಲು ನೇರ ಜಿಎಲ್ ನಮೂದುಗಳನ್ನು ರಚಿಸಲಾಗುತ್ತದೆ,
Submit Journal Entries,ಜರ್ನಲ್ ನಮೂದುಗಳನ್ನು ಸಲ್ಲಿಸಿ,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,ಇದನ್ನು ಪರಿಶೀಲಿಸದಿದ್ದರೆ ಜರ್ನಲ್ ನಮೂದುಗಳನ್ನು ಕರಡು ಸ್ಥಿತಿಯಲ್ಲಿ ಉಳಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ಅದನ್ನು ಕೈಯಾರೆ ಸಲ್ಲಿಸಬೇಕಾಗುತ್ತದೆ,
Enable Distributed Cost Center,ವಿತರಣಾ ವೆಚ್ಚ ಕೇಂದ್ರವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ,
@@ -8901,8 +8823,6 @@
Is Inter State,ಇಂಟರ್ ಸ್ಟೇಟ್ ಆಗಿದೆ,
Purchase Details,ಖರೀದಿ ವಿವರಗಳು,
Depreciation Posting Date,ಸವಕಳಿ ಪೋಸ್ಟ್ ದಿನಾಂಕ,
-Purchase Order Required for Purchase Invoice & Receipt Creation,ಖರೀದಿ ಸರಕುಪಟ್ಟಿ ಮತ್ತು ರಶೀದಿ ಸೃಷ್ಟಿಗೆ ಖರೀದಿ ಆದೇಶ ಅಗತ್ಯವಿದೆ,
-Purchase Receipt Required for Purchase Invoice Creation,ಖರೀದಿ ಸರಕುಪಟ್ಟಿ ಸೃಷ್ಟಿಗೆ ಖರೀದಿ ರಶೀದಿ ಅಗತ್ಯವಿದೆ,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ಸರಬರಾಜುದಾರರ ಹೆಸರನ್ನು ನಮೂದಿಸಿದಂತೆ ಸರಬರಾಜುದಾರರ ಹೆಸರನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ. ನೀವು ಸರಬರಾಜುದಾರರನ್ನು ಹೆಸರಿಸಲು ಬಯಸಿದರೆ a",
choose the 'Naming Series' option.,'ನಾಮಕರಣ ಸರಣಿ' ಆಯ್ಕೆಯನ್ನು ಆರಿಸಿ.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,ಹೊಸ ಖರೀದಿ ವಹಿವಾಟನ್ನು ರಚಿಸುವಾಗ ಡೀಫಾಲ್ಟ್ ಬೆಲೆ ಪಟ್ಟಿಯನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ. ಈ ಬೆಲೆ ಪಟ್ಟಿಯಿಂದ ಐಟಂ ಬೆಲೆಗಳನ್ನು ಪಡೆಯಲಾಗುತ್ತದೆ.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,ಆದಾಯ ತೆರಿಗೆ ಘಟಕವಾಗಿದೆ,
Component properties and references ,ಘಟಕ ಗುಣಲಕ್ಷಣಗಳು ಮತ್ತು ಉಲ್ಲೇಖಗಳು,
Additional Salary ,ಹೆಚ್ಚುವರಿ ಸಂಬಳ,
-Condtion and formula,ಸ್ಥಿತಿ ಮತ್ತು ಸೂತ್ರ,
Unmarked days,ಗುರುತು ಹಾಕದ ದಿನಗಳು,
Absent Days,ಅನುಪಸ್ಥಿತಿಯ ದಿನಗಳು,
Conditions and Formula variable and example,ಷರತ್ತುಗಳು ಮತ್ತು ಫಾರ್ಮುಲಾ ವೇರಿಯಬಲ್ ಮತ್ತು ಉದಾಹರಣೆ,
Feedback By,ಪ್ರತಿಕ್ರಿಯೆ,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,ಉತ್ಪಾದನಾ ವಿಭಾಗ,
-Sales Order Required for Sales Invoice & Delivery Note Creation,ಮಾರಾಟ ಸರಕುಪಟ್ಟಿ ಮತ್ತು ವಿತರಣಾ ಟಿಪ್ಪಣಿ ಸೃಷ್ಟಿಗೆ ಮಾರಾಟ ಆದೇಶ ಅಗತ್ಯವಿದೆ,
-Delivery Note Required for Sales Invoice Creation,ಮಾರಾಟ ಸರಕುಪಟ್ಟಿ ಸೃಷ್ಟಿಗೆ ವಿತರಣಾ ಟಿಪ್ಪಣಿ ಅಗತ್ಯವಿದೆ,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ನಮೂದಿಸಿದ ಪೂರ್ಣ ಹೆಸರಿನ ಪ್ರಕಾರ ಗ್ರಾಹಕರ ಹೆಸರನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ. ಗ್ರಾಹಕರನ್ನು ಹೆಸರಿಸಲು ನೀವು ಬಯಸಿದರೆ ಎ",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,ಹೊಸ ಮಾರಾಟ ವಹಿವಾಟನ್ನು ರಚಿಸುವಾಗ ಡೀಫಾಲ್ಟ್ ಬೆಲೆ ಪಟ್ಟಿಯನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ. ಈ ಬೆಲೆ ಪಟ್ಟಿಯಿಂದ ಐಟಂ ಬೆಲೆಗಳನ್ನು ಪಡೆಯಲಾಗುತ್ತದೆ.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","ಈ ಆಯ್ಕೆಯನ್ನು 'ಹೌದು' ಎಂದು ಕಾನ್ಫಿಗರ್ ಮಾಡಿದ್ದರೆ, ಮೊದಲು ಮಾರಾಟ ಆದೇಶವನ್ನು ರಚಿಸದೆ ಮಾರಾಟ ಸರಕುಪಟ್ಟಿ ಅಥವಾ ವಿತರಣಾ ಟಿಪ್ಪಣಿಯನ್ನು ರಚಿಸುವುದನ್ನು ERPNext ತಡೆಯುತ್ತದೆ. ಗ್ರಾಹಕ ಮಾಸ್ಟರ್ನಲ್ಲಿ 'ಮಾರಾಟ ಆದೇಶವಿಲ್ಲದೆ ಮಾರಾಟ ಸರಕುಪಟ್ಟಿ ಸೃಷ್ಟಿಗೆ ಅನುಮತಿಸು' ಚೆಕ್ಬಾಕ್ಸ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವ ಮೂಲಕ ನಿರ್ದಿಷ್ಟ ಗ್ರಾಹಕರಿಗಾಗಿ ಈ ಸಂರಚನೆಯನ್ನು ಅತಿಕ್ರಮಿಸಬಹುದು.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,ಆಯ್ದ ಎಲ್ಲಾ ವಿಷಯಗಳಿಗೆ {0} {1} ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಸೇರಿಸಲಾಗಿದೆ.,
Topics updated,ವಿಷಯಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ,
Academic Term and Program,ಶೈಕ್ಷಣಿಕ ಅವಧಿ ಮತ್ತು ಕಾರ್ಯಕ್ರಮ,
-Last Stock Transaction for item {0} was on {1}.,ಐಟಂ {0 for ಗಾಗಿ ಕೊನೆಯ ಸ್ಟಾಕ್ ವಹಿವಾಟು {1 on ನಲ್ಲಿತ್ತು.,
-Stock Transactions for Item {0} cannot be posted before this time.,ಐಟಂ {0 for ಗಾಗಿ ಸ್ಟಾಕ್ ವಹಿವಾಟುಗಳನ್ನು ಈ ಸಮಯದ ಮೊದಲು ಪೋಸ್ಟ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ.,
Please remove this item and try to submit again or update the posting time.,ದಯವಿಟ್ಟು ಈ ಐಟಂ ಅನ್ನು ತೆಗೆದುಹಾಕಿ ಮತ್ತು ಮತ್ತೆ ಸಲ್ಲಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಪೋಸ್ಟ್ ಮಾಡುವ ಸಮಯವನ್ನು ನವೀಕರಿಸಿ.,
Failed to Authenticate the API key.,API ಕೀಲಿಯನ್ನು ದೃ ate ೀಕರಿಸಲು ವಿಫಲವಾಗಿದೆ.,
Invalid Credentials,ಅಮಾನ್ಯ ರುಜುವಾತುಗಳು,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,ದಯವಿಟ್ಟು ನಿಮ್ಮ ಪ್ಲೈಡ್ ಕ್ಲೈಂಟ್ ಐಡಿ ಮತ್ತು ರಹಸ್ಯ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಶೀಲಿಸಿ,
Bank transaction creation error,ಬ್ಯಾಂಕ್ ವಹಿವಾಟು ರಚನೆ ದೋಷ,
Unit of Measurement,ಅಳತೆಯ ಘಟಕ,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},ಸಾಲು # {}: ಐಟಂ for for ಗೆ ಮಾರಾಟ ದರ ಅದರ than than ಗಿಂತ ಕಡಿಮೆಯಾಗಿದೆ. ಮಾರಾಟ ದರ ಕನಿಷ್ಠ be} ಆಗಿರಬೇಕು,
Fiscal Year {0} Does Not Exist,ಹಣಕಾಸಿನ ವರ್ಷ {0 Ex ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ,
Row # {0}: Returned Item {1} does not exist in {2} {3},ಸಾಲು # {0}: ಹಿಂತಿರುಗಿದ ಐಟಂ {1} {2} {3 in ನಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ,
Valuation type charges can not be marked as Inclusive,ಮೌಲ್ಯಮಾಪನ ಪ್ರಕಾರದ ಶುಲ್ಕಗಳನ್ನು ಅಂತರ್ಗತ ಎಂದು ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,{1 row ಸಾಲಿನಲ್ಲಿ {0} ಆದ್ಯತೆಯ ಪ್ರತಿಕ್ರಿಯೆ ಸಮಯ ರೆಸಲ್ಯೂಶನ್ ಸಮಯಕ್ಕಿಂತ ಹೆಚ್ಚಿರಬಾರದು.,
{0} is not enabled in {1},{0 in ಅನ್ನು {1 in ನಲ್ಲಿ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿಲ್ಲ,
Group by Material Request,ವಸ್ತು ವಿನಂತಿಯ ಪ್ರಕಾರ ಗುಂಪು,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","ಸಾಲು {0}: ಪೂರೈಕೆದಾರ {0 For ಗೆ, ಇಮೇಲ್ ಕಳುಹಿಸಲು ಇಮೇಲ್ ವಿಳಾಸದ ಅಗತ್ಯವಿದೆ",
Email Sent to Supplier {0},ಇಮೇಲ್ ಸರಬರಾಜುದಾರರಿಗೆ ಕಳುಹಿಸಲಾಗಿದೆ {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","ಪೋರ್ಟಲ್ನಿಂದ ಉದ್ಧರಣಕ್ಕಾಗಿ ವಿನಂತಿಯ ಪ್ರವೇಶವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಲು, ಪೋರ್ಟಲ್ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಅದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.",
Supplier Quotation {0} Created,ಪೂರೈಕೆದಾರ ಉದ್ಧರಣ {0} ರಚಿಸಲಾಗಿದೆ,
Valid till Date cannot be before Transaction Date,ವಹಿವಾಟು ದಿನಾಂಕದ ಮೊದಲು ದಿನಾಂಕದವರೆಗೆ ಮಾನ್ಯವಾಗಿಲ್ಲ,
+Unlink Advance Payment on Cancellation of Order,ಆದೇಶವನ್ನು ರದ್ದುಗೊಳಿಸುವ ಕುರಿತು ಮುಂಗಡ ಪಾವತಿಯನ್ನು ಅನ್ಲಿಂಕ್ ಮಾಡಿ,
+"Simple Python Expression, Example: territory != 'All Territories'","ಸರಳ ಪೈಥಾನ್ ಅಭಿವ್ಯಕ್ತಿ, ಉದಾಹರಣೆ: ಪ್ರದೇಶ! = 'ಎಲ್ಲಾ ಪ್ರಾಂತ್ಯಗಳು'",
+Sales Contributions and Incentives,ಮಾರಾಟ ಕೊಡುಗೆಗಳು ಮತ್ತು ಪ್ರೋತ್ಸಾಹಕಗಳು,
+Sourced by Supplier,ಸರಬರಾಜುದಾರರಿಂದ ಹುಳಿ,
+Total weightage assigned should be 100%.<br>It is {0},ನಿಗದಿಪಡಿಸಿದ ಒಟ್ಟು ತೂಕ 100% ಆಗಿರಬೇಕು.<br> ಇದು {0},
+Account {0} exists in parent company {1}.,ಪೋಷಕ ಕಂಪನಿ {1 in ನಲ್ಲಿ ಖಾತೆ {0} ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ.,
+"To overrule this, enable '{0}' in company {1}","ಇದನ್ನು ರದ್ದುಗೊಳಿಸಲು, {1 company ಕಂಪನಿಯಲ್ಲಿ '{0}' ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ",
+Invalid condition expression,ಅಮಾನ್ಯ ಸ್ಥಿತಿ ಅಭಿವ್ಯಕ್ತಿ,
+Please Select a Company First,ದಯವಿಟ್ಟು ಮೊದಲು ಕಂಪನಿಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿ,
+Please Select Both Company and Party Type First,ದಯವಿಟ್ಟು ಮೊದಲು ಕಂಪನಿ ಮತ್ತು ಪಕ್ಷದ ಪ್ರಕಾರ ಎರಡನ್ನೂ ಆಯ್ಕೆ ಮಾಡಿ,
+Provide the invoice portion in percent,ಸರಕುಪಟ್ಟಿ ಭಾಗವನ್ನು ಶೇಕಡಾವಾರು ಒದಗಿಸಿ,
+Give number of days according to prior selection,ಪೂರ್ವ ಆಯ್ಕೆಯ ಪ್ರಕಾರ ದಿನಗಳ ಸಂಖ್ಯೆಯನ್ನು ನೀಡಿ,
+Email Details,ಇಮೇಲ್ ವಿವರಗಳು,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","ಸ್ವೀಕರಿಸುವವರಿಗೆ ಶುಭಾಶಯ ಆಯ್ಕೆಮಾಡಿ. ಉದಾ. ಶ್ರೀ, ಮಿಸ್, ಇತ್ಯಾದಿ.",
+Preview Email,ಇಮೇಲ್ ಪೂರ್ವವೀಕ್ಷಣೆ ಮಾಡಿ,
+Please select a Supplier,ದಯವಿಟ್ಟು ಸರಬರಾಜುದಾರರನ್ನು ಆಯ್ಕೆ ಮಾಡಿ,
+Supplier Lead Time (days),ಸರಬರಾಜುದಾರರ ಪ್ರಮುಖ ಸಮಯ (ದಿನಗಳು),
+"Home, Work, etc.","ಮನೆ, ಕೆಲಸ ಇತ್ಯಾದಿ.",
+Exit Interview Held On,ಸಂದರ್ಶನದಿಂದ ನಿರ್ಗಮಿಸಿ,
+Condition and formula,ಸ್ಥಿತಿ ಮತ್ತು ಸೂತ್ರ,
+Sets 'Target Warehouse' in each row of the Items table.,ಐಟಂಗಳ ಟೇಬಲ್ನ ಪ್ರತಿಯೊಂದು ಸಾಲಿನಲ್ಲಿ 'ಟಾರ್ಗೆಟ್ ವೇರ್ಹೌಸ್' ಅನ್ನು ಹೊಂದಿಸುತ್ತದೆ.,
+Sets 'Source Warehouse' in each row of the Items table.,ಐಟಂಗಳ ಕೋಷ್ಟಕದ ಪ್ರತಿಯೊಂದು ಸಾಲಿನಲ್ಲಿ 'ಮೂಲ ಗೋದಾಮು' ಹೊಂದಿಸುತ್ತದೆ.,
+POS Register,ಪಿಓಎಸ್ ರಿಜಿಸ್ಟರ್,
+"Can not filter based on POS Profile, if grouped by POS Profile",ಪಿಒಎಸ್ ಪ್ರೊಫೈಲ್ನಿಂದ ಗುಂಪು ಮಾಡಿದರೆ ಪಿಒಎಸ್ ಪ್ರೊಫೈಲ್ ಆಧರಿಸಿ ಫಿಲ್ಟರ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ,
+"Can not filter based on Customer, if grouped by Customer",ಗ್ರಾಹಕರಿಂದ ಗುಂಪು ಮಾಡಿದ್ದರೆ ಗ್ರಾಹಕರ ಆಧಾರದ ಮೇಲೆ ಫಿಲ್ಟರ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ,
+"Can not filter based on Cashier, if grouped by Cashier",ಕ್ಯಾಷಿಯರ್ನಿಂದ ಗುಂಪು ಮಾಡಿದ್ದರೆ ಕ್ಯಾಷಿಯರ್ ಆಧರಿಸಿ ಫಿಲ್ಟರ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ,
+Payment Method,ಪಾವತಿ ವಿಧಾನ,
+"Can not filter based on Payment Method, if grouped by Payment Method",ಪಾವತಿ ವಿಧಾನದಿಂದ ಗುಂಪು ಮಾಡಿದ್ದರೆ ಪಾವತಿ ವಿಧಾನವನ್ನು ಆಧರಿಸಿ ಫಿಲ್ಟರ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ,
+Supplier Quotation Comparison,ಪೂರೈಕೆದಾರ ಉದ್ಧರಣ ಹೋಲಿಕೆ,
+Price per Unit (Stock UOM),ಪ್ರತಿ ಯೂನಿಟ್ಗೆ ಬೆಲೆ (ಸ್ಟಾಕ್ ಯುಒಎಂ),
+Group by Supplier,ಸರಬರಾಜುದಾರರಿಂದ ಗುಂಪು,
+Group by Item,ಐಟಂ ಪ್ರಕಾರ ಗುಂಪು,
+Remember to set {field_label}. It is required by {regulation}.,{Field_label set ಅನ್ನು ಹೊಂದಿಸಲು ಮರೆಯದಿರಿ. {ನಿಯಂತ್ರಣ by ನಿಂದ ಇದು ಅಗತ್ಯವಿದೆ.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},ದಾಖಲಾತಿ ದಿನಾಂಕ ಶೈಕ್ಷಣಿಕ ವರ್ಷದ ಪ್ರಾರಂಭ ದಿನಾಂಕಕ್ಕಿಂತ ಮೊದಲು ಇರಬಾರದು {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},ದಾಖಲಾತಿ ದಿನಾಂಕ ಶೈಕ್ಷಣಿಕ ಅವಧಿಯ ಅಂತಿಮ ದಿನಾಂಕದ ನಂತರ ಇರಬಾರದು {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},ದಾಖಲಾತಿ ದಿನಾಂಕ ಶೈಕ್ಷಣಿಕ ಅವಧಿಯ ಪ್ರಾರಂಭ ದಿನಾಂಕಕ್ಕಿಂತ ಮೊದಲು ಇರಬಾರದು {0},
+Future Posting Not Allowed,ಭವಿಷ್ಯದ ಪೋಸ್ಟ್ ಮಾಡಲು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ,
+"To enable Capital Work in Progress Accounting, ","ಪ್ರೋಗ್ರೆಸ್ ಅಕೌಂಟಿಂಗ್ನಲ್ಲಿ ಕ್ಯಾಪಿಟಲ್ ವರ್ಕ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು,",
+you must select Capital Work in Progress Account in accounts table,ಖಾತೆಗಳ ಕೋಷ್ಟಕದಲ್ಲಿ ನೀವು ಪ್ರಗತಿ ಖಾತೆಯಲ್ಲಿ ಕ್ಯಾಪಿಟಲ್ ವರ್ಕ್ ಅನ್ನು ಆರಿಸಬೇಕು,
+You can also set default CWIP account in Company {},ಕಂಪನಿ} in ನಲ್ಲಿ ನೀವು ಡೀಫಾಲ್ಟ್ ಸಿಡಬ್ಲ್ಯುಐಪಿ ಖಾತೆಯನ್ನು ಸಹ ಹೊಂದಿಸಬಹುದು,
+The Request for Quotation can be accessed by clicking on the following button,ಕೆಳಗಿನ ಗುಂಡಿಯನ್ನು ಕ್ಲಿಕ್ ಮಾಡುವುದರ ಮೂಲಕ ಉದ್ಧರಣಕ್ಕಾಗಿ ವಿನಂತಿಯನ್ನು ಪ್ರವೇಶಿಸಬಹುದು,
+Regards,ಅಭಿನಂದನೆಗಳು,
+Please click on the following button to set your new password,ನಿಮ್ಮ ಹೊಸ ಪಾಸ್ವರ್ಡ್ ಹೊಂದಿಸಲು ದಯವಿಟ್ಟು ಕೆಳಗಿನ ಬಟನ್ ಕ್ಲಿಕ್ ಮಾಡಿ,
+Update Password,ಪಾಸ್ವರ್ಡ್ ನವೀಕರಿಸಿ,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},ಸಾಲು # {}: ಐಟಂ for for ಗೆ ಮಾರಾಟ ದರ ಅದರ than than ಗಿಂತ ಕಡಿಮೆಯಾಗಿದೆ. {Seling ಕನಿಷ್ಠ ಮಾರಾಟವಾಗಬೇಕು {},
+You can alternatively disable selling price validation in {} to bypass this validation.,ಈ ation ರ್ಜಿತಗೊಳಿಸುವಿಕೆಯನ್ನು ಬೈಪಾಸ್ ಮಾಡಲು ನೀವು ಪರ್ಯಾಯವಾಗಿ price in ನಲ್ಲಿ ಮಾರಾಟದ ಬೆಲೆ ಮೌಲ್ಯಮಾಪನವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು.,
+Invalid Selling Price,ಅಮಾನ್ಯ ಮಾರಾಟ ಬೆಲೆ,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,ವಿಳಾಸವನ್ನು ಕಂಪನಿಗೆ ಲಿಂಕ್ ಮಾಡಬೇಕಾಗಿದೆ. ದಯವಿಟ್ಟು ಲಿಂಕ್ಗಳ ಕೋಷ್ಟಕದಲ್ಲಿ ಕಂಪನಿಗೆ ಒಂದು ಸಾಲನ್ನು ಸೇರಿಸಿ.,
+Company Not Linked,ಕಂಪನಿ ಲಿಂಕ್ ಮಾಡಿಲ್ಲ,
+Import Chart of Accounts from CSV / Excel files,CSV / Excel ಫೈಲ್ಗಳಿಂದ ಖಾತೆಗಳ ಆಮದು ಚಾರ್ಟ್,
+Completed Qty cannot be greater than 'Qty to Manufacture',ಪೂರ್ಣಗೊಂಡ ಕ್ಯೂಟಿ 'ಉತ್ಪಾದನೆಗೆ ಕ್ಯೂಟಿ' ಗಿಂತ ಹೆಚ್ಚಿರಬಾರದು,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","ಸಾಲು {0}: ಸರಬರಾಜುದಾರ {1 For ಗೆ, ಇಮೇಲ್ ಕಳುಹಿಸಲು ಇಮೇಲ್ ವಿಳಾಸದ ಅಗತ್ಯವಿದೆ",
+"If enabled, the system will post accounting entries for inventory automatically","ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದರೆ, ಸಿಸ್ಟಮ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ದಾಸ್ತಾನುಗಾಗಿ ಲೆಕ್ಕಪತ್ರ ನಮೂದುಗಳನ್ನು ಪೋಸ್ಟ್ ಮಾಡುತ್ತದೆ",
+Accounts Frozen Till Date,ದಿನಾಂಕದವರೆಗೆ ಖಾತೆಗಳು ಸ್ಥಗಿತಗೊಂಡಿವೆ,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,ಅಕೌಂಟಿಂಗ್ ನಮೂದುಗಳನ್ನು ಈ ದಿನಾಂಕದವರೆಗೆ ಸ್ಥಗಿತಗೊಳಿಸಲಾಗಿದೆ. ಕೆಳಗೆ ನಿರ್ದಿಷ್ಟಪಡಿಸಿದ ಪಾತ್ರವನ್ನು ಹೊಂದಿರುವ ಬಳಕೆದಾರರನ್ನು ಹೊರತುಪಡಿಸಿ ಯಾರೂ ನಮೂದುಗಳನ್ನು ರಚಿಸಲು ಅಥವಾ ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,ಹೆಪ್ಪುಗಟ್ಟಿದ ಖಾತೆಗಳನ್ನು ಹೊಂದಿಸಲು ಮತ್ತು ಘನೀಕೃತ ನಮೂದುಗಳನ್ನು ಸಂಪಾದಿಸಲು ಪಾತ್ರವನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ,
+Address used to determine Tax Category in transactions,ವಹಿವಾಟಿನಲ್ಲಿ ತೆರಿಗೆ ವರ್ಗವನ್ನು ನಿರ್ಧರಿಸಲು ಬಳಸುವ ವಿಳಾಸ,
+"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 ","ಆದೇಶಿಸಿದ ಮೊತ್ತದ ವಿರುದ್ಧ ಹೆಚ್ಚು ಬಿಲ್ ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸಲಾದ ಶೇಕಡಾವಾರು. ಉದಾಹರಣೆಗೆ, ಐಟಂಗೆ ಆರ್ಡರ್ ಮೌಲ್ಯವು $ 100 ಮತ್ತು ಸಹಿಷ್ಣುತೆಯನ್ನು 10% ಎಂದು ಹೊಂದಿಸಿದರೆ, ನಿಮಗೆ bill 110 ವರೆಗೆ ಬಿಲ್ ಮಾಡಲು ಅನುಮತಿಸಲಾಗಿದೆ",
+This role is allowed to submit transactions that exceed credit limits,ಕ್ರೆಡಿಟ್ ಮಿತಿಗಳನ್ನು ಮೀರಿದ ವಹಿವಾಟುಗಳನ್ನು ಸಲ್ಲಿಸಲು ಈ ಪಾತ್ರವನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month",""ತಿಂಗಳುಗಳು" ಆಯ್ಕೆಮಾಡಿದರೆ, ಒಂದು ತಿಂಗಳಲ್ಲಿನ ದಿನಗಳ ಸಂಖ್ಯೆಯನ್ನು ಲೆಕ್ಕಿಸದೆ ನಿಗದಿತ ಮೊತ್ತವನ್ನು ಪ್ರತಿ ತಿಂಗಳು ಮುಂದೂಡಲ್ಪಟ್ಟ ಆದಾಯ ಅಥವಾ ವೆಚ್ಚವಾಗಿ ಕಾಯ್ದಿರಿಸಲಾಗುತ್ತದೆ. ಮುಂದೂಡಲ್ಪಟ್ಟ ಆದಾಯ ಅಥವಾ ವೆಚ್ಚವನ್ನು ಇಡೀ ತಿಂಗಳು ಕಾಯ್ದಿರಿಸದಿದ್ದರೆ ಅದನ್ನು ಸಾಬೀತುಪಡಿಸಲಾಗುತ್ತದೆ",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","ಇದನ್ನು ಪರಿಶೀಲಿಸದಿದ್ದರೆ, ಮುಂದೂಡಲ್ಪಟ್ಟ ಆದಾಯ ಅಥವಾ ವೆಚ್ಚವನ್ನು ಕಾಯ್ದಿರಿಸಲು ನೇರ ಜಿಎಲ್ ನಮೂದುಗಳನ್ನು ರಚಿಸಲಾಗುತ್ತದೆ",
+Show Inclusive Tax in Print,ಅಂತರ್ಗತ ತೆರಿಗೆಯನ್ನು ಮುದ್ರಣದಲ್ಲಿ ತೋರಿಸಿ,
+Only select this if you have set up the Cash Flow Mapper documents,ನೀವು ಕ್ಯಾಶ್ ಫ್ಲೋ ಮ್ಯಾಪರ್ ಡಾಕ್ಯುಮೆಂಟ್ಗಳನ್ನು ಹೊಂದಿಸಿದ್ದರೆ ಮಾತ್ರ ಇದನ್ನು ಆಯ್ಕೆ ಮಾಡಿ,
+Payment Channel,ಪಾವತಿ ಚಾನಲ್,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,ಖರೀದಿ ಸರಕುಪಟ್ಟಿ ಮತ್ತು ರಶೀದಿ ಸೃಷ್ಟಿಗೆ ಖರೀದಿ ಆದೇಶ ಅಗತ್ಯವಿದೆಯೇ?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,ಖರೀದಿ ಸರಕುಪಟ್ಟಿ ಸೃಷ್ಟಿಗೆ ಖರೀದಿ ರಶೀದಿ ಅಗತ್ಯವಿದೆಯೇ?,
+Maintain Same Rate Throughout the Purchase Cycle,ಖರೀದಿ ಸೈಕಲ್ನಾದ್ಯಂತ ಒಂದೇ ದರವನ್ನು ಕಾಯ್ದುಕೊಳ್ಳಿ,
+Allow Item To Be Added Multiple Times in a Transaction,ವಹಿವಾಟಿನಲ್ಲಿ ಐಟಂ ಅನ್ನು ಅನೇಕ ಬಾರಿ ಸೇರಿಸಲು ಅನುಮತಿಸಿ,
+Suppliers,ಪೂರೈಕೆದಾರರು,
+Send Emails to Suppliers,ಪೂರೈಕೆದಾರರಿಗೆ ಇಮೇಲ್ಗಳನ್ನು ಕಳುಹಿಸಿ,
+Select a Supplier,ಸರಬರಾಜುದಾರರನ್ನು ಆಯ್ಕೆಮಾಡಿ,
+Cannot mark attendance for future dates.,ಭವಿಷ್ಯದ ದಿನಾಂಕಗಳಿಗೆ ಹಾಜರಾತಿಯನ್ನು ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},ಹಾಜರಾತಿಯನ್ನು ನವೀಕರಿಸಲು ನೀವು ಬಯಸುವಿರಾ?<br> ಪ್ರಸ್ತುತ: {0}<br> ಅನುಪಸ್ಥಿತಿ: {1},
+Mpesa Settings,ಎಂಪೆಸಾ ಸೆಟ್ಟಿಂಗ್ಸ್,
+Initiator Name,ಇನಿಶಿಯೇಟರ್ ಹೆಸರು,
+Till Number,ಸಂಖ್ಯೆ ತನಕ,
+Sandbox,ಸ್ಯಾಂಡ್ಬಾಕ್ಸ್,
+ Online PassKey,ಆನ್ಲೈನ್ ಪಾಸ್ಕೆ,
+Security Credential,ಭದ್ರತಾ ರುಜುವಾತು,
+Get Account Balance,ಖಾತೆ ಬಾಕಿ ಪಡೆಯಿರಿ,
+Please set the initiator name and the security credential,ದಯವಿಟ್ಟು ಇನಿಶಿಯೇಟರ್ ಹೆಸರು ಮತ್ತು ಭದ್ರತಾ ರುಜುವಾತುಗಳನ್ನು ಹೊಂದಿಸಿ,
+Inpatient Medication Entry,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಪ್ರವೇಶ,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),ಐಟಂ ಕೋಡ್ (ಡ್ರಗ್),
+Medication Orders,Ation ಷಧಿ ಆದೇಶಗಳು,
+Get Pending Medication Orders,ಬಾಕಿ ಇರುವ ation ಷಧಿ ಆದೇಶಗಳನ್ನು ಪಡೆಯಿರಿ,
+Inpatient Medication Orders,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶಗಳು,
+Medication Warehouse,Ation ಷಧಿ ಉಗ್ರಾಣ,
+Warehouse from where medication stock should be consumed,From ಷಧಿ ದಾಸ್ತಾನು ಸೇವಿಸಬೇಕಾದ ಗೋದಾಮು,
+Fetching Pending Medication Orders,ಬಾಕಿ ಇರುವ ation ಷಧಿ ಆದೇಶಗಳನ್ನು ಪಡೆಯುವುದು,
+Inpatient Medication Entry Detail,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಪ್ರವೇಶ ವಿವರ,
+Medication Details,Ation ಷಧಿ ವಿವರಗಳು,
+Drug Code,ಡ್ರಗ್ ಕೋಡ್,
+Drug Name,ಡ್ರಗ್ ಹೆಸರು,
+Against Inpatient Medication Order,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶದ ವಿರುದ್ಧ,
+Against Inpatient Medication Order Entry,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶದ ಪ್ರವೇಶದ ವಿರುದ್ಧ,
+Inpatient Medication Order,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶ,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,ಒಟ್ಟು ಆದೇಶಗಳು,
+Completed Orders,ಪೂರ್ಣಗೊಂಡ ಆದೇಶಗಳು,
+Add Medication Orders,Ation ಷಧಿ ಆದೇಶಗಳನ್ನು ಸೇರಿಸಿ,
+Adding Order Entries,ಆದೇಶ ನಮೂದುಗಳನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ,
+{0} medication orders completed,{0} ation ಷಧಿ ಆದೇಶಗಳು ಪೂರ್ಣಗೊಂಡಿವೆ,
+{0} medication order completed,{0} ation ಷಧಿ ಆದೇಶ ಪೂರ್ಣಗೊಂಡಿದೆ,
+Inpatient Medication Order Entry,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶ ಪ್ರವೇಶ,
+Is Order Completed,ಆರ್ಡರ್ ಪೂರ್ಣಗೊಂಡಿದೆ,
+Employee Records to Be Created By,ರಚಿಸಬೇಕಾದ ನೌಕರರ ದಾಖಲೆಗಳು,
+Employee records are created using the selected field,ಆಯ್ದ ಕ್ಷೇತ್ರವನ್ನು ಬಳಸಿಕೊಂಡು ನೌಕರರ ದಾಖಲೆಗಳನ್ನು ರಚಿಸಲಾಗುತ್ತದೆ,
+Don't send employee birthday reminders,ನೌಕರರ ಹುಟ್ಟುಹಬ್ಬದ ಜ್ಞಾಪನೆಗಳನ್ನು ಕಳುಹಿಸಬೇಡಿ,
+Restrict Backdated Leave Applications,ಬ್ಯಾಕ್ಡೇಟೆಡ್ ರಜೆ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ,
+Sequence ID,ಅನುಕ್ರಮ ಐಡಿ,
+Sequence Id,ಅನುಕ್ರಮ ಐಡಿ,
+Allow multiple material consumptions against a Work Order,ಕೆಲಸದ ಆದೇಶದ ವಿರುದ್ಧ ಬಹು ವಸ್ತು ಬಳಕೆಗಳನ್ನು ಅನುಮತಿಸಿ,
+Plan time logs outside Workstation working hours,ಕಾರ್ಯಕ್ಷೇತ್ರದ ಕೆಲಸದ ಸಮಯದ ಹೊರಗೆ ಸಮಯದ ದಾಖಲೆಗಳನ್ನು ಯೋಜಿಸಿ,
+Plan operations X days in advance,ಎಕ್ಸ್ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಎಕ್ಸ್ ದಿನಗಳ ಮುಂಚಿತವಾಗಿ ಯೋಜಿಸಿ,
+Time Between Operations (Mins),ಕಾರ್ಯಾಚರಣೆಗಳ ನಡುವಿನ ಸಮಯ (ನಿಮಿಷಗಳು),
+Default: 10 mins,ಡೀಫಾಲ್ಟ್: 10 ನಿಮಿಷಗಳು,
+Overproduction for Sales and Work Order,ಮಾರಾಟ ಮತ್ತು ಕೆಲಸದ ಆದೇಶಕ್ಕಾಗಿ ಅಧಿಕ ಉತ್ಪಾದನೆ,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",ಇತ್ತೀಚಿನ ಮೌಲ್ಯಮಾಪನ ದರ / ಬೆಲೆ ಪಟ್ಟಿ ದರ / ಕಚ್ಚಾ ವಸ್ತುಗಳ ಕೊನೆಯ ಖರೀದಿ ದರವನ್ನು ಆಧರಿಸಿ ವೇಳಾಪಟ್ಟಿ ಮೂಲಕ BOM ವೆಚ್ಚವನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನವೀಕರಿಸಿ,
+Purchase Order already created for all Sales Order items,ಎಲ್ಲಾ ಮಾರಾಟ ಆದೇಶ ಐಟಂಗಳಿಗಾಗಿ ಈಗಾಗಲೇ ಖರೀದಿ ಆದೇಶವನ್ನು ರಚಿಸಲಾಗಿದೆ,
+Select Items,ಐಟಂಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ,
+Against Default Supplier,ಡೀಫಾಲ್ಟ್ ಸರಬರಾಜುದಾರರ ವಿರುದ್ಧ,
+Auto close Opportunity after the no. of days mentioned above,ಇಲ್ಲ ನಂತರ ಆಟೋ ಕ್ಲೋಸ್ ಅವಕಾಶ. ಮೇಲೆ ತಿಳಿಸಿದ ದಿನಗಳ,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,ಮಾರಾಟ ಸರಕುಪಟ್ಟಿ ಮತ್ತು ವಿತರಣಾ ಟಿಪ್ಪಣಿ ಸೃಷ್ಟಿಗೆ ಮಾರಾಟ ಆದೇಶ ಅಗತ್ಯವಿದೆಯೇ?,
+Is Delivery Note Required for Sales Invoice Creation?,ಮಾರಾಟ ಸರಕುಪಟ್ಟಿ ಸೃಷ್ಟಿಗೆ ವಿತರಣಾ ಟಿಪ್ಪಣಿ ಅಗತ್ಯವಿದೆಯೇ?,
+How often should Project and Company be updated based on Sales Transactions?,ಮಾರಾಟ ವಹಿವಾಟಿನ ಆಧಾರದ ಮೇಲೆ ಪ್ರಾಜೆಕ್ಟ್ ಮತ್ತು ಕಂಪನಿಯನ್ನು ಎಷ್ಟು ಬಾರಿ ನವೀಕರಿಸಬೇಕು?,
+Allow User to Edit Price List Rate in Transactions,ವಹಿವಾಟಿನಲ್ಲಿ ಬೆಲೆ ಪಟ್ಟಿ ದರವನ್ನು ಸಂಪಾದಿಸಲು ಬಳಕೆದಾರರನ್ನು ಅನುಮತಿಸಿ,
+Allow Item to Be Added Multiple Times in a Transaction,ವಹಿವಾಟಿನಲ್ಲಿ ಐಟಂ ಅನ್ನು ಅನೇಕ ಬಾರಿ ಸೇರಿಸಲು ಅನುಮತಿಸಿ,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,ಗ್ರಾಹಕರ ಖರೀದಿ ಆದೇಶದ ವಿರುದ್ಧ ಬಹು ಮಾರಾಟ ಆದೇಶಗಳನ್ನು ಅನುಮತಿಸಿ,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,ಖರೀದಿ ದರ ಅಥವಾ ಮೌಲ್ಯಮಾಪನ ದರದ ವಿರುದ್ಧ ಐಟಂಗೆ ಮಾರಾಟದ ಬೆಲೆಯನ್ನು ಮೌಲ್ಯೀಕರಿಸಿ,
+Hide Customer's Tax ID from Sales Transactions,ಮಾರಾಟ ವಹಿವಾಟಿನಿಂದ ಗ್ರಾಹಕರ ತೆರಿಗೆ ID ಅನ್ನು ಮರೆಮಾಡಿ,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","ಆದೇಶಿಸಿದ ಪ್ರಮಾಣಕ್ಕೆ ವಿರುದ್ಧವಾಗಿ ಹೆಚ್ಚಿನದನ್ನು ಸ್ವೀಕರಿಸಲು ಅಥವಾ ತಲುಪಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸಲಾದ ಶೇಕಡಾವಾರು. ಉದಾಹರಣೆಗೆ, ನೀವು 100 ಘಟಕಗಳನ್ನು ಆದೇಶಿಸಿದ್ದರೆ, ಮತ್ತು ನಿಮ್ಮ ಭತ್ಯೆ 10% ಆಗಿದ್ದರೆ, ನಿಮಗೆ 110 ಘಟಕಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಅನುಮತಿ ಇದೆ.",
+Action If Quality Inspection Is Not Submitted,ಗುಣಮಟ್ಟದ ತಪಾಸಣೆ ಸಲ್ಲಿಸದಿದ್ದರೆ ಕ್ರಮ,
+Auto Insert Price List Rate If Missing,ಕಾಣೆಯಾಗಿದ್ದರೆ ಆಟೋ ಇನ್ಸರ್ಟ್ ಬೆಲೆ ಪಟ್ಟಿ ದರ,
+Automatically Set Serial Nos Based on FIFO,FIFO ಆಧರಿಸಿ ಸರಣಿ ಸಂಖ್ಯೆಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಹೊಂದಿಸಿ,
+Set Qty in Transactions Based on Serial No Input,ಸರಣಿ ಇಲ್ಲ ಇನ್ಪುಟ್ ಆಧರಿಸಿ ವಹಿವಾಟಿನಲ್ಲಿ Qty ಅನ್ನು ಹೊಂದಿಸಿ,
+Raise Material Request When Stock Reaches Re-order Level,ಸ್ಟಾಕ್ ಮರು-ಆದೇಶ ಮಟ್ಟವನ್ನು ತಲುಪಿದಾಗ ವಸ್ತು ವಿನಂತಿಯನ್ನು ಹೆಚ್ಚಿಸಿ,
+Notify by Email on Creation of Automatic Material Request,ಸ್ವಯಂಚಾಲಿತ ವಸ್ತು ವಿನಂತಿಯನ್ನು ರಚಿಸುವ ಕುರಿತು ಇಮೇಲ್ ಮೂಲಕ ತಿಳಿಸಿ,
+Allow Material Transfer from Delivery Note to Sales Invoice,ವಿತರಣಾ ಟಿಪ್ಪಣಿಯಿಂದ ಮಾರಾಟ ಸರಕುಪಟ್ಟಿಗೆ ವಸ್ತು ವರ್ಗಾವಣೆಯನ್ನು ಅನುಮತಿಸಿ,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,ಖರೀದಿ ರಶೀದಿಯಿಂದ ಖರೀದಿ ಸರಕುಪಟ್ಟಿಗೆ ವಸ್ತು ವರ್ಗಾವಣೆಯನ್ನು ಅನುಮತಿಸಿ,
+Freeze Stocks Older Than (Days),(ದಿನಗಳು) ಹಳೆಯದಾದ ಷೇರುಗಳನ್ನು ಫ್ರೀಜ್ ಮಾಡಿ,
+Role Allowed to Edit Frozen Stock,ಘನೀಕೃತ ಸ್ಟಾಕ್ ಅನ್ನು ಸಂಪಾದಿಸಲು ಪಾತ್ರವನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,ಹಂಚಿಕೆಯಿಲ್ಲದ ನಮೂದು {0 the ಬ್ಯಾಂಕ್ ವಹಿವಾಟಿನ ಹಂಚಿಕೆಯಾಗದ ಮೊತ್ತಕ್ಕಿಂತ ಹೆಚ್ಚಾಗಿದೆ,
+Payment Received,ಪಾವತಿ ಸ್ವೀಕರಿಸಲಾಗಿದೆ,
+Attendance cannot be marked outside of Academic Year {0},ಹಾಜರಾತಿಯನ್ನು ಶೈಕ್ಷಣಿಕ ವರ್ಷ {0 outside ಹೊರಗೆ ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ,
+Student is already enrolled via Course Enrollment {0},ಕೋರ್ಸ್ ದಾಖಲಾತಿ {0 via ಮೂಲಕ ವಿದ್ಯಾರ್ಥಿಯನ್ನು ಈಗಾಗಲೇ ದಾಖಲಿಸಲಾಗಿದೆ,
+Attendance cannot be marked for future dates.,ಭವಿಷ್ಯದ ದಿನಾಂಕಗಳಿಗೆ ಹಾಜರಾತಿಯನ್ನು ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.,
+Please add programs to enable admission application.,ಪ್ರವೇಶ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ದಯವಿಟ್ಟು ಕಾರ್ಯಕ್ರಮಗಳನ್ನು ಸೇರಿಸಿ.,
+The following employees are currently still reporting to {0}:,ಕೆಳಗಿನ ಉದ್ಯೋಗಿಗಳು ಪ್ರಸ್ತುತ {0 to ಗೆ ವರದಿ ಮಾಡುತ್ತಿದ್ದಾರೆ:,
+Please make sure the employees above report to another Active employee.,ದಯವಿಟ್ಟು ಮೇಲಿನ ಉದ್ಯೋಗಿಗಳು ಇನ್ನೊಬ್ಬ ಸಕ್ರಿಯ ಉದ್ಯೋಗಿಗೆ ವರದಿ ಮಾಡಿದ್ದಾರೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.,
+Cannot Relieve Employee,ಉದ್ಯೋಗಿಯನ್ನು ನಿವಾರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ,
+Please enter {0},ದಯವಿಟ್ಟು {0 enter ಅನ್ನು ನಮೂದಿಸಿ,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',ದಯವಿಟ್ಟು ಮತ್ತೊಂದು ಪಾವತಿ ವಿಧಾನವನ್ನು ಆಯ್ಕೆಮಾಡಿ. '{0}' ಕರೆನ್ಸಿಯಲ್ಲಿನ ವಹಿವಾಟುಗಳನ್ನು ಎಂಪೆಸಾ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ,
+Transaction Error,ವಹಿವಾಟು ದೋಷ,
+Mpesa Express Transaction Error,ಎಂಪೆಸಾ ಎಕ್ಸ್ಪ್ರೆಸ್ ವಹಿವಾಟು ದೋಷ,
+"Issue detected with Mpesa configuration, check the error logs for more details","ಎಂಪೆಸಾ ಸಂರಚನೆಯೊಂದಿಗೆ ಸಮಸ್ಯೆಯನ್ನು ಪತ್ತೆ ಮಾಡಲಾಗಿದೆ, ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗಾಗಿ ದೋಷ ದಾಖಲೆಗಳನ್ನು ಪರಿಶೀಲಿಸಿ",
+Mpesa Express Error,ಎಂಪೆಸಾ ಎಕ್ಸ್ಪ್ರೆಸ್ ದೋಷ,
+Account Balance Processing Error,ಖಾತೆ ಬಾಕಿ ಪ್ರಕ್ರಿಯೆ ದೋಷ,
+Please check your configuration and try again,ದಯವಿಟ್ಟು ನಿಮ್ಮ ಕಾನ್ಫಿಗರೇಶನ್ ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ,
+Mpesa Account Balance Processing Error,ಎಂಪೆಸಾ ಖಾತೆ ಬಾಕಿ ಪ್ರಕ್ರಿಯೆ ದೋಷ,
+Balance Details,ಸಮತೋಲನ ವಿವರಗಳು,
+Current Balance,ಪ್ರಸ್ತುತ ಸಮತೋಲನ,
+Available Balance,ಲಭ್ಯವಿರುವ ಬ್ಯಾಲೆನ್ಸ್,
+Reserved Balance,ಕಾಯ್ದಿರಿಸಿದ ಬಾಕಿ,
+Uncleared Balance,ಅಸ್ಪಷ್ಟ ಸಮತೋಲನ,
+Payment related to {0} is not completed,{0 to ಗೆ ಸಂಬಂಧಿಸಿದ ಪಾವತಿ ಪೂರ್ಣಗೊಂಡಿಲ್ಲ,
+Row #{}: Item Code: {} is not available under warehouse {}.,ಸಾಲು # {}: ಐಟಂ ಕೋಡ್: w} ಗೋದಾಮಿನ ಅಡಿಯಲ್ಲಿ ಲಭ್ಯವಿಲ್ಲ {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,ಸಾಲು # {}: ಐಟಂ ಕೋಡ್ಗೆ ಸ್ಟಾಕ್ ಪ್ರಮಾಣ ಸಾಕಾಗುವುದಿಲ್ಲ: ware ಗೋದಾಮಿನ ಅಡಿಯಲ್ಲಿ}}. ಲಭ್ಯವಿರುವ ಪ್ರಮಾಣ {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,ಸಾಲು # {}: ದಯವಿಟ್ಟು ಸರಣಿ ಸಂಖ್ಯೆ ಆಯ್ಕೆಮಾಡಿ ಮತ್ತು ಐಟಂ ವಿರುದ್ಧ ಬ್ಯಾಚ್ ಮಾಡಿ: {} ಅಥವಾ ವ್ಯವಹಾರವನ್ನು ಪೂರ್ಣಗೊಳಿಸಲು ಅದನ್ನು ತೆಗೆದುಹಾಕಿ.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,ಸಾಲು # {}: ಐಟಂ ವಿರುದ್ಧ ಯಾವುದೇ ಸರಣಿ ಸಂಖ್ಯೆಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ: {}. ವ್ಯವಹಾರವನ್ನು ಪೂರ್ಣಗೊಳಿಸಲು ದಯವಿಟ್ಟು ಒಂದನ್ನು ಆರಿಸಿ ಅಥವಾ ತೆಗೆದುಹಾಕಿ.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,ಸಾಲು # {}: ಐಟಂ ವಿರುದ್ಧ ಯಾವುದೇ ಬ್ಯಾಚ್ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ: {}. ವ್ಯವಹಾರವನ್ನು ಪೂರ್ಣಗೊಳಿಸಲು ದಯವಿಟ್ಟು ಬ್ಯಾಚ್ ಆಯ್ಕೆಮಾಡಿ ಅಥವಾ ತೆಗೆದುಹಾಕಿ.,
+Payment amount cannot be less than or equal to 0,ಪಾವತಿ ಮೊತ್ತವು 0 ಕ್ಕಿಂತ ಕಡಿಮೆ ಅಥವಾ ಸಮನಾಗಿರಬಾರದು,
+Please enter the phone number first,ದಯವಿಟ್ಟು ಮೊದಲು ಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ,
+Row #{}: {} {} does not exist.,ಸಾಲು # {}: {} {ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,ಆರಂಭಿಕ {2} ಇನ್ವಾಯ್ಸ್ಗಳನ್ನು ರಚಿಸಲು ಸಾಲು # {0}: {1 ಅಗತ್ಯವಿದೆ,
+You had {} errors while creating opening invoices. Check {} for more details,ಆರಂಭಿಕ ಇನ್ವಾಯ್ಸ್ಗಳನ್ನು ರಚಿಸುವಾಗ ನೀವು}} ದೋಷಗಳನ್ನು ಹೊಂದಿದ್ದೀರಿ. ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗಾಗಿ {Check ಪರಿಶೀಲಿಸಿ,
+Error Occured,ದೋಷ ಸಂಭವಿಸಿದೆ,
+Opening Invoice Creation In Progress,ಸರಕುಪಟ್ಟಿ ಸೃಷ್ಟಿಯನ್ನು ತೆರೆಯಲಾಗುತ್ತಿದೆ,
+Creating {} out of {} {},{} {ನಿಂದ {} ರಚಿಸಲಾಗುತ್ತಿದೆ,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(ಸರಣಿ ಸಂಖ್ಯೆ: {0}) ಇದನ್ನು ಪೂರ್ಣ ಭರ್ತಿ ಮಾರಾಟ ಆದೇಶ {1 to ಗೆ ಮರುಹೊಂದಿಸಲಾಗಿದೆ.,
+Item {0} {1},ಐಟಂ {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,ಗೋದಾಮಿನ {1 under ಅಡಿಯಲ್ಲಿ {0 item ಐಟಂಗೆ ಕೊನೆಯ ಸ್ಟಾಕ್ ವಹಿವಾಟು {2 on ನಲ್ಲಿತ್ತು.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,ಗೋದಾಮು {1 under ಅಡಿಯಲ್ಲಿ ಐಟಂ {0 for ಗಾಗಿ ಸ್ಟಾಕ್ ವಹಿವಾಟುಗಳನ್ನು ಈ ಸಮಯದ ಮೊದಲು ಪೋಸ್ಟ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ.,
+Posting future stock transactions are not allowed due to Immutable Ledger,ಬದಲಾಯಿಸಲಾಗದ ಲೆಡ್ಜರ್ನಿಂದಾಗಿ ಭವಿಷ್ಯದ ಸ್ಟಾಕ್ ವಹಿವಾಟುಗಳನ್ನು ಪೋಸ್ಟ್ ಮಾಡಲು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ,
+A BOM with name {0} already exists for item {1}.,{0 item ಹೆಸರಿನ BOM ಈಗಾಗಲೇ item 1 item ಐಟಂಗೆ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1 you ನೀವು ಐಟಂ ಅನ್ನು ಮರುಹೆಸರಿಸಿದ್ದೀರಾ? ದಯವಿಟ್ಟು ನಿರ್ವಾಹಕರು / ತಂತ್ರಜ್ಞಾನದ ಬೆಂಬಲವನ್ನು ಸಂಪರ್ಕಿಸಿ,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},# {0 row ಸಾಲಿನಲ್ಲಿ: ಅನುಕ್ರಮ ಐಡಿ {1 previous ಹಿಂದಿನ ಸಾಲು ಅನುಕ್ರಮ ಐಡಿ {2 than ಗಿಂತ ಕಡಿಮೆಯಿರಬಾರದು,
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) {2} ({3}) ಗೆ ಸಮನಾಗಿರಬೇಕು,
+"{0}, complete the operation {1} before the operation {2}.","{0}, {2 operation ಕಾರ್ಯಾಚರಣೆಯ ಮೊದಲು {1 operation ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,ಐಟಂ {0} ಅನ್ನು ಸೇರಿಸಿದಂತೆ ಮತ್ತು ಇಲ್ಲದೆ ಸೀರಿಯಲ್ ನಂ ಮೂಲಕ ವಿತರಣೆಯನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,ಐಟಂ {0} ಗೆ ಸರಣಿ ಸಂಖ್ಯೆ ಇಲ್ಲ. ಸೀರಿಯಲೈಸ್ ಮಾಡಲಾದ ವಸ್ತುಗಳು ಮಾತ್ರ ಸೀರಿಯಲ್ ಸಂಖ್ಯೆ ಆಧರಿಸಿ ವಿತರಣೆಯನ್ನು ಹೊಂದಬಹುದು,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,ಐಟಂ {0 for ಗಾಗಿ ಯಾವುದೇ ಸಕ್ರಿಯ BOM ಕಂಡುಬಂದಿಲ್ಲ. ಸೀರಿಯಲ್ ಸಂಖ್ಯೆ ಮೂಲಕ ವಿತರಣೆಯನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ,
+No pending medication orders found for selected criteria,ಆಯ್ದ ಮಾನದಂಡಗಳಿಗೆ ಯಾವುದೇ ಬಾಕಿ ಇರುವ ation ಷಧಿ ಆದೇಶಗಳು ಕಂಡುಬಂದಿಲ್ಲ,
+From Date cannot be after the current date.,ದಿನಾಂಕದಿಂದ ಪ್ರಸ್ತುತ ದಿನಾಂಕದ ನಂತರ ಇರಬಾರದು.,
+To Date cannot be after the current date.,ದಿನಾಂಕವು ಪ್ರಸ್ತುತ ದಿನಾಂಕದ ನಂತರ ಇರಬಾರದು.,
+From Time cannot be after the current time.,ಸಮಯದಿಂದ ಪ್ರಸ್ತುತ ಸಮಯದ ನಂತರ ಇರಬಾರದು.,
+To Time cannot be after the current time.,ಪ್ರಸ್ತುತ ಸಮಯದ ನಂತರ ಸಮಯಕ್ಕೆ ಸಾಧ್ಯವಿಲ್ಲ.,
+Stock Entry {0} created and ,ಸ್ಟಾಕ್ ಎಂಟ್ರಿ {0} ರಚಿಸಲಾಗಿದೆ ಮತ್ತು,
+Inpatient Medication Orders updated successfully,ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶಗಳನ್ನು ಯಶಸ್ವಿಯಾಗಿ ನವೀಕರಿಸಲಾಗಿದೆ,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},ಸಾಲು {0}: ರದ್ದಾದ ಒಳರೋಗಿಗಳ ation ಷಧಿ ಆದೇಶದ ವಿರುದ್ಧ ಒಳರೋಗಿಗಳ ation ಷಧಿ ನಮೂದನ್ನು ರಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ {1},
+Row {0}: This Medication Order is already marked as completed,ಸಾಲು {0}: ಈ ation ಷಧಿ ಆದೇಶವನ್ನು ಈಗಾಗಲೇ ಪೂರ್ಣಗೊಂಡಿದೆ ಎಂದು ಗುರುತಿಸಲಾಗಿದೆ,
+Quantity not available for {0} in warehouse {1},ಗೋದಾಮಿನಲ್ಲಿ {1 for ಗೆ ಪ್ರಮಾಣ ಲಭ್ಯವಿಲ್ಲ,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,ದಯವಿಟ್ಟು ಸ್ಟಾಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ನಕಾರಾತ್ಮಕ ಸ್ಟಾಕ್ ಅನ್ನು ಅನುಮತಿಸಿ ಅಥವಾ ಮುಂದುವರಿಸಲು ಸ್ಟಾಕ್ ಎಂಟ್ರಿ ರಚಿಸಿ.,
+No Inpatient Record found against patient {0},ರೋಗಿಯ ವಿರುದ್ಧ ಒಳರೋಗಿಗಳ ದಾಖಲೆ ಕಂಡುಬಂದಿಲ್ಲ {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,ರೋಗಿಯ ಎನ್ಕೌಂಟರ್ {1 against ವಿರುದ್ಧ ಒಳರೋಗಿ ation ಷಧಿ ಆದೇಶ {0 already ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ.,
+Allow In Returns,ರಿಟರ್ನ್ಸ್ನಲ್ಲಿ ಅನುಮತಿಸಿ,
+Hide Unavailable Items,ಲಭ್ಯವಿಲ್ಲದ ವಸ್ತುಗಳನ್ನು ಮರೆಮಾಡಿ,
+Apply Discount on Discounted Rate,ರಿಯಾಯಿತಿ ದರದಲ್ಲಿ ರಿಯಾಯಿತಿ ಅನ್ವಯಿಸಿ,
+Therapy Plan Template,ಚಿಕಿತ್ಸೆಯ ಯೋಜನೆ ಟೆಂಪ್ಲೇಟು,
+Fetching Template Details,ಟೆಂಪ್ಲೇಟು ವಿವರಗಳನ್ನು ಪಡೆಯಲಾಗುತ್ತಿದೆ,
+Linked Item Details,ಲಿಂಕ್ ಮಾಡಿದ ಐಟಂ ವಿವರಗಳು,
+Therapy Types,ಚಿಕಿತ್ಸೆಯ ವಿಧಗಳು,
+Therapy Plan Template Detail,ಚಿಕಿತ್ಸೆಯ ಯೋಜನೆ ಟೆಂಪ್ಲೇಟು ವಿವರ,
+Non Conformance,ಅನುಗುಣವಾಗಿಲ್ಲ,
+Process Owner,ಪ್ರಕ್ರಿಯೆ ಮಾಲೀಕ,
+Corrective Action,ಸರಿಪಡಿಸುವ ಕ್ರಿಯೆ,
+Preventive Action,ತಡೆಗಟ್ಟುವ ಕ್ರಮ,
+Problem,ಸಮಸ್ಯೆ,
+Responsible,ಜವಾಬ್ದಾರಿ,
+Completion By,ಇವರಿಂದ ಪೂರ್ಣಗೊಂಡಿದೆ,
+Process Owner Full Name,ಪ್ರಕ್ರಿಯೆ ಮಾಲೀಕರ ಪೂರ್ಣ ಹೆಸರು,
+Right Index,ಬಲ ಸೂಚ್ಯಂಕ,
+Left Index,ಎಡ ಸೂಚ್ಯಂಕ,
+Sub Procedure,ಉಪ ಕಾರ್ಯವಿಧಾನ,
+Passed,ಉತ್ತೀರ್ಣರಾದರು,
+Print Receipt,ರಶೀದಿ ಮುದ್ರಿಸಿ,
+Edit Receipt,ರಶೀದಿಯನ್ನು ಸಂಪಾದಿಸಿ,
+Focus on search input,ಹುಡುಕಾಟ ಇನ್ಪುಟ್ಗೆ ಗಮನ ಕೊಡಿ,
+Focus on Item Group filter,ಐಟಂ ಗ್ರೂಪ್ ಫಿಲ್ಟರ್ ಮೇಲೆ ಕೇಂದ್ರೀಕರಿಸಿ,
+Checkout Order / Submit Order / New Order,ಚೆಕ್ out ಟ್ ಆದೇಶ / ಸಲ್ಲಿಕೆ ಆದೇಶ / ಹೊಸ ಆದೇಶ,
+Add Order Discount,ಆದೇಶ ರಿಯಾಯಿತಿ ಸೇರಿಸಿ,
+Item Code: {0} is not available under warehouse {1}.,ಐಟಂ ಕೋಡ್: ಗೋದಾಮಿನ {1 under ಅಡಿಯಲ್ಲಿ {0} ಲಭ್ಯವಿಲ್ಲ.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,ಗೋದಾಮಿನ {1 under ಅಡಿಯಲ್ಲಿ ಐಟಂ {0 for ಗೆ ಸರಣಿ ಸಂಖ್ಯೆಗಳು ಲಭ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಗೋದಾಮು ಬದಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸಿ.,
+Fetched only {0} available serial numbers.,{0} ಲಭ್ಯವಿರುವ ಸರಣಿ ಸಂಖ್ಯೆಗಳನ್ನು ಮಾತ್ರ ಪಡೆಯಲಾಗಿದೆ.,
+Switch Between Payment Modes,ಪಾವತಿ ಮೋಡ್ಗಳ ನಡುವೆ ಬದಲಿಸಿ,
+Enter {0} amount.,{0} ಮೊತ್ತವನ್ನು ನಮೂದಿಸಿ.,
+You don't have enough points to redeem.,ರಿಡೀಮ್ ಮಾಡಲು ನಿಮಗೆ ಸಾಕಷ್ಟು ಅಂಕಗಳಿಲ್ಲ.,
+You can redeem upto {0}.,ನೀವು {0 to ವರೆಗೆ ರಿಡೀಮ್ ಮಾಡಬಹುದು.,
+Enter amount to be redeemed.,ರಿಡೀಮ್ ಮಾಡಬೇಕಾದ ಮೊತ್ತವನ್ನು ನಮೂದಿಸಿ.,
+You cannot redeem more than {0}.,ನೀವು {0 than ಗಿಂತ ಹೆಚ್ಚಿನದನ್ನು ಪಡೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ.,
+Open Form View,ಫಾರ್ಮ್ ವೀಕ್ಷಣೆಯನ್ನು ತೆರೆಯಿರಿ,
+POS invoice {0} created succesfully,ಪಿಒಎಸ್ ಸರಕುಪಟ್ಟಿ {0 ಯಶಸ್ವಿಯಾಗಿ ರಚಿಸಲಾಗಿದೆ,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,ಐಟಂ ಕೋಡ್ಗೆ ಸ್ಟಾಕ್ ಪ್ರಮಾಣ ಸಾಕಾಗುವುದಿಲ್ಲ: ಗೋದಾಮಿನ {1 under ಅಡಿಯಲ್ಲಿ {0}. ಲಭ್ಯವಿರುವ ಪ್ರಮಾಣ {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,ಸರಣಿ ಸಂಖ್ಯೆ: P 0 already ಅನ್ನು ಈಗಾಗಲೇ ಮತ್ತೊಂದು ಪಿಒಎಸ್ ಇನ್ವಾಯ್ಸ್ಗೆ ವಹಿವಾಟು ಮಾಡಲಾಗಿದೆ.,
+Balance Serial No,ಬ್ಯಾಲೆನ್ಸ್ ಸೀರಿಯಲ್ ನಂ,
+Warehouse: {0} does not belong to {1},ಗೋದಾಮು: {0} {1 to ಗೆ ಸೇರಿಲ್ಲ,
+Please select batches for batched item {0},ದಯವಿಟ್ಟು ಬ್ಯಾಚ್ ಮಾಡಿದ ಐಟಂ {0 for ಗಾಗಿ ಬ್ಯಾಚ್ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ,
+Please select quantity on row {0},ದಯವಿಟ್ಟು row 0 row ಸಾಲಿನಲ್ಲಿ ಪ್ರಮಾಣವನ್ನು ಆರಿಸಿ,
+Please enter serial numbers for serialized item {0},ಸರಣಿ ಐಟಂ {0 for ಗೆ ದಯವಿಟ್ಟು ಸರಣಿ ಸಂಖ್ಯೆಗಳನ್ನು ನಮೂದಿಸಿ,
+Batch {0} already selected.,ಬ್ಯಾಚ್ {0} ಅನ್ನು ಈಗಾಗಲೇ ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ.,
+Please select a warehouse to get available quantities,ಲಭ್ಯವಿರುವ ಪ್ರಮಾಣಗಳನ್ನು ಪಡೆಯಲು ದಯವಿಟ್ಟು ಗೋದಾಮು ಆಯ್ಕೆಮಾಡಿ,
+"For transfer from source, selected quantity cannot be greater than available quantity","ಮೂಲದಿಂದ ವರ್ಗಾವಣೆಗಾಗಿ, ಆಯ್ದ ಪ್ರಮಾಣವು ಲಭ್ಯವಿರುವ ಪ್ರಮಾಣಕ್ಕಿಂತ ಹೆಚ್ಚಿರಬಾರದು",
+Cannot find Item with this Barcode,ಈ ಬಾರ್ಕೋಡ್ನೊಂದಿಗೆ ಐಟಂ ಅನ್ನು ಕಂಡುಹಿಡಿಯಲಾಗುವುದಿಲ್ಲ,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} ಕಡ್ಡಾಯವಾಗಿದೆ. ಕರೆನ್ಸಿ ಎಕ್ಸ್ಚೇಂಜ್ ದಾಖಲೆಯನ್ನು {1} ರಿಂದ {2 for ಗೆ ರಚಿಸಲಾಗಿಲ್ಲ,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,link} ಅದಕ್ಕೆ ಲಿಂಕ್ ಮಾಡಲಾದ ಸ್ವತ್ತುಗಳನ್ನು ಸಲ್ಲಿಸಿದೆ. ಖರೀದಿ ಆದಾಯವನ್ನು ರಚಿಸಲು ನೀವು ಸ್ವತ್ತುಗಳನ್ನು ರದ್ದುಗೊಳಿಸಬೇಕಾಗಿದೆ.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,ಸಲ್ಲಿಸಿದ ಸ್ವತ್ತು {0 with ನೊಂದಿಗೆ ಲಿಂಕ್ ಮಾಡಲಾಗಿರುವುದರಿಂದ ಈ ಡಾಕ್ಯುಮೆಂಟ್ ಅನ್ನು ರದ್ದು ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಮುಂದುವರಿಸಲು ದಯವಿಟ್ಟು ಅದನ್ನು ರದ್ದುಗೊಳಿಸಿ.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,ಸಾಲು # {}: ಸರಣಿ ಸಂಖ್ಯೆ {already ಅನ್ನು ಈಗಾಗಲೇ ಮತ್ತೊಂದು ಪಿಒಎಸ್ ಇನ್ವಾಯ್ಸ್ಗೆ ವಹಿವಾಟು ಮಾಡಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಮಾನ್ಯ ಸರಣಿ ಸಂಖ್ಯೆ ಆಯ್ಕೆಮಾಡಿ.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,ಸಾಲು # {}: ಸರಣಿ ಸಂಖ್ಯೆ.} Already ಅನ್ನು ಈಗಾಗಲೇ ಮತ್ತೊಂದು ಪಿಒಎಸ್ ಇನ್ವಾಯ್ಸ್ಗೆ ವಹಿವಾಟು ಮಾಡಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಮಾನ್ಯ ಸರಣಿ ಸಂಖ್ಯೆ ಆಯ್ಕೆಮಾಡಿ.,
+Item Unavailable,ಐಟಂ ಲಭ್ಯವಿಲ್ಲ,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},ಸಾಲು # {}: ಮೂಲ ಇನ್ವಾಯ್ಸ್ನಲ್ಲಿ ವಹಿವಾಟು ಮಾಡದ ಕಾರಣ ಸರಣಿ ಸಂಖ್ಯೆ {return ಅನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗುವುದಿಲ್ಲ {},
+Please set default Cash or Bank account in Mode of Payment {},ಪಾವತಿ ಕ್ರಮದಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ನಗದು ಅಥವಾ ಬ್ಯಾಂಕ್ ಖಾತೆಯನ್ನು ಹೊಂದಿಸಿ {},
+Please set default Cash or Bank account in Mode of Payments {},ಪಾವತಿ ಮೋಡ್ನಲ್ಲಿ ದಯವಿಟ್ಟು ಡೀಫಾಲ್ಟ್ ನಗದು ಅಥವಾ ಬ್ಯಾಂಕ್ ಖಾತೆಯನ್ನು ಹೊಂದಿಸಿ {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,ದಯವಿಟ್ಟು {} ಖಾತೆಯು ಬ್ಯಾಲೆನ್ಸ್ ಶೀಟ್ ಖಾತೆಯಾಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ. ನೀವು ಪೋಷಕ ಖಾತೆಯನ್ನು ಬ್ಯಾಲೆನ್ಸ್ ಶೀಟ್ ಖಾತೆಗೆ ಬದಲಾಯಿಸಬಹುದು ಅಥವಾ ಬೇರೆ ಖಾತೆಯನ್ನು ಆಯ್ಕೆ ಮಾಡಬಹುದು.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,ದಯವಿಟ್ಟು {} ಖಾತೆಯು ಪಾವತಿಸಬಹುದಾದ ಖಾತೆಯಾಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ. ಪಾವತಿಸಬೇಕಾದ ಖಾತೆ ಪ್ರಕಾರವನ್ನು ಬದಲಾಯಿಸಿ ಅಥವಾ ಬೇರೆ ಖಾತೆಯನ್ನು ಆರಿಸಿ.,
+Row {}: Expense Head changed to {} ,ಸಾಲು {}: ಖರ್ಚು ಹೆಡ್ ಅನ್ನು {to ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ,
+because account {} is not linked to warehouse {} ,ಏಕೆಂದರೆ ಖಾತೆ {} ಗೋದಾಮಿನೊಂದಿಗೆ ಸಂಪರ್ಕ ಹೊಂದಿಲ್ಲ}},
+or it is not the default inventory account,ಅಥವಾ ಇದು ಡೀಫಾಲ್ಟ್ ದಾಸ್ತಾನು ಖಾತೆಯಲ್ಲ,
+Expense Head Changed,ಖರ್ಚು ತಲೆ ಬದಲಾಯಿಸಲಾಗಿದೆ,
+because expense is booked against this account in Purchase Receipt {},ಏಕೆಂದರೆ ಖರೀದಿ ರಶೀದಿಯಲ್ಲಿ ಈ ಖಾತೆಯ ವಿರುದ್ಧ ವೆಚ್ಚವನ್ನು ಕಾಯ್ದಿರಿಸಲಾಗಿದೆ}},
+as no Purchase Receipt is created against Item {}. ,ಐಟಂ against against ಗೆ ವಿರುದ್ಧವಾಗಿ ಯಾವುದೇ ಖರೀದಿ ರಶೀದಿಯನ್ನು ರಚಿಸಲಾಗಿಲ್ಲ.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,ಖರೀದಿ ಸರಕುಪಟ್ಟಿ ನಂತರ ಖರೀದಿ ರಶೀದಿಯನ್ನು ರಚಿಸಿದಾಗ ಪ್ರಕರಣಗಳ ಲೆಕ್ಕಪತ್ರವನ್ನು ನಿರ್ವಹಿಸಲು ಇದನ್ನು ಮಾಡಲಾಗುತ್ತದೆ,
+Purchase Order Required for item {},ಐಟಂ for for ಗೆ ಖರೀದಿ ಆದೇಶ ಅಗತ್ಯವಿದೆ,
+To submit the invoice without purchase order please set {} ,ಖರೀದಿ ಆದೇಶವಿಲ್ಲದೆ ಸರಕುಪಟ್ಟಿ ಸಲ್ಲಿಸಲು ದಯವಿಟ್ಟು set set ಅನ್ನು ಹೊಂದಿಸಿ,
+as {} in {},{} ನಲ್ಲಿ {as ನಂತೆ,
+Mandatory Purchase Order,ಕಡ್ಡಾಯ ಖರೀದಿ ಆದೇಶ,
+Purchase Receipt Required for item {},ಐಟಂ for for ಗೆ ಖರೀದಿ ರಶೀದಿ ಅಗತ್ಯವಿದೆ,
+To submit the invoice without purchase receipt please set {} ,ಖರೀದಿ ರಶೀದಿ ಇಲ್ಲದೆ ಸರಕುಪಟ್ಟಿ ಸಲ್ಲಿಸಲು ದಯವಿಟ್ಟು set set ಅನ್ನು ಹೊಂದಿಸಿ,
+Mandatory Purchase Receipt,ಕಡ್ಡಾಯ ಖರೀದಿ ರಶೀದಿ,
+POS Profile {} does not belongs to company {},ಪಿಒಎಸ್ ವಿವರ {company ಕಂಪನಿಗೆ ಸೇರಿಲ್ಲ {},
+User {} is disabled. Please select valid user/cashier,ಬಳಕೆದಾರ {Disable ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಮಾನ್ಯ ಬಳಕೆದಾರ / ಕ್ಯಾಷಿಯರ್ ಆಯ್ಕೆಮಾಡಿ,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,ಸಾಲು # {}: ರಿಟರ್ನ್ ಇನ್ವಾಯ್ಸ್ನ ಮೂಲ ಸರಕುಪಟ್ಟಿ {} {} ಆಗಿದೆ.,
+Original invoice should be consolidated before or along with the return invoice.,ರಿಟರ್ನ್ ಇನ್ವಾಯ್ಸ್ಗೆ ಮುಂಚಿತವಾಗಿ ಅಥವಾ ಅದರೊಂದಿಗೆ ಮೂಲ ಇನ್ವಾಯ್ಸ್ ಅನ್ನು ಕ್ರೋ id ೀಕರಿಸಬೇಕು.,
+You can add original invoice {} manually to proceed.,ಮುಂದುವರಿಯಲು ನೀವು ಮೂಲ ಇನ್ವಾಯ್ಸ್ ಅನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ಸೇರಿಸಬಹುದು.,
+Please ensure {} account is a Balance Sheet account. ,ದಯವಿಟ್ಟು {} ಖಾತೆಯು ಬ್ಯಾಲೆನ್ಸ್ ಶೀಟ್ ಖಾತೆಯಾಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.,
+You can change the parent account to a Balance Sheet account or select a different account.,ನೀವು ಪೋಷಕ ಖಾತೆಯನ್ನು ಬ್ಯಾಲೆನ್ಸ್ ಶೀಟ್ ಖಾತೆಗೆ ಬದಲಾಯಿಸಬಹುದು ಅಥವಾ ಬೇರೆ ಖಾತೆಯನ್ನು ಆಯ್ಕೆ ಮಾಡಬಹುದು.,
+Please ensure {} account is a Receivable account. ,ದಯವಿಟ್ಟು}} ಖಾತೆ ಸ್ವೀಕರಿಸುವ ಖಾತೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.,
+Change the account type to Receivable or select a different account.,ಸ್ವೀಕರಿಸುವಂತಹ ಖಾತೆ ಪ್ರಕಾರವನ್ನು ಬದಲಾಯಿಸಿ ಅಥವಾ ಬೇರೆ ಖಾತೆಯನ್ನು ಆರಿಸಿ.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},ಗಳಿಸಿದ ಲಾಯಲ್ಟಿ ಪಾಯಿಂಟ್ಗಳನ್ನು ಪುನಃ ಪಡೆದುಕೊಳ್ಳುವುದರಿಂದ} cancel ರದ್ದು ಮಾಡಲಾಗುವುದಿಲ್ಲ. ಮೊದಲು cancel} ಇಲ್ಲ {cancel ಅನ್ನು ರದ್ದುಗೊಳಿಸಿ,
+already exists,ಈಗಾಗಲೇ ಇದೆ,
+POS Closing Entry {} against {} between selected period,ಪಿಒಎಸ್ ಮುಚ್ಚುವ ಪ್ರವೇಶ {} ವಿರುದ್ಧ {} ಆಯ್ದ ಅವಧಿಯ ನಡುವೆ,
+POS Invoice is {},ಪಿಒಎಸ್ ಸರಕುಪಟ್ಟಿ {is ಆಗಿದೆ,
+POS Profile doesn't matches {},ಪಿಓಎಸ್ ಪ್ರೊಫೈಲ್ match match ಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ,
+POS Invoice is not {},ಪಿಒಎಸ್ ಸರಕುಪಟ್ಟಿ {not ಅಲ್ಲ,
+POS Invoice isn't created by user {},POS ಸರಕುಪಟ್ಟಿ ಬಳಕೆದಾರರಿಂದ ರಚಿಸಲ್ಪಟ್ಟಿಲ್ಲ {},
+Row #{}: {},ಸಾಲು # {}: {},
+Invalid POS Invoices,ಅಮಾನ್ಯ ಪಿಓಎಸ್ ಇನ್ವಾಯ್ಸ್ಗಳು,
+Please add the account to root level Company - {},ದಯವಿಟ್ಟು ಮೂಲ ಮಟ್ಟದ ಕಂಪನಿಗೆ ಖಾತೆಯನ್ನು ಸೇರಿಸಿ - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","ಚೈಲ್ಡ್ ಕಂಪನಿ {0 for ಗೆ ಖಾತೆಯನ್ನು ರಚಿಸುವಾಗ, ಪೋಷಕ ಖಾತೆ {1 found ಕಂಡುಬಂದಿಲ್ಲ. ಅನುಗುಣವಾದ COA ನಲ್ಲಿ ದಯವಿಟ್ಟು ಪೋಷಕ ಖಾತೆಯನ್ನು ರಚಿಸಿ",
+Account Not Found,ಖಾತೆ ಕಂಡುಬಂದಿಲ್ಲ,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","ಚೈಲ್ಡ್ ಕಂಪನಿ {0 for ಗೆ ಖಾತೆಯನ್ನು ರಚಿಸುವಾಗ, ಪೋಷಕ ಖಾತೆ {1 a ಲೆಡ್ಜರ್ ಖಾತೆಯಾಗಿ ಕಂಡುಬರುತ್ತದೆ.",
+Please convert the parent account in corresponding child company to a group account.,ದಯವಿಟ್ಟು ಅನುಗುಣವಾದ ಮಕ್ಕಳ ಕಂಪನಿಯಲ್ಲಿನ ಪೋಷಕ ಖಾತೆಯನ್ನು ಗುಂಪು ಖಾತೆಗೆ ಪರಿವರ್ತಿಸಿ.,
+Invalid Parent Account,ಅಮಾನ್ಯ ಪೋಷಕ ಖಾತೆ,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",ಹೊಂದಿಕೆಯಾಗದಂತೆ ತಪ್ಪಿಸಲು ಅದನ್ನು ಮರುಹೆಸರಿಸಲು ಮೂಲ ಕಂಪನಿ {0 via ಮೂಲಕ ಮಾತ್ರ ಅನುಮತಿಸಲಾಗಿದೆ.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","ನೀವು {2} ಐಟಂನ {0} {1} ಪ್ರಮಾಣಗಳಾಗಿದ್ದರೆ, {3 the ಸ್ಕೀಮ್ ಅನ್ನು ಐಟಂನಲ್ಲಿ ಅನ್ವಯಿಸಲಾಗುತ್ತದೆ.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","ನೀವು {2} ಮೌಲ್ಯದ ಐಟಂ {2 If ಆಗಿದ್ದರೆ, {3 the ಸ್ಕೀಮ್ ಅನ್ನು ಐಟಂನಲ್ಲಿ ಅನ್ವಯಿಸಲಾಗುತ್ತದೆ.",
+"As the field {0} is enabled, the field {1} is mandatory.","{0 field ಕ್ಷೇತ್ರವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಂತೆ, {1 field ಕ್ಷೇತ್ರವು ಕಡ್ಡಾಯವಾಗಿದೆ.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","{0 field ಕ್ಷೇತ್ರವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಂತೆ, {1 the ಕ್ಷೇತ್ರದ ಮೌಲ್ಯವು 1 ಕ್ಕಿಂತ ಹೆಚ್ಚಿರಬೇಕು.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},ಪೂರ್ಣ ಪ್ರಮಾಣದ ಮಾರಾಟ ಆದೇಶ {2 to ಗೆ ಕಾಯ್ದಿರಿಸಲಾಗಿರುವ ಕಾರಣ {1 item ಐಟಂ {0 Ser ನ ಸರಣಿ ಸಂಖ್ಯೆ ತಲುಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.,
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","ಮಾರಾಟ ಆದೇಶ {0 the ಐಟಂಗೆ reservation 1 reservation ಅನ್ನು ಕಾಯ್ದಿರಿಸಿದೆ, ನೀವು ಕಾಯ್ದಿರಿಸಿದ {1} ಅನ್ನು {0 against ಗೆ ಮಾತ್ರ ತಲುಪಿಸಬಹುದು.",
+{0} Serial No {1} cannot be delivered,{0} ಸರಣಿ ಸಂಖ್ಯೆ {1 delivery ತಲುಪಿಸಲಾಗುವುದಿಲ್ಲ,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},ಸಾಲು {0}: ಕಚ್ಚಾ ವಸ್ತು {1 for ಗೆ ಉಪಗುತ್ತಿಗೆ ವಸ್ತು ಕಡ್ಡಾಯವಾಗಿದೆ,
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","ಸಾಕಷ್ಟು ಕಚ್ಚಾ ವಸ್ತುಗಳು ಇರುವುದರಿಂದ, ಉಗ್ರಾಣ {0 for ಗೆ ವಸ್ತು ವಿನಂತಿ ಅಗತ್ಯವಿಲ್ಲ.",
+" If you still want to proceed, please enable {0}.","ನೀವು ಇನ್ನೂ ಮುಂದುವರಿಯಲು ಬಯಸಿದರೆ, ದಯವಿಟ್ಟು {0 enable ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.",
+The item referenced by {0} - {1} is already invoiced,{0} - {1 by ನಿಂದ ಉಲ್ಲೇಖಿಸಲಾದ ಐಟಂ ಈಗಾಗಲೇ ಇನ್ವಾಯ್ಸ್ ಆಗಿದೆ,
+Therapy Session overlaps with {0},ಥೆರಪಿ ಸೆಷನ್ {0 with ನೊಂದಿಗೆ ಅತಿಕ್ರಮಿಸುತ್ತದೆ,
+Therapy Sessions Overlapping,ಥೆರಪಿ ಸೆಷನ್ಗಳು ಅತಿಕ್ರಮಿಸುತ್ತವೆ,
+Therapy Plans,ಚಿಕಿತ್ಸೆಯ ಯೋಜನೆಗಳು,
+"Item Code, warehouse, quantity are required on row {0}","Code 0 row ಸಾಲಿನಲ್ಲಿ ಐಟಂ ಕೋಡ್, ಗೋದಾಮು, ಪ್ರಮಾಣ ಅಗತ್ಯವಿದೆ",
+Get Items from Material Requests against this Supplier,ಈ ಸರಬರಾಜುದಾರರ ವಿರುದ್ಧ ವಸ್ತು ವಿನಂತಿಗಳಿಂದ ವಸ್ತುಗಳನ್ನು ಪಡೆಯಿರಿ,
+Enable European Access,ಯುರೋಪಿಯನ್ ಪ್ರವೇಶವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ,
+Creating Purchase Order ...,ಖರೀದಿ ಆದೇಶವನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","ಕೆಳಗಿನ ಐಟಂಗಳ ಡೀಫಾಲ್ಟ್ ಪೂರೈಕೆದಾರರಿಂದ ಸರಬರಾಜುದಾರರನ್ನು ಆಯ್ಕೆಮಾಡಿ. ಆಯ್ಕೆಯ ಮೇಲೆ, ಆಯ್ದ ಸರಬರಾಜುದಾರರಿಗೆ ಮಾತ್ರ ಸೇರಿದ ವಸ್ತುಗಳ ವಿರುದ್ಧ ಖರೀದಿ ಆದೇಶವನ್ನು ಮಾಡಲಾಗುತ್ತದೆ.",
+Row #{}: You must select {} serial numbers for item {}.,ಸಾಲು # {}: ನೀವು item item ಐಟಂಗೆ {} ಸರಣಿ ಸಂಖ್ಯೆಗಳನ್ನು ಆರಿಸಬೇಕು.,
diff --git a/erpnext/translations/ko.csv b/erpnext/translations/ko.csv
index cf25b92..c051b07 100644
--- a/erpnext/translations/ko.csv
+++ b/erpnext/translations/ko.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},실제의 형태 세금은 행의 항목 요금에 포함 할 수없는 {0},
Add,추가,
Add / Edit Prices,가격 추가/편집,
-Add All Suppliers,모든 공급 업체 추가,
Add Comment,코멘트를 추가,
Add Customers,고객 추가,
Add Employees,직원 추가,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',카테고리는 '평가'또는 'Vaulation과 전체'에 대한 때 공제 할 수 없음,
"Cannot delete Serial No {0}, as it is used in stock transactions","삭제할 수 없습니다 시리얼 번호 {0}, 그것은 증권 거래에 사용되는로",
Cannot enroll more than {0} students for this student group.,이 학생 그룹에 대한 {0} 학생 이상 등록 할 수 없습니다.,
-Cannot find Item with this barcode,이 바코드가있는 항목을 찾을 수 없습니다.,
Cannot find active Leave Period,활성 휴가 기간을 찾을 수 없습니다.,
Cannot produce more Item {0} than Sales Order quantity {1},더 많은 항목을 생성 할 수 없습니다 {0}보다 판매 주문 수량 {1},
Cannot promote Employee with status Left,상태가 왼쪽 인 직원을 승격 할 수 없습니다.,
Cannot refer row number greater than or equal to current row number for this Charge type,이 충전 유형에 대한보다 크거나 현재의 행의 수와 동일한 행 번호를 참조 할 수 없습니다,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,첫 번째 행에 대한 '이전 행 전체에'이전 행에 금액 '또는로 충전 타입을 선택할 수 없습니다,
-Cannot set a received RFQ to No Quote,수신 RFQ를 견적으로 설정할 수 없습니다.,
Cannot set as Lost as Sales Order is made.,판매 주문이 이루어질으로 분실로 설정할 수 없습니다.,
Cannot set authorization on basis of Discount for {0},에 대한 할인의 기준으로 권한을 설정할 수 없습니다 {0},
Cannot set multiple Item Defaults for a company.,한 회사에 대해 여러 개의 항목 기본값을 설정할 수 없습니다.,
@@ -521,7 +518,6 @@
Chargeble,Chileble,
Charges are updated in Purchase Receipt against each item,요금은 각 항목에 대해 구매 영수증에 업데이트됩니다,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","요금은 비례 적으로 사용자의 선택에 따라, 상품 수량 또는 금액에 따라 배포됩니다",
-Chart Of Accounts,계정 차트,
Chart of Cost Centers,코스트 센터의 차트,
Check all,모두 확인,
Checkout,점검,
@@ -581,7 +577,6 @@
Compensatory Off,보상 오프,
Compensatory leave request days not in valid holidays,유효한 휴가가 아닌 보상 휴가 요청 일,
Complaint,불평,
-Completed Qty can not be greater than 'Qty to Manufacture',보다 '수량 제조하는'완료 수량은 클 수 없습니다,
Completion Date,완료일,
Computer,컴퓨터,
Condition,조건,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","만들고, 매일, 매주 및 매월 이메일 다이제스트를 관리 할 수 있습니다.",
Create customer quotes,고객 따옴표를 만들기,
Create rules to restrict transactions based on values.,값을 기준으로 거래를 제한하는 규칙을 만듭니다.,
-Created By,제작,
Created {0} scorecards for {1} between: ,{1}의 {0} 스코어 카드 생성 :,
Creating Company and Importing Chart of Accounts,회사 만들기 및 계정 차트 가져 오기,
Creating Fees,수수료 만들기,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,이전 날짜 이전에 사원 이체는 제출할 수 없습니다.,
Employee cannot report to himself.,직원은 자신에게보고 할 수 없습니다.,
Employee relieved on {0} must be set as 'Left',{0}에 안심 직원은 '왼쪽'으로 설정해야합니다,
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,다음 직원이 현재이 직원에게보고하고 있으므로 직원 상태를 '왼쪽'으로 설정할 수 없습니다.,
Employee {0} already submited an apllication {1} for the payroll period {2},직원 {0}이 급여 기간 {2}에 대한 신청서 {1}을 이미 제출했습니다.,
Employee {0} has already applied for {1} between {2} and {3} : ,직원 {0}이 (가) {1}에 {2}에서 {3} 사이에 이미 신청했습니다 :,
Employee {0} has no maximum benefit amount,직원 {0}에게는 최대 혜택 금액이 없습니다.,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,행 {0} : 계획 수량 입력,
"For {0}, only credit accounts can be linked against another debit entry",{0} 만 신용 계정은 자동 이체 항목에 링크 할 수 있습니다 들어,
"For {0}, only debit accounts can be linked against another credit entry",{0} 만 직불 계정은 다른 신용 항목에 링크 할 수 있습니다 들어,
-Form View,양식보기,
Forum Activity,포럼 활동,
Free item code is not selected,무료 항목 코드가 선택되지 않았습니다.,
Freight and Forwarding Charges,화물 운송 및 포워딩 요금,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","이전에 할당 할 수없는 남기기 {0}, 휴가 균형이 이미 반입 전달 미래 휴가 할당 기록되었습니다로 {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","휴가 밸런스 이미 캐리 전달 미래두고 할당 레코드되었습니다로서, {0} 전에 취소 / 적용될 수 없다 남겨 {1}",
Leave of type {0} cannot be longer than {1},유형의 휴가는 {0}을 넘을 수 없습니다 {1},
-Leave the field empty to make purchase orders for all suppliers,모든 공급 업체의 구매 주문을 작성하려면 필드를 비워 둡니다.,
Leaves,이파리,
Leaves Allocated Successfully for {0},잎에 성공적으로 할당 된 {0},
Leaves has been granted sucessfully,나뭇잎이 성공적으로 부여되었습니다.,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,재료 명세서 (BOM)와 어떤 항목은 제조 없습니다,
No Items with Bill of Materials.,BOM이없는 항목이 없습니다.,
No Permission,아무 권한이 없습니다,
-No Quote,견적 없음,
No Remarks,없음 비고,
No Result to submit,제출할 결과가 없습니다.,
No Salary Structure assigned for Employee {0} on given date {1},주어진 날짜 {1}에 직원 {0}에게 지정된 급여 구조가 없습니다.,
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,사이에있는 중복 조건 :,
Owner,소유권자,
PAN,팬,
-PO already created for all sales order items,모든 판매 오더 품목에 대해 PO가 생성되었습니다.,
POS,POS,
POS Profile,POS 프로필,
POS Profile is required to use Point-of-Sale,POS 프로파일은 Point-of-Sale을 사용해야합니다.,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,충전 유형을 먼저 선택하세요,
Please select Company,회사를 선택하세요,
Please select Company and Designation,회사 명 및 지명을 선택하십시오.,
-Please select Company and Party Type first,첫번째 회사와 파티 유형을 선택하세요,
Please select Company and Posting Date to getting entries,항목을 얻으려면 회사 및 전기 일을 선택하십시오.,
Please select Company first,처음 회사를 선택하세요,
Please select Completion Date for Completed Asset Maintenance Log,Completed Asset Maintenance Log의 완료 날짜를 선택하십시오.,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,행 {0} : UOM 변환 계수는 필수입니다,
Row {0}: select the workstation against the operation {1},행 {0} : 작업 {1}에 대한 워크 스테이션을 선택하십시오.,
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,행 {0} : {1} 품목 {2}에 필요한 일련 번호. 귀하는 {3}을 (를) 제공했습니다.,
-Row {0}: {1} is required to create the Opening {2} Invoices,행 {0} : 개회 {2} 송장 생성에 {1}이 (가) 필요합니다.,
Row {0}: {1} must be greater than 0,행 {0} : {1}은 0보다 커야합니다.,
Row {0}: {1} {2} does not match with {3},행 {0} : {1} {2}과 일치하지 않는 {3},
Row {0}:Start Date must be before End Date,행 {0} : 시작 날짜가 종료 날짜 이전이어야합니다,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Grant Review 이메일 보내기,
Send Now,지금 보내기,
Send SMS,SMS 보내기,
-Send Supplier Emails,공급 업체 이메일 보내기,
Send mass SMS to your contacts,상대에게 대량 SMS를 보내기,
Sensitivity,감광도,
Sent,발신,
-Serial #,직렬 #,
Serial No and Batch,일련 번호 및 배치,
Serial No is mandatory for Item {0},일련 번호는 항목에 대해 필수입니다 {0},
Serial No {0} does not belong to Batch {1},일련 번호 {0}이 배치 {1}에 속해 있지 않습니다.,
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,이 시스템을 설정하는하는 기업의 이름입니다.,
The number of shares and the share numbers are inconsistent,주식 수와 주식 수는 일치하지 않습니다.,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,{0} 계획의 지불 게이트웨이 계정이이 지불 요청의 지불 게이트웨이 계정과 다릅니다.,
-The request for quotation can be accessed by clicking on the following link,견적 요청은 다음 링크를 클릭하여 액세스 할 수 있습니다,
The selected BOMs are not for the same item,선택한 BOM의 동일한 항목에 대한 없습니다,
The selected item cannot have Batch,선택한 항목이 배치를 가질 수 없습니다,
The seller and the buyer cannot be the same,판매자와 구매자는 같을 수 없습니다.,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},총 탄력적 인 혜택 구성 요소 금액 {0}은 최대 이점보다 적어서는 안됩니다 {1},
Total hours: {0},총 시간 : {0},
Total leaves allocated is mandatory for Leave Type {0},할당 된 총 나뭇잎 수는 {0} 휴가 유형의 경우 필수입니다.,
-Total weightage assigned should be 100%. It is {0},할당 된 총 weightage 100 %이어야한다.그것은 {0},
Total working hours should not be greater than max working hours {0},총 근무 시간은 최대 근무 시간보다 더 안 {0},
Total {0} ({1}),총 {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","총 {0} 모든 항목에 대해 당신이 '를 기반으로 요금을 분배'변경해야 할 수있다, 제로",
@@ -3316,7 +3299,6 @@
What do you need help with?,어떤 도움이 필요 하신가요?,
What does it do?,그것은 무엇을 하는가?,
Where manufacturing operations are carried.,제조 작업은 어디를 수행한다.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",하위 회사 {0}에 대한 계정을 만드는 동안 상위 계정 {1}을 (를) 찾을 수 없습니다. 해당 COA에서 상위 계정을 생성하십시오.,
White,화이트,
Wire Transfer,송금,
WooCommerce Products,WooCommerce 제품,
@@ -3448,7 +3430,6 @@
{0} variants created.,변형 {0}이 생성되었습니다.,
{0} {1} created,{0} {1} 작성,
{0} {1} does not exist,{0} {1} 존재하지 않습니다,
-{0} {1} does not exist.,{0} {1}이 (가) 존재하지 않습니다.,
{0} {1} has been modified. Please refresh.,{0} {1} 수정되었습니다.새로 고침하십시오.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1}이 (가) 제출되지 않았으므로 조치를 완료 할 수 없습니다.,
"{0} {1} is associated with {2}, but Party Account is {3}",{0} {1}은 (는) {2}와 연관되어 있지만 Party Account는 {3}과 (과) 연관되어 있습니다.,
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0} : {1} 수행하지 존재,
{0}: {1} not found in Invoice Details table,{0} {1} 송장 정보 테이블에서 찾을 수 없습니다,
{} of {},{} 의 {},
+Assigned To,담당자,
Chat,채팅,
Completed By,작성자,
Conditions,정황,
@@ -3506,7 +3488,9 @@
Merge with existing,기존에 병합,
Office,사무실,
Orientation,정위,
+Parent,부모의,
Passive,수동,
+Payment Failed,결제 실패,
Percent,퍼센트,
Permanent,퍼머넌트,
Personal,개인의,
@@ -3544,7 +3528,6 @@
Company field is required,회사 필드가 필요합니다.,
Creating Dimensions...,치수 만들기 ...,
Duplicate entry against the item code {0} and manufacturer {1},항목 코드 {0} 및 제조업체 {1}에 대한 중복 항목,
-Import Chart Of Accounts from CSV / Excel files,CSV / Excel 파일에서 Chart of Accounts 가져 오기,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN이 잘못되었습니다! 입력 한 입력 내용이 UIN 소지자 또는 비거주 OIDAR 서비스 공급자의 GSTIN 형식과 일치하지 않습니다.,
Invoice Grand Total,인보이스 총액,
Last carbon check date cannot be a future date,마지막 탄소 체크 날짜는 미래 날짜가 될 수 없습니다.,
@@ -3556,6 +3539,7 @@
Show {0},{0} 표시,
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","이름 계열에 허용되지 않는 "-", "#", ".", "/", "{"및 "}"을 제외한 특수 문자",
Target Details,대상 세부 정보,
+{0} already has a Parent Procedure {1}.,{0}에 이미 상위 절차 {1}이 있습니다.,
API,API,
Annual,연간,
Approved,인가 된,
@@ -3572,6 +3556,8 @@
No data to export,내보낼 데이터가 없습니다.,
Portrait,초상화,
Print Heading,인쇄 제목,
+Scheduler Inactive,스케줄러 비활성,
+Scheduler is inactive. Cannot import data.,스케줄러가 비활성화되었습니다. 데이터를 가져올 수 없습니다.,
Show Document,문서 표시,
Show Traceback,역 추적 표시,
Video,비디오,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},항목 {0}에 대한 품질 검사 생성,
Creating Accounts...,계정 생성 중 ...,
Creating bank entries...,은행 엔트리 생성 중 ...,
-Creating {0},{0} 생성 중,
Credit limit is already defined for the Company {0},회사 {0}에 대한 여신 한도가 이미 정의되어 있습니다.,
Ctrl + Enter to submit,제출하려면 Ctrl + Enter,
Ctrl+Enter to submit,제출하려면 Ctrl + Enter 키를 누르십시오.,
@@ -3921,7 +3906,6 @@
Plaid public token error,격자 무늬 공용 토큰 오류,
Plaid transactions sync error,격자 무늬 거래 동기화 오류,
Please check the error log for details about the import errors,가져 오기 오류에 대한 자세한 내용은 오류 로그를 확인하십시오.,
-Please click on the following link to set your new password,새 암호를 설정하려면 다음 링크를 클릭하십시오,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,회사 <b>{}에</b> 대한 <b>DATEV 설정</b> 을 작성하십시오.,
Please create adjustment Journal Entry for amount {0} ,금액 {0}에 대한 조정 분개를 생성하십시오,
Please do not create more than 500 items at a time,한 번에 500 개 이상의 항목을 만들지 마세요.,
@@ -3997,6 +3981,7 @@
Release date must be in the future,출시 날짜가 미래 여야합니다.,
Relieving Date must be greater than or equal to Date of Joining,완화 날짜는 가입 날짜보다 크거나 같아야합니다.,
Rename,이름,
+Rename Not Allowed,허용되지 않는 이름 바꾸기,
Repayment Method is mandatory for term loans,상환 방법은 기간 대출에 필수적입니다,
Repayment Start Date is mandatory for term loans,상환 시작 날짜는 기간 대출에 필수입니다,
Report Item,보고서 항목,
@@ -4043,7 +4028,6 @@
Select All,모두 선택,
Select Difference Account,차이 계정 선택,
Select a Default Priority.,기본 우선 순위를 선택하십시오.,
-Select a Supplier from the Default Supplier List of the items below.,아래 항목의 기본 공급 업체 목록에서 공급 업체를 선택하십시오.,
Select a company,회사 선택,
Select finance book for the item {0} at row {1},{1} 행의 항목 {0}에 대한 재무 책을 선택하십시오.,
Select only one Priority as Default.,Priority as Default를 하나만 선택하십시오.,
@@ -4247,7 +4231,6 @@
Actual ,실제,
Add to cart,쇼핑 카트에 담기,
Budget,예산,
-Chart Of Accounts Importer,계정 수입 차트,
Chart of Accounts,회계 계통도,
Customer database.,고객 데이터베이스.,
Days Since Last order,일 이후 마지막 주문,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,종료일은 시작일보다 짧을 수 없습니다.,
For Default Supplier (Optional),기본 공급 업체 (선택 사항),
From date cannot be greater than To date,날짜에서 날짜보다 클 수 없습니다,
-Get items from,에서 항목을 가져 오기,
Group by,그룹으로,
In stock,재고,
Item name,품명,
@@ -4532,32 +4514,22 @@
Accounts Settings,계정 설정,
Settings for Accounts,계정에 대한 설정,
Make Accounting Entry For Every Stock Movement,모든 재고 이동을위한 회계 항목을 만듭니다,
-"If enabled, the system will post accounting entries for inventory automatically.","활성화되면, 시스템이 자동으로 재고에 대한 회계 항목을 게시 할 예정입니다.",
-Accounts Frozen Upto,까지에게 동결계정,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","회계 항목이 날짜까지 동결, 아무도 / 아래 지정된 역할을 제외하고 항목을 수정하지 않을 수 있습니다.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,역할 동결 계정 및 편집 동결 항목을 설정할 수,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,이 역할이있는 사용자는 고정 된 계정에 대한 계정 항목을 수정 / 동결 계정을 설정하고 만들 수 있습니다,
Determine Address Tax Category From,주소 세금 카테고리 결정,
-Address used to determine Tax Category in transactions.,거래에서 세금 범주를 결정하는 데 사용되는 주소.,
Over Billing Allowance (%),청구 대금 지급 (%),
-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 for $110.,주문한 금액에 대해 더 많은 금액을 청구 할 수있는 비율. 예 : 주문 값이 항목에 대해 $ 100이고 공차가 10 %로 설정된 경우 110 달러를 청구 할 수 있습니다.,
Credit Controller,신용 컨트롤러,
-Role that is allowed to submit transactions that exceed credit limits set.,설정 신용 한도를 초과하는 거래를 제출하도록 허용 역할.,
Check Supplier Invoice Number Uniqueness,체크 공급 업체 송장 번호 특이 사항,
Make Payment via Journal Entry,분개를 통해 결제하기,
Unlink Payment on Cancellation of Invoice,송장의 취소에 지불 연결 해제,
-Unlink Advance Payment on Cancelation of Order,주문 취소시 사전 지불 연결 해제,
Book Asset Depreciation Entry Automatically,장부 자산 감가 상각 항목 자동 입력,
Automatically Add Taxes and Charges from Item Tax Template,항목 세금 템플릿에서 세금 및 요금 자동 추가,
Automatically Fetch Payment Terms,지불 조건 자동 가져 오기,
-Show Inclusive Tax In Print,인쇄시 포함 세금 표시,
Show Payment Schedule in Print,인쇄시 지불 일정 표시,
Currency Exchange Settings,통화 교환 설정,
Allow Stale Exchange Rates,부실 환율 허용,
Stale Days,부실한 날들,
Report Settings,보고서 설정,
Use Custom Cash Flow Format,맞춤형 현금 흐름 형식 사용,
-Only select if you have setup Cash Flow Mapper documents,현금 흐름 매퍼 문서를 설정 한 경우에만 선택하십시오.,
Allowed To Transact With,함께 처리 할 수있는 권한,
SWIFT number,빠른 번호,
Branch Code,지점 코드,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS 고객 그룹,
POS Field,POS 분야,
POS Item Group,POS 항목 그룹,
-[Select],[선택],
Company Address,회사 주소,
Update Stock,재고 업데이트,
Ignore Pricing Rule,가격 규칙을 무시,
@@ -5495,8 +5466,6 @@
Supplier Naming By,공급 업체 이름 지정으로,
Default Supplier Group,기본 공급 업체 그룹,
Default Buying Price List,기본 구매 가격 목록,
-Maintain same rate throughout purchase cycle,구매주기 동안 동일한 비율을 유지,
-Allow Item to be added multiple times in a transaction,항목은 트랜잭션에 여러 번 추가 할 수,
Backflush Raw Materials of Subcontract Based On,하청의 원자재 Backflush,
Material Transferred for Subcontract,외주로 이전 된 자재,
Over Transfer Allowance (%),초과 이체 수당 (%),
@@ -5540,7 +5509,6 @@
Current Stock,현재 재고,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,개별 업체에 대한,
-Supplier Detail,공급 업체 세부 정보,
Link to Material Requests,자재 요청 링크,
Message for Supplier,공급 업체에 대한 메시지,
Request for Quotation Item,견적 항목에 대한 요청,
@@ -6481,7 +6449,6 @@
Appraisal Template,평가 템플릿,
For Employee Name,직원 이름에,
Goals,목표,
-Calculate Total Score,총 점수를 계산,
Total Score (Out of 5),전체 점수 (5 점 만점),
"Any other remarks, noteworthy effort that should go in the records.","다른 발언, 기록에 가야한다 주목할만한 노력.",
Appraisal Goal,평가목표,
@@ -6599,11 +6566,6 @@
Reason for Leaving,떠나는 이유,
Leave Encashed?,Encashed 남겨?,
Encashment Date,현금화 날짜,
-Exit Interview Details,출구 인터뷰의 자세한 사항,
-Held On,개최,
-Reason for Resignation,사임 이유,
-Better Prospects,더 나은 전망,
-Health Concerns,건강 문제,
New Workplace,새로운 직장,
HR-EAD-.YYYY.-,HR-EAD- .YYYY.-,
Returned Amount,반품 금액,
@@ -6740,10 +6702,7 @@
Employee Settings,직원 설정,
Retirement Age,정년,
Enter retirement age in years,년에 은퇴 연령을 입력,
-Employee Records to be created by,직원 기록에 의해 생성되는,
-Employee record is created using selected field. ,,
Stop Birthday Reminders,정지 생일 알림,
-Don't send Employee Birthday Reminders,직원 생일 알림을 보내지 마십시오,
Expense Approver Mandatory In Expense Claim,경비 청구서에 필수적인 경비 승인자,
Payroll Settings,급여 설정,
Leave,떠나다,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,신청서를 제출할 때 승인자를 필수로 둡니다.,
Show Leaves Of All Department Members In Calendar,캘린더의 모든 부서 멤버의 잎 표시,
Auto Leave Encashment,자동 휴가 현금,
-Restrict Backdated Leave Application,퇴직 휴가 신청 제한,
Hiring Settings,채용 설정,
Check Vacancies On Job Offer Creation,구인 제안서 작성시 공석을 확인하십시오,
Identification Document Type,식별 문서 유형,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,제조 설정,
Raw Materials Consumption,원료 소비,
Allow Multiple Material Consumption,다중 자재 소비 허용,
-Allow multiple Material Consumption against a Work Order,작업 공정에 대해 여러 자재 소비 허용,
Backflush Raw Materials Based On,백 플러시 원료 기반에,
Material Transferred for Manufacture,재료 제조에 양도,
Capacity Planning,용량 계획,
Disable Capacity Planning,용량 계획 비활성화,
Allow Overtime,초과 근무 허용,
-Plan time logs outside Workstation Working Hours.,워크 스테이션 근무 시간 외에 시간 로그를 계획합니다.,
Allow Production on Holidays,휴일에 생산 허용,
Capacity Planning For (Days),(일)에 대한 용량 계획,
-Try planning operations for X days in advance.,사전에 X 일에 대한 작업을 계획 해보십시오.,
-Time Between Operations (in mins),(분에) 작업 사이의 시간,
-Default 10 mins,10 분을 기본,
Default Warehouses for Production,생산을위한 기본 창고,
Default Work In Progress Warehouse,진행웨어 하우스의 기본 작업,
Default Finished Goods Warehouse,기본 완제품 창고,
Default Scrap Warehouse,기본 스크랩 창고,
-Over Production for Sales and Work Order,판매 및 작업 오더에 대한 생산 초과,
Overproduction Percentage For Sales Order,판매 오더에 대한 과잉 생산 백분율,
Overproduction Percentage For Work Order,작업 주문에 대한 과잉 생산 백분율,
Other Settings,기타 설정,
Update BOM Cost Automatically,BOM 비용 자동 갱신,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",최신 평가 률 / 가격 목록 비율 / 원자재의 최종 구매 률을 기반으로 Scheduler를 통해 자동으로 BOM 비용을 업데이트합니다.,
Material Request Plan Item,자재 요청 계획 항목,
Material Request Type,자료 요청 유형,
Material Issue,소재 호,
@@ -7603,10 +7554,6 @@
Quality Goal,품질 목표,
Monitoring Frequency,모니터링 빈도,
Weekday,주일,
-January-April-July-October,1 월 -4 월 -7 월 -10 월,
-Revision and Revised On,개정 및 개정,
-Revision,개정,
-Revised On,개정일,
Objectives,목표,
Quality Goal Objective,품질 목표 목표,
Objective,목표,
@@ -7619,7 +7566,6 @@
Processes,프로세스,
Quality Procedure Process,품질 절차 과정,
Process Description,프로세스 설명,
-Child Procedure,아동 수속,
Link existing Quality Procedure.,기존 품질 절차 링크.,
Additional Information,추가 정보,
Quality Review Objective,품질 검토 목표,
@@ -7787,15 +7733,9 @@
Default Customer Group,기본 고객 그룹,
Default Territory,기본 지역,
Close Opportunity After Days,일 후 닫기 기회,
-Auto close Opportunity after 15 days,15 일이 경과되면 자동 가까운 기회,
Default Quotation Validity Days,기본 견적 유효 기간,
Sales Update Frequency,판매 갱신 빈도,
-How often should project and company be updated based on Sales Transactions.,판매 트랜잭션을 기준으로 프로젝트 및 회사를 얼마나 자주 업데이트해야합니까?,
Each Transaction,각 거래,
-Allow user to edit Price List Rate in transactions,사용자가 거래 가격리스트 평가를 편집 할 수,
-Allow multiple Sales Orders against a Customer's Purchase Order,고객의 구매 주문에 대해 여러 판매 주문 허용,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,구매 평가 또는 평가 평가에 대한 품목에 대한 판매 가격의 유효성을 검사합니다,
-Hide Customer's Tax Id from Sales Transactions,판매 거래에서 고객의 세금 아이디를 숨기기,
SMS Center,SMS 센터,
Send To,보내기,
All Contact,모든 연락처,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,항목에 사용 제조 업체,
Limited to 12 characters,12 자로 제한,
MAT-MR-.YYYY.-,매트 - MR - .YYYY.-,
-Set Warehouse,창고 설정,
-Sets 'For Warehouse' in each row of the Items table.,Items 테이블의 각 행에 'For Warehouse'를 설정합니다.,
-Requested For,에 대해 요청,
Partially Ordered,부분적으로 주문 됨,
Transferred,이전 됨,
% Ordered,% 발주,
@@ -8407,24 +8344,14 @@
Default Stock UOM,기본 재고 UOM,
Sample Retention Warehouse,샘플 보관 창고,
Default Valuation Method,기본 평가 방법,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,당신이 양에 대해 더 수신하거나 전달하도록 허용 비율 명령했다.예를 들면 : 당신이 100 대를 주문한 경우. 당신의 수당은 다음 110 단위를받을 10 % 허용된다.,
-Action if Quality inspection is not submitted,품질 검사가 제출되지 않은 경우의 조치,
Show Barcode Field,쇼 바코드 필드,
Convert Item Description to Clean HTML,항목 설명을 HTML로 변환,
-Auto insert Price List rate if missing,자동 삽입 가격표 속도없는 경우,
Allow Negative Stock,음의 재고 허용,
Automatically Set Serial Nos based on FIFO,자동으로 FIFO를 기반으로 제 직렬 설정,
-Set Qty in Transactions based on Serial No Input,일련 번호가없는 입력을 기준으로 트랜잭션의 수량 설정,
Auto Material Request,자동 자료 요청,
-Raise Material Request when stock reaches re-order level,재고가 다시 주문 수준에 도달 할 때 자료 요청을 올립니다,
-Notify by Email on creation of automatic Material Request,자동 자료 요청의 생성에 이메일로 통보,
Inter Warehouse Transfer Settings,창고 간 이전 설정,
-Allow Material Transfer From Delivery Note and Sales Invoice,납품서 및 판매 송장에서 자재 이전 허용,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,구매 영수증 및 구매 송장에서 자재 이전 허용,
Freeze Stock Entries,동결 재고 항목,
Stock Frozen Upto,재고 동결 개까지,
-Freeze Stocks Older Than [Days],고정 재고 이전보다 [일],
-Role Allowed to edit frozen stock,동결 재고을 편집 할 수 있는 역할,
Batch Identification,배치 식별,
Use Naming Series,이름 지정 시리즈 사용,
Naming Series Prefix,네이밍 시리즈 접두사,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,구매 영수증 동향,
Purchase Register,회원에게 구매,
Quotation Trends,견적 동향,
-Quoted Item Comparison,인용 상품 비교,
Received Items To Be Billed,청구에 주어진 항목,
Qty to Order,수량은 주문,
Requested Items To Be Transferred,전송할 요청 항목,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,자재 요청을위한 창고 선택,
Transfer Materials For Warehouse {0},창고 {0}의 자재 전송,
Production Plan Material Request Warehouse,생산 계획 자재 요청 창고,
-Set From Warehouse,창고에서 설정,
-Source Warehouse (Material Transfer),출처 창고 (자재 이전),
Sets 'Source Warehouse' in each row of the items table.,항목 테이블의 각 행에 '소스 창고'를 설정합니다.,
Sets 'Target Warehouse' in each row of the items table.,항목 테이블의 각 행에 '대상 창고'를 설정합니다.,
Show Cancelled Entries,취소 된 항목 표시,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,서비스를 받았지만 청구되지 않음,
Deferred Accounting Settings,이연 회계 설정,
Book Deferred Entries Based On,다음을 기준으로 지연된 항목 예약,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","월"을 선택하면 한 달의 일수에 관계없이 매월 고정 된 금액이 이연 수익 또는 비용으로 기장됩니다. 이연 된 수익 또는 비용이 한 달 동안 예약되지 않은 경우 일할 계산됩니다.,
Days,일,
Months,개월,
Book Deferred Entries Via Journal Entry,분개를 통해 지연된 항목 예약,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,선택하지 않으면 직접 GL 입력 사항이 생성되어 이연 수익 / 비용을 기장합니다.,
Submit Journal Entries,분개 제출,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,선택하지 않으면 분개가 초안 상태로 저장되며 수동으로 제출해야합니다.,
Enable Distributed Cost Center,분산 비용 센터 활성화,
@@ -8901,8 +8823,6 @@
Is Inter State,Inter State,
Purchase Details,구매 내역,
Depreciation Posting Date,감가 상각 전기 일,
-Purchase Order Required for Purchase Invoice & Receipt Creation,구매 송장 및 영수증 생성에 필요한 구매 오더,
-Purchase Receipt Required for Purchase Invoice Creation,구매 송장 생성에 필요한 구매 영수증,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ",기본적으로 공급 업체 이름은 입력 한 공급 업체 이름에 따라 설정됩니다. 공급 업체의 이름을,
choose the 'Naming Series' option.,'이름 지정 시리즈'옵션을 선택합니다.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,새 구매 트랜잭션을 생성 할 때 기본 가격 목록을 구성합니다. 이 가격 목록에서 항목 가격을 가져옵니다.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,소득세 구성 요소,
Component properties and references ,구성 요소 속성 및 참조,
Additional Salary ,추가 급여,
-Condtion and formula,조건 및 공식,
Unmarked days,표시되지 않은 날짜,
Absent Days,결석 일,
Conditions and Formula variable and example,조건 및 수식 변수 및 예,
Feedback By,피드백,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,제조 섹션,
-Sales Order Required for Sales Invoice & Delivery Note Creation,판매 송장 및 납품서 생성에 필요한 판매 오더,
-Delivery Note Required for Sales Invoice Creation,판매 송장 생성에 필요한 납품서,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",기본적으로 고객 이름은 입력 한 전체 이름에 따라 설정됩니다. 고객의 이름을,
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,새 판매 트랜잭션을 생성 할 때 기본 가격 목록을 구성합니다. 이 가격 목록에서 항목 가격을 가져옵니다.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.",이 옵션이 '예'로 구성된 경우 ERPNext는 먼저 판매 주문을 생성하지 않고는 판매 송장 또는 배송 노트를 생성하지 못하도록합니다. 이 구성은 고객 마스터에서 '판매 주문없이 판매 송장 생성 허용'확인란을 활성화하여 특정 고객에 대해 재정의 할 수 있습니다.,
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1}이 (가) 선택한 모든 주제에 성공적으로 추가되었습니다.,
Topics updated,주제가 업데이트되었습니다.,
Academic Term and Program,학기 및 프로그램,
-Last Stock Transaction for item {0} was on {1}.,{0} 항목에 대한 마지막 주식 거래가 {1}에있었습니다.,
-Stock Transactions for Item {0} cannot be posted before this time.,이 시간 이전에는 항목 {0}에 대한 주식 거래를 게시 할 수 없습니다.,
Please remove this item and try to submit again or update the posting time.,이 항목을 제거하고 다시 제출하거나 게시 시간을 업데이트하십시오.,
Failed to Authenticate the API key.,API 키를 인증하지 못했습니다.,
Invalid Credentials,잘못된 자격 증명,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Plaid 클라이언트 ID와 비밀 값을 확인하세요.,
Bank transaction creation error,은행 거래 생성 오류,
Unit of Measurement,측정 단위,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},행 # {} : 항목 {}의 판매율이 {}보다 낮습니다. 판매율은 {} 이상이어야합니다.,
Fiscal Year {0} Does Not Exist,회계 연도 {0}이 (가) 존재하지 않음,
Row # {0}: Returned Item {1} does not exist in {2} {3},행 # {0} : 반품 된 항목 {1}이 {2} {3}에 없습니다.,
Valuation type charges can not be marked as Inclusive,평가 유형 요금은 포함으로 표시 할 수 없습니다.,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,{1} 행의 {0} 우선 순위에 대한 응답 시간은 해결 시간보다 클 수 없습니다.,
{0} is not enabled in {1},{0}은 (는) {1}에서 사용할 수 없습니다.,
Group by Material Request,자재 요청별로 그룹화,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",{0} 행 : 공급 업체 {0}의 경우 이메일을 보내려면 이메일 주소가 필요합니다.,
Email Sent to Supplier {0},공급 업체 {0}에 이메일을 보냈습니다.,
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.",포털에서 견적 요청에 대한 액세스가 비활성화되었습니다. 액세스를 허용하려면 포털 설정에서 활성화하십시오.,
Supplier Quotation {0} Created,공급 업체 견적 {0} 생성됨,
Valid till Date cannot be before Transaction Date,유효 종료 날짜는 거래 날짜 이전 일 수 없습니다.,
+Unlink Advance Payment on Cancellation of Order,주문 취소시 선지급 연결 해제,
+"Simple Python Expression, Example: territory != 'All Territories'","간단한 Python 표현식, 예 : 지역! = '모든 지역'",
+Sales Contributions and Incentives,판매 기여 및 인센티브,
+Sourced by Supplier,공급자에 의해 공급,
+Total weightage assigned should be 100%.<br>It is {0},할당 된 총 가중치는 100 % 여야합니다.<br> {0}입니다,
+Account {0} exists in parent company {1}.,{0} 계정이 모회사 {1}에 있습니다.,
+"To overrule this, enable '{0}' in company {1}",이를 무시하려면 {1} 회사에서 '{0}'을 (를) 활성화하십시오.,
+Invalid condition expression,잘못된 조건식,
+Please Select a Company First,먼저 회사를 선택하십시오,
+Please Select Both Company and Party Type First,먼저 회사 및 당사자 유형을 모두 선택하십시오.,
+Provide the invoice portion in percent,송장 부분을 백분율로 제공,
+Give number of days according to prior selection,사전 선택에 따라 일수 제공,
+Email Details,이메일 세부 정보,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","수신자를위한 인사말을 선택하십시오. 예 : Mr., Ms. 등",
+Preview Email,이메일 미리보기,
+Please select a Supplier,공급자를 선택하십시오,
+Supplier Lead Time (days),공급 업체 리드 타임 (일),
+"Home, Work, etc.","집, 직장 등",
+Exit Interview Held On,보류 된 인터뷰 종료,
+Condition and formula,조건 및 공식,
+Sets 'Target Warehouse' in each row of the Items table.,Items 테이블의 각 행에 'Target Warehouse'를 설정합니다.,
+Sets 'Source Warehouse' in each row of the Items table.,Items 테이블의 각 행에 'Source Warehouse'를 설정합니다.,
+POS Register,POS 등록,
+"Can not filter based on POS Profile, if grouped by POS Profile",POS 프로필로 그룹화 된 경우 POS 프로필을 기준으로 필터링 할 수 없습니다.,
+"Can not filter based on Customer, if grouped by Customer",고객별로 그룹화 된 경우 고객을 기준으로 필터링 할 수 없습니다.,
+"Can not filter based on Cashier, if grouped by Cashier",계산원별로 그룹화 된 경우 계산원을 기준으로 필터링 할 수 없습니다.,
+Payment Method,결제 방법,
+"Can not filter based on Payment Method, if grouped by Payment Method",결제 수단별로 그룹화 한 경우 결제 수단을 기준으로 필터링 할 수 없습니다.,
+Supplier Quotation Comparison,공급 업체 견적 비교,
+Price per Unit (Stock UOM),단가 (재고 UOM),
+Group by Supplier,공급 업체별 그룹화,
+Group by Item,항목 별 그룹화,
+Remember to set {field_label}. It is required by {regulation}.,{field_label}을 설정해야합니다. {regulation}에서 요구합니다.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},등록일은 학년도 {0}의 시작일 이전 일 수 없습니다.,
+Enrollment Date cannot be after the End Date of the Academic Term {0},등록일은 학기 종료일 {0} 이후 일 수 없습니다.,
+Enrollment Date cannot be before the Start Date of the Academic Term {0},등록일은 학기 시작일 {0} 이전 일 수 없습니다.,
+Future Posting Not Allowed,향후 전기가 허용되지 않음,
+"To enable Capital Work in Progress Accounting, ",자본 재공품 회계를 활성화하려면,
+you must select Capital Work in Progress Account in accounts table,계정 테이블에서 자본 진행중인 계정을 선택해야합니다.,
+You can also set default CWIP account in Company {},회사 {}에서 기본 CWIP 계정을 설정할 수도 있습니다.,
+The Request for Quotation can be accessed by clicking on the following button,견적 요청은 다음 버튼을 클릭하여 액세스 할 수 있습니다.,
+Regards,문안 인사,
+Please click on the following button to set your new password,새 비밀번호를 설정하려면 다음 버튼을 클릭하십시오.,
+Update Password,비밀번호 업데이트,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},행 # {} : 항목 {}의 판매율이 {}보다 낮습니다. {} 판매는 {} 이상이어야합니다.,
+You can alternatively disable selling price validation in {} to bypass this validation.,또는 {}에서 판매 가격 검증을 비활성화하여이 검증을 우회 할 수 있습니다.,
+Invalid Selling Price,잘못된 판매 가격,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,주소는 회사에 연결되어야합니다. 링크 테이블에 회사 행을 추가하십시오.,
+Company Not Linked,연결되지 않은 회사,
+Import Chart of Accounts from CSV / Excel files,CSV / Excel 파일에서 계정과 목표 가져 오기,
+Completed Qty cannot be greater than 'Qty to Manufacture',완료된 수량은 '제조 수량'보다 클 수 없습니다.,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",{0} 행 : 공급 업체 {1}의 경우 이메일을 보내려면 이메일 주소가 필요합니다.,
+"If enabled, the system will post accounting entries for inventory automatically",활성화 된 경우 시스템은 재고에 대한 회계 항목을 자동으로 전기합니다.,
+Accounts Frozen Till Date,계정 동결 일까지,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,회계 항목은이 날짜까지 동결됩니다. 아래에 지정된 역할을 가진 사용자를 제외하고는 아무도 항목을 만들거나 수정할 수 없습니다.,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,고정 계정을 설정하고 고정 된 항목을 편집 할 수있는 역할,
+Address used to determine Tax Category in transactions,거래에서 세금 범주를 결정하는 데 사용되는 주소,
+"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 ",주문한 금액에 대해 더 많이 청구 할 수있는 비율입니다. 예를 들어 주문 금액이 품목에 대해 $ 100이고 허용 한도가 10 %로 설정된 경우 최대 $ 110까지 청구 할 수 있습니다.,
+This role is allowed to submit transactions that exceed credit limits,이 역할은 신용 한도를 초과하는 거래를 제출할 수 있습니다.,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","월"을 선택하면 한 달의 일수에 관계없이 고정 된 금액이 매월 이연 수익 또는 비용으로 기장됩니다. 이연 된 수익 또는 비용이 한 달 동안 예약되지 않은 경우 일할 계산됩니다.,
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense",선택하지 않으면 이연 수익 또는 비용을 기장하기 위해 직접 GL 입력 사항이 생성됩니다.,
+Show Inclusive Tax in Print,인쇄물에 포함 세금 표시,
+Only select this if you have set up the Cash Flow Mapper documents,Cash Flow Mapper 문서를 설정 한 경우에만 선택하십시오.,
+Payment Channel,결제 채널,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,구매 송장 및 영수증 생성에 구매 주문이 필요합니까?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,구매 송장 생성시 구매 영수증이 필요합니까?,
+Maintain Same Rate Throughout the Purchase Cycle,구매주기 동안 동일한 요율 유지,
+Allow Item To Be Added Multiple Times in a Transaction,트랜잭션에서 항목이 여러 번 추가되도록 허용,
+Suppliers,공급자,
+Send Emails to Suppliers,공급 업체에 이메일 보내기,
+Select a Supplier,공급 업체 선택,
+Cannot mark attendance for future dates.,향후 날짜에 대한 출석을 표시 할 수 없습니다.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},출석을 업데이트 하시겠습니까?<br> 현재 : {0}<br> 결석 : {1},
+Mpesa Settings,Mpesa 설정,
+Initiator Name,이니시에이터 이름,
+Till Number,번호까지,
+Sandbox,모래 상자,
+ Online PassKey,온라인 패스 키,
+Security Credential,보안 자격 증명,
+Get Account Balance,계정 잔액 얻기,
+Please set the initiator name and the security credential,이니시에이터 이름과 보안 자격 증명을 설정하십시오.,
+Inpatient Medication Entry,입원 환자 투약 항목,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),품목 코드 (약품),
+Medication Orders,약물 주문,
+Get Pending Medication Orders,보류중인 약물 주문 받기,
+Inpatient Medication Orders,입원 환자 약물 주문,
+Medication Warehouse,약물 창고,
+Warehouse from where medication stock should be consumed,의약품 재고를 소비해야하는 창고,
+Fetching Pending Medication Orders,보류중인 약물 주문을 가져 오는 중,
+Inpatient Medication Entry Detail,입원 환자 투약 항목 세부 정보,
+Medication Details,약물 세부 사항,
+Drug Code,약물 코드,
+Drug Name,약물 이름,
+Against Inpatient Medication Order,입원 환자 투약 명령 반대,
+Against Inpatient Medication Order Entry,입원 환자 약물 주문 입력 반대,
+Inpatient Medication Order,입원 환자 약물 주문,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,총 주문,
+Completed Orders,완료된 주문,
+Add Medication Orders,약물 주문 추가,
+Adding Order Entries,주문 항목 추가,
+{0} medication orders completed,{0} 약물 주문 완료,
+{0} medication order completed,{0} 약물 주문 완료,
+Inpatient Medication Order Entry,입원 환자 약물 주문 입력,
+Is Order Completed,주문 완료,
+Employee Records to Be Created By,생성 할 직원 레코드,
+Employee records are created using the selected field,선택한 필드를 사용하여 직원 레코드가 생성됩니다.,
+Don't send employee birthday reminders,직원 생일 알림을 보내지 마십시오.,
+Restrict Backdated Leave Applications,기한이 지난 휴가 신청 제한,
+Sequence ID,시퀀스 ID,
+Sequence Id,시퀀스 ID,
+Allow multiple material consumptions against a Work Order,작업 주문에 대해 여러 재료 소비 허용,
+Plan time logs outside Workstation working hours,Workstation 근무 시간 이외의 시간 로그 계획,
+Plan operations X days in advance,X 일 전에 운영 계획,
+Time Between Operations (Mins),작업 간격 (분),
+Default: 10 mins,기본값 : 10 분,
+Overproduction for Sales and Work Order,판매 및 작업 주문에 대한 과잉 생산,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials",최신 평가 비율 / 가격 목록 비율 / 원료의 마지막 구매 비율을 기반으로 스케줄러를 통해 BOM 비용을 자동으로 업데이트합니다.,
+Purchase Order already created for all Sales Order items,모든 판매 주문 항목에 대해 이미 생성 된 구매 주문,
+Select Items,항목 선택,
+Against Default Supplier,기본 공급자에 대해,
+Auto close Opportunity after the no. of days mentioned above,아니오 이후 자동 닫기 기회. 위에 언급 된 일수,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,판매 송장 및 납품서 작성에 판매 주문이 필요합니까?,
+Is Delivery Note Required for Sales Invoice Creation?,판매 송장 생성에 납품서가 필요합니까?,
+How often should Project and Company be updated based on Sales Transactions?,판매 거래를 기반으로 프로젝트 및 회사를 얼마나 자주 업데이트해야합니까?,
+Allow User to Edit Price List Rate in Transactions,사용자가 거래에서 가격 목록 비율을 편집하도록 허용,
+Allow Item to Be Added Multiple Times in a Transaction,트랜잭션에서 항목이 여러 번 추가되도록 허용,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,고객의 구매 주문에 대해 여러 판매 주문 허용,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,구매율 또는 평가율에 대한 품목의 판매 가격 검증,
+Hide Customer's Tax ID from Sales Transactions,판매 거래에서 고객의 세금 ID 숨기기,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","주문 수량에 대해 더 많이 받거나 배달 할 수있는 비율입니다. 예를 들어, 100 개를 주문했고 허용량이 10 %이면 110 개를받을 수 있습니다.",
+Action If Quality Inspection Is Not Submitted,품질 검사가 제출되지 않은 경우 조치,
+Auto Insert Price List Rate If Missing,누락 된 경우 가격 목록 비율 자동 삽입,
+Automatically Set Serial Nos Based on FIFO,FIFO를 기반으로 일련 번호 자동 설정,
+Set Qty in Transactions Based on Serial No Input,일련 번호 입력 없음을 기준으로 거래 수량 설정,
+Raise Material Request When Stock Reaches Re-order Level,재고가 재주문 레벨에 도달하면 자재 요청 제기,
+Notify by Email on Creation of Automatic Material Request,자동 자재 요청 생성시 이메일로 알림,
+Allow Material Transfer from Delivery Note to Sales Invoice,납품서에서 판매 송장으로 자재 이전 허용,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,구매 영수증에서 구매 송장으로 자재 이전 허용,
+Freeze Stocks Older Than (Days),(일)보다 오래된 주식 동결,
+Role Allowed to Edit Frozen Stock,고정 재고를 편집 할 수있는 역할,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,할당되지 않은 결제 항목 {0} 금액이 은행 거래의 할당되지 않은 금액보다 큽니다.,
+Payment Received,지불 수신,
+Attendance cannot be marked outside of Academic Year {0},Academic Year {0} 이외의 출석은 표시 할 수 없습니다.,
+Student is already enrolled via Course Enrollment {0},학생은 이미 과정 등록 {0}을 통해 등록되었습니다.,
+Attendance cannot be marked for future dates.,출석은 미래 날짜로 표시 할 수 없습니다.,
+Please add programs to enable admission application.,입학 신청을 할 수있는 프로그램을 추가하십시오.,
+The following employees are currently still reporting to {0}:,다음 직원은 현재 {0}에 계속보고합니다.,
+Please make sure the employees above report to another Active employee.,위의 직원이 다른 활성 직원에게보고하도록하십시오.,
+Cannot Relieve Employee,직원을 구제 할 수 없습니다,
+Please enter {0},{0}을 (를) 입력하십시오,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',다른 결제 방법을 선택하십시오. Mpesa는 '{0}'통화로 거래를 지원하지 않습니다.,
+Transaction Error,거래 오류,
+Mpesa Express Transaction Error,Mpesa Express 거래 오류,
+"Issue detected with Mpesa configuration, check the error logs for more details",Mpesa 구성에서 문제가 감지되었습니다. 자세한 내용은 오류 로그를 확인하십시오.,
+Mpesa Express Error,Mpesa Express 오류,
+Account Balance Processing Error,계정 잔액 처리 오류,
+Please check your configuration and try again,구성을 확인하고 다시 시도하십시오.,
+Mpesa Account Balance Processing Error,Mpesa 계정 잔액 처리 오류,
+Balance Details,잔액 세부 정보,
+Current Balance,현재의 균형,
+Available Balance,사용 가능한 잔액,
+Reserved Balance,예약 잔액,
+Uncleared Balance,미 정산 잔액,
+Payment related to {0} is not completed,{0} 관련 결제가 완료되지 않았습니다.,
+Row #{}: Item Code: {} is not available under warehouse {}.,행 # {} : 품목 코드 : {}은 창고 {}에서 사용할 수 없습니다.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,행 # {} : 창고 {} 아래의 품목 코드 : {}에 대한 재고 수량이 충분하지 않습니다. 사용 가능한 수량 {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,행 # {} : 품목 {}에 대해 일련 번호 및 배치를 선택하거나 제거하여 트랜잭션을 완료하십시오.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,행 # {} : 항목 : {}에 대해 선택된 일련 번호가 없습니다. 거래를 완료하려면 하나를 선택하거나 삭제하세요.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,행 # {} : {} 항목에 대해 선택된 배치가 없습니다. 거래를 완료하려면 배치를 선택하거나 제거하십시오.,
+Payment amount cannot be less than or equal to 0,결제 금액은 0보다 작거나 같을 수 없습니다.,
+Please enter the phone number first,먼저 전화 번호를 입력하세요,
+Row #{}: {} {} does not exist.,행 # {} : {} {}이 (가) 없습니다.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,{0} 행 : {1}은 (는) 개시 {2} 인보이스를 작성하는 데 필요합니다.,
+You had {} errors while creating opening invoices. Check {} for more details,개시 인보이스를 만드는 동안 {} 오류가 발생했습니다. 자세한 내용은 {}을 확인하십시오.,
+Error Occured,오류가 발생했습니다,
+Opening Invoice Creation In Progress,개시 송장 생성 진행 중,
+Creating {} out of {} {},{} {} 중 {} 생성,
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(일련 번호 : {0})은 (는) 판매 주문 {1}을 (를) 채우기 위해 예약되어 있으므로 사용할 수 없습니다.,
+Item {0} {1},항목 {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,{1} 창고 아래의 {0} 품목에 대한 마지막 재고 거래가 {2}에있었습니다.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,{1} 창고에있는 {0} 항목에 대한 재고 거래는이 시간 전에 전기 할 수 없습니다.,
+Posting future stock transactions are not allowed due to Immutable Ledger,불변 원장으로 인해 미래 주식 거래를 전기 할 수 없습니다.,
+A BOM with name {0} already exists for item {1}.,{1} 항목에 대해 이름이 {0} 인 BOM이 이미 있습니다.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} 항목 이름을 변경 했습니까? 관리자 / 기술 지원에 문의하십시오.,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},행 # {0} : 시퀀스 ID {1}은 (는) 이전 행 시퀀스 ID {2}보다 작을 수 없습니다.,
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1})은 {2} ({3})와 같아야합니다.,
+"{0}, complete the operation {1} before the operation {2}.","{0}, {2} 작업 전에 {1} 작업을 완료하십시오.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,품목 {0}이 (가) 일련 번호로 납품 보장을 포함하거나 포함하지 않고 추가되었으므로 일련 번호로 납품을 보장 할 수 없습니다.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,{0} 항목에 일련 번호가 없습니다. 일련 번호가 지정된 항목 만 일련 번호를 기준으로 배송 할 수 있습니다.,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,{0} 항목에 대한 활성 BOM이 없습니다. 일련 번호에 의한 배송을 보장 할 수 없습니다.,
+No pending medication orders found for selected criteria,선택한 기준에 대한 보류중인 약물 주문이 없습니다.,
+From Date cannot be after the current date.,시작 날짜는 현재 날짜 이후 일 수 없습니다.,
+To Date cannot be after the current date.,종료 날짜는 현재 날짜 이후 일 수 없습니다.,
+From Time cannot be after the current time.,시작 시간은 현재 시간 이후 일 수 없습니다.,
+To Time cannot be after the current time.,To Time은 현재 시간 이후 일 수 없습니다.,
+Stock Entry {0} created and ,주식 항목 {0} 생성 및,
+Inpatient Medication Orders updated successfully,입원 환자 약물 주문이 성공적으로 업데이트되었습니다.,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},행 {0} : 취소 된 입원 환자 약물 주문 {1}에 대해 입원 환자 약물 항목을 만들 수 없습니다.,
+Row {0}: This Medication Order is already marked as completed,{0} 행 :이 약물 주문은 이미 완료된 것으로 표시되었습니다.,
+Quantity not available for {0} in warehouse {1},{1} 창고에서 {0}에 대해 사용할 수없는 수량,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,계속하려면 재고 설정에서 음수 재고 허용을 활성화하거나 재고 항목을 생성하십시오.,
+No Inpatient Record found against patient {0},{0} 환자에 대한 입원 기록이 없습니다.,
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,환자 만남 {1}에 대한 입원 환자 약물 명령 {0}이 (가) 이미 존재합니다.,
+Allow In Returns,반품 허용,
+Hide Unavailable Items,사용할 수없는 항목 숨기기,
+Apply Discount on Discounted Rate,할인 요금에 할인 적용,
+Therapy Plan Template,치료 계획 템플릿,
+Fetching Template Details,템플릿 세부 정보 가져 오기,
+Linked Item Details,링크 된 항목 세부 정보,
+Therapy Types,치료 유형,
+Therapy Plan Template Detail,치료 계획 템플릿 세부 정보,
+Non Conformance,부적합,
+Process Owner,프로세스 소유자,
+Corrective Action,시정 조치,
+Preventive Action,예방 조치,
+Problem,문제,
+Responsible,책임감,
+Completion By,완료 자,
+Process Owner Full Name,프로세스 소유자 전체 이름,
+Right Index,오른쪽 색인,
+Left Index,왼쪽 색인,
+Sub Procedure,하위 절차,
+Passed,합격,
+Print Receipt,영수증 인쇄,
+Edit Receipt,영수증 편집,
+Focus on search input,검색 입력에 집중,
+Focus on Item Group filter,항목 그룹 필터에 집중,
+Checkout Order / Submit Order / New Order,주문 확인 / 주문 제출 / 새 주문,
+Add Order Discount,주문 할인 추가,
+Item Code: {0} is not available under warehouse {1}.,상품 코드 : {0}은 (는) {1} 창고에서 사용할 수 없습니다.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,{1} 창고에있는 {0} 항목에 대해 일련 번호를 사용할 수 없습니다. 창고 변경을 시도하십시오.,
+Fetched only {0} available serial numbers.,{0} 개의 사용 가능한 일련 번호 만 가져 왔습니다.,
+Switch Between Payment Modes,결제 모드 간 전환,
+Enter {0} amount.,{0} 금액을 입력하세요.,
+You don't have enough points to redeem.,사용할 포인트가 충분하지 않습니다.,
+You can redeem upto {0}.,최대 {0}까지 사용할 수 있습니다.,
+Enter amount to be redeemed.,사용할 금액을 입력하세요.,
+You cannot redeem more than {0}.,{0} 이상 사용할 수 없습니다.,
+Open Form View,양식보기 열기,
+POS invoice {0} created succesfully,POS 인보이스 {0}이 (가) 성공적으로 생성되었습니다.,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,항목 코드에 대한 재고 수량이 충분하지 않습니다. {0} 창고 아래 {1}. 사용 가능한 수량 {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,일련 번호 : {0}은 (는) 이미 다른 POS 인보이스로 거래되었습니다.,
+Balance Serial No,잔액 일련 번호,
+Warehouse: {0} does not belong to {1},창고 : {0}은 (는) {1}에 속하지 않습니다.,
+Please select batches for batched item {0},일괄 항목 {0}에 대한 일괄을 선택하십시오.,
+Please select quantity on row {0},{0} 행에서 수량을 선택하십시오.,
+Please enter serial numbers for serialized item {0},일련 번호가있는 항목 {0}의 일련 번호를 입력하십시오.,
+Batch {0} already selected.,일괄 {0}이 (가) 이미 선택되었습니다.,
+Please select a warehouse to get available quantities,사용 가능한 수량을 확인하려면 창고를 선택하십시오.,
+"For transfer from source, selected quantity cannot be greater than available quantity",출처에서 이전하는 경우 선택한 수량이 가용 수량보다 클 수 없습니다.,
+Cannot find Item with this Barcode,이 바코드로 항목을 찾을 수 없습니다,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0}은 (는) 필수입니다. {1}에서 {2}까지의 환전 기록이 생성되지 않았을 수 있습니다.,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{}이 (가) 연결된 자산을 제출했습니다. 구매 반품을 생성하려면 자산을 취소해야합니다.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,이 문서는 제출 된 자산 {0}에 연결되어 있으므로 취소 할 수 없습니다. 계속하려면 취소하세요.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,행 # {} : 일련 번호 {}이 이미 다른 POS 송장으로 거래되었습니다. 유효한 일련 번호를 선택하십시오.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,행 # {} : 일련 번호 {}이 이미 다른 POS 송장으로 거래되었습니다. 유효한 일련 번호를 선택하십시오.,
+Item Unavailable,사용할 수없는 항목,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},행 # {} : 일련 번호 {}이 원래 송장 {}에서 거래되지 않았으므로 반환 할 수 없습니다.,
+Please set default Cash or Bank account in Mode of Payment {},결제 모드에서 기본 현금 또는 은행 계좌를 설정하세요. {},
+Please set default Cash or Bank account in Mode of Payments {},결제 모드에서 기본 현금 또는 은행 계좌를 설정하십시오 {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,{} 계정이 대차 대조표 계정인지 확인하십시오. 상위 계정을 대차 대조표 계정으로 변경하거나 다른 계정을 선택할 수 있습니다.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,{} 계정이 Payable 계정인지 확인하십시오. 계정 유형을 Payable로 변경하거나 다른 계정을 선택하십시오.,
+Row {}: Expense Head changed to {} ,{} 행 : 비용 헤드가 {} (으)로 변경되었습니다.,
+because account {} is not linked to warehouse {} ,{} 계정이 {} 창고에 연결되어 있지 않기 때문입니다.,
+or it is not the default inventory account,또는 기본 인벤토리 계정이 아닙니다.,
+Expense Head Changed,비용 헤드 변경됨,
+because expense is booked against this account in Purchase Receipt {},구매 영수증 {}에서이 계정에 대한 비용이 기장 되었기 때문입니다.,
+as no Purchase Receipt is created against Item {}. ,항목 {}에 대해 구매 영수증이 생성되지 않았기 때문입니다.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,구매 인보이스 후 구매 영수증이 생성되는 경우에 대한 회계 처리를 위해 수행됩니다.,
+Purchase Order Required for item {},{} 항목에 대한 구매 주문 필요,
+To submit the invoice without purchase order please set {} ,구매 주문없이 인보이스를 제출하려면 {}을 (를) 설정하십시오.,
+as {} in {},{}에서 {}로,
+Mandatory Purchase Order,필수 구매 오더,
+Purchase Receipt Required for item {},{} 항목에 대한 구매 영수증 필요,
+To submit the invoice without purchase receipt please set {} ,구매 영수증없이 인보이스를 제출하려면 {}를 설정하세요.,
+Mandatory Purchase Receipt,필수 구매 영수증,
+POS Profile {} does not belongs to company {},POS 프로필 {}은 (는) 회사 {}에 속하지 않습니다.,
+User {} is disabled. Please select valid user/cashier,{} 사용자가 비활성화되었습니다. 유효한 사용자 / 직원을 선택하십시오,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,행 # {} : 반품 인보이스 {}의 원래 인보이스 {}은 {}입니다.,
+Original invoice should be consolidated before or along with the return invoice.,원래 인보이스는 반품 인보이스와 함께 통합되어야합니다.,
+You can add original invoice {} manually to proceed.,계속하려면 원본 인보이스 {}를 수동으로 추가 할 수 있습니다.,
+Please ensure {} account is a Balance Sheet account. ,{} 계정이 대차 대조표 계정인지 확인하십시오.,
+You can change the parent account to a Balance Sheet account or select a different account.,상위 계정을 대차 대조표 계정으로 변경하거나 다른 계정을 선택할 수 있습니다.,
+Please ensure {} account is a Receivable account. ,{} 계정이 미수금 계정인지 확인하십시오.,
+Change the account type to Receivable or select a different account.,계정 유형을 Receivable로 변경하거나 다른 계정을 선택합니다.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},적립 된 로열티 포인트가 사용되었으므로 {}을 취소 할 수 없습니다. 먼저 {} 아니요 {} 취소,
+already exists,이미 존재 함,
+POS Closing Entry {} against {} between selected period,선택한 기간 사이에 {}에 대한 POS 마감 항목 {},
+POS Invoice is {},POS 송장은 {}입니다.,
+POS Profile doesn't matches {},POS 프로필이 {}과 (와) 일치하지 않습니다.,
+POS Invoice is not {},POS 송장이 {}이 아닙니다.,
+POS Invoice isn't created by user {},{} 사용자가 POS 인보이스를 생성하지 않았습니다.,
+Row #{}: {},행 # {} : {},
+Invalid POS Invoices,잘못된 POS 송장,
+Please add the account to root level Company - {},루트 수준 회사에 계정을 추가하십시오-{},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA",하위 회사 {0}에 대한 계정을 만드는 동안 상위 계정 {1}을 (를) 찾을 수 없습니다. 해당 COA에서 상위 계정을 만드십시오.,
+Account Not Found,계정을 찾지 못했습니다,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.",하위 회사 {0}에 대한 계정을 만드는 동안 상위 계정 {1}이 (가) 원장 계정으로 발견되었습니다.,
+Please convert the parent account in corresponding child company to a group account.,해당 하위 회사의 상위 계정을 그룹 계정으로 전환하십시오.,
+Invalid Parent Account,잘못된 부모 계정,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.",이름 변경은 불일치를 방지하기 위해 모회사 {0}를 통해서만 허용됩니다.,
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.",{0} 항목 {1} 수량 {2} 인 경우 {3} 체계가 항목에 적용됩니다.,
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.",항목 {2}에 대해 {0} {1} 가치가있는 경우 {3} 체계가 항목에 적용됩니다.,
+"As the field {0} is enabled, the field {1} is mandatory.",{0} 필드가 사용 가능하므로 {1} 필드는 필수입니다.,
+"As the field {0} is enabled, the value of the field {1} should be more than 1.",{0} 필드가 사용 가능하므로 {1} 필드의 값은 1보다 커야합니다.,
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},판매 주문 {2}을 (를) 채우기 위해 예약되어 있으므로 {1} 항목의 일련 번호 {0}을 (를) 배송 할 수 없습니다.,
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",판매 주문 {0}에 {1} 항목에 대한 예약이 있습니다. {0}에 대해 예약 된 {1} 만 배송 할 수 있습니다.,
+{0} Serial No {1} cannot be delivered,{0} 일련 번호 {1}을 (를) 배송 할 수 없습니다.,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},행 {0} : 원자재 {1}에 대한 외주 품목은 필수입니다.,
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.",충분한 원자재가 있으므로 창고 {0}에 대한 자재 요청이 필요하지 않습니다.,
+" If you still want to proceed, please enable {0}.",계속하려면 {0}을 (를) 활성화하십시오.,
+The item referenced by {0} - {1} is already invoiced,{0}-{1}에서 참조하는 항목은 이미 인보이스가 발행되었습니다.,
+Therapy Session overlaps with {0},치료 세션이 {0}와 (과) 겹칩니다.,
+Therapy Sessions Overlapping,겹치는 치료 세션,
+Therapy Plans,치료 계획,
+"Item Code, warehouse, quantity are required on row {0}","{0} 행에 품목 코드, 창고, 수량이 필요합니다.",
+Get Items from Material Requests against this Supplier,이 공급자에 대한 자재 요청에서 품목 가져 오기,
+Enable European Access,유럽 액세스 활성화,
+Creating Purchase Order ...,구매 오더 생성 ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.",아래 항목의 기본 공급자에서 공급자를 선택합니다. 선택시 선택한 공급 업체에 속한 품목에 대해서만 구매 주문이 작성됩니다.,
+Row #{}: You must select {} serial numbers for item {}.,행 # {} : 항목 {}에 대해 {} 일련 번호를 선택해야합니다.,
diff --git a/erpnext/translations/ku.csv b/erpnext/translations/ku.csv
index 56be7a1..6962ea1 100644
--- a/erpnext/translations/ku.csv
+++ b/erpnext/translations/ku.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},baca type rastî dikarin di rêjeya babetî di row ne bê beşdar kirin {0},
Add,Lêzêdekirin,
Add / Edit Prices,Lê zêde bike / Edit Prices,
-Add All Suppliers,All Suppliers,
Add Comment,lê zêde bike Comment,
Add Customers,lê zêde muşteriyan,
Add Employees,lê zêde bike Karmendên,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',ne dikarin dadixînin dema kategoriyê e ji bo 'Valuation' an jî 'Vaulation û Total',
"Cannot delete Serial No {0}, as it is used in stock transactions","ne dikarin jêbirin Serial No {0}, wekî ku di karbazarên stock bikaranîn",
Cannot enroll more than {0} students for this student group.,ne dikarin zêdetir ji {0} xwendekar ji bo vê koma xwendekaran kul.,
-Cannot find Item with this barcode,Naha bi vê barcode re Dîtin,
Cannot find active Leave Period,Dema vekêşanê ya Çalakî nayê dîtin,
Cannot produce more Item {0} than Sales Order quantity {1},Can babet zêdetir {0} ji Sales Order dorpêçê de hilberandina ne {1},
Cannot promote Employee with status Left,Kes nikare karûbarê çepê ya Çep bigirin,
Cannot refer row number greater than or equal to current row number for this Charge type,Can hejmara row mezintir an wekhev ji bo hejmara row niha ji bo vî cureyê Charge kirîza ne,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Can type pere weke 'li ser Previous Mîqdar Row' hilbijêre ne an 'li ser Previous Row Total' ji bo rêza yekem,
-Cannot set a received RFQ to No Quote,Nikarî raketek RFQ qebûl nabe,
Cannot set as Lost as Sales Order is made.,ne dikarin set wek Lost wek Sales Order çêkirin.,
Cannot set authorization on basis of Discount for {0},Can destûr li ser bingeha Discount bo set ne {0},
Cannot set multiple Item Defaults for a company.,Dibe ku ji bo şirketek pir ji hêla şîfreyê veguherînin.,
@@ -521,7 +518,6 @@
Chargeble,Argearkbarî,
Charges are updated in Purchase Receipt against each item,Li dijî wan doz bi wergirtina Purchase dijî hev babete ve,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Li dijî wan doz dê were belavkirin bibihure li ser QTY babete an miqdar bingeha, wek per selection te",
-Chart Of Accounts,Chart Dageriyê,
Chart of Cost Centers,Chart Navendên Cost,
Check all,Check hemû,
Checkout,Lêkolîn,
@@ -581,7 +577,6 @@
Compensatory Off,heger Off,
Compensatory leave request days not in valid holidays,Daxwaza berdêla dayîna mûçûna dermanê ne di nav betlanên derbasdar de ne,
Complaint,Gilî,
-Completed Qty can not be greater than 'Qty to Manufacture',Qediya Qty ne dikarin bibin mezintir 'Qty ji bo Manufacture',
Completion Date,Date cebîr,
Computer,Komûter,
Condition,Rewş,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Create û rêvebirin û digests email rojane, hefteyî û mehane.",
Create customer quotes,Create quotes mişterî,
Create rules to restrict transactions based on values.,Create qaîdeyên ji bo bisînorkirina muamele li ser bingeha nirxên.,
-Created By,created By,
Created {0} scorecards for {1} between: ,{1} ji bo {1} scorecards {,
Creating Company and Importing Chart of Accounts,Afirandina Pargîdaniyê û Danûstendina Damezrênerê,
Creating Fees,Pargîdanî,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Beriya Transfer Dîroka Veguhastinê ya Xweser nikare nabe,
Employee cannot report to himself.,Xebatkarê ne dikarin ji xwe re rapor.,
Employee relieved on {0} must be set as 'Left',Xebatkarê hebekî li ser {0} bê mîhenkirin wek 'Çepê',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,Rewşa karmend nikare bi 'areep' were binavkirin ji ber ku karmendên jêrîn vê carê ji vî karmend re ragihandine:,
Employee {0} already submited an apllication {1} for the payroll period {2},Karmend {0} ji berê ve ji bo {3} ji bo payrollê ya payal {1},
Employee {0} has already applied for {1} between {2} and {3} : ,Karmend {0} ji berê ve ji {1} di navbera {2} û {3} de hatiye dayîn.,
Employee {0} has no maximum benefit amount,Karmend {0} tune ye heqê herî zêde tune,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Ji bo row {0},
"For {0}, only credit accounts can be linked against another debit entry","Ji bo {0}, tenê bikarhênerên credit dikare li dijî entry debit din ve girêdayî",
"For {0}, only debit accounts can be linked against another credit entry","Ji bo {0}, tenê bikarhênerên debit dikare li dijî entry credit din ve girêdayî",
-Form View,Form View,
Forum Activity,Çalakiya Forum,
Free item code is not selected,Koda belaş belaş nayê hilbijartin,
Freight and Forwarding Charges,Koçberên êşkencebûyî tê û şandinê de doz li,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Leave nikarim li ber terxan kirin {0}, wekî parsenga îzinê jixwe-hilgire hatiye şandin, di qeyda dabeşkirina îzna pêş {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Leave ne dikarin bên bicîhkirin / berî {0} betalkirin, wekî parsenga îzinê jixwe-hilgire hatiye şandin, di qeyda dabeşkirina îzna pêş {1}",
Leave of type {0} cannot be longer than {1},Leave a type {0} nikare were êdî ji {1},
-Leave the field empty to make purchase orders for all suppliers,Destûra vala vala bistînin ku ji bo hemî pargîdaneyên kirînê ji bo kirînê bikirin,
Leaves,Dikeve,
Leaves Allocated Successfully for {0},Pelên bi awayekî serketî ji bo bi rêk û {0},
Leaves has been granted sucessfully,Gelek destûr dan,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,No babet bi Bill ji materyalên ji bo Manufacture,
No Items with Bill of Materials.,No madeyên bi Bill of Material.,
No Permission,No Destûr,
-No Quote,No Quote,
No Remarks,No têbînî,
No Result to submit,Ne encam nabe ku şandin,
No Salary Structure assigned for Employee {0} on given date {1},Pêvek Mûçeya No Salary ji bo {1} roja xuyakirin {0},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,şert û mercên gihîjte dîtin navbera:,
Owner,Xwedî,
PAN,TAWE,
-PO already created for all sales order items,PO ji bo tiştên ku ji bo hemû firotina firotanê firotin hate afirandin,
POS,POS,
POS Profile,Profile POS,
POS Profile is required to use Point-of-Sale,POS Profê pêwîst e ku ji bo Point-of-Sale bikar bînin,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Ji kerema xwe ve yekem Charge Type hilbijêre,
Please select Company,Ji kerema xwe ve Company hilbijêre,
Please select Company and Designation,Ji kerema xwe şirket û şirove hilbijêrin,
-Please select Company and Party Type first,Ji kerema xwe ve yekem Company û Partiya Type hilbijêre,
Please select Company and Posting Date to getting entries,Ji kerema xwe şîrket û Dîroka Navnîşê hilbijêre ku têkevin navnîşan,
Please select Company first,Ji kerema xwe ve yekem Company hilbijêre,
Please select Completion Date for Completed Asset Maintenance Log,Ji kerema xwe ji bo temamkirina Dîroka Dawîn hilbijêre Ji bo Endamiya Hêza Navîn ya Têketinê hilbijêre,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Row {0}: UOM Factor Converter wêneke e,
Row {0}: select the workstation against the operation {1},Row {0}: Li dijî xebatê {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Row {0}: {1} Hejmarên Serial Ji bo {2} Pêdivî ye. Te destnîşan kir {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Row {0}: {1} hewce ye ku ji bo veguherandina {2} vekirî ve ava bike,
Row {0}: {1} must be greater than 0,Row {0}: {1} ji 0 re mezintir be,
Row {0}: {1} {2} does not match with {3},Row {0}: {1} {2} nayê bi hev nagirin {3},
Row {0}:Start Date must be before End Date,Row {0}: Destpêk Date divê berî End Date be,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,E-mail bişîne Send Review,
Send Now,Send Now,
Send SMS,Send SMS,
-Send Supplier Emails,Send Emails Supplier,
Send mass SMS to your contacts,Send SMS girseyî ji bo têkiliyên xwe,
Sensitivity,Hisê nazik,
Sent,Şandin,
-Serial #,Serial #,
Serial No and Batch,Serial No û Batch,
Serial No is mandatory for Item {0},No Serial ji bo babet wêneke e {0},
Serial No {0} does not belong to Batch {1},No Serial No {0} ne girêdayî ye {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,The name of şirketa we ji bo ku hûn bi avakirina vê sîstemê.,
The number of shares and the share numbers are inconsistent,Hejmarên parve û hejmarên parvekirî ne hevkar in,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Di plana navnîşan a daîreya navnîşan de {0} ji vê daxwazê deynê hesabê navnîşê ya ji derê ve ye,
-The request for quotation can be accessed by clicking on the following link,Daxwaz ji bo gotinên li dikare were bi tikandina li ser vê lînkê tê xwestin,
The selected BOMs are not for the same item,The dikeye hilbijartî ne ji bo em babete eynî ne,
The selected item cannot have Batch,The em babete kilîk ne dikarin Batch hene,
The seller and the buyer cannot be the same,Pêwîstker û kirrûbir nabe,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Hêjeya maddeya tevlîheviya neteweyî ya {0} divê bêtir xercên herî kêmtir tune {1},
Total hours: {0},Total saetan: {0},
Total leaves allocated is mandatory for Leave Type {0},Tevahiya pelên veguhestin divê ji cureyê derketinê {0},
-Total weightage assigned should be 100%. It is {0},Total weightage rêdan divê 100% be. Ev e {0},
Total working hours should not be greater than max working hours {0},"Total dema xebatê ne, divê ji bilî dema xebatê max be mezintir {0}",
Total {0} ({1}),Total {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Total {0} ji bo hemû tomar sifir e, dibe ku ji te re pêwîst 'Li dijî wan doz li ser xwer'a' biguhere",
@@ -3316,7 +3299,6 @@
What do you need help with?,Çi ji we re alîkarî pêwîst bi?,
What does it do?,Çi bikim?,
Where manufacturing operations are carried.,Li ku derê operasyonên bi aktîvîteyên bi çalakiyek hatiye lidarxistin.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Dema ku hesab ji bo Companyirketa zarokan {0} çê kir, hesabê dêûbavê {1} nehat dîtin. Ji kerema xwe hesabê dêûbav di COA-yê ya têkildar de biafirînin",
White,spî,
Wire Transfer,Transfer wire,
WooCommerce Products,Berhemên WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,Guhertin {0}.,
{0} {1} created,{0} {1} tên afirandin,
{0} {1} does not exist,{0} {1} tune,
-{0} {1} does not exist.,{0} {1} nîne.,
{0} {1} has been modified. Please refresh.,{0} {1} hate guherandin. Ji kerema xwe nû dikin.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} hatiye nehatine şandin, da ku çalakiyên ne dikarin bi dawî bê",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} têkildarî {2} ye, lê Hesabê partiyê {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} nizane heye ne,
{0}: {1} not found in Invoice Details table,{0}: {1} li ser sifrê bi fatûreyên Details dîtin ne,
{} of {},} of {},
+Assigned To,rêdan û To,
Chat,Galgalî,
Completed By,Bi tevahî,
Conditions,Şertên,
@@ -3506,7 +3488,9 @@
Merge with existing,Merge bi heyî,
Office,Dayre,
Orientation,Orientation,
+Parent,dê û bav,
Passive,Nejîr,
+Payment Failed,Payment biserneket,
Percent,ji sedî,
Permanent,Herdem,
Personal,Şexsî,
@@ -3544,7 +3528,6 @@
Company field is required,Qada pargîdaniyê pêdivî ye,
Creating Dimensions...,Dimîne Afirandin ...,
Duplicate entry against the item code {0} and manufacturer {1},Li dijî koda kodê {0} û hilberê {1},
-Import Chart Of Accounts from CSV / Excel files,Ji pelên CSV / Excel Pêkvekirina Hesabê Damezrînin,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN nederbasdar e! Navnîşa ku we têkevî bi formasyona GSTIN re ji bo Mêvanên UIN-ê an Niştecîhên Karûbarên OIDAR-yê Niştecîhan nabin,
Invoice Grand Total,Pêşkêşiya Grand Total,
Last carbon check date cannot be a future date,Dîroka kontrolkirina karbonê ya paşîn nikare tarîxek pêşerojê be,
@@ -3556,6 +3539,7 @@
Show {0},Show {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Di tîpa navnasî de ji bilî "-", "#", ".", "/", "{" Û "}" tîpên Taybet",
Target Details,Hûrgulên armancê,
+{0} already has a Parent Procedure {1}.,{0} ji berê ve heye Parent Procedure {1}.,
API,API,
Annual,Yeksalî,
Approved,pejirandin,
@@ -3572,6 +3556,8 @@
No data to export,Danasîna hinardekirinê tune,
Portrait,Portûgal,
Print Heading,Print Hawara,
+Scheduler Inactive,Scheduler Inactive,
+Scheduler is inactive. Cannot import data.,Scheduler neçalak e. Danûstandin nekare.,
Show Document,Belge nîşan bide,
Show Traceback,Traceback nîşan bikin,
Video,Vîdeo,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Inspavdêriya Qeydeyê ji Bo Babetê {0 Create,
Creating Accounts...,Afirandina Hesaban ...,
Creating bank entries...,Afirandina qeydên bankayê ...,
-Creating {0},Creating {0},
Credit limit is already defined for the Company {0},Sînorê krediyê ji bo pargîdaniya already 0 berê hatî destnîşankirin,
Ctrl + Enter to submit,Ctrl + Ji bo şandin,
Ctrl+Enter to submit,Ctrl + Enter bişîne,
@@ -3921,7 +3906,6 @@
Plaid public token error,Errorewtiya nîşana gelemperî ya plaid,
Plaid transactions sync error,Errorewtiya hevdemkirina transaksiyonên plaid,
Please check the error log for details about the import errors,Ji kerema xwe hûrguliyên çewtiyê ji bo hûrguliyên li ser xeletiyên import kontrol bikin,
-Please click on the following link to set your new password,Ji kerema xwe li ser vê lînkê click to set şîfreya xwe ya nû,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Ji kerema <b>DATEV Mîhengên</b> ji bo Company <b>{}.</b>,
Please create adjustment Journal Entry for amount {0} ,Ji kerema xwe amount 0},
Please do not create more than 500 items at a time,Ji kerema xwe di yek carek de ji zêdeyî 500 hêsan neyên afirandin,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Dîroka berdanê divê di pêşerojê de be,
Relieving Date must be greater than or equal to Date of Joining,Dîroka Baweriyê ji Dîroka Beşdariyê divê ji Mezin an Dîroka Beşdariyê mezintir be,
Rename,Nav biguherîne,
+Rename Not Allowed,Navnedayin Nakokirin,
Repayment Method is mandatory for term loans,Rêbaza vegerandina ji bo deynên termîn mecbûrî ye,
Repayment Start Date is mandatory for term loans,Dîroka Ragihandina Dravê ji bo deynên termîn mecbûrî ye,
Report Item,Report Babetê,
@@ -4043,7 +4028,6 @@
Select All,Select All,
Select Difference Account,Hesabê Cudahiyê hilbijêrin,
Select a Default Priority.,Pêşerojek Default hilbijêrin.,
-Select a Supplier from the Default Supplier List of the items below.,Hilberînerek ji navnîşa Pargîdaniya Default ya tiştên li jêr hilbijêrin.,
Select a company,Pargîdanek hilbijêrin,
Select finance book for the item {0} at row {1},Ji bo tiştên finance 0} li rêza the 1 book pirtûka fînansê hilbijêrin,
Select only one Priority as Default.,Tenê Pêşniyar wekî Yek Pêşek hilbijêrin.,
@@ -4247,7 +4231,6 @@
Actual ,Rast,
Add to cart,Têxe,
Budget,Sermîyan,
-Chart Of Accounts Importer,Chart Of Accounts Importer,
Chart of Accounts,Karta Karûbar,
Customer database.,Database Database,
Days Since Last order,Rojan de ji sala Last Order,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Dîrok Dîroka Destpêk Destpêk Dibe,
For Default Supplier (Optional),Ji bo Default Supplier (alternatîf),
From date cannot be greater than To date,Ji Date ne dikarin bibin mezintir To Date,
-Get items from,Get tomar ji,
Group by,Koma By,
In stock,Ez bêzarim,
Item name,Navê Navekî,
@@ -4532,32 +4514,22 @@
Accounts Settings,Hesabên Settings,
Settings for Accounts,Mîhengên ji bo Accounts,
Make Accounting Entry For Every Stock Movement,Make Peyam Accounting bo her Stock Tevgera,
-"If enabled, the system will post accounting entries for inventory automatically.","Heke hilbijartî be, di sîstema wê entries hisêba ji bo ambaran de automatically binivîse.",
-Accounts Frozen Upto,Hesabên Frozen Upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","entry Accounting ji vê dîrokê de sar up, kes nikare do / ya xeyrandin di entry ji bilî rola li jêr hatiye diyarkirin.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Role Yorumlar ji bo Set Accounts Frozen & Edit berheman Frozen,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,"Bikarhêner li ser bi vê rola bi destûr ji bo bikarhênerên frozen biafirînin û / ya xeyrandin di entries, hesabgirê dijî bikarhênerên bêhest",
Determine Address Tax Category From,Navnîşa Kategoriya Baca Navnîşanê Ji,
-Address used to determine Tax Category in transactions.,Navnîşan da ku di danûstandinan de Kategoriya Bacê de destnîşan bike.,
Over Billing Allowance (%),Li ser Alîkariya Billing (%),
-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 for $110.,"Ji sedî ku hûn destûr bidin ku hûn bêtir li dijî dravê ferman dane. Mînak: Heke nirxa fermanê ji bo her tiştî 100 $ ye û toleransa wekî% 10 tê destnîşan kirin, wê hingê tê destûr kirin ku ji bo 110 $ $ bill were dayîn.",
Credit Controller,Controller Credit,
-Role that is allowed to submit transactions that exceed credit limits set.,Rola ku destûr ji bo pêşkêşkirina muamele ku di mideyeka sînorên credit danîn.,
Check Supplier Invoice Number Uniqueness,Check Supplier bi fatûreyên Hejmara bêhempabûna,
Make Payment via Journal Entry,Make Payment via Peyam di Journal,
Unlink Payment on Cancellation of Invoice,Unlink Payment li ser komcivîna me ya bi fatûreyên,
-Unlink Advance Payment on Cancelation of Order,Pêşniyara Dravê Daxistinê li ser Betalkirina Fermanê veqetîne,
Book Asset Depreciation Entry Automatically,Book Asset Peyam Farhad otomatîk,
Automatically Add Taxes and Charges from Item Tax Template,Ji Temablonê Bacê ya Bacê Bixwe bixwe baca û bacan zêde bikin,
Automatically Fetch Payment Terms,Allyertên Dravê bixweber Bawer bikin,
-Show Inclusive Tax In Print,Di Print Inclusive Tax Print,
Show Payment Schedule in Print,Di çapkirinê de Payday Schedule Show,
Currency Exchange Settings,Guhertina Exchange Exchange,
Allow Stale Exchange Rates,Allow Stale Exchange Rates,
Stale Days,Rojên Stale,
Report Settings,Rapora rapora,
Use Custom Cash Flow Format,Forma Qanûna Kredê Custom Use,
-Only select if you have setup Cash Flow Mapper documents,Tenê hilbijêre ku hûn dokumentên dirûşmeyên mûçeyê yên damezirandin hilbijêre,
Allowed To Transact With,Destûra ku Bi Têkilî Veguhestin,
SWIFT number,Hejmara SWIFT,
Branch Code,Koda Branchê,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Mişterî Group,
POS Field,POS Field,
POS Item Group,POS babetî Pula,
-[Select],[Neqandin],
Company Address,Company Address,
Update Stock,update Stock,
Ignore Pricing Rule,Guh Rule Pricing,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Supplier Qada By,
Default Supplier Group,Default Supplier Group,
Default Buying Price List,Default Lîsteya Buying Price,
-Maintain same rate throughout purchase cycle,Pêkanîna heman rêjeya li seranserê cycle kirîn,
-Allow Item to be added multiple times in a transaction,Destûrê babet ji bo çend caran bê zêdekirin di mêjera,
Backflush Raw Materials of Subcontract Based On,Raw Material of Deposit Based On,
Material Transferred for Subcontract,Mînak ji bo veguhestinê veguhastin,
Over Transfer Allowance (%),Allowance Transfer (%),
@@ -5540,7 +5509,6 @@
Current Stock,Stock niha:,
PUR-RFQ-.YYYY.-,PUR-RFQ-YYYY-,
For individual supplier,Ji bo dabînkerê şexsî,
-Supplier Detail,Detail Supplier,
Link to Material Requests,Girêdana Daxwazên Materyalê,
Message for Supplier,Peyam ji bo Supplier,
Request for Quotation Item,Daxwaza ji bo babet Quotation,
@@ -6481,7 +6449,6 @@
Appraisal Template,appraisal Şablon,
For Employee Name,Ji bo Name Xebatkara,
Goals,armancên,
-Calculate Total Score,Calcolo Total Score,
Total Score (Out of 5),Total Score: (Out of 5),
"Any other remarks, noteworthy effort that should go in the records.","Bęjeyek ji axaftinên din jî, hewldana wê xalê de, ku divê di qeydên here.",
Appraisal Goal,Goal appraisal,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Sedem ji bo Leaving,
Leave Encashed?,Dev ji Encashed?,
Encashment Date,Date Encashment,
-Exit Interview Details,Details Exit Hevpeyvîn,
-Held On,held ser,
-Reason for Resignation,Sedem ji bo îstîfakirinê,
-Better Prospects,baştir e,
-Health Concerns,Gûman Health,
New Workplace,New Workplace,
HR-EAD-.YYYY.-,HR-EAD-.YYYY-,
Returned Amount,Dravê vegerandî,
@@ -6740,10 +6702,7 @@
Employee Settings,Settings karker,
Retirement Age,temenê teqawidîyê,
Enter retirement age in years,temenê teqawidîyê Enter di salên,
-Employee Records to be created by,Records karker ji aliyê tên afirandin bê,
-Employee record is created using selected field. ,record Employee bikaranîna hilbijartî tên afirandin e.,
Stop Birthday Reminders,Stop Birthday Reminders,
-Don't send Employee Birthday Reminders,Ma Employee Birthday Reminders bişîne ne,
Expense Approver Mandatory In Expense Claim,Mesrefên Derheqê Bêguman Têkoşîna Derheqê,
Payroll Settings,Settings payroll,
Leave,Terikandin,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Di Perestgehê de Vegerîna Derfeta Nerazîbûnê Nerazî bibin,
Show Leaves Of All Department Members In Calendar,Di Calendar de Hemû Endamên Endamên Hilbijartinan Hilbijêre,
Auto Leave Encashment,Otomêja Bişkojinê Bide,
-Restrict Backdated Leave Application,Serlêdana Bişkojiya Vegera Bişkêş Bixebitîne,
Hiring Settings,Mîhengên Kirînê,
Check Vacancies On Job Offer Creation,Afirandinên Li Ser Afirandina Pêşniyara Karê Vegerin,
Identification Document Type,Tîpa Belgeyê nasnameyê,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Settings manufacturing,
Raw Materials Consumption,Serfiraziya Rawêjan,
Allow Multiple Material Consumption,Destûra Pirrjimar Pirrjimar Pirrjimar,
-Allow multiple Material Consumption against a Work Order,Destûra Pirrjimar Pirrjimar Li dijî Karê Karê Mirov bike,
Backflush Raw Materials Based On,Backflush madeyên xav ser,
Material Transferred for Manufacture,Maddî Transferred bo Manufacture,
Capacity Planning,Planning kapasîteya,
Disable Capacity Planning,Plansaziya kapasîteyê asteng bikin,
Allow Overtime,Destûrê bide Heqê,
-Plan time logs outside Workstation Working Hours.,Plan dem têketin derveyî Hours Workstation Xebatê.,
Allow Production on Holidays,Destûrê bide Production li ser Holidays,
Capacity Planning For (Days),Planning kapasîteya For (Days),
-Try planning operations for X days in advance.,Try plan operasyonên ji bo rojên X di pêş.,
-Time Between Operations (in mins),Time di navbera Operasyonên (li mins),
-Default 10 mins,Default 10 mins,
Default Warehouses for Production,Ji bo Hilberînê Wargehên Default,
Default Work In Progress Warehouse,Default Kar In Warehouse Progress,
Default Finished Goods Warehouse,Default QediyayîComment Goods Warehouse,
Default Scrap Warehouse,Wargeha Pêşkêş a Pêşkêşkerê,
-Over Production for Sales and Work Order,Over Hilberîn ji bo Firotanê û Fermana Kar,
Overproduction Percentage For Sales Order,Percentage Overgduction For Sale Order,
Overproduction Percentage For Work Order,Percentiya zêdebûna% ji bo Karê Karkerê,
Other Settings,Mîhengên din,
Update BOM Cost Automatically,Bom Costa xwe bixweber bike,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","BOM bi otomatîk bi otomotîfê xwe bixweber bike, li ser rêjeya bihayê bihayê / bihayê rêjeya bihayê / rêjeya kirînê ya bihayê rawestî.",
Material Request Plan Item,Material Request Plan,
Material Request Type,Maddî request type,
Material Issue,Doza maddî,
@@ -7603,10 +7554,6 @@
Quality Goal,Armanca Qalîteyê,
Monitoring Frequency,Frekansa avdêrî,
Weekday,Hefteya çûyî,
-January-April-July-October,Januaryile-Avrêl-Tîrmeh-irî,
-Revision and Revised On,Revîzekirin û Li ser Dît,
-Revision,Nûxwestin,
-Revised On,Li ser revandin,
Objectives,Armanc,
Quality Goal Objective,Armanca Armanca Qalîteyê,
Objective,Berdest,
@@ -7619,7 +7566,6 @@
Processes,Pêvajoyên,
Quality Procedure Process,Pêvajoya Karûbarê kalîteyê,
Process Description,Danasîna pêvajoyê,
-Child Procedure,Rêbaza Zarok,
Link existing Quality Procedure.,Pêvajoya Kêmasiyê ya heyî girêdin.,
Additional Information,Agahdariya Zêdeyî,
Quality Review Objective,Armanca nirxandina kalîteyê,
@@ -7787,15 +7733,9 @@
Default Customer Group,Default Mişterî Group,
Default Territory,Default Herêma,
Close Opportunity After Days,Close Opportunity Piştî Rojan,
-Auto close Opportunity after 15 days,Auto Opportunity nêzîkî piştî 15 rojan de,
Default Quotation Validity Days,Rojên Dersa Nermalav,
Sales Update Frequency,Frequency Demjimêrk Demjimêr,
-How often should project and company be updated based on Sales Transactions.,Divê pir caran divê projeyê û firotanê li ser Guhertina Kirêdariyên Demkî bêne nûkirin.,
Each Transaction,Her Transaction,
-Allow user to edit Price List Rate in transactions,Destûrê bide bikarhêneran ji bo weşînertiya Price List Rate li muamele,
-Allow multiple Sales Orders against a Customer's Purchase Order,Destûrê bide multiple Orders Sales dijî Mişterî ya Purchase Order,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Validate Selling Beha bo Babetê dijî Rate Purchase an Rate Valuation,
-Hide Customer's Tax Id from Sales Transactions,Hide Id Bacê Mişterî ji Transactions Sales,
SMS Center,Navenda SMS,
Send To,Send To,
All Contact,Hemû Contact,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,"Manufacturers bikaranîn, di babetî",
Limited to 12 characters,Bi sînor ji 12 tîpan,
MAT-MR-.YYYY.-,MAT-MR-.YYYY-,
-Set Warehouse,Set Warehouse,
-Sets 'For Warehouse' in each row of the Items table.,Di her rêza maseya Tiştikan de 'Ji bo Warehouse' saz dike.,
-Requested For,"xwestin, çimkî",
Partially Ordered,Qismî Ferman,
Transferred,veguhestin,
% Ordered,% داواکراوە,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Default Stock UOM,
Sample Retention Warehouse,Warehouse Sample Retention,
Default Valuation Method,Default Method Valuation,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,Rêjeya we bi destûr bistînin an rizgar zêdetir li dijî dorpêçê de ferman da. Ji bo nimûne: Ger tu 100 yekîneyên emir kirine. û bistînin xwe 10% îdî tu bi destûr bo wergirtina 110 yekîneyên e.,
-Action if Quality inspection is not submitted,Heke ku teftîşa kalîteyê nehatiye pêşkêş kirin çalakî,
Show Barcode Field,Show Barcode Field,
Convert Item Description to Clean HTML,Vebijêrk Nîşan Bigere HTML to Clean,
-Auto insert Price List rate if missing,insert Auto List Price rêjeya eger wenda,
Allow Negative Stock,Destûrê bide Stock Negative,
Automatically Set Serial Nos based on FIFO,Otomatîk Set Serial Nos li ser FIFOScheduler,
-Set Qty in Transactions based on Serial No Input,Li Qanûna Qanûna Saziyê Hilbijêre Li ser Serial No Serial,
Auto Material Request,Daxwaza Auto Material,
-Raise Material Request when stock reaches re-order level,Bilind Daxwaza Material dema stock asta re-da digihîje,
-Notify by Email on creation of automatic Material Request,Notify by Email li ser çêkirina Daxwaza Material otomatîk,
Inter Warehouse Transfer Settings,Mîhengên Veguhastina Warehouse Inter,
-Allow Material Transfer From Delivery Note and Sales Invoice,Destûrê bide Veguhestina Madeyê Ji Nîşeya Radestkirinê û Fatûra Firotanê,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Ji Destûra Kirînê û Fatûra Kirînê Destûrê bide Veguhestina Madeyê,
Freeze Stock Entries,Freeze Stock Arşîva,
Stock Frozen Upto,Stock Upto Frozen,
-Freeze Stocks Older Than [Days],Rêzefîlma Cîran Cîran Freeze kevintir Than [Rojan],
-Role Allowed to edit frozen stock,Role Yorumlar ji bo weşînertiya stock bêhest,
Batch Identification,Nasnameya Batchê,
Use Naming Series,Sîstema Namingê bikar bînin,
Naming Series Prefix,Naming Series Prefix,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Trends kirînê Meqbûz,
Purchase Register,Buy Register,
Quotation Trends,Trends quotation,
-Quoted Item Comparison,Babetê têbinî eyna,
Received Items To Be Billed,Pêşwaziya Nawy ye- Be,
Qty to Order,Qty siparîş,
Requested Items To Be Transferred,Nawy xwestin veguhestin,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Ji bo daxwazên materyalê embarê hilbijêrin,
Transfer Materials For Warehouse {0},Materyalên Veguhêzbar Ji bo Warehouse {0},
Production Plan Material Request Warehouse,Plana Hilberînê Depoya Daxwaza Materyalê,
-Set From Warehouse,Ji Warehouse Saz Bike,
-Source Warehouse (Material Transfer),Depoya Çavkaniyê (Veguhestina Madeyê),
Sets 'Source Warehouse' in each row of the items table.,Di her rêza maseya tiştan de 'Depoya Çavkaniyê' saz dike.,
Sets 'Target Warehouse' in each row of the items table.,Di her rêza maseya tiştan de 'Warehouse Target' saz dike.,
Show Cancelled Entries,Navnîşên Betalkirî Nîşan bidin,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,Xizmeta Ku Wergirtin Lê Nekir,
Deferred Accounting Settings,Mîhengên Hesabê Deferred,
Book Deferred Entries Based On,Navnîşên Paşvengandî yên Li Ser Bingehê,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ger "Meh" were hilbijartin wê hingê mîqdara sabît wekî dahat an lêçûnê taloqkirî ji bo her mehê tê veqetandin, bêyî ku hejmarek rojên mehê hebe. Heke dahat an lêçûnê taloqkirî ji bo mehekê tev neyê veqetandin dê were pêşwazîkirin.",
Days,Rojan,
Months,Mehan,
Book Deferred Entries Via Journal Entry,Bi Navnîşana Rojnameyê Navnîşanên Dewsekandî Pirtûk,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,Heke viya neyê vebijartin dê GL-yên rasterast ji bo pirtûka Hatina Dereng / Xercê werin afirandin,
Submit Journal Entries,Navnîşên Kovarê bişînin,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,Ger ev neyê vebijartin Navnîşanên Kovarê dê di dewleta Pêşnûmeyê de werin tomarkirin û pêdivî ye ku bi destan werin şandin,
Enable Distributed Cost Center,Navenda Lêçûna Belavkirî Çalak bikin,
@@ -8901,8 +8823,6 @@
Is Inter State,Dewleta Inter e,
Purchase Details,Agahdariyên Kirînê,
Depreciation Posting Date,Daxistina Daxuyaniya Daxistinê,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Siparîşa Kirînê Ji bo Fatûra Kirînê & Afirandina Meqamê Pêdivî ye,
-Purchase Receipt Required for Purchase Invoice Creation,Ji bo Afirandina Fatureya Kirînê Reçeteya Kirînê Pêdivî ye,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Wekî standard, Navê Pêşkêşker li gorî Navê Pêşkêşkerê ku hatî danîn tête saz kirin. Heke hûn dixwazin Pêşniyar ji hêla a ve bêne nav kirin",
choose the 'Naming Series' option.,vebijêrka 'Navê Rêzê' hilbijêrin.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Dema ku danûstendinek Kirînê ya nû çêbikin Lîsteya Bihayê ya default vesaz bikin. Bihayên tiştan dê ji vê Lîsteya Bihayê werin girtin.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Pêkhateya Baca Dahatê ye,
Component properties and references ,Taybetmendî û referansên pêkhateyê,
Additional Salary ,Mûçeyê Zêdeyî,
-Condtion and formula,Tionert û formul,
Unmarked days,Rojên nevekirî,
Absent Days,Rojên Tunebûyî,
Conditions and Formula variable and example,Itionsert û Formula guhêrbar û mînak,
Feedback By,Feedback By,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Beşa Çêkirinê,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Siparîşa Firotanê Ji Bo Fatûreya Firotanê & Afirandina Nîşeya Radestkirinê Pêdivî ye,
-Delivery Note Required for Sales Invoice Creation,Têbînî Delivery Ji bo Afirandina Fatûra Firotanê Pêdivî ye,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Bi default, Navê Xerîdar li gorî Navê Tevahî yê hatî nivîsandin tê saz kirin. Heke hûn dixwazin Xerîdar ji hêla a ve bêne nav kirin",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Dema ku danûstendinek firotanê ya nû çêbikin Lîsteya Bihayê ya default saz bikin. Bihayên tiştan dê ji vê Lîsteya Bihayê werin girtin.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ger ev vebijêrk 'Erê' were vesaz kirin, ERPNext dê pêşî li afirandina Fatureya Firotanê an Biparêza Radestkirinê bigire bêyî ku pêşî Biryarnameya Firotinê çêbike. Vê veavakirina hanê ji hêla mişteriyek taybetî ve bi rahiştina çerxa 'Destûrê bide Afirandina Fatûra Firotanê Bê Biryarnameya Firotanê' dikare di masterê Xerîdar de were derbas kirin.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} bi serfirazî li hemî mijarên hilbijartî hate zêdekirin.,
Topics updated,Mijar nûve kirin,
Academic Term and Program,Term û Bernameya Akademîk,
-Last Stock Transaction for item {0} was on {1}.,Danûstendina Stockê ya Dawîn ji bo tiştê {0} li ser {1} bû.,
-Stock Transactions for Item {0} cannot be posted before this time.,Danûstendinên Stockê ji bo Hêmana {0} berî vê demê nayê şandin.,
Please remove this item and try to submit again or update the posting time.,Ji kerema xwe vî tiştî hilînin û hewl bidin ku carek din bişînin an dema şandina nûve bikin.,
Failed to Authenticate the API key.,Bişkojka API-yê rastnekirî nehat.,
Invalid Credentials,Bawernameyên nederbasdar,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Ji kerema xwe nasnameya xerîdarê Plaid û nirxên xweyên nepenî kontrol bikin,
Bank transaction creation error,Çewtiya afirandina danûstendina bankê,
Unit of Measurement,Yekeya Pîvandinê,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Rêzok # {}: Rêjeya firotanê ji bo hêmanê {} ji ya wê {} kêmtir e. Divê rêjeya firotanê herî kêm be {},
Fiscal Year {0} Does Not Exist,Sala Darayî {0} Heye,
Row # {0}: Returned Item {1} does not exist in {2} {3},Rêzeya # {0}: Tişta vegerandî {1} li {2} {3} tune,
Valuation type charges can not be marked as Inclusive,Dozên celebê nirxandinê wekî Inclusive nayên nîşankirin,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Dema Bersivê ji bo {0} pêşanî di rêzê de {1} nikare ji Dema Biryarê mezintir be.,
{0} is not enabled in {1},{0} di {1} de nayê çalakirin,
Group by Material Request,Ji hêla Daxwaza Maddî ve kom,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Rêz {0}: Ji bo Pêşkêşker {0}, Ji bo Sendandina E-name Navnîşana E-nameyê Pêdivî ye",
Email Sent to Supplier {0},E-name ji bo Pêşkêşker şandiye {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Gihîştina Daxwaza Gotinê Ji Portalê Neçalak e. Ji bo Destûra Destûrê, Di Mîhengên Portalê de Vê çalak bikin.",
Supplier Quotation {0} Created,Pêşniyara Pêşkêşker {0} Afirandî,
Valid till Date cannot be before Transaction Date,Derbasdar heya Dîrok nikare li ber Dîroka Danûstandinê be,
+Unlink Advance Payment on Cancellation of Order,Li Ser Betalkirina Biryarê Destpêka Peredanê Veqetînin,
+"Simple Python Expression, Example: territory != 'All Territories'","Vegotina Python a Sade, Mînak: erd! = 'Hemî Ax'",
+Sales Contributions and Incentives,Beşdariyên firotanê û teşwîqan,
+Sourced by Supplier,Çavkaniya Çavkaniyê,
+Total weightage assigned should be 100%.<br>It is {0},Giraniya tevahî ya hatî diyar kirin divê% 100 be.<br> Ew {0} e,
+Account {0} exists in parent company {1}.,Hesab {0} di pargîdaniya dêûbavan de heye {1}.,
+"To overrule this, enable '{0}' in company {1}","Ji bo binpêkirina vê yekê, '{0}' di pargîdaniyê de çalak bikin {1}",
+Invalid condition expression,Vegotina rewşa nederbasdar,
+Please Select a Company First,Ji kerema xwe Pêşîn Pargîdaniyek Hilbijêrin,
+Please Select Both Company and Party Type First,Ji kerema xwe Yekem Tîpa Pargîdanî û Partiyê Hilbijêrin,
+Provide the invoice portion in percent,Beşa fatureyê ji sedî peyda bikin,
+Give number of days according to prior selection,Li gorî hilbijartina pêşîn hejmarek rojan bidin,
+Email Details,Email Details,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Silavek ji bo wergir hilbijêrin. Mînak birêz, xanim û hwd.",
+Preview Email,Pêşdîtina E-nameyê,
+Please select a Supplier,Ji kerema xwe Pêşniyarek hilbijêrin,
+Supplier Lead Time (days),Demjimêrê Pêşkêşker (rojan),
+"Home, Work, etc.","Mal, Kar û hwd.",
+Exit Interview Held On,Derketin Hevpeyivîn Çêdibe,
+Condition and formula,Condert û formul,
+Sets 'Target Warehouse' in each row of the Items table.,Li her rêza maseya Tişkan 'Depoya Armanc' danîne.,
+Sets 'Source Warehouse' in each row of the Items table.,Di her rêza maseya Tişkan de 'Depoya Çavkaniyê' saz dike.,
+POS Register,POS Register,
+"Can not filter based on POS Profile, if grouped by POS Profile","Heke ji hêla Profîla POS-ê ve were komkirin, li gorî Profîla POS-ê parzûn nabe",
+"Can not filter based on Customer, if grouped by Customer","Heke ji hêla Xerîdar ve were kom kirin, nikare li ser bingeha Xerîdar parzûn bibe",
+"Can not filter based on Cashier, if grouped by Cashier",Heke ji hêla Xezîneyê ve were komkirin nikare li ser Bingeha Cezîrê fîltre bike,
+Payment Method,Rêbaza dayinê,
+"Can not filter based on Payment Method, if grouped by Payment Method","Heke li gorî Rêbaza Bidestpêkbûnê were komkirin, li gorî Rêbaza Dravkirinê nikare parzûn bibe",
+Supplier Quotation Comparison,Berawirdekirina Pêşkêşkerê Pêşkêşker,
+Price per Unit (Stock UOM),Bihayê yekeya (Stock UOM),
+Group by Supplier,Kom ji hêla Pargîdaniyê ve,
+Group by Item,Kom bi Babet,
+Remember to set {field_label}. It is required by {regulation}.,Bînin bîra xwe ku {zeviyê_ etîketê} danîn. Ew ji hêla {rêziknameyê} ve pêdivî ye.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Dîroka Tomarbûnê nikare berî Dîroka Destpêka Sala Akademîk be {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Dîroka Tomarbûnê nikare piştî Dîroka Dawiya Termê Akademîkî be {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Dîroka Tomarbûnê nikare berî Dîroka Destpêka Heyama Akademîk be {0},
+Future Posting Not Allowed,Ingandina Pêşerojê Destûr Nabe,
+"To enable Capital Work in Progress Accounting, ","Ji bo Di Karûbarê Pêşkeftinê de Karê Kapîtal çalak bike,",
+you must select Capital Work in Progress Account in accounts table,divê hûn li sermaseya hesaban Karê Sermiyan di Hesabê Pêşkeftinê de hilbijêrin,
+You can also set default CWIP account in Company {},Di heman demê de hûn dikarin li Pargîdaniyê hesabê pêşdibistana CWIP jî saz bikin {},
+The Request for Quotation can be accessed by clicking on the following button,Daxwaza Nirxandinê bi tikandina bişkoja jêrîn ve tête peyda kirin,
+Regards,Silav û rêz,
+Please click on the following button to set your new password,Ji kerema xwe bişkoja jêrîn bikirtînin da ku şîfreya xweya nû saz bikin,
+Update Password,Passwordîfreyê nûve bikin,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Rêzok # {}: Rêjeya firotanê ji bo hêmanê {} ji ya wê {} kêmtir e. Firotin {} divê herî kêm {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Hûn dikarin bi alternatîfî pejirandina bihayê firotanê li {} betal bikin ku vê pejirandinê derbas bikin.,
+Invalid Selling Price,Bihayê Firotinê Neheq e,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Navnîşan hewce ye ku bi Pargîdaniyek ve were girêdan. Ji kerema xwe rêzek ji bo Pargîdaniyê di tabloya Girêdanan de zêde bikin.,
+Company Not Linked,Companyirket Ne Girêdayî ye,
+Import Chart of Accounts from CSV / Excel files,Chart of Accounts ji pelên CSV / Excel Import bikin,
+Completed Qty cannot be greater than 'Qty to Manufacture',Qty-ya qediyayî ji 'Qty-ya Çêkirinê' mezintir nabe,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Rêz {0}: Ji bo Pêşkêşker {1}, Navnîşana E-nameyê Pêdivî ye ku e-nameyek bişîne",
+"If enabled, the system will post accounting entries for inventory automatically","Ger çalak be, pergalê dê navnîşên hesabê ji bo envanterê bixweber bişîne",
+Accounts Frozen Till Date,Hesabên Heya Tarîxê Froştin,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,Navnîşên hesabê heya vê tarîxê têne cemidandin. Tu kes nikare navnîşan biafirîne an biguherîne ji bilî bikarhêneran bi rola ku li jêr hatî diyar kirin,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Rol Destûr Kir ku Hesabên Qedexe Saz Bikin û Navnîşên Qewirandî Serast Bikin,
+Address used to determine Tax Category in transactions,Navnîşan ji bo destnîşankirina Kategoriya Bacê di danûstandinan de tê bikar anîn,
+"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 ","Rêjeya ku hûn destûr dane ku li hember mîqdara ku hatî ferman kirin bêtir fature bikin. Mînakî, heke nirxa siparîşê ji bo tiştek 100 $ be û tolerans wekî% 10 were danîn, wê hingê hûn ê destûr bidin heya 110 $",
+This role is allowed to submit transactions that exceed credit limits,Vê rolê tête pejirandin ku danûstandinên ku ji sînorên krediyê derbas dibin bişîne,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ger "Meh" were bijartin, dê mîqdarek sabît ji bo her mehê wekî dahat an lêçûnê ya taloqkirî bête veqetandin, bêyî ku hejmarek rojên mehê hebe. Heke dahat an lêçûnê taloqkirî ji bo mehekê tev neyê veqetandin dê were pêşwazîkirin",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Heke ev yek neyê vebijartin, dê navnîşên GL-yên rasterast werin çêkirin ku dahat an lêçûna taloqkirî bidin hev",
+Show Inclusive Tax in Print,Bacê Tevlêbûnê di Çapê de Nîşan bidin,
+Only select this if you have set up the Cash Flow Mapper documents,Heke we belgeyên Cash Flow Mapper saz kirine tenê vê yekê hilbijêrin,
+Payment Channel,Channel Payment,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Biryara Kirînê Ji Bo Fatûreya Kirînê & Afirandina Meqbûzê Pêdivî ye?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Ma Ji bo Afirandina Fatureya Kirînê Meqbûza Kirînê Pêdivî ye?,
+Maintain Same Rate Throughout the Purchase Cycle,Di Çerxa Kirînê de Heman Rêjeyê biparêzin,
+Allow Item To Be Added Multiple Times in a Transaction,Di Danûstendinê de Destûr Bikin ku Tiştik Pir caran Zêde Be,
+Suppliers,Pêşkêşker,
+Send Emails to Suppliers,E-nameyan ji Pêşkeran re bişînin,
+Select a Supplier,Hilbijêrek Hilbijêrin,
+Cannot mark attendance for future dates.,Ji bo tarîxên pêşerojê nikanin amadebûnê nîşan bikin.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Ma hûn dixwazin amadebûnê nûve bikin?<br> Pêşkêş: {0}<br> Nabe: {1},
+Mpesa Settings,Mpesa Mîhengan,
+Initiator Name,Navê Destpêker,
+Till Number,Ta Hejmar,
+Sandbox,Sandbox,
+ Online PassKey,PassKey serhêl,
+Security Credential,Baweriya Ewlekariyê,
+Get Account Balance,Balansa Hesabê bistînin,
+Please set the initiator name and the security credential,Ji kerema xwe navê destpêker û pêbaweriya ewlehiyê saz bikin,
+Inpatient Medication Entry,Ketina Dermanên Nexweşan,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Koda Babetê (Derman),
+Medication Orders,Fermanên Dermanan,
+Get Pending Medication Orders,Biryarnameyên Dermanên Bendewar Bistînin,
+Inpatient Medication Orders,Biryarnameyên Dermanên Nexweşxaneyê,
+Medication Warehouse,Depoya Dermanan,
+Warehouse from where medication stock should be consumed,Depoya ku divê pargîdaniya dermanê lê were xerckirin,
+Fetching Pending Medication Orders,Wergirtina Biryarnameyên Dermanên Bendewar,
+Inpatient Medication Entry Detail,Detaliya Têketina Dermanên Nexweşxaneyê,
+Medication Details,Agahdariyên Derman,
+Drug Code,Koda Derman,
+Drug Name,Navê Derman,
+Against Inpatient Medication Order,Li dijî Biryara Dermanên Nexweşan,
+Against Inpatient Medication Order Entry,Li dijî Têketina Biryara Dermanên Nexweşan,
+Inpatient Medication Order,Biryara Dermanên Nexweşan,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Total Orders,
+Completed Orders,Fermanên Temamkirî,
+Add Medication Orders,Fermanên Dermanan Zêde bikin,
+Adding Order Entries,Zêdekirina Entries Order,
+{0} medication orders completed,{0} emrên dermanan qediyan,
+{0} medication order completed,{0} emrê derman qediya,
+Inpatient Medication Order Entry,Navnîşa Biryara Dermanên Nexweşan,
+Is Order Completed,Ferman Qediya ye,
+Employee Records to Be Created By,Qeydên Karmendên Ku Ji hêla Afirandin,
+Employee records are created using the selected field,Qeydên karmendan bi karanîna qada bijartî têne afirandin,
+Don't send employee birthday reminders,Bîranînên rojbûna karmendan neşînin,
+Restrict Backdated Leave Applications,Serîlêdanên Bihêleyên Dîrokkirî Sînorkirin,
+Sequence ID,Nasnameya rêzê,
+Sequence Id,Nasnameya Rêzê,
+Allow multiple material consumptions against a Work Order,Li dijî Biryarnameya Karûbarê destûrê bidin serfermakên gelek maddî,
+Plan time logs outside Workstation working hours,Têketinên demjimêran li derveyî demjimêrên xebata Workstation plan bikin,
+Plan operations X days in advance,Operasyonên X roj pêş plansaz bikin,
+Time Between Operations (Mins),Dema Navbera Operasyonan (Mîn),
+Default: 10 mins,Default: 10 hûrdem,
+Overproduction for Sales and Work Order,Ji bo Firotanê û Karûbarê Karûbarê Zêde,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Mesrefa BOM-ê bi otomatîkî bi rêkûpêkkerê ve nûve bikin, li gorî Rêjeya Nirxandinê / Lîsteya Bihayê Rêjeya / Rêjeya Kirîna Dawîn a materyalên xav",
+Purchase Order already created for all Sales Order items,Biryara Kirînê jixwe ji bo hemî hêmanên Biryara Firotanê hatî afirandin,
+Select Items,Tiştan hilbijêrin,
+Against Default Supplier,Li dijî Pêşkêşkera Default,
+Auto close Opportunity after the no. of days mentioned above,Otêlê piştî no. rojên li jor behs kirin,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Biryara Firotanê Ji bo Afirandina Bihaya Firotanê & Têbîna Deliverê Pêdivî ye?,
+Is Delivery Note Required for Sales Invoice Creation?,Ma Ji bo Afirandina Fatûra Firotanê Têbînî Delivery Pêdivî ye?,
+How often should Project and Company be updated based on Sales Transactions?,Divê Proje û Pargîdanî li ser bingeha Danûstandinên Firotanê çend caran werin nûve kirin?,
+Allow User to Edit Price List Rate in Transactions,Di Danûstandinan de Destûr Bikin ku Bikarhêner Rêjeya Lîsteya Bihayê Biguherîne,
+Allow Item to Be Added Multiple Times in a Transaction,Di Danûstendinê de Bihêlin Destûrê bide Tiştê ku Çend caran Zêde Bikin,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Li dijî Biryara Kirîna Xerîdarek Destûrê bidin Pir Biryarên Firotinê,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Li dijî Rêjeya Kirînê an Rêjeya Nirxandinê Bihayê Firotinê Ji Bo Tiştê Rast bikin,
+Hide Customer's Tax ID from Sales Transactions,Nasnameya Baca Xerîdar ji Danûstandinên Firotanê Veşêre,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Rêjeya ku hûn li hember mîqdara fermankirî bêtir destûr têne girtin an radest kirin. Mînakî, heke we 100 yekîneyên ferman dane, û Alîkariya we% 10 e, wê hingê hûn destûr têne girtin ku 110 yekîneyan bistînin.",
+Action If Quality Inspection Is Not Submitted,Çalak Ger Ger Kontrola Kalîteyê Neyê andin,
+Auto Insert Price List Rate If Missing,Ger Nedît Rêjeya Lîsteya Bihayê Bixwe Bikin,
+Automatically Set Serial Nos Based on FIFO,Jixweber Serî Nîşeyên Li gorî FIFO saz bikin,
+Set Qty in Transactions Based on Serial No Input,Di danûstandinên li ser bingeha nexşeya serial de Qty danîne,
+Raise Material Request When Stock Reaches Re-order Level,Daxwaza Materyalê Bilind Bikin Gava Stock Bihêst Asta Dîsa-Rêzkirin,
+Notify by Email on Creation of Automatic Material Request,Li ser Afirandina Daxwaza Materyalê ya Otomatîk bi E-nameyê agahdar bikin,
+Allow Material Transfer from Delivery Note to Sales Invoice,Destûrê bide Veguheztina Madeyê ji Nîşeya Radestkirinê li Fatûra Firotanê,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Destûrê bide Veguheztina Madeyê ji Meqaleya Kirînê ji bo Fatûra Kirînê,
+Freeze Stocks Older Than (Days),Stokên Kevn Ji (Rojan) Bidomînin,
+Role Allowed to Edit Frozen Stock,Rola Destûrdayîn Ji Bo Serastkirina Frozen Stock,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Mêjera nevekirî ya Têketina Deynê {0} ji mîqdara nevekirî ya Danûstendina Bankê mezintire,
+Payment Received,Dayîn hate wergirtin,
+Attendance cannot be marked outside of Academic Year {0},Beşdarî li derveyî Sala Akademîk nayê nîşankirin {0},
+Student is already enrolled via Course Enrollment {0},Xwendekar jixwe bi navnîşkirina qursê ve hatî tomar kirin {0},
+Attendance cannot be marked for future dates.,Beşdarî ji bo tarîxên pêşerojê nayê nîşankirin.,
+Please add programs to enable admission application.,Ji kerema xwe bernameyan zêde bikin ku serîlêdana destûrnameyê çalak bikin.,
+The following employees are currently still reporting to {0}:,Karmendên jêrîn niha jî ji {0} re rapor dikin:,
+Please make sure the employees above report to another Active employee.,Ji kerema xwe karmendên li jor ji karkerekî Çalak ê din re ragihînin.,
+Cannot Relieve Employee,Nekare Xebatkarê Rehet Bike,
+Please enter {0},Ji kerema xwe {0} binivîse,
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Ji kerema xwe rêbaza dravdanek din hilbijêrin. Mpesa danûstendinên bi dirava '{0}' piştgirî nake,
+Transaction Error,Çewtiya Tevgerê,
+Mpesa Express Transaction Error,Çewtiya Danûstendina Mpesa Express,
+"Issue detected with Mpesa configuration, check the error logs for more details","Pirsgirêka bi veavakirina Mpesa ve hate dîtin, ji bo bêtir agahdariyê têketinên çewtiyê kontrol bikin",
+Mpesa Express Error,Çewtiya Expressê ya Mpesa,
+Account Balance Processing Error,Çewtiya Pêvajoya Bilaniya Hesabê,
+Please check your configuration and try again,Ji kerema xwe veavakirina xwe kontrol bikin û dîsa biceribînin,
+Mpesa Account Balance Processing Error,Çewtiya Pêvajoya Bilaniya Hesabê Mpesa,
+Balance Details,Agahdariyên Balance,
+Current Balance,Bîlançoya heyî,
+Available Balance,Bîlançoya berdest,
+Reserved Balance,Bilaniya Reserve,
+Uncleared Balance,Bîlançoya Nediyar,
+Payment related to {0} is not completed,Dravdayîna têkildarî {0} neqediyaye,
+Row #{}: Item Code: {} is not available under warehouse {}.,Rêzeya # {}: Koda Tiştê: {} di bin embarê de tune ye {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Rêzok # {}: Hêjmara pargîdaniyê ji bo Code Code têr nake: {} di bin embarê de {}. Hêjmara heyî {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Rêzok # {}: Ji kerema xwe li dijî hejmar rêzeyek û rêzek hilbijêrin: {} an jî wê hilînin da ku danûstendinê biqedînin.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Rêzok # {}: Li hember hêmanê jimareyek rêzeyî nehatiye hilbijartin: {}. Ji kerema xwe yekê hilbijêrin an jê bikin da ku danûstendinê biqedînin.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Rêzok # {}: Tu komek li hember tiştê nehatî hilbijartin: {}. Ji kerema xwe komek hilbijêrin an jê bikin da ku danûstendinê biqedînin.,
+Payment amount cannot be less than or equal to 0,Mîqdara dravê nikare ji 0-an kêmtir be an jî wekhev be,
+Please enter the phone number first,Ji kerema xwe pêşî jimara têlefonê binivîsin,
+Row #{}: {} {} does not exist.,Rêza # {}: {} {} tune.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Rêzeya # {0}: Ji bo afirandina Vekirina {2} Fatûreyan {1} pêdivî ye,
+You had {} errors while creating opening invoices. Check {} for more details,Di afirandina fatûrên vekirinê de {} xeletiyên we hebûn. Ji bo bêtir agahdariyê {} bigerin,
+Error Occured,Çewtî rû da,
+Opening Invoice Creation In Progress,Vekirina Afirandina Fatûrê Di Pêş ve,
+Creating {} out of {} {},Afirandina {} ji {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Hejmara rêzê: {0}) nayê vexwarin ji ber ku ew ji bo dagirtina Biryara Firotanê {1} ye.,
+Item {0} {1},Tişt {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Danûstendina Stockê ya Dawîn ji bo tiştê {0} di bin embarê de {1} li ser {2} bû.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Danûstendinên Stockê ji bo Hêmana {0} di bin embarê de {1} berî vê demê nayê şandin.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Ingandina danûstandinên firotanê yên pêşerojê ji ber Ledger-a Guhestbar nayê destûr kirin,
+A BOM with name {0} already exists for item {1}.,BOM-a bi navê {0} ji bo hêmanê {1} berê heye.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} We navê tiştê nav kir? Ji kerema xwe bi desteka Administrator / Teknîkî re têkilî daynin,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Li rêza # {0}: nasnameya rêzê {1} nikare ji nasnameya rêza berê ya berê kêmtir be {2},
+The {0} ({1}) must be equal to {2} ({3}),Divê {0} ({1}) bi {2} ({3}) re wekhev be,
+"{0}, complete the operation {1} before the operation {2}.","{0}, operasyonê {1} berî operasyonê temam bikin {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,Çawa ku Hêmana {0} bi û bêyî Zêdekirina Zînayê bi Rêzeya Nêzîk ve hatî zêdekirin nikare radestkirina bi Hejmara Rêzeyê piştrast bike.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Hêjeya rêzeya {0} tune. Tenê tiştên rêzkirî dikarin li gorî Rêzeya Serial radest bibin,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,BOM-a çalak ji bo tiştê {0} nehat dîtin. Radestkirina ji hêla Serial No ve nayê piştrast kirin,
+No pending medication orders found for selected criteria,Ji bo krîterên bijarte ti fermanên dermankirinê yên li bendê nayên dîtin,
+From Date cannot be after the current date.,Ji Dîrok nikare piştî roja heyî be.,
+To Date cannot be after the current date.,To Date nikare piştî roja heyî be.,
+From Time cannot be after the current time.,Ji Wext nikare li dû dema niha be.,
+To Time cannot be after the current time.,To Time nikare li dû dema niha be.,
+Stock Entry {0} created and ,Stock Entry {0} afirandin û,
+Inpatient Medication Orders updated successfully,Fermanên Dermanên Nexweşxaneyê bi serfirazî nûve kirin,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Rêza {0}: Li dijî Biryara Tiba Bijî ya Nexweşxaneyê Têketina Dermanên Nexweşxaneyê nayê afirandin {1},
+Row {0}: This Medication Order is already marked as completed,Rêza {0}: Vê Fermana Derman jixwe wekî qediyayî nîşankirî ye,
+Quantity not available for {0} in warehouse {1},Hêjmar ji bo {0} li depo {1} tune,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Ji kerema xwe Destûra Negatîfek Bişkojk di Mîhengên Bişkojkê de çalak bikin an Bişêwira Stock-ê biafirînin da ku berdewam bike.,
+No Inpatient Record found against patient {0},Li dijî nexweş tomarek Nexweşxaneyê nehat dîtin {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Biryarnameyek Dermanên Nexweşxaneyê {0} li dijî Hevdîtina Nexweşan {1} jixwe heye.,
+Allow In Returns,Di Vegerê de Destûrê bide,
+Hide Unavailable Items,Tiştên Çêdibe Veşêre,
+Apply Discount on Discounted Rate,Li Rêjeya Daxistî Dakêşan Bikin,
+Therapy Plan Template,Planablon Plana Terapiyê,
+Fetching Template Details,Fetching Details Details,
+Linked Item Details,Agahdariyên Tişkî Giredayî,
+Therapy Types,Cureyên Terapiyê,
+Therapy Plan Template Detail,Detail plateablon a Plana Terapiyê,
+Non Conformance,Ne Lihevhatin,
+Process Owner,Xwediyê Pêvajoyê,
+Corrective Action,Çalakiya Ragihandinê,
+Preventive Action,Çalakiya Pêşîlêgir,
+Problem,Pirsegirêk,
+Responsible,Berpirsîyare,
+Completion By,Temamkirin Ji hêla,
+Process Owner Full Name,Xwediyê Pêvajoyê Navê Tevahî,
+Right Index,Indeksa Rast,
+Left Index,Indeksa Çep,
+Sub Procedure,Bû prosedure,
+Passed,Derbas bû,
+Print Receipt,Receipt Print,
+Edit Receipt,Receipt biguherînin,
+Focus on search input,Li ser input lêgerîn bisekinin,
+Focus on Item Group filter,Li ser Parzûna Koma Item bisekinin,
+Checkout Order / Submit Order / New Order,Biryarnameya Kirînê / Biryarnameyê / Biryara Nû bişînin,
+Add Order Discount,Zencîreya Rêzê zêde bikin,
+Item Code: {0} is not available under warehouse {1}.,Koda Tiştê: {0} di bin embarê de tune {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Hejmarên rêzê ji bo Hêmana {0} di bin embarê de {1} tune. Ji kerema xwe ambaran biguherînin.,
+Fetched only {0} available serial numbers.,Tenê {0} hejmarên rêzê yên berdest hatin stendin.,
+Switch Between Payment Modes,Di Navbera Modên Peredanê de Guherîn,
+Enter {0} amount.,Hejmara {0} binivîse.,
+You don't have enough points to redeem.,Ji we re xalên ku hûn xilas bikin têr nakin.,
+You can redeem upto {0}.,Hûn dikarin heya {0} bikar bînin.,
+Enter amount to be redeemed.,Hejmara ku were xilas kirin têkevinê.,
+You cannot redeem more than {0}.,Hûn nekarin ji {0} pirtirîn bikirin.,
+Open Form View,Dîtina Formê Vekin,
+POS invoice {0} created succesfully,Fatura POS-ê {0} bi serfirazî hate afirandin,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Hêjmara pargîdaniyê ji bo Koda Tiştê têr nake: {0} bin embarê {1} Hejmara heyî {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Hejmara rêzê: {0} berê li Fatûreya POS-a din hatiye veguhastin.,
+Balance Serial No,Hejmara Rêzeya Hevsengiyê,
+Warehouse: {0} does not belong to {1},Warehouse: {0} ne ya {1} e,
+Please select batches for batched item {0},Ji kerema xwe ji bo pargîdaniya pargîdanî komek hilbijêrin {0},
+Please select quantity on row {0},Ji kerema xwe hejmar li ser rêzê hilbijêrin {0},
+Please enter serial numbers for serialized item {0},Ji kerema xwe jimarên rêzê ji bo hêjmara rêzkirî binivîse {0},
+Batch {0} already selected.,Koma {0} jixwe hilbijartî.,
+Please select a warehouse to get available quantities,Ji kerema xwe embarek hilbijêrin da ku mîqdarên berdest bistînin,
+"For transfer from source, selected quantity cannot be greater than available quantity","Ji bo veguhastina ji çavkaniyê, mîqdara bijarte ji hejmaiya berdest mezintir nabe",
+Cannot find Item with this Barcode,Bi vê Barkodê Nikarin Tiştê bibînin,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} mecbûrî ye. Dibe ku tomara Danûstandina Pereyê ji bo {1} heya {2} neyê afirandin,
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} hebûnên pê ve girêdayî ve şandiye. Hûn hewce ne ku sermayeyan betal bikin da ku vegera kirînê çêbikin.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Nikare vê belgeyê betal bike ji ber ku bi sermayeya şandî ve girêdayî ye {0}. Ji kerema xwe wê betal bikin ku berdewam bike.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Rêzok # {}: Hejmara rêzê. {} Jixwe li Fatûreya POS-a din hatiye veguheztin. Ji kerema xwe serial no derbasdar hilbijêrin.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Rêza # {}: Hejmarên rêzê. {} Berê jî li Fatûreya POS-a din hate veguheztin. Ji kerema xwe serial no derbasdar hilbijêrin.,
+Item Unavailable,Tişt Nayê,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Rêzok # {}: Serial No {} nayê vegerandin ji ber ku di fatûreya orjînal de nehatiye peywirdarkirin {},
+Please set default Cash or Bank account in Mode of Payment {},Ji kerema xwe Dravê Dravê an Bankê ya pêşdibistanê di Awayê dayinê de saz bikin {},
+Please set default Cash or Bank account in Mode of Payments {},Ji kerema xwe Dravê Dravê an Bankê ya pêşdibistanê di Awayê Payments de saz bikin {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Ji kerema xwe hesabê {} hesabek Bilanî ye. Hûn dikarin hesabê dêûbav bi hesabek Bilanço biguherînin an jî hesabek cûda hilbijêrin.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Ji kerema xwe hesabê {} hesabek Payable ye. Celebê hesabê bi Payable-ê biguherînin an jî hesabek cûda hilbijêrin.,
+Row {}: Expense Head changed to {} ,Rêz {}: Serê Lêçûnê hate guherandin bo {},
+because account {} is not linked to warehouse {} ,ji ber ku hesabê {} bi embarê ve nehatiye girêdan {},
+or it is not the default inventory account,an ew ne hesabê envanterê yê pêşdibistanê ye,
+Expense Head Changed,Serê Lêçûn Guherî,
+because expense is booked against this account in Purchase Receipt {},ji ber ku lêçûn li dijî vê hesabê di Rastnameya Kirînê de tê veqetandin {},
+as no Purchase Receipt is created against Item {}. ,ji ber ku li dijî Qanûna Kirînê li dijî Item {} nayê çêkirin.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Ev tête kirin ku ji bo hesabkirina dozên dema Receival Kirînê piştî Fatûra Kirînê tê afirandin,
+Purchase Order Required for item {},Siparîşa Kirînê Ji bo tiştê Pêdivî ye {},
+To submit the invoice without purchase order please set {} ,Ji bo ku fatoreya bêyî kirîna kirînê bişînin ji kerema xwe {} saz bikin,
+as {} in {},wekî {} li {},
+Mandatory Purchase Order,Biryara Kirînê ya Bicîh,
+Purchase Receipt Required for item {},Wergirtina Kirînê Ji bo tiştê Pêdivî ye {},
+To submit the invoice without purchase receipt please set {} ,Ji bo ku fatûreya bêyî meqbûza kirînê bişînin ji kerema xwe {} saz bikin,
+Mandatory Purchase Receipt,Wergirtina Kirîna Derveyî,
+POS Profile {} does not belongs to company {},POS Profile {} ne ya pargîdaniyê ye {},
+User {} is disabled. Please select valid user/cashier,Bikarhêner {} neçalak e. Ji kerema xwe bikarhêner / kerekî derbasdar hilbijêrin,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Rêzok # {}: Fatûra Eslî {} fatura vegerê {} e {}.,
+Original invoice should be consolidated before or along with the return invoice.,Divê fatûreya orjînal berî an digel fatûreya vegerê were yek kirin.,
+You can add original invoice {} manually to proceed.,Hûn dikarin faturaya xwerû {} bi destan lê zêde bikin ku berdewam bikin.,
+Please ensure {} account is a Balance Sheet account. ,Ji kerema xwe hesabê {} hesabek Bilanî ye.,
+You can change the parent account to a Balance Sheet account or select a different account.,Hûn dikarin hesabê dêûbav bi hesabek Bilanço biguherînin an jî hesabek cûda hilbijêrin.,
+Please ensure {} account is a Receivable account. ,Ji kerema xwe hesabê {} hesabek wergirî ye.,
+Change the account type to Receivable or select a different account.,Cûreyek hesabê biguhezînin Receiveable an hesabek cûda hilbijêrin.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} ji ber ku Pûanên Dilsoziyê yên hatine bidestxistin hate xilas kirin nayê betalkirin. Pêşîn {} Na {} betal bikin,
+already exists,Jixwe heye,
+POS Closing Entry {} against {} between selected period,Di navbera heyama bijartî de Têketina Girtî ya POS {} dijî {},
+POS Invoice is {},Fatûra POS {} e,
+POS Profile doesn't matches {},Profîla POS-ê li hev nake {},
+POS Invoice is not {},Fatura POS ne {},
+POS Invoice isn't created by user {},POS Fature ji hêla bikarhêner ve nayê afirandin {},
+Row #{}: {},Rêzeya # {}: {},
+Invalid POS Invoices,Fatûrên POS-ê yên nederbasdar,
+Please add the account to root level Company - {},Ji kerema xwe hesabê li asta rootirket zêde bikin - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Dema ku ji bo Pargîdaniya Zarok hesab çêdikir {0}, hesabê dêûbav {1} nehat dîtin. Ji kerema xwe hesabê dêûbav di COA-ya têkildar de çêbikin",
+Account Not Found,Hesab nehat dîtin,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Dema ku hesabê ji bo Pargîdaniya Zarok çêdikir {0}, hesabê dêûbav {1} wekî hesabek pirtûkê hate dîtin.",
+Please convert the parent account in corresponding child company to a group account.,Ji kerema xwe hesabê dêûbavê di pargîdaniya zarokan a pêwendîdar de veguherînin hesabek komê.,
+Invalid Parent Account,Hesabê Dêûbavê Neheq e,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Navnîşkirina wê tenê bi navgîniya pargîdaniya dêûbav {0} ve tête destûr kirin, da ku ji hevnêzîkbûnê dûr bikeve.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Heke hûn {0} {1} mîqdarên tiştê {2} bikin, dê şemaya {3} li ser tiştê were sepandin.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ger hûn {0} {1} hêjayî hêmanê ne {2}, dê şemaya {3} li ser tiştê were sepandin.",
+"As the field {0} is enabled, the field {1} is mandatory.","Ji ber ku qada {0} çalak e, qada {1} ferz e.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Ji ber ku qada {0} çalak e, divê nirxa qada {1} ji 1-ê zêdetir be.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Çênabe Serial No {0} alavê {1} radest bike ji ber ku ew ji bo dagirtina Biryara Firotanê veqetandî ye {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Fermana Firotanê {0} ji bo tiştê {1} rezervasyon heye, hûn tenê dikarin li hember {0} rezerva {1} bidin.",
+{0} Serial No {1} cannot be delivered,{0} Serial No {1} nayê şandin,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Rêz {0}: Tişta taşeron ji bo madeya xav mecbûrî ye {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Ji ber ku materyalên xav ên têra xwe hene, Ji bo Warehouse {0} Daxwaza Materyalê ne hewce ye.",
+" If you still want to proceed, please enable {0}.","Heke hûn hîn jî dixwazin berdewam bikin, ji kerema xwe {0} çalak bikin.",
+The item referenced by {0} - {1} is already invoiced,Tişta ku ji hêla {0} - {1} ve hatî referans kirin jixwe fatûre ye,
+Therapy Session overlaps with {0},Danişîna Terapiyê bi {0} re li hevûdu dike,
+Therapy Sessions Overlapping,Danişînên Terapiyê Li Hev Dikevin,
+Therapy Plans,Planên Terapiyê,
+"Item Code, warehouse, quantity are required on row {0}","Koda tiştê, embarê, hejmar li ser rêzê hewce ne {0}",
+Get Items from Material Requests against this Supplier,Li dijî vê Pêşkêşkerê Tiştan ji Daxwazên Maddî bistînin,
+Enable European Access,Destûra Ewropî çalak bikin,
+Creating Purchase Order ...,Afirandina Biryara Kirînê ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Ji Pargîdaniyên Pêşwext ên jêrîn ve Pêşkêşvanek hilbijêrin. Li ser hilbijartinê, dê Biryarnameyek Kirînê li dijî tiştên ku tenê ji Pêşkêşkarê hilbijartî ne pêk were.",
+Row #{}: You must select {} serial numbers for item {}.,Rêzok # {}: Divê hûn {} hejmarên rêzê ji bo hêmanê {} hilbijêrin.,
diff --git a/erpnext/translations/lo.csv b/erpnext/translations/lo.csv
index a72a7cd..b61476c 100644
--- a/erpnext/translations/lo.csv
+++ b/erpnext/translations/lo.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},ພາສີປະເພດທີ່ແທ້ຈິງບໍ່ສາມາດລວມຢູ່ໃນລາຍການຕິດຕໍ່ກັນ {0},
Add,ຕື່ມ,
Add / Edit Prices,ເພີ່ມ / ແກ້ໄຂລາຄາ,
-Add All Suppliers,ຕື່ມການສະຫນອງທັງຫມົດ,
Add Comment,ຕື່ມການຄໍາເຫັນ,
Add Customers,ຕື່ມການລູກຄ້າ,
Add Employees,ຕື່ມການພະນັກງານ,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',ບໍ່ສາມາດຫັກໃນເວລາທີ່ປະເພດແມ່ນສໍາລັບການ 'ປະເມີນມູນຄ່າ' ຫຼື 'Vaulation ແລະລວມ,
"Cannot delete Serial No {0}, as it is used in stock transactions","ບໍ່ສາມາດລົບ Serial No {0}, ຍ້ອນວ່າມັນໄດ້ຖືກນໍາໃຊ້ໃນທຸລະກໍາຫຼັກຊັບ",
Cannot enroll more than {0} students for this student group.,ບໍ່ສາມາດລົງທະບຽນຫຼາຍກ່ວາ {0} ນັກສຶກສາສໍາລັບກຸ່ມນັກສຶກສານີ້.,
-Cannot find Item with this barcode,ບໍ່ສາມາດຊອກຫາລາຍການດ້ວຍລະຫັດບາໂຄ້ດນີ້,
Cannot find active Leave Period,ບໍ່ສາມາດຊອກຫາກໍາໄລໄລຍະເວລາການເຄື່ອນໄຫວ,
Cannot produce more Item {0} than Sales Order quantity {1},ບໍ່ສາມາດຜະລິດສິນຄ້າຫຼາຍ {0} ກ່ວາປະລິມານສັ່ງຂາຍ {1},
Cannot promote Employee with status Left,ບໍ່ສາມາດສົ່ງເສີມພະນັກງານທີ່ມີສະຖານະພາບໄວ້,
Cannot refer row number greater than or equal to current row number for this Charge type,ບໍ່ສາມາດສົ່ງຈໍານວນການຕິດຕໍ່ກັນຫຼາຍກ່ວາຫຼືເທົ່າກັບຈໍານວນການຕິດຕໍ່ກັນໃນປັດຈຸບັນສໍາລັບປະເພດຄ່າໃຊ້ຈ່າຍນີ້,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,ບໍ່ສາມາດເລືອກເອົາປະເພດຄ່າໃຊ້ຈ່າຍເປັນຈໍານວນເງິນຕິດຕໍ່ກັນກ່ອນຫນ້ານີ້ 'ຫລື' ໃນທີ່ຜ່ານມາຕິດຕໍ່ກັນທັງຫມົດສໍາລັບການຕິດຕໍ່ກັນຄັ້ງທໍາອິດ,
-Cannot set a received RFQ to No Quote,ບໍ່ສາມາດກໍານົດໄດ້ຮັບ RFQ ກັບ No ອ້າງ,
Cannot set as Lost as Sales Order is made.,ບໍ່ສາມາດກໍານົດເປັນການສູນເສຍທີ່ເປັນຄໍາສັ່ງຂາຍແມ່ນ.,
Cannot set authorization on basis of Discount for {0},ບໍ່ສາມາດກໍານົດການອະນຸຍາດບົນພື້ນຖານຂອງການ Discount {0},
Cannot set multiple Item Defaults for a company.,ບໍ່ສາມາດຕັ້ງຄ່າ Defaults ຂອງສິນຄ້າຈໍານວນຫລາຍສໍາລັບບໍລິສັດ.,
@@ -521,7 +518,6 @@
Chargeble,ຮັບຜິດຊອບ,
Charges are updated in Purchase Receipt against each item,ຄ່າບໍລິການມີການປັບປຸງໃນການຮັບຊື້ຕໍ່ແຕ່ລະລາຍການ,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","ຄ່າບໍລິການຈະໄດ້ຮັບການແຈກຢາຍໂດຍອີງທຽບໃນຈໍານວນລາຍການຫຼືຈໍານວນເງິນທີ່, ເປັນຕໍ່ການຄັດເລືອກຂອງ",
-Chart Of Accounts,ຕາຕະລາງຂອງການບັນຊີ,
Chart of Cost Centers,ຕາຕະລາງຂອງສູນຕົ້ນທຶນ,
Check all,ກວດເບິ່ງທັງຫມົດ,
Checkout,ກວດເບິ່ງ,
@@ -581,7 +577,6 @@
Compensatory Off,ການຊົດເຊີຍ Off,
Compensatory leave request days not in valid holidays,ວັນທີ່ຕ້ອງການຄ່າຊົດເຊີຍບໍ່ແມ່ນວັນທີ່ຖືກຕ້ອງ,
Complaint,ຄໍາຮ້ອງທຸກ,
-Completed Qty can not be greater than 'Qty to Manufacture',ສໍາເລັດຈໍານວນບໍ່ສາມາດຈະມີຫຼາຍຂຶ້ນກ່ວາ 'ຈໍານວນການຜະລິດ',
Completion Date,ວັນທີ່ສະຫມັກສໍາເລັດ,
Computer,ຄອມພິວເຕີ,
Condition,ສະພາບ,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","ສ້າງແລະຄຸ້ມຄອງປະຈໍາວັນ, ປະຈໍາອາທິດແລະປະຈໍາເດືອນຫົວເລື່ອງອີເມລ໌.",
Create customer quotes,ສ້າງລູກຄ້າ,
Create rules to restrict transactions based on values.,ສ້າງລະບຽບການເພື່ອຈໍາກັດການເຮັດທຸລະກໍາໂດຍອີງໃສ່ຄ່າ.,
-Created By,ສ້າງໂດຍ,
Created {0} scorecards for {1} between: ,ສ້າງ {0} scorecards ສໍາລັບ {1} ລະຫວ່າງ:,
Creating Company and Importing Chart of Accounts,ສ້າງບໍລິສັດແລະ ນຳ ເຂົ້າຕາຕະລາງບັນຊີ,
Creating Fees,ສ້າງຄ່າທໍານຽມ,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,ບໍ່ສາມາດສົ່ງຄືນການໂອນເງິນພະນັກງານກ່ອນວັນທີໂອນ,
Employee cannot report to himself.,ພະນັກງານບໍ່ສາມາດລາຍງານໃຫ້ຕົນເອງ.,
Employee relieved on {0} must be set as 'Left',ພະນັກງານສະບາຍໃຈໃນ {0} ຕ້ອງໄດ້ຮັບການສ້າງຕັ້ງເປັນ 'ຊ້າຍ',
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,ສະຖານະພາບຂອງພະນັກງານບໍ່ສາມາດຖືກຕັ້ງເປັນ 'ຊ້າຍ' ເນື່ອງຈາກວ່າພະນັກງານຕໍ່ໄປນີ້ ກຳ ລັງລາຍງານຕໍ່ພະນັກງານຜູ້ນີ້:,
Employee {0} already submited an apllication {1} for the payroll period {2},ພະນັກງານ {0} ແລ້ວໄດ້ຍື່ນຄໍາປະກາດ {1} ສໍາລັບໄລຍະເວລາການຈ່າຍເງິນ {2},
Employee {0} has already applied for {1} between {2} and {3} : ,ພະນັກງານ {0} ໄດ້ຖືກນໍາໃຊ້ແລ້ວສໍາລັບ {1} ລະຫວ່າງ {2} ແລະ {3}:,
Employee {0} has no maximum benefit amount,ພະນັກງານ {0} ບໍ່ມີເງິນຊ່ວຍເຫຼືອສູງສຸດ,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,ສໍາຫລັບແຖວ {0}: ກະລຸນາໃສ່ qty ວາງແຜນ,
"For {0}, only credit accounts can be linked against another debit entry","{0}, ພຽງແຕ່ລະເງິນກູ້ຢືມສາມາດໄດ້ຮັບການເຊື່ອມຕໍ່ເຂົ້າເດບິດອື່ນ",
"For {0}, only debit accounts can be linked against another credit entry","{0}, ພຽງແຕ່ບັນຊີເດບິດສາມາດເຊື່ອມໂຍງກັບເຂົ້າການປ່ອຍສິນເຊື່ອອີກ",
-Form View,Form View,
Forum Activity,Forum Activity,
Free item code is not selected,ລະຫັດສິນຄ້າບໍ່ຖືກເລືອກ,
Freight and Forwarding Charges,ຂົນສົ່ງສິນຄ້າແລະການສົ່ງຕໍ່ຄ່າບໍລິການ,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ອອກຈາກບໍ່ສາມາດໄດ້ຮັບການຈັດສັນກ່ອນ {0}, ເປັນການດຸ່ນດ່ຽງອອກໄດ້ແລ້ວປະຕິບັດ, ສົ່ງໃນການບັນທຶກການຈັດສັນອອກໃນອະນາຄົດ {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","ອອກຈາກບໍ່ສາມາດໄດ້ຮັບການນໍາໃຊ້ / ຍົກເລີກກ່ອນ {0}, ເປັນການດຸ່ນດ່ຽງອອກໄດ້ແລ້ວປະຕິບັດ, ສົ່ງໃນການບັນທຶກການຈັດສັນອອກໃນອະນາຄົດ {1}",
Leave of type {0} cannot be longer than {1},ອອກຈາກການປະເພດ {0} ບໍ່ສາມາດຈະຕໍ່ໄປອີກແລ້ວກ່ວາ {1},
-Leave the field empty to make purchase orders for all suppliers,ອອກຈາກບ່ອນຫວ່າງເພື່ອເຮັດໃຫ້ຄໍາສັ່ງຊື້ສໍາລັບຜູ້ສະຫນອງທັງຫມົດ,
Leaves,ໃບ,
Leaves Allocated Successfully for {0},ໃບຈັດສັນສົບຜົນສໍາເລັດສໍາລັບການ {0},
Leaves has been granted sucessfully,ໃບໄດ້ຮັບການຍອມຮັບຢ່າງສົມບູນ,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,ບໍ່ມີສິນຄ້າທີ່ມີບັນຊີລາຍການຂອງວັດສະດຸໃນການຜະລິດ,
No Items with Bill of Materials.,ບໍ່ມີສິນຄ້າທີ່ມີໃບບິນຄ່າວັດສະດຸ.,
No Permission,ບໍ່ມີການອະນຸຍາດ,
-No Quote,No ອ້າງ,
No Remarks,ບໍ່ມີຂໍ້ສັງເກດ,
No Result to submit,ບໍ່ມີຜົນການສົ່ງ,
No Salary Structure assigned for Employee {0} on given date {1},ບໍ່ມີໂຄງສ້າງເງິນເດືອນທີ່ມອບຫມາຍໃຫ້ພະນັກງານ {0} ໃນວັນທີ່ກໍານົດ {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,ເງື່ອນໄຂທີ່ທັບຊ້ອນກັນພົບເຫັນລະຫວ່າງ:,
Owner,ເຈົ້າຂອງ,
PAN,PAN,
-PO already created for all sales order items,PO ໄດ້ສ້າງແລ້ວສໍາລັບລາຍການສັ່ງຊື້ທັງຫມົດ,
POS,POS,
POS Profile,ຂໍ້ມູນ POS,
POS Profile is required to use Point-of-Sale,ໂປຼແກຼມ POS ຕ້ອງໃຊ້ Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,ກະລຸນາເລືອກປະເພດຄ່າໃຊ້ຈ່າຍຄັ້ງທໍາອິດ,
Please select Company,ກະລຸນາເລືອກບໍລິສັດ,
Please select Company and Designation,ກະລຸນາເລືອກບໍລິສັດແລະການອອກແບບ,
-Please select Company and Party Type first,ກະລຸນາເລືອກບໍລິສັດແລະພັກປະເພດທໍາອິດ,
Please select Company and Posting Date to getting entries,ກະລຸນາເລືອກບໍລິສັດແລະວັນທີການລົງທືນເພື່ອຮັບເອົາລາຍການ,
Please select Company first,ກະລຸນາເລືອກບໍລິສັດທໍາອິດ,
Please select Completion Date for Completed Asset Maintenance Log,ກະລຸນາເລືອກວັນສໍາເລັດສໍາລັບບັນທຶກການບໍາລຸງຮັກສາທີ່ສົມບູນແລ້ວ,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,ຕິດຕໍ່ກັນ {0}: UOM ປັດໄຈການແປງເປັນການບັງຄັບ,
Row {0}: select the workstation against the operation {1},ແຖວ {0}: ເລືອກເອົາສະຖານທີ່ເຮັດວຽກຕໍ່ການດໍາເນີນງານ {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,ແຖວ {0}: {1} ຈໍານວນ Serial ຈໍາເປັນສໍາລັບລາຍການ {2}. ທ່ານໄດ້ສະຫນອງ {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,ແຖວ {0}: ຕ້ອງມີ {1} ເພື່ອສ້າງການເປີດ {2} ໃບແຈ້ງຫນີ້,
Row {0}: {1} must be greater than 0,ແຖວ {0}: {1} ຕ້ອງຫຼາຍກວ່າ 0,
Row {0}: {1} {2} does not match with {3},ຕິດຕໍ່ກັນ {0}: {1} {2} ບໍ່ກົງກັບ {3},
Row {0}:Start Date must be before End Date,ຕິດຕໍ່ກັນ {0}: ວັນທີ່ເລີ່ມຕ້ອງມີກ່ອນວັນທີ່ສິ້ນສຸດ,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,ສົ່ງອີເມວການທົບທວນການຊ່ວຍເຫຼືອ,
Send Now,ສົ່ງໃນປັດຈຸບັນ,
Send SMS,ສົ່ງ SMS,
-Send Supplier Emails,ສົ່ງອີເມວ Supplier,
Send mass SMS to your contacts,ສົ່ງ SMS ມະຫາຊົນເພື່ອຕິດຕໍ່ພົວພັນຂອງທ່ານ,
Sensitivity,ຄວາມອ່ອນໄຫວ,
Sent,ສົ່ງ,
-Serial #,Serial:,
Serial No and Batch,ບໍ່ມີ Serial ແລະ Batch,
Serial No is mandatory for Item {0},ບໍ່ມີ Serial ເປັນການບັງຄັບສໍາລັບລາຍການ {0},
Serial No {0} does not belong to Batch {1},Serial No {0} ບໍ່ແມ່ນຂອງ {B} {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,ຊື່ຂອງບໍລິສັດຂອງທ່ານສໍາລັບການທີ່ທ່ານຈະຕິດຕັ້ງລະບົບນີ້.,
The number of shares and the share numbers are inconsistent,ຈໍານວນຮຸ້ນແລະຈໍານວນຮຸ້ນແມ່ນບໍ່ສອດຄ່ອງກັນ,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,ບັນຊີປະຕູຜ່ານການຈ່າຍເງິນໃນແຜນ {0} ແມ່ນແຕກຕ່າງກັນຈາກບັນຊີປະຕູຜ່ານການຊໍາລະເງິນໃນຄໍາຮ້ອງຂໍການຊໍາລະເງິນນີ້,
-The request for quotation can be accessed by clicking on the following link,ການຮ້ອງຂໍສໍາລັບວົງຢືມສາມາດໄດ້ຮັບການເຂົ້າເຖິງໄດ້ໂດຍການຄລິກໃສ່ການເຊື່ອມຕໍ່ດັ່ງຕໍ່ໄປນີ້,
The selected BOMs are not for the same item,ໄດ້ແອບເປີ້ນເລືອກບໍ່ໄດ້ສໍາລັບການບໍ່ວ່າຈະເປັນ,
The selected item cannot have Batch,ການລາຍການທີ່ເລືອກບໍ່ສາມາດມີ Batch,
The seller and the buyer cannot be the same,ຜູ້ຂາຍແລະຜູ້ຊື້ບໍ່ສາມາດດຽວກັນ,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},ຈຳ ນວນສ່ວນປະກອບການຊ່ວຍເຫຼືອທີ່ປ່ຽນແປງໄດ້ທັງ ໝົດ {0} ບໍ່ຄວນຈະ ໜ້ອຍ ກວ່າຜົນປະໂຫຍດສູງສຸດ {1},
Total hours: {0},ຊົ່ວໂມງທັງຫມົດ: {0},
Total leaves allocated is mandatory for Leave Type {0},ໃບທັງຫມົດທີ່ຖືກຈັດສັນແມ່ນບັງຄັບໃຫ້ປ່ອຍປະເພດ {0},
-Total weightage assigned should be 100%. It is {0},weightage ທັງຫມົດໄດ້ຮັບມອບຫມາຍຄວນຈະເປັນ 100%. ມັນເປັນ {0},
Total working hours should not be greater than max working hours {0},ຊົ່ວໂມງການເຮັດວຽກທັງຫມົດບໍ່ຄວນຈະມີຫຼາຍກ່ວາຊົ່ວໂມງເຮັດວຽກສູງສຸດ {0},
Total {0} ({1}),ທັງຫມົດ {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'",ທັງຫມົດ {0} ສໍາລັບລາຍການທັງຫມົດເປັນສູນອາດຈະເປັນທີ່ທ່ານຄວນຈະມີການປ່ຽນແປງ 'ແຈກຢາຍຄ່າບໍລິການຂຶ້ນຢູ່ກັບ',
@@ -3316,7 +3299,6 @@
What do you need help with?,ສິ່ງທີ່ທ່ານຈໍາເປັນຕ້ອງຊ່ວຍ?,
What does it do?,ມັນຈະເປັນແນວໃດເຮັດແນວໃດ?,
Where manufacturing operations are carried.,ບ່ອນທີ່ການດໍາເນີນງານການຜະລິດກໍາລັງດໍາເນີນ.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","ໃນຂະນະທີ່ສ້າງບັນຊີ ສຳ ລັບບໍລິສັດເດັກ {0}, ບັນຊີພໍ່ແມ່ {1} ບໍ່ພົບ. ກະລຸນາສ້າງບັນຊີຜູ້ປົກຄອງໃນ COA ທີ່ສອດຄ້ອງກັນ",
White,ສີຂາວ,
Wire Transfer,ການໂອນ,
WooCommerce Products,ຜະລິດຕະພັນ WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} variants ສ້າງ.,
{0} {1} created,{0} {1} ສ້າງ,
{0} {1} does not exist,{0} {1} ບໍ່ມີ,
-{0} {1} does not exist.,{0} {1} ບໍ່ມີຢູ່.,
{0} {1} has been modified. Please refresh.,{0} {1} ໄດ້ຮັບການແກ້ໄຂ. ກະລຸນາໂຫຼດຫນ້າຈໍຄືນ.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} ຍັງບໍ່ທັນໄດ້ສົ່ງສະນັ້ນການດໍາເນີນການບໍ່ສາມາດໄດ້ຮັບການສໍາເລັດ,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} ຖືກທີ່ກ່ຽວຂ້ອງກັບ {2}, ແຕ່ Account ພັກແມ່ນ {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} ບໍ່ໄດ້ຢູ່,
{0}: {1} not found in Invoice Details table,{0}: {1} ບໍ່ພົບເຫັນຢູ່ໃນຕາຕະລາງລາຍລະອຽດໃບແຈ້ງຫນີ້,
{} of {},{} ຂອງ {},
+Assigned To,ການມອບຫມາຍໃຫ້,
Chat,ສົນທະນາ,
Completed By,Completed By,
Conditions,ເງື່ອນໄຂ,
@@ -3506,7 +3488,9 @@
Merge with existing,merge ກັບທີ່ມີຢູ່ແລ້ວ,
Office,ຫ້ອງການ,
Orientation,ປະຖົມນິເທດ,
+Parent,ພໍ່ແມ່,
Passive,ຕົວຕັ້ງຕົວຕີ,
+Payment Failed,ການຊໍາລະເງິນບໍ່ສາມາດ,
Percent,ເປີເຊັນ,
Permanent,ຖາວອນ,
Personal,ສ່ວນບຸກຄົນ,
@@ -3544,7 +3528,6 @@
Company field is required,ຕ້ອງມີພາກສະ ໜາມ ຂອງບໍລິສັດ,
Creating Dimensions...,ກຳ ລັງສ້າງຂະ ໜາດ ...,
Duplicate entry against the item code {0} and manufacturer {1},ການປ້ອນຂໍ້ມູນຊ້ ຳ ກັບລະຫັດສິນຄ້າ {0} ແລະຜູ້ຜະລິດ {1},
-Import Chart Of Accounts from CSV / Excel files,ນຳ ເຂົ້າ Chart Of Accounts ຈາກ CSV / Excel files,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,GSTIN ບໍ່ຖືກຕ້ອງ! ວັດສະດຸປ້ອນທີ່ທ່ານໄດ້ໃສ່ບໍ່ກົງກັບຮູບແບບ GSTIN ສຳ ລັບຜູ້ໃຫ້ບໍລິການ UIN ຫຼືຜູ້ໃຫ້ບໍລິການທີ່ບໍ່ແມ່ນຜູ້ຢູ່ອາໃສ,
Invoice Grand Total,ໃບເກັບເງິນ Grand Total,
Last carbon check date cannot be a future date,ວັນທີກວດກາຄາບອນສຸດທ້າຍບໍ່ສາມາດເປັນວັນທີໃນອະນາຄົດ,
@@ -3556,6 +3539,7 @@
Show {0},ສະແດງ {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","ຕົວລະຄອນພິເສດຍົກເວັ້ນ "-", "#", ".", "/", "{" ແລະ "}" ບໍ່ໄດ້ຖືກອະນຸຍາດໃນຊຸດຊື່",
Target Details,ລາຍລະອຽດເປົ້າ ໝາຍ,
+{0} already has a Parent Procedure {1}.,{0} ມີຂັ້ນຕອນການເປັນພໍ່ແມ່ {1} ແລ້ວ.,
API,API,
Annual,ປະຈໍາປີ,
Approved,ການອະນຸມັດ,
@@ -3572,6 +3556,8 @@
No data to export,ບໍ່ມີຂໍ້ມູນທີ່ຈະສົ່ງອອກ,
Portrait,ຮູບຄົນ,
Print Heading,ຫົວພິມ,
+Scheduler Inactive,Scheduler Inactive,
+Scheduler is inactive. Cannot import data.,ຜູ້ ກຳ ນົດເວລາແມ່ນບໍ່ເຄື່ອນໄຫວ. ບໍ່ສາມາດ ນຳ ເຂົ້າຂໍ້ມູນໄດ້.,
Show Document,ສະແດງເອກະສານ,
Show Traceback,ສະແດງ Traceback,
Video,ວິດີໂອ,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},ສ້າງການກວດກາຄຸນນະພາບ ສຳ ລັບລາຍການ {0},
Creating Accounts...,ການສ້າງບັນຊີ ...,
Creating bank entries...,ກຳ ລັງສ້າງລາຍການທະນາຄານ ...,
-Creating {0},ການສ້າງ {0},
Credit limit is already defined for the Company {0},ຂອບເຂດ ຈຳ ກັດສິນເຊື່ອແມ່ນ ກຳ ນົດໄວ້ແລ້ວ ສຳ ລັບບໍລິສັດ {0},
Ctrl + Enter to submit,Ctrl + Enter ເພື່ອສົ່ງ,
Ctrl+Enter to submit,Ctrl + Enter ເພື່ອສົ່ງ,
@@ -3921,7 +3906,6 @@
Plaid public token error,ຂໍ້ຜິດພາດ token ສາທາລະນະ Plaid,
Plaid transactions sync error,ຂໍ້ຜິດພາດຂອງການເຮັດທຸລະ ກຳ ແບບ Plaid,
Please check the error log for details about the import errors,ກະລຸນາກວດເບິ່ງຂໍ້ມູນບັນທຶກຂໍ້ຜິດພາດກ່ຽວກັບຂໍ້ຜິດພາດຂອງການ ນຳ ເຂົ້າ,
-Please click on the following link to set your new password,ກະລຸນາຄລິກໃສ່ການເຊື່ອມຕໍ່ດັ່ງຕໍ່ໄປນີ້ການຕັ້ງລະຫັດຜ່ານໃຫມ່ຂອງທ່ານ,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,ກະລຸນາສ້າງ <b>ການຕັ້ງຄ່າ DATEV</b> ສຳ ລັບບໍລິສັດ <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,ກະລຸນາສ້າງການປັບການເຂົ້າວາລະສານ ສຳ ລັບ ຈຳ ນວນເງິນ {0},
Please do not create more than 500 items at a time,ກະລຸນາຢ່າສ້າງຫຼາຍກວ່າ 500 ລາຍການໃນຄັ້ງດຽວ,
@@ -3997,6 +3981,7 @@
Release date must be in the future,ວັນທີປ່ອຍຕ້ອງຢູ່ໃນອະນາຄົດ,
Relieving Date must be greater than or equal to Date of Joining,ວັນທີຜ່ອນຄາຍຕ້ອງມີຂະ ໜາດ ໃຫຍ່ກວ່າຫຼືເທົ່າກັບວັນເຂົ້າຮ່ວມ,
Rename,ປ່ຽນຊື່,
+Rename Not Allowed,ປ່ຽນຊື່ບໍ່ອະນຸຍາດ,
Repayment Method is mandatory for term loans,ວິທີການຈ່າຍຄືນແມ່ນ ຈຳ ເປັນ ສຳ ລັບການກູ້ຢືມໄລຍະ,
Repayment Start Date is mandatory for term loans,ວັນທີເລີ່ມຕົ້ນການຈ່າຍຄືນແມ່ນ ຈຳ ເປັນ ສຳ ລັບການກູ້ຢືມໄລຍະ,
Report Item,ລາຍງານລາຍການ,
@@ -4043,7 +4028,6 @@
Select All,ເລືອກທັງຫມົດ,
Select Difference Account,ເລືອກບັນຊີຄວາມແຕກຕ່າງ,
Select a Default Priority.,ເລືອກບູລິມະສິດ Default.,
-Select a Supplier from the Default Supplier List of the items below.,ເລືອກຜູ້ສະ ໜອງ ສິນຄ້າຈາກບັນຊີລາຍຊື່ຜູ້ສະ ໜອງ ສິນຄ້າໃນເບື້ອງຕົ້ນຂອງລາຍການຂ້າງລຸ່ມນີ້.,
Select a company,ເລືອກບໍລິສັດ,
Select finance book for the item {0} at row {1},ເລືອກປື້ມການເງິນ ສຳ ລັບລາຍການ {0} ຢູ່ແຖວ {1},
Select only one Priority as Default.,ເລືອກເອົາ ໜຶ່ງ ສິ່ງບູລິມະສິດເປັນຄ່າເລີ່ມຕົ້ນ.,
@@ -4247,7 +4231,6 @@
Actual ,ທີ່ແທ້ຈິງ,
Add to cart,ຕື່ມການກັບໂຄງຮ່າງການ,
Budget,ງົບປະມານ,
-Chart Of Accounts Importer,ຜູ້ ນຳ ເຂົ້າບັນຊີ,
Chart of Accounts,Chart Of Accounts,
Customer database.,ຖານຂໍ້ມູນລູກຄ້າ.,
Days Since Last order,ວັນນັບຕັ້ງແຕ່ສັ່ງຫຼ້າສຸດ,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,ວັນສິ້ນສຸດບໍ່ສາມາດນ້ອຍກວ່າວັນເລີ່ມຕົ້ນ,
For Default Supplier (Optional),ສໍາລັບຜູ້ໃຫ້ບໍລິການມາດຕະຖານ (ທາງເລືອກ),
From date cannot be greater than To date,ຈາກວັນທີບໍ່ສາມາດຈະມີຫຼາຍຂຶ້ນກ່ວາເຖິງວັນທີ່,
-Get items from,ໄດ້ຮັບການລາຍການຈາກ,
Group by,ກຸ່ມໂດຍ,
In stock,ໃນສາງ,
Item name,ຊື່ສິນຄ້າ,
@@ -4532,32 +4514,22 @@
Accounts Settings,ບັນຊີ Settings,
Settings for Accounts,ການຕັ້ງຄ່າສໍາລັບການບັນຊີ,
Make Accounting Entry For Every Stock Movement,ເຮັດໃຫ້ການເຂົ້າບັນຊີສໍາຫລັບທຸກການເຄື່ອນໄຫວ Stock,
-"If enabled, the system will post accounting entries for inventory automatically.","ຖ້າຫາກວ່າເປີດການໃຊ້ງານ, ລະບົບຈະສະແດງການອອກສຽງການບັນຊີສໍາລັບສິນຄ້າຄົງຄັງອັດຕະໂນມັດ.",
-Accounts Frozen Upto,ບັນຊີ Frozen ເກີນ,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","ເຂົ້າບັນຊີ frozen ເຖິງວັນນີ້, ບໍ່ມີໃຜສາມາດເຮັດໄດ້ / ປັບປຸງແກ້ໄຂການເຂົ້າຍົກເວັ້ນພາລະບົດບາດທີ່ລະບຸໄວ້ຂ້າງລຸ່ມນີ້.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,ພາລະບົດບາດອະນຸຍາດໃຫ້ກໍານົດບັນຊີ Frozen ແລະແກ້ໄຂການອອກສຽງ Frozen,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,ຜູ້ໃຊ້ທີ່ມີພາລະບົດບາດນີ້ໄດ້ຖືກອະນຸຍາດໃຫ້ສ້າງຕັ້ງບັນຊີ frozen ແລະສ້າງ / ປັບປຸງແກ້ໄຂການອອກສຽງການບັນຊີກັບບັນຊີ frozen,
Determine Address Tax Category From,ກຳ ນົດປະເພດພາສີທີ່ຢູ່ຈາກ,
-Address used to determine Tax Category in transactions.,ທີ່ຢູ່ໃຊ້ໃນການ ກຳ ນົດ ໝວດ ພາສີໃນການເຮັດທຸລະ ກຳ.,
Over Billing Allowance (%),ເກີນ ກຳ ນົດໃບເກັບເງິນ (%),
-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 for $110.,ເປີເຊັນທີ່ທ່ານໄດ້ຮັບອະນຸຍາດໃຫ້ເກັບໃບບິນຫຼາຍກວ່າ ຈຳ ນວນທີ່ສັ່ງ. ຕົວຢ່າງ: ຖ້າມູນຄ່າການສັ່ງສິນຄ້າແມ່ນ $ 100 ສຳ ລັບສິນຄ້າແລະຄວາມທົນທານໄດ້ຖືກ ກຳ ນົດເປັນ 10% ແລ້ວທ່ານຈະໄດ້ຮັບອະນຸຍາດໃຫ້ເກັບເງີນເປັນ 110 ໂດລາ.,
Credit Controller,ຄວບຄຸມການປ່ອຍສິນເຊື່ອ,
-Role that is allowed to submit transactions that exceed credit limits set.,ພາລະບົດບາດທີ່ຖືກອະນຸຍາດໃຫ້ສົ່ງການທີ່ເກີນຂອບເຂດຈໍາກັດການປ່ອຍສິນເຊື່ອທີ່ກໍານົດໄວ້.,
Check Supplier Invoice Number Uniqueness,ການກວດສອບຜະລິດ Invoice ຈໍານວນເປັນເອກະລັກ,
Make Payment via Journal Entry,ເຮັດໃຫ້ການຊໍາລະເງິນໂດຍຜ່ານການອະນຸທິນ,
Unlink Payment on Cancellation of Invoice,Unlink ການຊໍາລະເງິນກ່ຽວກັບການຍົກເລີກການໃບເກັບເງິນ,
-Unlink Advance Payment on Cancelation of Order,ຍົກເລີກການຈ່າຍລ່ວງ ໜ້າ ກ່ຽວກັບການຍົກເລີກການສັ່ງຊື້,
Book Asset Depreciation Entry Automatically,ປື້ມບັນ Asset Entry ຄ່າເສື່ອມລາຄາອັດຕະໂນມັດ,
Automatically Add Taxes and Charges from Item Tax Template,ເພີ່ມພາສີແລະຄ່າບໍລິການໂດຍອັດຕະໂນມັດຈາກແມ່ແບບລາຍການພາສີ,
Automatically Fetch Payment Terms,ດຶງຂໍ້ມູນເງື່ອນໄຂການຈ່າຍເງິນໂດຍອັດຕະໂນມັດ,
-Show Inclusive Tax In Print,ສະແດງພາສີລວມໃນການພິມ,
Show Payment Schedule in Print,ສະແດງຕາຕະລາງການຊໍາລະເງິນໃນການພິມ,
Currency Exchange Settings,ການຕັ້ງຄ່າແລກປ່ຽນສະກຸນເງິນ,
Allow Stale Exchange Rates,ອະນຸຍາດໃຫ້ອັດຕາແລກປ່ຽນຂອງ Stale,
Stale Days,Stale Days,
Report Settings,Report Settings,
Use Custom Cash Flow Format,ໃຊ້ Custom Flow Format Format,
-Only select if you have setup Cash Flow Mapper documents,ພຽງແຕ່ເລືອກຖ້າຫາກທ່ານມີເອກະສານສະຫຼັບ Cash Flow Mapper,
Allowed To Transact With,ອະນຸຍາດໃຫ້ກັບການເຮັດວຽກດ້ວຍ,
SWIFT number,ເລກ SWIFT,
Branch Code,ລະຫັດສາຂາ,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS ກຸ່ມລູກຄ້າ,
POS Field,POS Field,
POS Item Group,ກຸ່ມສິນຄ້າ POS,
-[Select],[ເລືອກ],
Company Address,ທີ່ຢູ່ບໍລິສັດ,
Update Stock,ຫລັກຊັບ,
Ignore Pricing Rule,ບໍ່ສົນໃຈກົດລະບຽບການຕັ້ງລາຄາ,
@@ -5495,8 +5466,6 @@
Supplier Naming By,ຜູ້ຜະລິດໂດຍຊື່,
Default Supplier Group,Default Supplier Group,
Default Buying Price List,ມາດຕະຖານບັນຊີການຊື້ລາຄາ,
-Maintain same rate throughout purchase cycle,ຮັກສາອັດຕາການດຽວກັນຕະຫຼອດວົງຈອນການຊື້,
-Allow Item to be added multiple times in a transaction,ອະນຸຍາດໃຫ້ສິນຄ້າທີ່ຈະເພີ່ມເວລາຫຼາຍໃນການເປັນ,
Backflush Raw Materials of Subcontract Based On,Backflush ວັດຖຸດິບຂອງ Subcontract Based On,
Material Transferred for Subcontract,ການໂອນສິນຄ້າສໍາລັບການເຮັດສັນຍາຍ່ອຍ,
Over Transfer Allowance (%),ເກີນໂອນເງິນອຸດ ໜູນ (%),
@@ -5540,7 +5509,6 @@
Current Stock,Stock ປັດຈຸບັນ,
PUR-RFQ-.YYYY.-,PUR-RFQ-yYYY.-,
For individual supplier,ສໍາລັບການສະຫນອງບຸກຄົນ,
-Supplier Detail,ຂໍ້ມູນຈໍາຫນ່າຍ,
Link to Material Requests,ເຊື່ອມໂຍງກັບການຮ້ອງຂໍດ້ານວັດຖຸ,
Message for Supplier,ຂໍ້ຄວາມສໍາລັບຜູ້ຜະລິດ,
Request for Quotation Item,ການຮ້ອງຂໍສໍາລັບການສະເຫນີລາຄາສິນຄ້າ,
@@ -6481,7 +6449,6 @@
Appraisal Template,ແມ່ແບບການປະເມີນຜົນ,
For Employee Name,ສໍາລັບຊື່ຂອງພະນັກງານ,
Goals,ເປົ້າຫມາຍ,
-Calculate Total Score,ຄິດໄລ່ຄະແນນທັງຫມົດ,
Total Score (Out of 5),ຄະແນນທັງຫມົດ (Out of 5),
"Any other remarks, noteworthy effort that should go in the records.","ໃດຂໍ້ສັງເກດອື່ນໆ, ຄວາມພະຍາຍາມສັງເກດວ່າຄວນຈະຢູ່ໃນບັນທຶກດັ່ງກ່າວ.",
Appraisal Goal,ການປະເມີນຜົນເປົ້າຫມາຍ,
@@ -6599,11 +6566,6 @@
Reason for Leaving,ເຫດຜົນສໍາລັບການຊຶ່ງເຮັດໃຫ້,
Leave Encashed?,ອອກຈາກ Encashed?,
Encashment Date,ວັນທີ່ສະຫມັກ Encashment,
-Exit Interview Details,ລາຍລະອຽດການທ່ອງທ່ຽວສໍາພາດ,
-Held On,ຈັດຂຶ້ນໃນວັນກ່ຽວກັບ,
-Reason for Resignation,ເຫດຜົນສໍາລັບການລາອອກ,
-Better Prospects,ອະນາຄົດທີ່ດີກວ່າ,
-Health Concerns,ຄວາມກັງວົນສຸຂະພາບ,
New Workplace,ຖານທີ່ເຮັດວຽກໃຫມ່,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,ຈຳ ນວນເງິນທີ່ສົ່ງຄືນ,
@@ -6740,10 +6702,7 @@
Employee Settings,ການຕັ້ງຄ່າພະນັກງານ,
Retirement Age,ເງິນກະສຽນອາຍຸ,
Enter retirement age in years,ກະລຸນາໃສ່ອາຍຸບໍານານໃນປີ,
-Employee Records to be created by,ການບັນທຶກຂອງພະນັກງານຈະໄດ້ຮັບການສ້າງຕັ້ງຂື້ນໂດຍ,
-Employee record is created using selected field. ,ການບັນທຶກຂອງພະນັກງານແມ່ນການສ້າງຕັ້ງການນໍາໃຊ້ພາກສະຫນາມການຄັດເລືອກ.,
Stop Birthday Reminders,ຢຸດວັນເດືອນປີເກີດເຕືອນ,
-Don't send Employee Birthday Reminders,ບໍ່ໄດ້ສົ່ງພະນັກງານວັນເດືອນປີເກີດເຕືອນ,
Expense Approver Mandatory In Expense Claim,ໃບອະນຸຍາດຄ່າໃຊ້ຈ່າຍໃນການຮ້ອງຂໍຄ່າໃຊ້ຈ່າຍ,
Payroll Settings,ການຕັ້ງຄ່າ Payroll,
Leave,ອອກຈາກ,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,ອອກຈາກໃບອະນຸຍາດໃນການອອກຄໍາຮ້ອງສະຫມັກ,
Show Leaves Of All Department Members In Calendar,ສະແດງໃບຂອງສະມາຊິກທັງຫມົດໃນປະຕິທິນ,
Auto Leave Encashment,ອັດຕະໂນມັດ,
-Restrict Backdated Leave Application,ຈຳ ກັດ ຄຳ ຮ້ອງສະ ໝັກ ຂໍລາພັກຜ່ອນແບບເກົ່າ,
Hiring Settings,ຈ້າງການຕັ້ງຄ່າ,
Check Vacancies On Job Offer Creation,ກວດສອບການວ່າງວຽກໃນການສ້າງການສະ ເໜີ ວຽກ,
Identification Document Type,Identity Document Type,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,ການຕັ້ງຄ່າການຜະລິດ,
Raw Materials Consumption,ການບໍລິໂພກວັດຖຸດິບ,
Allow Multiple Material Consumption,ອະນຸຍາດໃຫ້ໃຊ້ວັດສະດຸຫຼາຍຊະນິດ,
-Allow multiple Material Consumption against a Work Order,ອະນຸຍາດໃຫ້ນໍາໃຊ້ວັດສະດຸການນໍາໃຊ້ວັດຖຸຫຼາຍຢ່າງຕໍ່ກັບຄໍາສັ່ງການເຮັດວຽກ,
Backflush Raw Materials Based On,ວັດຖຸດິບ Backflush ຖານກ່ຽວກັບ,
Material Transferred for Manufacture,ອຸປະກອນການໂອນສໍາລັບການຜະລິດ,
Capacity Planning,ການວາງແຜນຄວາມອາດສາມາດ,
Disable Capacity Planning,ປິດການວາງແຜນຄວາມສາມາດ,
Allow Overtime,ອະນຸຍາດໃຫ້ເຮັດວຽກລ່ວງເວ,
-Plan time logs outside Workstation Working Hours.,ການວາງແຜນການບັນທຶກທີ່ໃຊ້ເວລານອກຊົ່ວໂມງ Workstation ເຮັດວຽກ.,
Allow Production on Holidays,ອະນຸຍາດໃຫ້ຜະລິດໃນວັນຢຸດ,
Capacity Planning For (Days),ການວາງແຜນຄວາມອາດສາມາດສໍາລັບການ (ວັນ),
-Try planning operations for X days in advance.,ພະຍາຍາມການວາງແຜນການດໍາເນີນງານສໍາລັບມື້ X ໃນການລ່ວງຫນ້າ.,
-Time Between Operations (in mins),ທີ່ໃຊ້ເວລາລະຫວ່າງການປະຕິບັດ (ໃນນາທີ),
-Default 10 mins,ມາດຕະຖານ 10 ນາທີ,
Default Warehouses for Production,ສາງເລີ່ມຕົ້ນ ສຳ ລັບການຜະລິດ,
Default Work In Progress Warehouse,ເຮັດໃນຕອນຕົ້ນໃນ Warehouse Progress,
Default Finished Goods Warehouse,ສໍາເລັດຮູບມາດຕະຖານສິນຄ້າ Warehouse,
Default Scrap Warehouse,ສາງເກັບຂີ້ເຫຍື່ອເລີ່ມຕົ້ນ,
-Over Production for Sales and Work Order,ເກີນການຜະລິດ ສຳ ລັບການຂາຍແລະການສັ່ງເຮັດວຽກ,
Overproduction Percentage For Sales Order,ອັດຕາສ່ວນເກີນມູນຄ່າສໍາລັບຄໍາສັ່ງຂາຍ,
Overproduction Percentage For Work Order,ອັດຕາສ່ວນເກີນມູນຄ່າສໍາລັບຄໍາສັ່ງເຮັດວຽກ,
Other Settings,ການຕັ້ງຄ່າອື່ນໆ,
Update BOM Cost Automatically,Update BOM ຄ່າອັດຕະໂນມັດ,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","ຄ່າໃຊ້ຈ່າຍການປັບປຸງອັດຕະໂນມັດ BOM ຜ່ານ Scheduler, ໂດຍອີງໃສ່ບັນຊີລາຍຊື່ອັດຕາມູນຄ່າ / ລາຄາອັດຕາການ / ອັດຕາການຊື້ຫລ້າສຸດທີ່ຜ່ານມາຂອງວັດຖຸດິບ.",
Material Request Plan Item,Material Request Plan Item,
Material Request Type,ອຸປະກອນການຮ້ອງຂໍປະເພດ,
Material Issue,ສະບັບອຸປະກອນການ,
@@ -7603,10 +7554,6 @@
Quality Goal,ເປົ້າ ໝາຍ ຄຸນນະພາບ,
Monitoring Frequency,ຄວາມຖີ່ຂອງການກວດສອບ,
Weekday,ວັນອາທິດ,
-January-April-July-October,ເດືອນມັງກອນ - ເມສາ - ກໍລະກົດ - ຕຸລາ,
-Revision and Revised On,ການປັບປຸງແລະປັບປຸງ ໃໝ່,
-Revision,ການດັດແກ້,
-Revised On,ປັບປຸງ ໃໝ່,
Objectives,ຈຸດປະສົງ,
Quality Goal Objective,ຈຸດປະສົງເປົ້າ ໝາຍ ຄຸນນະພາບ,
Objective,ຈຸດປະສົງ,
@@ -7619,7 +7566,6 @@
Processes,ຂະບວນການຕ່າງໆ,
Quality Procedure Process,ຂັ້ນຕອນການປະຕິບັດຄຸນນະພາບ,
Process Description,ລາຍລະອຽດຂອງຂະບວນການ,
-Child Procedure,ຂັ້ນຕອນຂອງເດັກ,
Link existing Quality Procedure.,ເຊື່ອມໂຍງຂັ້ນຕອນຄຸນນະພາບທີ່ມີຢູ່.,
Additional Information,ຂໍ້ມູນເພີ່ມເຕີມ,
Quality Review Objective,ຈຸດປະສົງການທົບທວນຄຸນນະພາບ,
@@ -7787,15 +7733,9 @@
Default Customer Group,ມາດຕະຖານກຸ່ມລູກຄ້າ,
Default Territory,ມາດຕະຖານອານາເຂດ,
Close Opportunity After Days,ປິດໂອກາດຫຼັງຈາກວັນ,
-Auto close Opportunity after 15 days,Auto ໃກ້ໂອກາດພາຍໃນ 15 ວັນ,
Default Quotation Validity Days,ວັນທີ Validity Default Quotation,
Sales Update Frequency,Sales Update Frequency,
-How often should project and company be updated based on Sales Transactions.,ບໍລິສັດແລະບໍລິສັດຄວນຈະໄດ້ຮັບການປັບປຸງໂດຍວິທີການຂາຍໄລຍະເວລາເທົ່າໃດ.,
Each Transaction,ແຕ່ລະການເຮັດທຸລະກໍາ,
-Allow user to edit Price List Rate in transactions,ອະນຸຍາດໃຫ້ຜູ້ໃຊ້ເພື່ອແກ້ໄຂລາຄາອັດຕາການທຸລະກໍາ,
-Allow multiple Sales Orders against a Customer's Purchase Order,ອະນຸຍາດໃຫ້ຂາຍສິນຄ້າຫລາຍຕໍ່ການສັ່ງຊື້ຂອງລູກຄ້າເປັນ,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,ກວດສອບລາຄາຂາຍສໍາລັບລາຍການຕໍ່ອັດຕາການຊື້ຫຼືອັດຕາປະເມີນມູນຄ່າ,
-Hide Customer's Tax Id from Sales Transactions,ເຊື່ອງ Id ພາສີຂອງລູກຄ້າຈາກທຸລະກໍາການຂາຍ,
SMS Center,SMS Center,
Send To,ສົ່ງເຖິງ,
All Contact,ທັງຫມົດຕິດຕໍ່,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,ຜູ້ຜະລິດນໍາໃຊ້ໃນການ,
Limited to 12 characters,ຈໍາກັດເຖິງ 12 ລັກສະນະ,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,ຕັ້ງສາງ,
-Sets 'For Warehouse' in each row of the Items table.,ຕັ້ງ 'ສຳ ລັບສາງ' ໃນແຕ່ລະແຖວຂອງຕາຕະລາງສິນຄ້າ.,
-Requested For,ຕ້ອງການສໍາລັບ,
Partially Ordered,ສັ່ງບາງສ່ວນ,
Transferred,ໂອນ,
% Ordered,% ຄໍາສັ່ງ,
@@ -8407,24 +8344,14 @@
Default Stock UOM,ມາດຕະຖານ Stock UOM,
Sample Retention Warehouse,Sample Retention Warehouse,
Default Valuation Method,ວິທີການປະເມີນມູນຄ່າໃນຕອນຕົ້ນ,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,ອັດຕາສ່ວນທີ່ທ່ານກໍາລັງອະນຸຍາດໃຫ້ໄດ້ຮັບຫຼືໃຫ້ຫຼາຍຕໍ່ກັບປະລິມານຂອງຄໍາສັ່ງ. ສໍາລັບການຍົກຕົວຢ່າງ: ຖ້າຫາກວ່າທ່ານມີຄໍາສັ່ງ 100 ຫົວຫນ່ວຍ. ແລະອະນຸຍາດຂອງທ່ານແມ່ນ 10% ຫຼັງຈາກນັ້ນທ່ານກໍາລັງອະນຸຍາດໃຫ້ໄດ້ຮັບ 110 ຫົວຫນ່ວຍ.,
-Action if Quality inspection is not submitted,ການປະຕິບັດຖ້າການກວດກາຄຸນນະພາບບໍ່ຖືກສົ່ງ,
Show Barcode Field,ສະແດງໃຫ້ເຫັນພາກສະຫນາມ Barcode,
Convert Item Description to Clean HTML,ແປງລາຍລະອຽດຂອງລາຍການເພື່ອຄວາມສະອາດ HTML,
-Auto insert Price List rate if missing,ໃສ່ອັດຕະໂນມັດອັດຕາລາຄາຖ້າຫາກວ່າຫາຍສາບສູນ,
Allow Negative Stock,ອະນຸຍາດໃຫ້ລົບ Stock,
Automatically Set Serial Nos based on FIFO,ກໍານົດ Serial Nos ອັດຕະໂນມັດຂຶ້ນຢູ່ກັບ FIFO,
-Set Qty in Transactions based on Serial No Input,ຕັ້ງຄ່າ Qty ໃນການປະຕິບັດການໂດຍອີງໃສ່ການນໍາເຂົ້າບໍ່ມີ Serial,
Auto Material Request,ວັດສະດຸອັດຕະໂນມັດຄໍາຮ້ອງຂໍ,
-Raise Material Request when stock reaches re-order level,ຍົກສູງບົດບາດການວັດສະດຸຂໍເວລາຫຸ້ນຮອດລະດັບ Re: ຄໍາສັ່ງ,
-Notify by Email on creation of automatic Material Request,ແຈ້ງໂດຍ Email ກ່ຽວກັບການສ້າງຂອງຄໍາຮ້ອງຂໍອຸປະກອນອັດຕະໂນມັດ,
Inter Warehouse Transfer Settings,ການຕັ້ງຄ່າໂອນຍ້າຍລະຫວ່າງສາກົນ,
-Allow Material Transfer From Delivery Note and Sales Invoice,ອະນຸຍາດໃຫ້ໂອນເອກະສານຈາກໃບສົ່ງແລະໃບເກັບເງິນການຂາຍ,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,ອະນຸຍາດໃຫ້ໂອນເອກະສານຈາກໃບຮັບເງິນຊື້ແລະໃບເກັບເງິນຊື້,
Freeze Stock Entries,Freeze Entries Stock,
Stock Frozen Upto,Stock Frozen ເກີນ,
-Freeze Stocks Older Than [Days],Freeze ຫຸ້ນເກີນ [ວັນ],
-Role Allowed to edit frozen stock,ພາລະບົດບາດອະນຸຍາດໃຫ້ແກ້ໄຂຫຸ້ນ frozen,
Batch Identification,Batch Identification,
Use Naming Series,ໃຊ້ນາມສະກຸນ,
Naming Series Prefix,Naming Series Prefix,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,ແນວໂນ້ມການຊື້ຮັບ,
Purchase Register,ລົງທະບຽນການຊື້,
Quotation Trends,ແນວໂນ້ມວົງຢືມ,
-Quoted Item Comparison,ປຽບທຽບບາຍດີທຸກທ່ານ Item,
Received Items To Be Billed,ລາຍການທີ່ໄດ້ຮັບການໄດ້ຮັບການ billed,
Qty to Order,ຈໍານວນທີ່ຈະສັ່ງຊື້ສິນຄ້າ,
Requested Items To Be Transferred,ການຮ້ອງຂໍໃຫ້ໄດ້ຮັບການໂອນ,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,ເລືອກສາງ ສຳ ລັບການຮ້ອງຂໍດ້ານວັດຖຸ,
Transfer Materials For Warehouse {0},ໂອນວັດສະດຸ ສຳ ລັບສາງ {0},
Production Plan Material Request Warehouse,ການຂໍອຸປະກອນການວາງແຜນການຜະລິດສາງ,
-Set From Warehouse,ຕັ້ງຈາກສາງ,
-Source Warehouse (Material Transfer),ສາງແຫຼ່ງຂໍ້ມູນ (ໂອນຍ້າຍວັດສະດຸ),
Sets 'Source Warehouse' in each row of the items table.,ຕັ້ງ 'ສາງແຫຼ່ງຂໍ້ມູນ' ໃນແຕ່ລະແຖວຂອງຕາຕະລາງສິນຄ້າ.,
Sets 'Target Warehouse' in each row of the items table.,ຕັ້ງ 'ສາງເປົ້າ ໝາຍ' ໃນແຕ່ລະແຖວຂອງຕາຕະລາງ.,
Show Cancelled Entries,ສະແດງລາຍການທີ່ຖືກຍົກເລີກ,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,ບໍລິການໄດ້ຮັບແຕ່ບໍ່ໄດ້ເກັບເງິນ,
Deferred Accounting Settings,ການຕັ້ງຄ່າບັນຊີທີ່ຍອມຮັບ,
Book Deferred Entries Based On,ການເຂົ້າປື້ມທີ່ອີງໃສ່,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",ຖ້າຫາກວ່າ "ເດືອນ" ຖືກເລືອກແລ້ວ ຈຳ ນວນເງິນຄົງທີ່ຈະຖືກຈອງເປັນລາຍໄດ້ທີ່ໄດ້ຮັບການ ຊຳ ລະຫຼືລາຍຈ່າຍ ສຳ ລັບແຕ່ລະເດືອນໂດຍບໍ່ ຈຳ ກັດ ຈຳ ນວນມື້ໃນເດືອນ. ຈະໄດ້ຮັບການປັບປຸງຖ້າລາຍໄດ້ຫລືລາຍຈ່າຍທີ່ບໍ່ຖືກຕ້ອງບໍ່ໄດ້ຖືກຈອງເປັນເວລາ ໜຶ່ງ ເດືອນ.,
Days,ວັນ,
Months,ເດືອນ,
Book Deferred Entries Via Journal Entry,ການອອກສຽງປື້ມທີ່ຝາກຜ່ານວາລະສານ,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,ຖ້າສິ່ງນີ້ບໍ່ຖືກກວດກາໂດຍກົງ GL Entries ຈະຖືກສ້າງຂື້ນເພື່ອຈອງລາຍໄດ້ / ລາຍຈ່າຍ,
Submit Journal Entries,ຍື່ນສະ ເໜີ ການອອກສຽງຂອງວາລະສານ,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,ຖ້າສິ່ງນີ້ບໍ່ຖືກກວດກາການອອກສຽງວາລະສານຈະຖືກບັນທຶກໄວ້ໃນສະພາບຮ່າງແລະຈະຕ້ອງຖືກສົ່ງດ້ວຍຕົນເອງ,
Enable Distributed Cost Center,ເປີດໃຊ້ສູນຄ່າໃຊ້ຈ່າຍແຈກຢາຍ,
@@ -8901,8 +8823,6 @@
Is Inter State,ແມ່ນລັດ Inter,
Purchase Details,ລາຍລະອຽດການຊື້,
Depreciation Posting Date,ວັນໂພສຄ່າຫຼຸ້ຍຫ້ຽນ,
-Purchase Order Required for Purchase Invoice & Receipt Creation,ໃບສັ່ງຊື້ທີ່ ຈຳ ເປັນ ສຳ ລັບການຊື້ໃບເກັບເງິນແລະການສ້າງໃບຮັບເງິນ,
-Purchase Receipt Required for Purchase Invoice Creation,ໃບຮັບເງິນຊື້ທີ່ ຈຳ ເປັນ ສຳ ລັບການສ້າງໃບເກັບເງິນຊື້,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","ໂດຍຄ່າເລີ່ມຕົ້ນ, ຊື່ຜູ້ສະ ໜອງ ຖືກຕັ້ງຕາມຊື່ຜູ້ສະ ໜອງ ທີ່ປ້ອນເຂົ້າ. ຖ້າທ່ານຕ້ອງການຊື່ຜູ້ສະ ໜອງ ໃຫ້ໂດຍ a",
choose the 'Naming Series' option.,ເລືອກຕົວເລືອກ 'Naming Series'.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,ຕັ້ງຄ່າລາຍການລາຄາເລີ່ມຕົ້ນເມື່ອສ້າງການສັ່ງຊື້ ໃໝ່. ລາຄາສິນຄ້າຈະຖືກດຶງມາຈາກບັນຊີລາຄານີ້.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,ແມ່ນສ່ວນປະກອບອາກອນລາຍໄດ້,
Component properties and references ,ຄຸນສົມບັດແລະເອກະສານອ້າງອິງ,
Additional Salary ,ເງິນເດືອນເພີ່ມ,
-Condtion and formula,ເງື່ອນໄຂແລະສູດ,
Unmarked days,ມື້ທີ່ບໍ່ໄດ້ ໝາຍ,
Absent Days,ວັນຂາດ,
Conditions and Formula variable and example,ເງື່ອນໄຂແລະຕົວປ່ຽນແປງສູດແລະຕົວຢ່າງ,
Feedback By,ຄຳ ຕິຊົມໂດຍ,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,ພາກສ່ວນການຜະລິດ,
-Sales Order Required for Sales Invoice & Delivery Note Creation,ຕ້ອງມີໃບສັ່ງຊື້ຂາຍ ສຳ ລັບໃບເກັບເງິນການຂາຍ & ການສ້າງປື້ມບັນທຶກການສົ່ງ,
-Delivery Note Required for Sales Invoice Creation,ຂໍ້ແນະ ນຳ ສົ່ງ ສຳ ລັບການສ້າງໃບເກັບເງິນຂາຍ,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","ໂດຍຄ່າເລີ່ມຕົ້ນ, ຊື່ລູກຄ້າຖືກຕັ້ງຄ່າຕາມຊື່ເຕັມທີ່ເຂົ້າມາ. ຖ້າທ່ານຕ້ອງການໃຫ້ລູກຄ້າຕັ້ງຊື່ໂດຍ a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,ຕັ້ງຄ່າລາຍການລາຄາເລີ່ມຕົ້ນເມື່ອສ້າງທຸລະ ກຳ ການຂາຍ ໃໝ່. ລາຄາສິນຄ້າຈະຖືກດຶງມາຈາກບັນຊີລາຄານີ້.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","ຖ້າຕົວເລືອກນີ້ຖືກຕັ້ງຄ່າ 'ແມ່ນແລ້ວ', ERPNext ຈະປ້ອງກັນທ່ານບໍ່ໃຫ້ສ້າງໃບແຈ້ງການກ່ຽວກັບການຂາຍຫຼືໃບສົ່ງສິນຄ້າໂດຍບໍ່ຕ້ອງສ້າງ Order Order ກ່ອນ. ການຕັ້ງຄ່ານີ້ສາມາດຖືກມອງຂ້າມ ສຳ ລັບລູກຄ້າສະເພາະໂດຍການເປີດໃຊ້ກ່ອງກາເຄື່ອງ ໝາຍ 'ອະນຸຍາດໃຫ້ສ້າງໃບແຈ້ງການຂາຍໂດຍບໍ່ມີໃບສັ່ງຂາຍ' ໃນແມ່ບົດລູກຄ້າ.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} ໄດ້ຖືກເພີ່ມເຂົ້າໃນທຸກໆຫົວຂໍ້ທີ່ເລືອກໄວ້ຢ່າງປະສົບຜົນ ສຳ ເລັດ.,
Topics updated,ຫົວຂໍ້ທີ່ຖືກປັບປຸງ,
Academic Term and Program,ໄລຍະການສຶກສາແລະໂຄງການ,
-Last Stock Transaction for item {0} was on {1}.,ການເຮັດທຸລະ ກຳ ຄັ້ງສຸດທ້າຍ ສຳ ລັບສິນຄ້າ {0} ແມ່ນຢູ່ {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,ທຸລະ ກຳ ສຳ ລັບສິນຄ້າ {0} ບໍ່ສາມາດໂພດກ່ອນ ໜ້າ ນີ້ໄດ້.,
Please remove this item and try to submit again or update the posting time.,ກະລຸນາເອົາລາຍການນີ້ອອກໄປແລະພະຍາຍາມສົ່ງອີກຫຼືອັບເດດເວລາປະກາດ.,
Failed to Authenticate the API key.,ລົ້ມເຫລວໃນການກວດສອບຫຼັກ API.,
Invalid Credentials,ໃບຢັ້ງຢືນທີ່ບໍ່ຖືກຕ້ອງ,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,ກະລຸນາກວດເບິ່ງ ID ຂອງລູກຄ້າ Plaid ແລະຄຸນຄ່າລັບ,
Bank transaction creation error,ຂໍ້ຜິດພາດໃນການສ້າງທຸລະ ກຳ ຂອງທະນາຄານ,
Unit of Measurement,ຫົວ ໜ່ວຍ ວັດແທກ,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},ແຖວ # {}: ອັດຕາການຂາຍ ສຳ ລັບລາຍການ {} ແມ່ນຕໍ່າກວ່າ {} ຂອງມັນ. ອັດຕາການຂາຍຄວນຈະເປັນອັນດັບ {},
Fiscal Year {0} Does Not Exist,ປີງົບປະມານ {0} ບໍ່ມີ,
Row # {0}: Returned Item {1} does not exist in {2} {3},ແຖວ # {0}: ສິນຄ້າທີ່ໄດ້ກັບມາ {1} ບໍ່ມີຢູ່ໃນ {2} {3},
Valuation type charges can not be marked as Inclusive,ຄ່າບໍລິການປະເພດການປະເມີນມູນຄ່າບໍ່ສາມາດຖືກ ໝາຍ ວ່າລວມ,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,ເວລາຕອບໂຕ້ ສຳ ລັບ {0} ບູລິມະສິດໃນແຖວ {1} ບໍ່ສາມາດໃຫຍ່ກວ່າເວລາ Resolution (Resolution Time).,
{0} is not enabled in {1},{0} ບໍ່ໄດ້ເປີດໃຊ້ໃນ {1},
Group by Material Request,ຈັດກຸ່ມໂດຍການຮ້ອງຂໍເອກະສານ,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","ແຖວ {0}: ສຳ ລັບຜູ້ສະ ໜອງ {0}, ທີ່ຢູ່ອີເມວ ຈຳ ເປັນຕ້ອງສົ່ງອີເມວ",
Email Sent to Supplier {0},ສົ່ງອີເມວໄປຫາຜູ້ສະ ໜອງ {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","ການເຂົ້າເຖິງການຂໍເອົາວົງຢືມຈາກປະຕູແມ່ນຖືກປິດໃຊ້ງານ. ເພື່ອອະນຸຍາດໃຫ້ເຂົ້າເຖິງ, ເປີດໃຊ້ມັນຢູ່ໃນ Portal Settings.",
Supplier Quotation {0} Created,ວົງຢືມຜູ້ສະ ໜອງ {0} ສ້າງຂື້ນມາ,
Valid till Date cannot be before Transaction Date,ຖືກຕ້ອງຈົນເຖິງວັນທີບໍ່ສາມາດກ່ອນວັນທີທຸລະ ກຳ,
+Unlink Advance Payment on Cancellation of Order,ຍົກເລີກການຈ່າຍເງິນລ່ວງ ໜ້າ ກ່ຽວກັບການຍົກເລີກການສັ່ງຊື້,
+"Simple Python Expression, Example: territory != 'All Territories'","ການສະແດງອອກ Python ແບບງ່າຍດາຍ, ຕົວຢ່າງ: ອານາເຂດ! = 'ອານາເຂດທັງ ໝົດ'",
+Sales Contributions and Incentives,ການປະກອບສ່ວນການຂາຍແລະແຮງຈູງໃຈ,
+Sourced by Supplier,ສະ ໜັບ ສະ ໜູນ ໂດຍຜູ້ສະ ໜອງ ສິນຄ້າ,
+Total weightage assigned should be 100%.<br>It is {0},ນ້ ຳ ໜັກ ທັງ ໝົດ ທີ່ມອບ ໝາຍ ໃຫ້ແມ່ນ 100%.<br> ມັນແມ່ນ {0},
+Account {0} exists in parent company {1}.,ບັນຊີ {0} ມີຢູ່ໃນບໍລິສັດແມ່ {1}.,
+"To overrule this, enable '{0}' in company {1}","ເພື່ອລົບລ້າງສິ່ງນີ້, ເປີດໃຊ້ '{0}' ໃນບໍລິສັດ {1}",
+Invalid condition expression,ການສະແດງອອກເງື່ອນໄຂທີ່ບໍ່ຖືກຕ້ອງ,
+Please Select a Company First,ກະລຸນາເລືອກບໍລິສັດກ່ອນ,
+Please Select Both Company and Party Type First,ກະລຸນາເລືອກເອົາທັງບໍລິສັດແລະປະເພດພັກກ່ອນ,
+Provide the invoice portion in percent,ໃຫ້ສ່ວນໃບເກັບເງິນເປັນເປີເຊັນ,
+Give number of days according to prior selection,ໃຫ້ ຈຳ ນວນມື້ຕາມການເລືອກກ່ອນ,
+Email Details,ລາຍລະອຽດອີເມວ,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","ເລືອກ ຄຳ ທັກທາຍ ສຳ ລັບຜູ້ຮັບ. ຕົວຢ່າງທ່ານ, ນາງ, ແລະອື່ນໆ.",
+Preview Email,ເບິ່ງຕົວຢ່າງ Email,
+Please select a Supplier,ກະລຸນາເລືອກຜູ້ສະ ໜອງ,
+Supplier Lead Time (days),ເວລາ ນຳ ຂອງຜູ້ສະ ໜອງ (ມື້),
+"Home, Work, etc.","ເຮືອນ, ບ່ອນເຮັດວຽກ, ແລະອື່ນໆ",
+Exit Interview Held On,ການ ສຳ ພາດອອກໄດ້ຈັດຂຶ້ນ,
+Condition and formula,ເງື່ອນໄຂແລະສູດ,
+Sets 'Target Warehouse' in each row of the Items table.,ຕັ້ງ 'ສາງເປົ້າ ໝາຍ' ໃນແຕ່ລະແຖວຂອງຕາຕະລາງສິນຄ້າ.,
+Sets 'Source Warehouse' in each row of the Items table.,ຕັ້ງ 'ສາງແຫຼ່ງຂໍ້ມູນ' ໃນແຕ່ລະແຖວຂອງຕາຕະລາງສິນຄ້າ.,
+POS Register,POS ລົງທະບຽນ,
+"Can not filter based on POS Profile, if grouped by POS Profile","ບໍ່ສາມາດກັ່ນຕອງໄດ້ໂດຍອີງໃສ່ໂປແກຼມ POS, ຖ້າຈັດເປັນກຸ່ມໂດຍໂປຼໄຟລ໌ POS",
+"Can not filter based on Customer, if grouped by Customer","ບໍ່ສາມາດກັ່ນຕອງໂດຍອີງໃສ່ລູກຄ້າ, ຖ້າຈັດເປັນກຸ່ມໂດຍລູກຄ້າ",
+"Can not filter based on Cashier, if grouped by Cashier","ບໍ່ສາມາດກັ່ນຕອງໄດ້ໂດຍອີງໃສ່ Cashier, ຖ້າຈັດເປັນກຸ່ມໂດຍ Cashier",
+Payment Method,ວິທີການຈ່າຍເງິນ,
+"Can not filter based on Payment Method, if grouped by Payment Method","ບໍ່ສາມາດກັ່ນຕອງໂດຍອີງໃສ່ວິທີການຈ່າຍເງິນ, ຖ້າຈັດເປັນກຸ່ມດ້ວຍວິທີການຈ່າຍເງິນ",
+Supplier Quotation Comparison,ການປຽບທຽບວົງຢືມຂອງຜູ້ສະ ໜອງ,
+Price per Unit (Stock UOM),ລາຄາຕໍ່ ໜ່ວຍ (Stock UOM),
+Group by Supplier,ກຸ່ມໂດຍຜູ້ສະ ໜອງ,
+Group by Item,ກຸ່ມໂດຍລາຍການ,
+Remember to set {field_label}. It is required by {regulation}.,ຢ່າລືມຕັ້ງຄ່າ {field_label}. ມັນຖືກ ກຳ ນົດໂດຍ {ລະບຽບການ}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},ວັນທີລົງທະບຽນບໍ່ສາມາດກ່ອນວັນເຂົ້າຮຽນຂອງປີການສຶກສາ {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},ວັນທີລົງທະບຽນບໍ່ໃຫ້ກາຍວັນສິ້ນສຸດໄລຍະການສຶກສາ {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},ວັນທີລົງທະບຽນບໍ່ສາມາດກ່ອນວັນທີເລີ່ມການສຶກສາ {0},
+Future Posting Not Allowed,ການປະກາດໃນອະນາຄົດບໍ່ໄດ້ຮັບອະນຸຍາດ,
+"To enable Capital Work in Progress Accounting, ","ເພື່ອເຮັດໃຫ້ນະຄອນຫຼວງເຮັດວຽກໃນຄວາມຄືບ ໜ້າ ໃນບັນຊີ,",
+you must select Capital Work in Progress Account in accounts table,ທ່ານຕ້ອງເລືອກບັນຊີ Capital Work in Progress Account ໃນຕາຕະລາງບັນຊີ,
+You can also set default CWIP account in Company {},ທ່ານຍັງສາມາດຕັ້ງຄ່າບັນຊີ CWIP ໃນບໍລິສັດ {},
+The Request for Quotation can be accessed by clicking on the following button,ຄຳ ຮ້ອງຂໍການສະ ເໜີ ລາຄາສາມາດເຂົ້າເບິ່ງໄດ້ໂດຍການກົດປຸ່ມຕໍ່ໄປນີ້,
+Regards,ກ່ຽວກັບ,
+Please click on the following button to set your new password,ກະລຸນາກົດປຸ່ມຕໍ່ໄປນີ້ເພື່ອຕັ້ງລະຫັດລັບ ໃໝ່ ຂອງທ່ານ,
+Update Password,ປັບປຸງລະຫັດຜ່ານ,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},ແຖວ # {}: ອັດຕາການຂາຍ ສຳ ລັບລາຍການ {} ແມ່ນຕໍ່າກວ່າ {} ຂອງມັນ. ການຂາຍ {} ຄວນຈະເປັນອັນດັບ {},
+You can alternatively disable selling price validation in {} to bypass this validation.,ທ່ານສາມາດປິດການ ນຳ ໃຊ້ຄວາມຖືກຕ້ອງຂອງລາຄາໃນ {} ເພື່ອຫລີກລ້ຽງການຢືນຢັນນີ້.,
+Invalid Selling Price,ລາຄາຂາຍບໍ່ຖືກຕ້ອງ,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,ທີ່ຢູ່ຕ້ອງໄດ້ເຊື່ອມໂຍງກັບບໍລິສັດ. ກະລຸນາຕື່ມແຖວ ສຳ ລັບບໍລິສັດໃນຕາຕະລາງ Links.,
+Company Not Linked,ບໍລິສັດບໍ່ເຊື່ອມໂຍງ,
+Import Chart of Accounts from CSV / Excel files,ນຳ ເຂົ້າຕາຕະລາງບັນຊີຈາກໄຟລ໌ CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',Qty ສຳ ເລັດແລ້ວບໍ່ສາມາດໃຫຍ່ກວ່າ 'Qty to manufacture',
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","ແຖວ {0}: ສຳ ລັບຜູ້ສະ ໜອງ {1}, ທີ່ຢູ່ອີເມວ ຈຳ ເປັນຕ້ອງສົ່ງອີເມວ",
+"If enabled, the system will post accounting entries for inventory automatically","ຖ້າເປີດໃຊ້ງານ, ລະບົບຈະປະກາດລາຍການບັນຊີ ສຳ ລັບສິນຄ້າຄົງຄັງໂດຍອັດຕະໂນມັດ",
+Accounts Frozen Till Date,ບັນຊີ Frozen Till ວັນທີ,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,ບັນຊີການບັນຊີແມ່ນ frozen ເຖິງວັນທີນີ້. ບໍ່ມີໃຜສາມາດສ້າງຫລືດັດແກ້ການອອກສຽງຍົກເວັ້ນຜູ້ໃຊ້ທີ່ມີບົດບາດທີ່ລະບຸໄວ້ຂ້າງລຸ່ມນີ້,
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,ພາລະບົດບາດທີ່ອະນຸຍາດໃຫ້ຕັ້ງບັນຊີ Frozen ແລະແກ້ໄຂບັນດາ Frozen Entries,
+Address used to determine Tax Category in transactions,ທີ່ຢູ່ທີ່ໃຊ້ໃນການ ກຳ ນົດ ໝວດ ພາສີໃນການເຮັດທຸລະ ກຳ,
+"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 ","ອັດຕາສ່ວນທີ່ທ່ານໄດ້ຮັບອະນຸຍາດໃຫ້ເກັບໃບບິນຫຼາຍກວ່າ ຈຳ ນວນທີ່ສັ່ງ. ຕົວຢ່າງ: ຖ້າມູນຄ່າການສັ່ງສິນຄ້າແມ່ນ $ 100 ສຳ ລັບສິນຄ້າແລະຄວາມທົນທານໄດ້ຖືກ ກຳ ນົດເປັນ 10%, ຫຼັງຈາກນັ້ນທ່ານໄດ້ຖືກອະນຸຍາດໃຫ້ເກັບເງິນເຖິງ 110 ໂດລາ",
+This role is allowed to submit transactions that exceed credit limits,ບົດບາດນີ້ໄດ້ຖືກອະນຸຍາດໃຫ້ສົ່ງທຸລະ ກຳ ທີ່ເກີນຂີດ ຈຳ ກັດຂອງສິນເຊື່ອ,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","ຖ້າວ່າ "ເດືອນ" ຖືກເລືອກ, ຈຳ ນວນເງິນຄົງທີ່ຈະຖືກຈອງເປັນລາຍໄດ້ທີ່ໄດ້ຮັບທີ່ຖືກຕ້ອງຫຼືລາຍຈ່າຍ ສຳ ລັບແຕ່ລະເດືອນໂດຍບໍ່ ຄຳ ນຶງເຖິງ ຈຳ ນວນມື້ໃນເດືອນ. ມັນຈະໄດ້ຮັບການພິຈາລະນາຖ້າລາຍຮັບຫລືລາຍຈ່າຍທີ່ບໍ່ຖືກຕ້ອງບໍ່ຖືກຈອງເປັນເວລາ ໜຶ່ງ ເດືອນ",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","ຖ້າສິ່ງນີ້ບໍ່ຖືກກວດກາ, ລາຍການ GL ໂດຍກົງຈະຖືກສ້າງຂື້ນເພື່ອສັ່ງຈອງລາຍໄດ້ທີ່ບໍ່ຖືກຕ້ອງຫລືລາຍຈ່າຍ",
+Show Inclusive Tax in Print,ສະແດງອາກອນລວມໃນການພິມ,
+Only select this if you have set up the Cash Flow Mapper documents,ເລືອກເອົາເທົ່ານັ້ນຖ້າທ່ານໄດ້ຕັ້ງເອກະສານ Cash Flow Mapper,
+Payment Channel,ຊ່ອງທາງການຈ່າຍເງິນ,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,ມີໃບສັ່ງຊື້ທີ່ຕ້ອງການ ສຳ ລັບການຊື້ໃບເກັບເງິນແລະການສ້າງໃບຮັບເງິນບໍ?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,ໃບເກັບເງິນການຊື້ແມ່ນ ຈຳ ເປັນ ສຳ ລັບການສ້າງໃບເກັບເງິນການຊື້ບໍ?,
+Maintain Same Rate Throughout the Purchase Cycle,ຮັກສາອັດຕາດຽວກັນຕະຫຼອດຮອບວຽນການຊື້,
+Allow Item To Be Added Multiple Times in a Transaction,ອະນຸຍາດໃຫ້ເພີ່ມລາຍການຫຼາຍໆຄັ້ງໃນການເຮັດທຸລະ ກຳ,
+Suppliers,ຜູ້ສະ ໜອງ,
+Send Emails to Suppliers,ສົ່ງອີເມວໄປຫາຜູ້ສະ ໜອງ,
+Select a Supplier,ເລືອກຜູ້ສະ ໜອງ ສິນຄ້າ,
+Cannot mark attendance for future dates.,ບໍ່ສາມາດ ໝາຍ ເອົາການເຂົ້າຮ່ວມ ສຳ ລັບວັນທີໃນອະນາຄົດ.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},ທ່ານຕ້ອງການປັບປຸງການເຂົ້າຮຽນບໍ?<br> ປະຈຸບັນ: {0}<br> ຂາດ: {1},
+Mpesa Settings,ການຕັ້ງຄ່າ Mpesa,
+Initiator Name,ຊື່ຜູ້ລິເລີ່ມ,
+Till Number,ຈຳ ນວນເລກ,
+Sandbox,Sandbox,
+ Online PassKey,Online PassKey,
+Security Credential,ໃບຢັ້ງຢືນຄວາມປອດໄພ,
+Get Account Balance,ຮັບບັນຊີຍອດເງິນ,
+Please set the initiator name and the security credential,ກະລຸນາຕັ້ງຊື່ຜູ້ລິເລີ່ມແລະຂໍ້ມູນຄວາມປອດໄພ,
+Inpatient Medication Entry,ການເຂົ້າມາໃຊ້ຢາພາຍໃນ,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),ລະຫັດສິນຄ້າ (ຢາ),
+Medication Orders,ໃບສັ່ງຊື້ຢາ,
+Get Pending Medication Orders,ຮັບໃບສັ່ງແພດທີ່ຍັງຄ້າງ,
+Inpatient Medication Orders,ການສັ່ງຊື້ຢາພາຍໃນປະເທດ,
+Medication Warehouse,ສາງຢາ,
+Warehouse from where medication stock should be consumed,ຄັງສິນຄ້າຈາກບ່ອນທີ່ຫຸ້ນຢາຄວນຈະບໍລິໂພກ,
+Fetching Pending Medication Orders,ເອົາໃຈໃສ່ສັ່ງຊື້ຢາທີ່ຍັງຄ້າງ,
+Inpatient Medication Entry Detail,ລາຍລະອຽດການເຂົ້າຢາພາຍໃນ,
+Medication Details,ລາຍລະອຽດກ່ຽວກັບຢາ,
+Drug Code,ລະຫັດຢາ,
+Drug Name,ຊື່ຢາ,
+Against Inpatient Medication Order,ຕໍ່ກັບໃບສັ່ງຊື້ຢາໃນຄົນເຈັບ,
+Against Inpatient Medication Order Entry,ຕ້ານການເຂົ້າມາສັ່ງຊື້ຢາພາຍໃນ,
+Inpatient Medication Order,ໃບສັ່ງຊື້ຢາໃນຄົນເຈັບ,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,ຄຳ ສັ່ງທັງ ໝົດ,
+Completed Orders,ສຳ ເລັດການສັ່ງຊື້,
+Add Medication Orders,ເພີ່ມ ຄຳ ສັ່ງກ່ຽວກັບຢາ,
+Adding Order Entries,ເພີ່ມການສັ່ງຊື້ສິນຄ້າ,
+{0} medication orders completed,{0} ສຳ ເລັດການສັ່ງຊື້ຢາແລ້ວ,
+{0} medication order completed,{0} ສຳ ເລັດການສັ່ງຊື້ຢາແລ້ວ,
+Inpatient Medication Order Entry,ການເຂົ້າມາສັ່ງຊື້ຢາພາຍໃນ,
+Is Order Completed,ແມ່ນ ຄຳ ສັ່ງ ສຳ ເລັດແລ້ວ,
+Employee Records to Be Created By,ບັນທຶກພະນັກງານທີ່ຕ້ອງໄດ້ຮັບການສ້າງຂື້ນໂດຍ,
+Employee records are created using the selected field,ບັນທຶກພະນັກງານຖືກສ້າງຂື້ນໂດຍໃຊ້ບ່ອນທີ່ເລືອກ,
+Don't send employee birthday reminders,ຢ່າສົ່ງ ຄຳ ເຕືອນວັນເກີດຂອງພະນັກງານ,
+Restrict Backdated Leave Applications,ຈຳ ກັດ ຄຳ ຮ້ອງສະ ໝັກ ການອອກເດີນທາງ Backdated,
+Sequence ID,ບັດປະ ຈຳ ຕົວ,
+Sequence Id,Id ລຳ ດັບ,
+Allow multiple material consumptions against a Work Order,ອະນຸຍາດໃຫ້ເອກະສານສົມມຸດຕິຖານຫຼາຍເອກະສານຕໍ່ກັບ ຄຳ ສັ່ງ Work,
+Plan time logs outside Workstation working hours,ວາງແຜນບັນທຶກເວລາຢູ່ນອກຊົ່ວໂມງເຮັດວຽກຂອງ Workstation,
+Plan operations X days in advance,ວາງແຜນການ ດຳ ເນີນງານ X ວັນລ່ວງ ໜ້າ,
+Time Between Operations (Mins),ເວລາລະຫວ່າງການປະຕິບັດງານ (Mins),
+Default: 10 mins,ເລີ່ມຕົ້ນ: 10 ນາທີ,
+Overproduction for Sales and Work Order,ການຜະລິດສິນຄ້າເກີນ ກຳ ນົດ ສຳ ລັບການຂາຍແລະ ຄຳ ສັ່ງເຮັດວຽກ,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","ປັບປຸງຄ່າໃຊ້ຈ່າຍ BOM ໂດຍອັດຕະໂນມັດຜ່ານຕາຕະລາງເວລາ, ອີງຕາມອັດຕາການຕີລາຄາຫຼ້າສຸດ / ອັດຕາລາຄາ / ອັດຕາການຊື້ວັດຖຸດິບສຸດທ້າຍ",
+Purchase Order already created for all Sales Order items,ໃບສັ່ງຊື້ທີ່ຖືກສ້າງຂື້ນມາແລ້ວ ສຳ ລັບທຸກລາຍການ Order Order,
+Select Items,ເລືອກລາຍການ,
+Against Default Supplier,ຕໍ່ຜູ້ສະ ໜອງ ສິນຄ້າໃນຕອນຕົ້ນ,
+Auto close Opportunity after the no. of days mentioned above,ໂອກາດໃກ້ອັດຕະໂນມັດຫຼັງຈາກທີ່ບໍ່. ຂອງມື້ທີ່ໄດ້ກ່າວມາຂ້າງເທິງ,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,ມີໃບສັ່ງການຂາຍ ສຳ ລັບໃບເກັບເງິນໃນການຂາຍແລະການສ້າງບັນທຶກການສົ່ງສິນຄ້າບໍ?,
+Is Delivery Note Required for Sales Invoice Creation?,ມີໃບຂົນສົ່ງທີ່ ຈຳ ເປັນ ສຳ ລັບການສ້າງໃບເກັບເງິນໃນການຂາຍບໍ?,
+How often should Project and Company be updated based on Sales Transactions?,ໂຄງການແລະບໍລິສັດຄວນປັບປຸງເລື້ອຍປານໃດໂດຍອີງໃສ່ທຸລະ ກຳ ການຂາຍ?,
+Allow User to Edit Price List Rate in Transactions,ອະນຸຍາດໃຫ້ຜູ້ໃຊ້ສາມາດແກ້ໄຂອັດຕາລາຄາບັນຊີໃນການເຮັດທຸລະ ກຳ,
+Allow Item to Be Added Multiple Times in a Transaction,ອະນຸຍາດໃຫ້ເພີ່ມລາຍການຫຼາຍໆຄັ້ງໃນການເຮັດທຸລະ ກຳ,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,ອະນຸຍາດໃຫ້ມີການສັ່ງການຂາຍຫຼາຍຄັ້ງຕໍ່ ຄຳ ສັ່ງຊື້ຂອງລູກຄ້າ,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,ກວດສອບລາຄາຂາຍ ສຳ ລັບສິນຄ້າທຽບກັບອັດຕາການຊື້ຫລືອັດຕາການປະເມີນມູນຄ່າ,
+Hide Customer's Tax ID from Sales Transactions,ເຊື່ອງລະຫັດພາສີຂອງລູກຄ້າຈາກການໂອນຂາຍ,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","ອັດຕາສ່ວນທີ່ທ່ານໄດ້ຮັບອະນຸຍາດໃຫ້ໄດ້ຮັບຫຼືຈັດສົ່ງໃຫ້ຫຼາຍຂື້ນທຽບກັບປະລິມານທີ່ສັ່ງ. ຕົວຢ່າງ: ຖ້າທ່ານໄດ້ສັ່ງ 100 ໜ່ວຍ, ແລະເງິນອຸດ ໜູນ ຂອງທ່ານແມ່ນ 10%, ແລ້ວທ່ານຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໄດ້ຮັບ 110 ໜ່ວຍ.",
+Action If Quality Inspection Is Not Submitted,ການປະຕິບັດຖ້າການກວດກາຄຸນນະພາບບໍ່ຖືກສົ່ງ,
+Auto Insert Price List Rate If Missing,ອັດຕາລາຄາບັນຊີລາຄາອັດຕະໂນມັດຖ້າຂາດ,
+Automatically Set Serial Nos Based on FIFO,ຕັ້ງ Serial Nos ໂດຍອັດຕະໂນມັດໂດຍອີງໃສ່ FIFO,
+Set Qty in Transactions Based on Serial No Input,ຕັ້ງຄ່າ Qty ໃນການເຮັດທຸລະ ກຳ ໂດຍອີງໃສ່ Serial No Input,
+Raise Material Request When Stock Reaches Re-order Level,ຍົກສູງການຮ້ອງຂໍເອກະສານເມື່ອຫຸ້ນບັນລຸລະດັບການສັ່ງຊື້ຄືນ ໃໝ່,
+Notify by Email on Creation of Automatic Material Request,ແຈ້ງທາງອີເມວກ່ຽວກັບການສ້າງ ຄຳ ຮ້ອງຂໍເອກະສານອັດຕະໂນມັດ,
+Allow Material Transfer from Delivery Note to Sales Invoice,ອະນຸຍາດໃຫ້ໂອນເອກະສານຈາກປື້ມບັນທຶກສົ່ງເຖິງໃບເກັບເງິນຂາຍ,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,ອະນຸຍາດໃຫ້ໂອນເອກະສານຈາກໃບຮັບເງິນເພື່ອຊື້ໃບເກັບເງິນ,
+Freeze Stocks Older Than (Days),ຫຸ້ນຮຸ້ນທີ່ບໍ່ມີອາຍຸເກົ່າກວ່າ (ວັນ),
+Role Allowed to Edit Frozen Stock,ພາລະບົດບາດອະນຸຍາດໃຫ້ແກ້ໄຂຫຸ້ນ Frozen,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,ຈຳ ນວນເງິນທີ່ບໍ່ໄດ້ຈັດສັນຂອງການເຂົ້າການ ຊຳ ລະເງິນ {0} ແມ່ນໃຫຍ່ກວ່າ ຈຳ ນວນເງິນທີ່ບໍ່ໄດ້ຖືກຍ້າຍຂອງທະນາຄານ,
+Payment Received,ໄດ້ຮັບການຊໍາລະເງິນ,
+Attendance cannot be marked outside of Academic Year {0},ການເຂົ້າຮຽນບໍ່ສາມາດຖືກ ໝາຍ ຢູ່ນອກສົກຮຽນ {0},
+Student is already enrolled via Course Enrollment {0},ນັກສຶກສາໄດ້ລົງທະບຽນແລ້ວໂດຍຜ່ານການລົງທະບຽນຮຽນ {0},
+Attendance cannot be marked for future dates.,ການເຂົ້າຮ່ວມບໍ່ສາມາດຖືກ ໝາຍ ໄວ້ ສຳ ລັບວັນທີໃນອະນາຄົດ.,
+Please add programs to enable admission application.,ກະລຸນາເພີ່ມໂປຼແກຼມເພື່ອເປີດການສະ ໝັກ ເຂົ້າຮຽນ.,
+The following employees are currently still reporting to {0}:,ພະນັກງານຕໍ່ໄປນີ້ແມ່ນ ກຳ ລັງລາຍງານຕໍ່ {0}:,
+Please make sure the employees above report to another Active employee.,ກະລຸນາຮັບປະກັນວ່າພະນັກງານຂ້າງເທິງຈະລາຍງານໃຫ້ພະນັກງານ Active ຄົນອື່ນ.,
+Cannot Relieve Employee,ບໍ່ສາມາດບັນເທົາພະນັກງານ,
+Please enter {0},ກະລຸນາໃສ່ {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',ກະລຸນາເລືອກວິທີການຈ່າຍເງິນອື່ນ. Mpesa ບໍ່ສະ ໜັບ ສະ ໜູນ ການເຮັດທຸລະ ກຳ ເປັນສະກຸນເງິນ '{0}',
+Transaction Error,ຂໍ້ຜິດພາດໃນການເຮັດທຸລະ ກຳ,
+Mpesa Express Transaction Error,ຄວາມຜິດພາດໃນການເຮັດທຸລະ ກຳ ແບບດ່ວນ,
+"Issue detected with Mpesa configuration, check the error logs for more details","ບັນຫາຖືກກວດພົບກັບການຕັ້ງຄ່າ Mpesa, ກວດເບິ່ງຂໍ້ມູນບັນທຶກຂໍ້ຜິດພາດ ສຳ ລັບລາຍລະອຽດເພີ່ມເຕີມ",
+Mpesa Express Error,ຂໍ້ຜິດພາດຂອງ Mpesa Express,
+Account Balance Processing Error,ຄວາມຜິດພາດໃນການປະມວນຜົນບັນຊີ,
+Please check your configuration and try again,ກະລຸນາກວດເບິ່ງການຕັ້ງຄ່າຂອງທ່ານແລະລອງ ໃໝ່ ອີກຄັ້ງ,
+Mpesa Account Balance Processing Error,ຄວາມຜິດພາດໃນການປະມວນຜົນບັນຊີ Mpesa,
+Balance Details,ລາຍລະອຽດຍອດເງິນ,
+Current Balance,ຍອດເງິນໃນປະຈຸບັນ,
+Available Balance,ຍອດຍັງເຫຼືອ,
+Reserved Balance,ຍອດເງິນທີ່ເກັບໄວ້,
+Uncleared Balance,ການດຸ່ນດ່ຽງທີ່ບໍ່ມີປະໂຫຍດ,
+Payment related to {0} is not completed,ການຈ່າຍເງິນທີ່ກ່ຽວຂ້ອງກັບ {0} ບໍ່ ສຳ ເລັດ,
+Row #{}: Item Code: {} is not available under warehouse {}.,ແຖວ # {}: ລະຫັດສິນຄ້າ: {} ບໍ່ມີຢູ່ໃນສາງ {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,ແຖວ # {}: ຈຳ ນວນຫຸ້ນບໍ່ພຽງພໍ ສຳ ລັບລະຫັດສິນຄ້າ: {} ພາຍໃຕ້ຄັງສິນຄ້າ {}. ປະລິມານທີ່ມີຢູ່ແລ້ວ {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,ແຖວ # {}: ກະລຸນາເລືອກ serial no ແລະ batch ຕໍ່ລາຍການ: {} ຫຼືເອົາມັນອອກເພື່ອ ດຳ ເນີນການເຮັດທຸລະ ກຳ.,
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,ແຖວ # {}: ບໍ່ມີຕົວເລກ ຈຳ ນວນຄັດເລືອກຕໍ່ສິນຄ້າ: {}. ກະລຸນາເລືອກ ໜຶ່ງ ຫຼືເອົາມັນອອກເພື່ອເຮັດການເຮັດທຸລະ ກຳ ສຳ ເລັດ.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,ແຖວ # {}: ບໍ່ມີການຄັດເລືອກກຸ່ມຕໍ່ກັບສິນຄ້າ: {}. ກະລຸນາເລືອກຊຸດຫຼືເອົາມັນອອກເພື່ອເຮັດການເຮັດທຸລະ ກຳ ສຳ ເລັດ.,
+Payment amount cannot be less than or equal to 0,ຈຳ ນວນການຈ່າຍເງິນບໍ່ສາມາດຕ່ ຳ ກ່ວາຫລືເທົ່າກັບ 0,
+Please enter the phone number first,ກະລຸນາໃສ່ເບີໂທລະສັບກ່ອນ,
+Row #{}: {} {} does not exist.,ແຖວ # {}: {} {} ບໍ່ມີ.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,ແຖວ # {0}: {1} ຈຳ ເປັນຕ້ອງສ້າງໃບແຈ້ງການເປີດ {2},
+You had {} errors while creating opening invoices. Check {} for more details,ທ່ານມີຂໍ້ຜິດພາດໃນຂະນະທີ່ສ້າງໃບເກັບເງິນເປີດ. ກວດເບິ່ງ {} ສຳ ລັບລາຍລະອຽດເພີ່ມເຕີມ,
+Error Occured,ຄວາມຜິດພາດເກີດຂື້ນ,
+Opening Invoice Creation In Progress,ເປີດການສ້າງໃບເກັບເງິນໃນຄວາມຄືບ ໜ້າ,
+Creating {} out of {} {},ສ້າງ {} ອອກຈາກ {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Serial No: {0}) ບໍ່ສາມາດບໍລິໂພກໄດ້ເນື່ອງຈາກມັນປ່ຽນໄປຕາມ ຄຳ ສັ່ງຂາຍເຕັມຮູບແບບ {1}.,
+Item {0} {1},ລາຍການ {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,ການໂອນຂາຍຮຸ້ນຄັ້ງສຸດທ້າຍ ສຳ ລັບສິນຄ້າ {0} ພາຍໃຕ້ຄັງສິນຄ້າ {1} ແມ່ນຢູ່ {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,ທຸລະ ກຳ ສຳ ລັບສິນຄ້າ,
+Posting future stock transactions are not allowed due to Immutable Ledger,ການປະກາດທຸລະ ກຳ ຫຼັກຊັບໃນອະນາຄົດແມ່ນບໍ່ໄດ້ຮັບອະນຸຍາດເນື່ອງຈາກ Immutable Ledger,
+A BOM with name {0} already exists for item {1}.,BOM ທີ່ມີຊື່ {0} ມີຢູ່ແລ້ວ ສຳ ລັບລາຍການ {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} ທ່ານໄດ້ປ່ຽນຊື່ສິນຄ້າບໍ? ກະລຸນາຕິດຕໍ່ຜູ້ບໍລິຫານ / ເຕັກໂນໂລຢີ,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},ຢູ່ແຖວ # {0}: id ລຳ ດັບ {1} ບໍ່ສາມາດຕ່ ຳ ກວ່າ id ລຳ ດັບທີ່ຜ່ານມາ {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) ຕ້ອງເທົ່າກັບ {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, ສຳ ເລັດການປະຕິບັດງານ {1} ກ່ອນການ ດຳ ເນີນງານ {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,ບໍ່ສາມາດຮັບປະກັນການຈັດສົ່ງໂດຍ Serial No ເປັນລາຍການ {0} ຖືກເພີ່ມເຂົ້າດ້ວຍແລະບໍ່ຕ້ອງຮັບປະກັນການຈັດສົ່ງໂດຍ Serial No.,
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,ສິນຄ້າ {0} ບໍ່ມີ Serial No. ພຽງແຕ່ສິນຄ້າທີ່ມີ serilialized ສາມາດສົ່ງໄດ້ໂດຍອີງໃສ່ Serial No,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,ບໍ່ພົບ BOM ທີ່ໃຊ້ວຽກ ສຳ ລັບລາຍການ {0}. ການຈັດສົ່ງໂດຍ Serial No ບໍ່ສາມາດຮັບປະກັນໄດ້,
+No pending medication orders found for selected criteria,ບໍ່ພົບການສັ່ງຊື້ຢາທີ່ຍັງຄ້າງຢູ່ ສຳ ລັບເງື່ອນໄຂທີ່ເລືອກ,
+From Date cannot be after the current date.,ຈາກວັນທີບໍ່ສາມາດເປັນໄປໄດ້ຫຼັງຈາກວັນທີປັດຈຸບັນ.,
+To Date cannot be after the current date.,ວັນທີບໍ່ສາມາດເປັນໄປໄດ້ຫຼັງຈາກວັນທີປັດຈຸບັນ.,
+From Time cannot be after the current time.,ຈາກທີ່ໃຊ້ເວລາບໍ່ສາມາດຈະຫຼັງຈາກທີ່ໃຊ້ເວລາປະຈຸບັນ.,
+To Time cannot be after the current time.,To Time ບໍ່ສາມາດເປັນໄປໄດ້ຫຼັງຈາກເວລາປະຈຸບັນ.,
+Stock Entry {0} created and ,ການເຂົ້າຫຸ້ນ {0} ສ້າງຂື້ນແລະ,
+Inpatient Medication Orders updated successfully,ການສັ່ງຊື້ຢາປິ່ນປົວຄົນເຈັບພາຍໃນສະບັບປັບປຸງຢ່າງ ສຳ ເລັດຜົນ,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},ແຖວຕໍ່ໄປ,
+Row {0}: This Medication Order is already marked as completed,ແຖວ {0}: ໃບສັ່ງຊື້ຢານີ້ໄດ້ຖືກ ໝາຍ ໄວ້ແລ້ວ ສຳ ເລັດແລ້ວ,
+Quantity not available for {0} in warehouse {1},ຈຳ ນວນບໍ່ສາມາດໃຊ້ໄດ້ ສຳ ລັບ {0} ໃນສາງ {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,ກະລຸນາເຮັດໃຫ້ສາມາດອະນຸຍາດໃຫ້ Stock Negative ໃນການຕັ້ງຄ່າຫຸ້ນຫຼືສ້າງ Stock Entry ເພື່ອ ດຳ ເນີນການຕໍ່ໄປ.,
+No Inpatient Record found against patient {0},ບໍ່ພົບບັນທຶກຄົນເຈັບທີ່ພົບກັບຄົນເຈັບ {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,ໃບສັ່ງຊື້ຢາປິ່ນປົວຄົນເຈັບ {0} ຕໍ່ກັບຜູ້ປະສົບໄພຄົນເຈັບ {1} ມີຢູ່ແລ້ວ.,
+Allow In Returns,ອະນຸຍາດໃຫ້ກັບຄືນ,
+Hide Unavailable Items,ເຊື່ອງລາຍການທີ່ບໍ່ມີ,
+Apply Discount on Discounted Rate,ສະ ໝັກ ເອົາສ່ວນຫຼຸດໃນອັດຕາຫຼຸດລາຄາ,
+Therapy Plan Template,ແມ່ແບບແຜນການປິ່ນປົວ,
+Fetching Template Details,ລາຍລະອຽດແມ່ແບບ,
+Linked Item Details,ລາຍລະອຽດຂອງລາຍການທີ່ເຊື່ອມໂຍງ,
+Therapy Types,ປະເພດການປິ່ນປົວ,
+Therapy Plan Template Detail,ລາຍລະອຽດແບບແຜນການປິ່ນປົວ,
+Non Conformance,ຄວາມສອດຄ່ອງທີ່ບໍ່ແມ່ນ,
+Process Owner,ເຈົ້າຂອງຂະບວນການ,
+Corrective Action,ການກະທໍາທີ່ຖືກຕ້ອງ,
+Preventive Action,ການປ້ອງກັນ,
+Problem,ປັນຫາ,
+Responsible,ຮັບຜິດຊອບ,
+Completion By,ສຳ ເລັດໂດຍ,
+Process Owner Full Name,ເຈົ້າຂອງຂະບວນການຊື່ເຕັມ,
+Right Index,ດັດຊະນີທີ່ຖືກຕ້ອງ,
+Left Index,ດັດສະນີຊ້າຍ,
+Sub Procedure,ຂັ້ນຕອນການຍ່ອຍ,
+Passed,ຜ່ານໄປ,
+Print Receipt,ໃບຮັບເງິນ,
+Edit Receipt,ແກ້ໄຂໃບຮັບເງິນ,
+Focus on search input,ສຸມໃສ່ການປ້ອນຂໍ້ມູນການຄົ້ນຫາ,
+Focus on Item Group filter,ສຸມໃສ່ການກັ່ນຕອງກຸ່ມສິນຄ້າ,
+Checkout Order / Submit Order / New Order,Checkout Order / ສົ່ງໃບສັ່ງຊື້ / ສັ່ງ ໃໝ່,
+Add Order Discount,ເພີ່ມສ່ວນຫຼຸດຕາມສັ່ງ,
+Item Code: {0} is not available under warehouse {1}.,ລະຫັດສິນຄ້າ: {0} ບໍ່ມີຢູ່ໃນສາງ {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,ບໍ່ມີ ຈຳ ນວນ Serial ສຳ ລັບລາຍການ {0} ພາຍໃຕ້ຄັງສິນຄ້າ {1}. ກະລຸນາລອງປ່ຽນສາງ.,
+Fetched only {0} available serial numbers.,ເອົາໄວ້ພຽງແຕ່ {0} ເລກ ລຳ ດັບທີ່ມີຢູ່.,
+Switch Between Payment Modes,ສັບປ່ຽນລະຫວ່າງຮູບແບບການຈ່າຍເງິນ,
+Enter {0} amount.,ໃສ່ {0} ຈຳ ນວນ.,
+You don't have enough points to redeem.,ທ່ານບໍ່ມີຈຸດພຽງພໍທີ່ຈະໄຖ່.,
+You can redeem upto {0}.,ທ່ານສາມາດເອົາເງິນຄືນໄດ້ {0}.,
+Enter amount to be redeemed.,ກະລຸນາໃສ່ ຈຳ ນວນເງິນທີ່ຈະຖືກໂອນ.,
+You cannot redeem more than {0}.,ທ່ານບໍ່ສາມາດຈ່າຍຄືນໄດ້ເກີນ {0}.,
+Open Form View,ເປີດເບິ່ງແບບຟອມ,
+POS invoice {0} created succesfully,ໃບເກັບເງິນ POS {0} ຖືກສ້າງຂື້ນຢ່າງ ສຳ ເລັດຜົນ,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,ຈຳ ນວນຫຸ້ນບໍ່ພຽງພໍ ສຳ ລັບລະຫັດສິນຄ້າ: {0} ພາຍໃຕ້ຄັງສິນຄ້າ {1}. ປະລິມານທີ່ມີຢູ່ {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Serial No: {0} ໄດ້ຖືກໂອນເຂົ້າໄປໃນໃບເກັບເງິນ POS ອື່ນແລ້ວ.,
+Balance Serial No,ຍອດເງິນ Serial No,
+Warehouse: {0} does not belong to {1},ສາງ: {0} ບໍ່ຂຶ້ນກັບ {1},
+Please select batches for batched item {0},ກະລຸນາເລືອກກະເປົາ ສຳ ລັບລາຍການທີ່ເບື່ອຫນ່າຍ {0},
+Please select quantity on row {0},ກະລຸນາເລືອກປະລິມານຢູ່ແຖວ {0},
+Please enter serial numbers for serialized item {0},ກະລຸນາໃສ່ເບີໂທລະສັບ ສຳ ລັບລາຍການທີ່ມີ serialized {0},
+Batch {0} already selected.,ຊຸດ {0} ເລືອກແລ້ວ.,
+Please select a warehouse to get available quantities,ກະລຸນາເລືອກສາງເພື່ອຮັບປະລິມານທີ່ມີ,
+"For transfer from source, selected quantity cannot be greater than available quantity","ສຳ ລັບການໂອນຍ້າຍຈາກແຫຼ່ງ, ປະລິມານທີ່ເລືອກບໍ່ສາມາດສູງກວ່າປະລິມານທີ່ມີຢູ່",
+Cannot find Item with this Barcode,ບໍ່ສາມາດຊອກຫາລາຍການດ້ວຍ Barcode ນີ້,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} ແມ່ນ ຈຳ ເປັນ. ບາງທີບັນທຶກການແລກປ່ຽນເງິນຕາບໍ່ໄດ້ຖືກສ້າງຂື້ນ ສຳ ລັບ {1} ເຖິງ {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} ໄດ້ສົ່ງຊັບສິນທີ່ເຊື່ອມໂຍງກັບມັນ. ທ່ານ ຈຳ ເປັນຕ້ອງຍົກເລີກຊັບສິນເພື່ອສ້າງການຊື້ຄືນ.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,ບໍ່ສາມາດຍົກເລີກເອກະສານນີ້ຍ້ອນວ່າມັນເຊື່ອມໂຍງກັບຊັບສິນທີ່ຖືກສົ່ງມາ {0}. ກະລຸນາຍົກເລີກມັນເພື່ອ ດຳ ເນີນການຕໍ່ໄປ.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,ແຖວ # {}: ເລກ Serial No. {} ໄດ້ຖືກໂອນເຂົ້າໄປໃນໃບເກັບເງິນ POS ອື່ນແລ້ວ. ກະລຸນາເລືອກລະຫັດທີ່ຖືກຕ້ອງ.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,ແຖວ # {}: Serial Nos. {} ໄດ້ຖືກໂອນເຂົ້າໄປໃນໃບເກັບເງິນ POS ອື່ນແລ້ວ. ກະລຸນາເລືອກລະຫັດທີ່ຖືກຕ້ອງ.,
+Item Unavailable,ລາຍການບໍ່ມີ,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},ແຖວ # {}: ເລກ ລຳ ດັບ {} ບໍ່ສາມາດສົ່ງຄືນໄດ້ເນື່ອງຈາກມັນບໍ່ຖືກໂອນໃນໃບເກັບເງິນຕົ້ນສະບັບ {},
+Please set default Cash or Bank account in Mode of Payment {},ກະລຸນາຕັ້ງຄ່າເງີນສົດຫຼືບັນຊີທະນາຄານໃນຮູບແບບການ ຊຳ ລະເງິນ {},
+Please set default Cash or Bank account in Mode of Payments {},ກະລຸນາຕັ້ງຄ່າເງີນສົດຫລືບັນຊີທະນາຄານໃນຮູບແບບການ ຊຳ ລະເງິນ {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,ກະລຸນາຮັບປະກັນ {} ບັນຊີແມ່ນບັນຊີ Balance Sheet. ທ່ານສາມາດປ່ຽນບັນຊີຜູ້ປົກຄອງເຂົ້າໃນບັນຊີ Balance Sheet ຫຼືເລືອກບັນຊີອື່ນ.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,ກະລຸນາຮັບປະກັນ {} ບັນຊີແມ່ນບັນຊີທີ່ຕ້ອງຈ່າຍ. ປ່ຽນປະເພດບັນຊີໃຫ້ເປັນ Payable ຫຼືເລືອກບັນຊີອື່ນ.,
+Row {}: Expense Head changed to {} ,ແຖວ {}: ຫົວປ່ຽນແປງໃຊ້ເປັນ {},
+because account {} is not linked to warehouse {} ,ເພາະວ່າບັນຊີ {} ບໍ່ໄດ້ເຊື່ອມໂຍງກັບສາງ {},
+or it is not the default inventory account,ຫຼືມັນບໍ່ແມ່ນບັນຊີສິນຄ້າຄົງຄັງໃນຕອນຕົ້ນ,
+Expense Head Changed,ລາຍຈ່າຍປ່ຽນຫົວ,
+because expense is booked against this account in Purchase Receipt {},ເພາະວ່າຄ່າໃຊ້ຈ່າຍຈະຖືກຈອງຕໍ່ບັນຊີນີ້ໃນໃບຮັບເງິນຊື້ {},
+as no Purchase Receipt is created against Item {}. ,ຍ້ອນວ່າບໍ່ມີໃບເກັບເງິນການຊື້ຖືກສ້າງຂື້ນມາຕໍ່ກັບລາຍການ {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,ນີ້ແມ່ນເຮັດເພື່ອຈັດການບັນຊີ ສຳ ລັບກໍລະນີເມື່ອໃບຮັບເງິນຊື້ຖືກສ້າງຂື້ນຫລັງຈາກໃບເກັບເງິນຊື້,
+Purchase Order Required for item {},ສັ່ງຊື້ສິນຄ້າທີ່ຕ້ອງການ ສຳ ລັບສິນຄ້າ {},
+To submit the invoice without purchase order please set {} ,ເພື່ອສົ່ງໃບເກັບເງິນໂດຍບໍ່ຕ້ອງສັ່ງຊື້ກະລຸນາ ກຳ ນົດ {},
+as {} in {},ເປັນ {} ໃນ {},
+Mandatory Purchase Order,ການສັ່ງຊື້ແບບບັງຄັບ,
+Purchase Receipt Required for item {},ໃບຮັບເງິນການຊື້ທີ່ ຈຳ ເປັນ ສຳ ລັບລາຍການ {},
+To submit the invoice without purchase receipt please set {} ,"ເພື່ອສົ່ງໃບເກັບເງິນໂດຍບໍ່ໄດ້ຮັບໃບສັ່ງຊື້, ກະລຸນາຕັ້ງຄ່າ {}",
+Mandatory Purchase Receipt,ໃບຮັບເງິນຊື້ແບບບັງຄັບ,
+POS Profile {} does not belongs to company {},ໂປແກຼມ POS {} ບໍ່ຂຶ້ນກັບບໍລິສັດ {},
+User {} is disabled. Please select valid user/cashier,ຜູ້ໃຊ້ {} ຖືກປິດໃຊ້ງານ. ກະລຸນາເລືອກຜູ້ໃຊ້ / ຜູ້ເກັບເງິນທີ່ຖືກຕ້ອງ,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,ແຖວ # {}: ໃບເກັບເງິນຕົ້ນສະບັບ {} ຂອງໃບແຈ້ງ ໜີ້ ສົ່ງຄືນ {} ແມ່ນ {}.,
+Original invoice should be consolidated before or along with the return invoice.,ໃບເກັບເງິນຕົ້ນສະບັບຄວນຈະຖືກລວບລວມກ່ອນຫຼືພ້ອມກັບໃບເກັບເງິນຄືນ.,
+You can add original invoice {} manually to proceed.,ທ່ານສາມາດເພີ່ມໃບເກັບເງິນຕົ້ນສະບັບ {} ດ້ວຍຕົນເອງເພື່ອ ດຳ ເນີນການ.,
+Please ensure {} account is a Balance Sheet account. ,ກະລຸນາຮັບປະກັນ {} ບັນຊີແມ່ນບັນຊີ Balance Sheet.,
+You can change the parent account to a Balance Sheet account or select a different account.,ທ່ານສາມາດປ່ຽນບັນຊີຜູ້ປົກຄອງເຂົ້າໃນບັນຊີ Balance Sheet ຫຼືເລືອກບັນຊີອື່ນ.,
+Please ensure {} account is a Receivable account. ,ກະລຸນາຮັບປະກັນວ່າ {} ບັນຊີແມ່ນບັນຊີທີ່ຕ້ອງຍອມຮັບ.,
+Change the account type to Receivable or select a different account.,ປ່ຽນປະເພດບັນຊີໃຫ້ເປັນ Receivable ຫຼືເລືອກບັນຊີອື່ນ.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} ບໍ່ສາມາດຍົກເລີກໄດ້ເນື່ອງຈາກຈຸດທີ່ໄດ້ຮັບຈາກຄວາມພັກດີໄດ້ຖືກໄຖ່ແລ້ວ. ຍົກເລີກການ ທຳ ອິດ {} ບໍ່ {},
+already exists,ມີຢູ່ແລ້ວ,
+POS Closing Entry {} against {} between selected period,POS ປິດການເຂົ້າ {} ຕໍ່ {} ລະຫວ່າງໄລຍະເວລາທີ່ເລືອກ,
+POS Invoice is {},ໃບເກັບເງິນ POS ແມ່ນ {},
+POS Profile doesn't matches {},POS Profile ບໍ່ກົງກັບ {},
+POS Invoice is not {},ໃບເກັບເງິນ POS ບໍ່ແມ່ນ {},
+POS Invoice isn't created by user {},ໃບເກັບເງິນ POS ບໍ່ໄດ້ຖືກສ້າງຂື້ນໂດຍຜູ້ໃຊ້ {},
+Row #{}: {},ແຖວ # {}: {},
+Invalid POS Invoices,ໃບເກັບເງິນ POS ບໍ່ຖືກຕ້ອງ,
+Please add the account to root level Company - {},ກະລຸນາເພີ່ມບັນຊີເຂົ້າໃນລະດັບຮາກຂອງບໍລິສັດ - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","ໃນຂະນະທີ່ສ້າງບັນຊີ ສຳ ລັບບໍລິສັດເດັກ {0}, ບັນຊີຜູ້ປົກຄອງ {1} ບໍ່ພົບ. ກະລຸນາສ້າງບັນຊີຜູ້ປົກຄອງໃນ COA ທີ່ສອດຄ້ອງກັນ",
+Account Not Found,ບໍ່ພົບບັນຊີ,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","ໃນຂະນະທີ່ສ້າງບັນຊີ ສຳ ລັບບໍລິສັດເດັກ {0}, ບັນຊີຜູ້ປົກຄອງ {1} ພົບວ່າບັນຊີ ນຳ ໃຊ້.",
+Please convert the parent account in corresponding child company to a group account.,ກະລຸນາປ່ຽນບັນຊີຜູ້ປົກຄອງໃນບໍລິສັດເດັກທີ່ສອດຄ້ອງກັນເຂົ້າໃນບັນຊີກຸ່ມ.,
+Invalid Parent Account,ບັນຊີພໍ່ແມ່ບໍ່ຖືກຕ້ອງ,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","ປ່ຽນຊື່ມັນຖືກອະນຸຍາດພຽງແຕ່ຜ່ານທາງບໍລິສັດແມ່ {0}, ເພື່ອຫລີກລ້ຽງຄວາມບໍ່ສອດຄ່ອງ.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","ຖ້າທ່ານ {0} {1} ປະລິມານຂອງລາຍການ {2}, ລະບົບ {3} ຈະຖືກ ນຳ ໃຊ້ໃນລາຍການ.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","ຖ້າທ່ານ {0} {1} ລາຍການທີ່ມີຄ່າ {2}, ໂຄງການ {3} ຈະຖືກ ນຳ ໃຊ້ໃນລາຍການ.",
+"As the field {0} is enabled, the field {1} is mandatory.","ຍ້ອນວ່າພາກສະ ໜາມ {0} ຖືກເປີດໃຊ້, ພາກສະ ໜາມ {1} ແມ່ນ ຈຳ ເປັນ.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","ຍ້ອນວ່າພາກສະຫນາມ {0} ຖືກເປີດໃຊ້, ມູນຄ່າຂອງພາກສະ ໜາມ {1} ຄວນຈະສູງກວ່າ 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},ບໍ່ສາມາດຈັດສົ່ງສິນຄ້າ Serial No {0} ຂອງສິນຄ້າ {1} ຍ້ອນວ່າມັນຖືກສະຫງວນໄວ້ເພື່ອສັ່ງຂາຍເຕັມຮູບແບບ {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","ຄຳ ສັ່ງຂາຍ {0} ມີການສັ່ງຈອງ ສຳ ລັບສິນຄ້າ {1}, ທ່ານພຽງແຕ່ສາມາດຈັດສົ່ງ {1} ສຳ ລັບ {0} ເທົ່ານັ້ນ.",
+{0} Serial No {1} cannot be delivered,{0} Serial No {1} ບໍ່ສາມາດຈັດສົ່ງໄດ້,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},ແຖວ {0}: ສິນຄ້າທີ່ໄດ້ຮັບການຮັບຮອງແມ່ນ ຈຳ ເປັນ ສຳ ລັບວັດຖຸດິບ {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","ຍ້ອນວ່າມີວັດຖຸດິບທີ່ພຽງພໍ, ບໍ່ ຈຳ ເປັນຕ້ອງຂໍວັດສະດຸ ສຳ ລັບສາງ {0}.",
+" If you still want to proceed, please enable {0}.","ຖ້າທ່ານຍັງຕ້ອງການ ດຳ ເນີນການ, ກະລຸນາເປີດ {0}.",
+The item referenced by {0} - {1} is already invoiced,ລາຍການທີ່ອ້າງອິງໂດຍ {0} - {1} ແມ່ນຖືກເອີ້ນເຂົ້າແລ້ວ,
+Therapy Session overlaps with {0},Therapy Session ຊ້ ຳ ກັບ {0},
+Therapy Sessions Overlapping,ການປິ່ນປົວດ້ວຍການຊໍ້າຊ້ອນ,
+Therapy Plans,ແຜນການປິ່ນປົວ,
+"Item Code, warehouse, quantity are required on row {0}","ລະຫັດສິນຄ້າ, ຄັງສິນຄ້າ, ຈຳ ນວນທີ່ຕ້ອງການຢູ່ແຖວ {0}",
+Get Items from Material Requests against this Supplier,ໄດ້ຮັບສິນຄ້າຈາກຂໍ້ຮຽກຮ້ອງດ້ານວັດຖຸຕໍ່ຜູ້ສະ ໜອງ ນີ້,
+Enable European Access,ເປີດໃຊ້ງານ European Access,
+Creating Purchase Order ...,ການສ້າງໃບສັ່ງຊື້ ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","ເລືອກຜູ້ສະ ໜອງ ສິນຄ້າຈາກຜູ້ສະ ໜອງ ສິນຄ້າເລີ່ມຕົ້ນຂອງລາຍການຂ້າງລຸ່ມນີ້. ໃນການເລືອກ, ຄຳ ສັ່ງຊື້ສິນຄ້າຈະຖືກຕໍ່ຕ້ານກັບສິນຄ້າທີ່ເປັນຂອງຜູ້ສະ ໜອງ ທີ່ຖືກຄັດເລືອກເທົ່ານັ້ນ.",
+Row #{}: You must select {} serial numbers for item {}.,ແຖວ # {}: ທ່ານຕ້ອງເລືອກ {} ເລກ ລຳ ດັບ ສຳ ລັບລາຍການ {}.,
diff --git a/erpnext/translations/lt.csv b/erpnext/translations/lt.csv
index cdcfe31..78571f9 100644
--- a/erpnext/translations/lt.csv
+++ b/erpnext/translations/lt.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Tikrasis tipas mokestis negali būti įtrauktos prekės lygis eilės {0},
Add,Papildyti,
Add / Edit Prices,Įdėti / Redaguoti kainas,
-Add All Suppliers,Pridėti visus tiekėjus,
Add Comment,Pridėti komentarą,
Add Customers,Pridėti klientams,
Add Employees,Pridėti Darbuotojai,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Negali atskaityti, kai kategorija skirta "Vertinimo" arba "Vaulation ir viso"",
"Cannot delete Serial No {0}, as it is used in stock transactions","Negalite trinti Serijos Nr {0}, kaip ji yra naudojama akcijų sandorių",
Cannot enroll more than {0} students for this student group.,Negalima registruotis daugiau nei {0} studentams šio studentų grupę.,
-Cannot find Item with this barcode,Neįmanoma rasti elemento su šiuo brūkšniniu kodu,
Cannot find active Leave Period,Nepavyko rasti aktyvios palikimo laikotarpio,
Cannot produce more Item {0} than Sales Order quantity {1},Negali gaminti daugiau Elementą {0} nei pardavimų užsakymų kiekio {1},
Cannot promote Employee with status Left,"Negalima reklamuoti darbuotojo, kurio statusas kairėje",
Cannot refer row number greater than or equal to current row number for this Charge type,Negali remtis eilutės skaičius didesnis nei arba lygus dabartinės eilutės numeris Šio mokesčio tipą,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"Negalima pasirinkti įkrovimo tipas, kaip "Dėl ankstesnės eilės Suma" arba "Dėl ankstesnės eilės Total" už pirmoje eilutėje",
-Cannot set a received RFQ to No Quote,Negalima nustatyti gauta RFQ jokiai citata,
Cannot set as Lost as Sales Order is made.,Negalima nustatyti kaip Pamiršote nes yra pagamintas pardavimų užsakymų.,
Cannot set authorization on basis of Discount for {0},Negalima nustatyti leidimo pagrindu Nuolaida {0},
Cannot set multiple Item Defaults for a company.,Negalima nustatyti kelios įmonės numatytosios pozicijos.,
@@ -521,7 +518,6 @@
Chargeble,Apmokestinamas,
Charges are updated in Purchase Receipt against each item,Mokesčiai yra atnaujinama pirkimo kvitą su kiekvieno elemento,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Mokesčiai bus platinamas proporcingai remiantis punktas Kiekis arba sumos, kaip už savo pasirinkimą",
-Chart Of Accounts,Sąskaitų planas,
Chart of Cost Centers,Schema sąnaudų centrams,
Check all,Viską Patikrink,
Checkout,Užsakymas,
@@ -581,7 +577,6 @@
Compensatory Off,kompensacinė Išjungtas,
Compensatory leave request days not in valid holidays,Kompensuojamųjų atostogų prašymo dienos netaikomos galiojančiomis atostogomis,
Complaint,Skundas,
-Completed Qty can not be greater than 'Qty to Manufacture',Užbaigtas Kiekis negali būti didesnis nei "Kiekis iki Gamyba",
Completion Date,užbaigimo data,
Computer,Kompiuteris,
Condition,būklė,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Kurkite ir tvarkykite savo dienos, savaitės ir mėnesio el suskaldyti.",
Create customer quotes,Sukurti klientų citatos,
Create rules to restrict transactions based on values.,"Sukurti taisykles, siekdama apriboti sandorius, pagrįstus vertybes.",
-Created By,Sukurta,
Created {0} scorecards for {1} between: ,"Sukurtos {0} rezultatų kortelės, skirtos {1}, tarp:",
Creating Company and Importing Chart of Accounts,Kurti įmonę ir importuoti sąskaitų schemą,
Creating Fees,Mokesčių kūrimas,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Darbuotojų pervedimas negali būti pateiktas prieš pervedimo datą,
Employee cannot report to himself.,Darbuotojas negali pranešti pats.,
Employee relieved on {0} must be set as 'Left',Darbuotojų atleidžiamas nuo {0} turi būti nustatyti kaip "Left",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Darbuotojo statuso negalima nustatyti į „kairę“, nes šiam darbuotojui šiuo metu atsiskaito šie darbuotojai:",
Employee {0} already submited an apllication {1} for the payroll period {2},Darbuotojas {0} jau pateikė apllication {1} už darbo užmokesčio laikotarpį {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Darbuotojas {0} jau pateikė paraišką {1} nuo {2} iki {3}:,
Employee {0} has no maximum benefit amount,Darbuotojas {0} neturi didžiausios naudos sumos,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Eilutėje {0}: įveskite numatytą kiekį,
"For {0}, only credit accounts can be linked against another debit entry",Dėl {0} tik kredito sąskaitos gali būti susijęs su kitos debeto įrašą,
"For {0}, only debit accounts can be linked against another credit entry","Dėl {0}, tik debeto sąskaitos gali būti susijęs su kitos kredito įrašą",
-Form View,Formos peržiūra,
Forum Activity,Forumo veikla,
Free item code is not selected,Nemokamas prekės kodas nepasirinktas,
Freight and Forwarding Charges,Krovinių ir ekspedijavimo mokesčiai,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Palikite negali būti skiriama iki {0}, kaip atostogos balansas jau perkėlimo persiunčiami būsimos atostogos paskirstymo įrašo {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Palikite negali būti taikomas / atšaukė prieš {0}, kaip atostogos balansas jau perkėlimo persiunčiami būsimos atostogos paskirstymo įrašo {1}",
Leave of type {0} cannot be longer than {1},Atostogos tipo {0} negali būti ilgesnis nei {1},
-Leave the field empty to make purchase orders for all suppliers,"Palikite lauką tuščią, kad pirkimo užsakymai būtų tiekiami visiems tiekėjams",
Leaves,Lapai,
Leaves Allocated Successfully for {0},Lapai Paskirti sėkmingai {0},
Leaves has been granted sucessfully,Lapai buvo sėkmingai suteiktos,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,"Neturite prekių su Bill iš medžiagų, Gamyba",
No Items with Bill of Materials.,"Nėra daiktų, turinčių medžiagų sąskaitą.",
No Permission,Nėra leidimo,
-No Quote,Nr citatos,
No Remarks,nėra Pastabos,
No Result to submit,Nėra rezultato pateikti,
No Salary Structure assigned for Employee {0} on given date {1},Nė viena atlyginimo struktūra darbuotojui {0} nurodytoje datoje {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,rasti tarp sutampančių sąlygos:,
Owner,Savininkas,
PAN,PAN,
-PO already created for all sales order items,PO jau sukurtas visiems pardavimo užsakymo elementams,
POS,POS,
POS Profile,POS profilis,
POS Profile is required to use Point-of-Sale,"Pozicijos profilis reikalingas, norint naudoti "Point-of-Sale"",
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Prašome pasirinkti mokesčių rūšis pirmą kartą,
Please select Company,Prašome pasirinkti kompaniją,
Please select Company and Designation,Pasirinkite bendrovę ir žymėjimą,
-Please select Company and Party Type first,Prašome pasirinkti bendrovė ir šalies tipo pirmas,
Please select Company and Posting Date to getting entries,"Jei norite gauti įrašus, pasirinkite Įmonės ir paskelbimo datą",
Please select Company first,Prašome pasirinkti Company pirmas,
Please select Completion Date for Completed Asset Maintenance Log,Prašome pasirinkti baigtinio turto priežiūros žurnalo užbaigimo datą,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Eilutės {0}: UOM konversijos faktorius yra privalomas,
Row {0}: select the workstation against the operation {1},Eilutė {0}: pasirinkite darbo vietą prieš operaciją {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Eilutė {0}: {1} {2} elementui reikalingi eilės numeriai. Jūs pateikė {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,"Rodyklė {0}: {1} reikalinga, norint sukurti atvirą {2} sąskaitą faktūrą",
Row {0}: {1} must be greater than 0,Eilutė {0}: {1} turi būti didesnė už 0,
Row {0}: {1} {2} does not match with {3},Eilutės {0}: {1} {2} nesutampa su {3},
Row {0}:Start Date must be before End Date,Eilutės {0}: pradžios data turi būti prieš End data,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Siųsti grantų peržiūrą el. Paštu,
Send Now,Išsiusti dabar,
Send SMS,Siųsti SMS,
-Send Supplier Emails,Siųsti Tiekėjo laiškus,
Send mass SMS to your contacts,Siųsti masės SMS į jūsų kontaktus,
Sensitivity,Jautrumas,
Sent,siunčiami,
-Serial #,Serijinis #,
Serial No and Batch,Serijos Nr paketais,
Serial No is mandatory for Item {0},Serijos Nr privaloma punkte {0},
Serial No {0} does not belong to Batch {1},Serijos numeris {0} nepriklauso paketui {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Jūsų įmonės pavadinimas, dėl kurių jūs nustatote šią sistemą.",
The number of shares and the share numbers are inconsistent,Akcijų skaičius ir akcijų skaičius yra nenuoseklūs,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Plano {0} mokėjimo sąsajos sąskaita skiriasi nuo mokėjimo sąsajos sąskaitos šiame mokėjimo prašyme,
-The request for quotation can be accessed by clicking on the following link,Už citatos prašymas gali būti atvertas paspaudę šią nuorodą,
The selected BOMs are not for the same item,Pasirinktos BOMs yra ne to paties objekto,
The selected item cannot have Batch,Pasirinktas elementas negali turėti Serija,
The seller and the buyer cannot be the same,Pardavėjas ir pirkėjas negali būti vienodi,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Bendra lanksčios išmokos komponento suma {0} neturėtų būti mažesnė už maksimalią naudą {1},
Total hours: {0},Iš viso valandų: {0},
Total leaves allocated is mandatory for Leave Type {0},"Iš viso paskirtų lapų privaloma, jei paliekamas tipas {0}",
-Total weightage assigned should be 100%. It is {0},Iš viso weightage priskirti turi būti 100%. Ji yra {0},
Total working hours should not be greater than max working hours {0},Iš viso darbo valandų turi būti ne didesnis nei maks darbo valandų {0},
Total {0} ({1}),Viso {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Viso {0} visoms prekėms yra lygus nuliui, gali būti, jūs turėtumėte pakeisti "Paskirstyti mokesčius pagal"",
@@ -3316,7 +3299,6 @@
What do you need help with?,Ką reikia pagalbos?,
What does it do?,Ką tai daro?,
Where manufacturing operations are carried.,Kur gamybos operacijos atliekamos.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Kuriant sąskaitą vaikų įmonei {0}, pagrindinė sąskaita {1} nerasta. Sukurkite pagrindinę sąskaitą atitinkamame COA",
White,baltas,
Wire Transfer,pavedimu,
WooCommerce Products,„WooCommerce“ produktai,
@@ -3448,7 +3430,6 @@
{0} variants created.,Sukurta {0} variantų.,
{0} {1} created,{0} {1} sukūrė,
{0} {1} does not exist,{0} {1} neegzistuoja,
-{0} {1} does not exist.,{0} {1} neegzistuoja.,
{0} {1} has been modified. Please refresh.,{0} {1} buvo pakeistas. Prašome atnaujinti.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} nebuvo pateikta ir todėl veiksmai negali būti užbaigti,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} susijęs su {2}, bet šalies sąskaita {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} neegzistuoja,
{0}: {1} not found in Invoice Details table,{0}: {1} nerasta Sąskaitos informacijos lentelės,
{} of {},{} apie {},
+Assigned To,Priskirtas,
Chat,kalbėtis,
Completed By,Užbaigtas,
Conditions,Sąlygos,
@@ -3506,7 +3488,9 @@
Merge with existing,Sujungti su esama,
Office,biuras,
Orientation,orientacija,
+Parent,tėvas,
Passive,pasyvus,
+Payment Failed,Mokėjimo Nepavyko,
Percent,procentai,
Permanent,nuolatinis,
Personal,Asmeninis,
@@ -3544,7 +3528,6 @@
Company field is required,Įmonės laukas yra būtinas,
Creating Dimensions...,Kuriami aspektai ...,
Duplicate entry against the item code {0} and manufacturer {1},Gaminio kodo {0} ir gamintojo {1} dublikatas,
-Import Chart Of Accounts from CSV / Excel files,Importuokite sąskaitų diagramą iš CSV / „Excel“ failų,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Neteisingas GSTIN! Jūsų įvestas įrašas neatitinka UIN turėtojų ar nerezidentų OIDAR paslaugų teikėjų GSTIN formato,
Invoice Grand Total,Sąskaita faktūra iš viso,
Last carbon check date cannot be a future date,Paskutinė anglies dioksido kiekio tikrinimo data negali būti būsima data,
@@ -3556,6 +3539,7 @@
Show {0},Rodyti {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Specialieji simboliai, išskyrus „-“, „#“, „.“, „/“, „{“ Ir „}“, neleidžiami įvardyti serijomis",
Target Details,Tikslinė informacija,
+{0} already has a Parent Procedure {1}.,{0} jau turi tėvų procedūrą {1}.,
API,API,
Annual,metinis,
Approved,patvirtinta,
@@ -3572,6 +3556,8 @@
No data to export,"Nėra duomenų, kuriuos būtų galima eksportuoti",
Portrait,Portretas,
Print Heading,Spausdinti pozicijoje,
+Scheduler Inactive,Tvarkaraštis neaktyvus,
+Scheduler is inactive. Cannot import data.,Tvarkaraštis neaktyvus. Neįmanoma importuoti duomenų.,
Show Document,Rodyti dokumentą,
Show Traceback,Rodyti „Traceback“,
Video,Vaizdo įrašas,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Sukurkite {0} elemento kokybės patikrinimą,
Creating Accounts...,Kuriamos paskyros ...,
Creating bank entries...,Kuriami banko įrašai ...,
-Creating {0},Kūrimas {0},
Credit limit is already defined for the Company {0},Kredito limitas įmonei jau yra apibrėžtas {0},
Ctrl + Enter to submit,„Ctrl“ + „Enter“ pateikti,
Ctrl+Enter to submit,"Ctrl + Enter, kad galėtumėte pateikti",
@@ -3921,7 +3906,6 @@
Plaid public token error,Akivaizdi viešojo ženklo klaida,
Plaid transactions sync error,Paprastų operacijų sinchronizavimo klaida,
Please check the error log for details about the import errors,"Patikrinkite klaidų žurnalą, kad gautumėte informacijos apie importavimo klaidas",
-Please click on the following link to set your new password,Spustelėkite šią nuorodą nustatyti naują slaptažodį,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,Sukurkite <b>DATEV nustatymus</b> įmonei <b>{}</b> .,
Please create adjustment Journal Entry for amount {0} ,Sukurkite {0} sumos koregavimo žurnalo įrašą,
Please do not create more than 500 items at a time,Nesukurkite daugiau nei 500 daiktų vienu metu,
@@ -3997,6 +3981,7 @@
Release date must be in the future,Išleidimo data turi būti ateityje,
Relieving Date must be greater than or equal to Date of Joining,Atleidimo data turi būti didesnė arba lygi prisijungimo datai,
Rename,pervadinti,
+Rename Not Allowed,Pervardyti neleidžiama,
Repayment Method is mandatory for term loans,Grąžinimo būdas yra privalomas terminuotoms paskoloms,
Repayment Start Date is mandatory for term loans,Grąžinimo pradžios data yra privaloma terminuotoms paskoloms,
Report Item,Pranešti apie prekę,
@@ -4043,7 +4028,6 @@
Select All,Pasirinkti viską,
Select Difference Account,Pasirinkite skirtumų sąskaitą,
Select a Default Priority.,Pasirinkite numatytąjį prioritetą.,
-Select a Supplier from the Default Supplier List of the items below.,"Iš tiekėjų, esančių žemiau esančiame prekių sąraše, pasirinkite tiekėją.",
Select a company,Pasirinkite įmonę,
Select finance book for the item {0} at row {1},Pasirinkite {0} eilutės {1} finansinę knygą,
Select only one Priority as Default.,Pasirinkite tik vieną prioritetą kaip numatytąjį.,
@@ -4247,7 +4231,6 @@
Actual ,faktinis,
Add to cart,Į krepšelį,
Budget,Biudžetas,
-Chart Of Accounts Importer,Sąskaitų diagrama,
Chart of Accounts,Sąskaitų diagrama,
Customer database.,Klientų duomenų bazė.,
Days Since Last order,Dienos nuo paskutinio įsakymo,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Galutinė data negali būti mažesnė už pradžios datą,
For Default Supplier (Optional),Numatytam tiekėjui (neprivaloma),
From date cannot be greater than To date,Nuo datos negali būti didesnis nei iki datos,
-Get items from,Gauk elementus iš,
Group by,Grupuoti pagal,
In stock,Sandelyje,
Item name,Daikto pavadinimas,
@@ -4532,32 +4514,22 @@
Accounts Settings,Sąskaitos Nustatymai,
Settings for Accounts,Nustatymai sąskaitų,
Make Accounting Entry For Every Stock Movement,Padaryti apskaitos įrašas Kiekvienas vertybinių popierių judėjimo,
-"If enabled, the system will post accounting entries for inventory automatically.","Jei įjungta, sistema bus po apskaitos įrašus inventoriaus automatiškai.",
-Accounts Frozen Upto,Sąskaitos Šaldyti upto,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Apskaitos įrašas, užšaldyti iki šios datos, niekas negali padaryti / pakeisti įrašą, išskyrus žemiau nurodytą vaidmenį.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Vaidmuo leidžiama nustatyti užšaldytų sąskaitų ir redaguoti Šaldyti įrašai,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,"Vartotojai, turintys šį vaidmenį yra leidžiama nustatyti įšaldytas sąskaitas ir sukurti / pakeisti apskaitos įrašus prieš įšaldytų sąskaitų",
Determine Address Tax Category From,Adreso mokesčio kategorijos nustatymas nuo,
-Address used to determine Tax Category in transactions.,"Adresas, naudojamas sandorių mokesčių kategorijai nustatyti.",
Over Billing Allowance (%),Viršijanti atsiskaitymo pašalpa (%),
-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 for $110.,"Procentas, kuriam leidžiama sumokėti daugiau už užsakytą sumą. Pvz .: Jei prekės užsakymo vertė yra 100 USD, o paklaida yra nustatyta 10%, tada leidžiama atsiskaityti už 110 USD.",
Credit Controller,kredito valdiklis,
-Role that is allowed to submit transactions that exceed credit limits set.,"Vaidmenį, kurį leidžiama pateikti sandorius, kurie viršija nustatytus kredito limitus.",
Check Supplier Invoice Number Uniqueness,Patikrinkite Tiekėjas sąskaitos faktūros numeris Unikalumas,
Make Payment via Journal Entry,Atlikti mokėjimą per žurnalo įrašą,
Unlink Payment on Cancellation of Invoice,Atsieti Apmokėjimas atšaukimas sąskaita faktūra,
-Unlink Advance Payment on Cancelation of Order,Atsiekite išankstinį mokėjimą už užsakymo atšaukimą,
Book Asset Depreciation Entry Automatically,Užsakyti Turto nusidėvėjimas Įėjimas Automatiškai,
Automatically Add Taxes and Charges from Item Tax Template,Automatiškai pridėti mokesčius ir rinkliavas iš elemento mokesčio šablono,
Automatically Fetch Payment Terms,Automatiškai gauti mokėjimo sąlygas,
-Show Inclusive Tax In Print,Rodyti inkliuzinį mokestį spausdinant,
Show Payment Schedule in Print,Rodyti mokėjimo grafiką Spausdinti,
Currency Exchange Settings,Valiutos keitimo nustatymai,
Allow Stale Exchange Rates,Leisti nejudančius valiutų keitimo kursus,
Stale Days,Pasenusios dienos,
Report Settings,Pranešimo nustatymai,
Use Custom Cash Flow Format,Naudokite tinkintą pinigų srautų formatą,
-Only select if you have setup Cash Flow Mapper documents,"Pasirinkite tik tada, jei turite nustatymus Pinigų srauto kartografavimo dokumentus",
Allowed To Transact With,Leidžiama sudaryti sandorius su,
SWIFT number,SWIFT numeris,
Branch Code,Filialo kodas,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Klientų grupė,
POS Field,POS laukas,
POS Item Group,POS punktas grupė,
-[Select],[Pasirinkti],
Company Address,Kompanijos adresas,
Update Stock,Atnaujinti sandėlyje,
Ignore Pricing Rule,Ignoruoti kainodaros taisyklė,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Tiekėjas įvardijimas Iki,
Default Supplier Group,Numatytoji tiekėjų grupė,
Default Buying Price List,Numatytasis Ieško Kainų sąrašas,
-Maintain same rate throughout purchase cycle,Išlaikyti tą patį tarifą visoje pirkimo ciklo,
-Allow Item to be added multiple times in a transaction,Leisti punktas turi būti pridėtas kelis kartus iš sandorio,
Backflush Raw Materials of Subcontract Based On,Subrangos pagrindu sukurtos žaliavos,
Material Transferred for Subcontract,Subrangos sutarčiai perduota medžiaga,
Over Transfer Allowance (%),Permokos pašalpa (%),
@@ -5540,7 +5509,6 @@
Current Stock,Dabartinis sandėlyje,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Dėl individualaus tiekėjo,
-Supplier Detail,tiekėjas detalės,
Link to Material Requests,Nuoroda į materialinius prašymus,
Message for Supplier,Pranešimo tiekėjas,
Request for Quotation Item,Užklausimas punktas,
@@ -6481,7 +6449,6 @@
Appraisal Template,vertinimas Šablono,
For Employee Name,Darbuotojo Vardas,
Goals,Tikslai,
-Calculate Total Score,Apskaičiuokite bendras rezultatas,
Total Score (Out of 5),Iš viso balas (iš 5),
"Any other remarks, noteworthy effort that should go in the records.","Bet koks kitas pastabas, pažymėtina pastangų, kad reikia eiti į apskaitą.",
Appraisal Goal,vertinimas tikslas,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Išvykimo priežastis,
Leave Encashed?,Palikite Encashed?,
Encashment Date,išgryninimo data,
-Exit Interview Details,Išeiti Interviu detalės,
-Held On,vyks,
-Reason for Resignation,"Priežastis, dėl atsistatydinimo",
-Better Prospects,Geresnės perspektyvos,
-Health Concerns,sveikatos problemas,
New Workplace,nauja Darbo,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Grąžinta suma,
@@ -6740,10 +6702,7 @@
Employee Settings,darbuotojų Nustatymai,
Retirement Age,pensijinis amžius,
Enter retirement age in years,Įveskite pensinį amžių metais,
-Employee Records to be created by,Darbuotojų Įrašai turi būti sukurtas,
-Employee record is created using selected field. ,Darbuotojų įrašas sukurtas naudojant pasirinktą lauką.,
Stop Birthday Reminders,Sustabdyti Gimimo diena Priminimai,
-Don't send Employee Birthday Reminders,Nesiųskite Darbuotojų Gimimo diena Priminimai,
Expense Approver Mandatory In Expense Claim,Išlaidų patvirtinimo priemonė privaloma išlaidų deklaracijoje,
Payroll Settings,Payroll Nustatymai,
Leave,Išeik,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Palikite patvirtinantįjį privaloma palikti paraišką,
Show Leaves Of All Department Members In Calendar,Rodyti visų departamento narių lapelius kalendoriuje,
Auto Leave Encashment,Automatinis atostogų užšifravimas,
-Restrict Backdated Leave Application,Apriboti pasenusių atostogų prašymą,
Hiring Settings,Nuomos nustatymai,
Check Vacancies On Job Offer Creation,Patikrinkite laisvų darbo vietų kūrimo darbo vietas,
Identification Document Type,Identifikacijos dokumento tipas,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Gamybos Nustatymai,
Raw Materials Consumption,Žaliavų vartojimas,
Allow Multiple Material Consumption,Leisti daug medžiagų sunaudojimą,
-Allow multiple Material Consumption against a Work Order,Leiskite kelis medžiagos sunaudojimą pagal darbo tvarką,
Backflush Raw Materials Based On,Backflush Žaliavos remiantis,
Material Transferred for Manufacture,"Medžiagos, perduotos gamybai",
Capacity Planning,Talpa planavimas,
Disable Capacity Planning,Išjungti talpos planavimą,
Allow Overtime,Leiskite viršvalandžius,
-Plan time logs outside Workstation Working Hours.,Planuokite laiką rąstų lauko Workstation "darbo valandomis.,
Allow Production on Holidays,Leiskite gamyba Šventės,
Capacity Planning For (Days),Talpa planavimas (dienos),
-Try planning operations for X days in advance.,Pabandykite planuoja operacijas X dienų iš anksto.,
-Time Between Operations (in mins),Laikas tarp operacijų (minutėmis),
-Default 10 mins,Numatytasis 10 min,
Default Warehouses for Production,Numatytieji sandėliai gamybai,
Default Work In Progress Warehouse,Numatytasis nebaigtos Warehouse,
Default Finished Goods Warehouse,Numatytieji gatavų prekių sandėlis,
Default Scrap Warehouse,Numatytasis laužo sandėlis,
-Over Production for Sales and Work Order,Virš produkcijos pardavimui ir užsakymas darbui,
Overproduction Percentage For Sales Order,Perprodukcijos procentas pardavimo užsakymui,
Overproduction Percentage For Work Order,Perprodukcijos procentas už darbo tvarką,
Other Settings,Kiti nustatymai,
Update BOM Cost Automatically,Atnaujinti BOM kainą automatiškai,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Atnaujinti BOM išlaidas automatiškai per planuotoją, remiantis naujausiu žaliavų įvertinimo / kainų sąrašo norma / paskutine pirkimo norma.",
Material Request Plan Item,Materialinio prašymo plano punktas,
Material Request Type,Medžiaga Prašymas tipas,
Material Issue,medžiaga išdavimas,
@@ -7603,10 +7554,6 @@
Quality Goal,Kokybės tikslas,
Monitoring Frequency,Stebėjimo dažnis,
Weekday,Savaitės diena,
-January-April-July-October,Sausis – balandis – liepa – spalis,
-Revision and Revised On,Peržiūrėta ir persvarstyta,
-Revision,Revizija,
-Revised On,Peržiūrėta,
Objectives,Tikslai,
Quality Goal Objective,Kokybės tikslas,
Objective,Tikslas,
@@ -7619,7 +7566,6 @@
Processes,Procesai,
Quality Procedure Process,Kokybės procedūros procesas,
Process Description,Proceso aprašymas,
-Child Procedure,Vaiko procedūra,
Link existing Quality Procedure.,Susiekite esamą kokybės procedūrą.,
Additional Information,Papildoma informacija,
Quality Review Objective,Kokybės peržiūros tikslas,
@@ -7787,15 +7733,9 @@
Default Customer Group,Pagal nutylėjimą klientų grupei,
Default Territory,numatytasis teritorija,
Close Opportunity After Days,Uždaryti progą dienų,
-Auto close Opportunity after 15 days,Auto arti Galimybė po 15 dienų,
Default Quotation Validity Days,Numatytų kuponų galiojimo dienos,
Sales Update Frequency,Pardavimų atnaujinimo dažnumas,
-How often should project and company be updated based on Sales Transactions.,Kaip dažnai reikia atnaujinti projektą ir įmonę remiantis pardavimo sandoriais.,
Each Transaction,Kiekvienas sandoris,
-Allow user to edit Price List Rate in transactions,Leisti vartotojui redaguoti kainoraštį Balsuok sandoriuose,
-Allow multiple Sales Orders against a Customer's Purchase Order,Leisti kelis pardavimų užsakymų prieš Kliento Užsakymo,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Patvirtinti pardavimo kaina už prekę prieš Pirkimo rodikliu Vertinimo koeficientas,
-Hide Customer's Tax Id from Sales Transactions,Slėpti Kliento mokesčių ID iš pardavimo sandorių,
SMS Center,SMS centro,
Send To,siųsti,
All Contact,visi Susisiekite,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Gamintojai naudojami daiktai,
Limited to 12 characters,Ribojamas iki 12 simbolių,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Nustatyti sandėlį,
-Sets 'For Warehouse' in each row of the Items table.,Kiekvienoje lentelės Elementai eilutėje nustatomas „Sandėliui“.,
-Requested For,prašoma Dėl,
Partially Ordered,Iš dalies užsakyta,
Transferred,Perduotas,
% Ordered,% Užsakytas,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Numatytasis sandėlyje UOM,
Sample Retention Warehouse,Mėginio saugojimo sandėlis,
Default Valuation Method,Numatytasis vertinimo metodas,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Procentas jums leidžiama gauti arba pristatyti daugiau prieš užsakyto kiekio. Pavyzdžiui: Jei užsisakėte 100 vienetų. ir jūsų pašalpa yra 10%, tada jums yra leidžiama gauti 110 vienetų.",
-Action if Quality inspection is not submitted,"Veiksmas, jei nepateikiama kokybės patikra",
Show Barcode Field,Rodyti Brūkšninis kodas laukas,
Convert Item Description to Clean HTML,"Konvertuoti elemento apibūdinimą, norint išvalyti HTML",
-Auto insert Price List rate if missing,"Automatinis įterpti Kainų sąrašas norma, jei trūksta",
Allow Negative Stock,Leiskite Neigiama Stock,
Automatically Set Serial Nos based on FIFO,Automatiškai Eilės Nr remiantis FIFO,
-Set Qty in Transactions based on Serial No Input,"Nustatykite kiekį sandoriuose, kurie yra pagrįsti serijiniu numeriu",
Auto Material Request,Auto Medžiaga Prašymas,
-Raise Material Request when stock reaches re-order level,Pakelkite Material užklausą Kai akcijų pasiekia naujo užsakymo lygį,
-Notify by Email on creation of automatic Material Request,Praneškite elektroniniu paštu steigti automatinio Medžiaga Užsisakyti,
Inter Warehouse Transfer Settings,Tarpinio sandėlio perkėlimo nustatymai,
-Allow Material Transfer From Delivery Note and Sales Invoice,Leisti perduoti medžiagą iš pristatymo lapo ir pardavimo sąskaitos faktūros,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Leisti perduoti medžiagą iš pirkimo kvito ir pirkimo sąskaitos faktūros,
Freeze Stock Entries,Freeze Akcijų įrašai,
Stock Frozen Upto,Akcijų Šaldyti upto,
-Freeze Stocks Older Than [Days],Freeze Atsargos senesnis nei [diena],
-Role Allowed to edit frozen stock,Vaidmuo leidžiama redaguoti šaldytą žaliavą,
Batch Identification,Partijos identifikavimas,
Use Naming Series,Naudokite vardų seriją,
Naming Series Prefix,Vardų serijos prefiksas,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Pirkimo kvito tendencijos,
Purchase Register,pirkimo Registruotis,
Quotation Trends,Kainų tendencijos,
-Quoted Item Comparison,Cituojamas punktas Palyginimas,
Received Items To Be Billed,Gauti duomenys turi būti apmokestinama,
Qty to Order,Kiekis užsisakyti,
Requested Items To Be Transferred,Pageidaujami daiktai turi būti perkeltos,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Pasirinkite sandėlį medžiagų užklausoms,
Transfer Materials For Warehouse {0},Sandėlio medžiagos perdavimas {0},
Production Plan Material Request Warehouse,Gamybos plano medžiagų užklausų sandėlis,
-Set From Warehouse,Rinkinys iš sandėlio,
-Source Warehouse (Material Transfer),Šaltinio sandėlis (medžiagų perdavimas),
Sets 'Source Warehouse' in each row of the items table.,Kiekvienoje elementų lentelės eilutėje nustatomas „Šaltinio sandėlis“.,
Sets 'Target Warehouse' in each row of the items table.,Kiekvienoje elementų lentelės eilutėje nustatomas „Tikslinis sandėlis“.,
Show Cancelled Entries,Rodyti atšauktus įrašus,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Paslauga gauta, bet neapmokėta",
Deferred Accounting Settings,Atidėti apskaitos nustatymai,
Book Deferred Entries Based On,Atidėtų įrašų knyga pagal,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Jei pasirenkamas „Mėnesiai“, fiksuota suma bus įrašoma į kiekvieno mėnesio atidėtas pajamas ar išlaidas, neatsižvelgiant į dienų skaičių per mėnesį. Bus proporcinga, jei atidėtos pajamos ar išlaidos nėra apskaitomos visą mėnesį.",
Days,Dienos,
Months,Mėnesių,
Book Deferred Entries Via Journal Entry,Atidėtų įrašų knyga per žurnalo įrašą,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Jei tai nėra pažymėta, tiesioginiai GL įrašai bus sukurti atidėtųjų pajamų / išlaidų knygai",
Submit Journal Entries,Pateikti žurnalo įrašus,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Jei tai nepažymėta, žurnalo įrašai bus išsaugoti juodraščio būsenoje ir turės būti pateikti rankiniu būdu",
Enable Distributed Cost Center,Įgalinti paskirstytų išlaidų centrą,
@@ -8901,8 +8823,6 @@
Is Inter State,Ar tarpvalstybinis,
Purchase Details,Išsami pirkimo informacija,
Depreciation Posting Date,Nusidėvėjimo įrašymo data,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Pirkimo sąskaita ir kvito kūrimas reikalingas pirkimo užsakymas,
-Purchase Receipt Required for Purchase Invoice Creation,"Norint sukurti pirkimo sąskaitą faktūrą, reikalingas pirkimo kvitas",
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Pagal numatytuosius nustatymus tiekėjo vardas nustatomas pagal įvestą tiekėjo vardą. Jei norite, kad tiekėjus pavadintų a",
choose the 'Naming Series' option.,pasirinkite parinktį „Pavadinti seriją“.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Konfigūruokite numatytąjį kainoraštį kurdami naują pirkimo operaciją. Prekių kainos bus pateiktos iš šio Kainyno.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Yra pajamų mokesčio komponentas,
Component properties and references ,Komponento savybės ir nuorodos,
Additional Salary ,Papildomas atlyginimas,
-Condtion and formula,Sąlyga ir formulė,
Unmarked days,Nepažymėtos dienos,
Absent Days,Nėra dienų,
Conditions and Formula variable and example,Sąlygos ir formulės kintamasis ir pavyzdys,
Feedback By,Atsiliepimus pateikė,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
Manufacturing Section,Gamybos skyrius,
-Sales Order Required for Sales Invoice & Delivery Note Creation,"Norint sukurti pardavimo sąskaitą faktūrą ir pristatymo lapą, reikalingas pardavimo užsakymas",
-Delivery Note Required for Sales Invoice Creation,Kuriant pardavimo sąskaitą būtina pristatymo žinia,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Pagal numatytuosius nustatymus kliento vardas nustatomas pagal įvestą vardą ir pavardę. Jei norite, kad klientus pavadintų a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Konfigūruokite numatytąjį kainoraštį kurdami naują pardavimo operaciją. Prekių kainos bus pateiktos iš šio Kainyno.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Jei ši parinktis sukonfigūruota „Taip“, „ERPNext“ neleis jums sukurti pardavimo sąskaitos faktūros ar pristatymo pastabos pirmiausia nesukūrus pardavimo užsakymo. Ši konfigūracija gali būti pakeista konkrečiam klientui, kliento pagrindiniame laukelyje įgalinant žymimąjį laukelį „Leisti kurti pardavimo sąskaitą faktūrą be pardavimo užsakymo“.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} sėkmingai pridėtas prie visų pasirinktų temų.,
Topics updated,Temos atnaujintos,
Academic Term and Program,Akademinis terminas ir programa,
-Last Stock Transaction for item {0} was on {1}.,Paskutinė prekės {0} akcijų sandoris buvo {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,{0} akcijų sandorių negalima paskelbti anksčiau.,
Please remove this item and try to submit again or update the posting time.,Pašalinkite šį elementą ir bandykite pateikti dar kartą arba atnaujinkite paskelbimo laiką.,
Failed to Authenticate the API key.,Nepavyko autentifikuoti API rakto.,
Invalid Credentials,Neteisingi įgaliojimai,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,Patikrinkite „Plaid“ kliento ID ir slaptas vertes,
Bank transaction creation error,Banko operacijos kūrimo klaida,
Unit of Measurement,Matavimo vienetas,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},# Eilutė: {} prekės pardavimo rodiklis yra mažesnis nei jos {}. Pardavimo norma turėtų būti mažiausiai {},
Fiscal Year {0} Does Not Exist,Finansiniai metai {0} neegzistuoja,
Row # {0}: Returned Item {1} does not exist in {2} {3},{0} eilutė: grąžinto elemento {1} nėra {2} {3},
Valuation type charges can not be marked as Inclusive,Vertinimo tipo mokesčiai negali būti pažymėti kaip imtinai,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Atsakymo laikas pagal {0} prioritetą {1} eilutėje negali būti ilgesnis nei skiriamosios gebos laikas.,
{0} is not enabled in {1},„{0}“ neįgalinta {1},
Group by Material Request,Grupuoti pagal medžiagos užklausą,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email",{0} eilutė: Tiekėjui {0} el. Pašto adresas reikalingas norint siųsti el. Laišką,
Email Sent to Supplier {0},El. Laiškas išsiųstas tiekėjui {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Išjungta prieiga prie prašymo pateikti citatą iš portalo. Norėdami leisti prieigą, įjunkite jį portalo nustatymuose.",
Supplier Quotation {0} Created,Tiekėjo pasiūlymas {0} sukurtas,
Valid till Date cannot be before Transaction Date,Galiojanti iki datos negali būti ankstesnė už operacijos datą,
+Unlink Advance Payment on Cancellation of Order,Atsiekite išankstinį mokėjimą atšaukdami užsakymą,
+"Simple Python Expression, Example: territory != 'All Territories'","Paprasta „Python“ išraiška, pavyzdys: territorija! = 'Visos teritorijos'",
+Sales Contributions and Incentives,Pardavimo įnašai ir paskatos,
+Sourced by Supplier,Tiekėjas tiekėjas,
+Total weightage assigned should be 100%.<br>It is {0},Bendras priskirtas svoris turėtų būti 100%.<br> Tai yra {0},
+Account {0} exists in parent company {1}.,Paskyra {0} yra pagrindinėje įmonėje {1}.,
+"To overrule this, enable '{0}' in company {1}","Norėdami tai atmesti, įgalinkite „{0}“ įmonėje {1}",
+Invalid condition expression,Netinkama sąlygos išraiška,
+Please Select a Company First,Pirmiausia pasirinkite įmonę,
+Please Select Both Company and Party Type First,"Pirmiausia pasirinkite tiek įmonės, tiek vakarėlio tipą",
+Provide the invoice portion in percent,Sąskaitos faktūros dalį pateikite procentais,
+Give number of days according to prior selection,Nurodykite dienų skaičių pagal išankstinę atranką,
+Email Details,Išsami el. Pašto informacija,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Pasirinkite sveikinimą gavėjui. Pvz., Ponia, ponia ir kt.",
+Preview Email,Peržiūrėti el. Paštą,
+Please select a Supplier,Pasirinkite tiekėją,
+Supplier Lead Time (days),Tiekėjo vykdymo laikas (dienomis),
+"Home, Work, etc.","Namai, darbas ir kt.",
+Exit Interview Held On,„Exit Interview Held On“,
+Condition and formula,Sąlyga ir formulė,
+Sets 'Target Warehouse' in each row of the Items table.,Kiekvienoje lentelės Elementai eilutėje nustatomas „Tikslinis sandėlis“.,
+Sets 'Source Warehouse' in each row of the Items table.,Kiekvienoje lentelės „Elementai“ eilutėje nustatomas „Šaltinio sandėlis“.,
+POS Register,POS registras,
+"Can not filter based on POS Profile, if grouped by POS Profile","Negalima filtruoti pagal POS profilį, jei jis grupuojamas pagal POS profilį",
+"Can not filter based on Customer, if grouped by Customer","Negalima filtruoti pagal klientą, jei jis sugrupuotas pagal klientą",
+"Can not filter based on Cashier, if grouped by Cashier","Negalima filtruoti pagal kasininką, jei grupuojama pagal kasininką",
+Payment Method,Mokėjimo būdas,
+"Can not filter based on Payment Method, if grouped by Payment Method","Negalima filtruoti pagal mokėjimo metodą, jei jis grupuojamas pagal mokėjimo metodą",
+Supplier Quotation Comparison,Tiekėjų pasiūlymų palyginimas,
+Price per Unit (Stock UOM),Vieneto kaina (atsargų UOM),
+Group by Supplier,Grupuoti pagal tiekėją,
+Group by Item,Grupuoti pagal punktą,
+Remember to set {field_label}. It is required by {regulation}.,Nepamirškite nustatyti {field_label}. To reikalauja {reglamentas}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Registracijos data negali būti ankstesnė nei mokslo metų pradžios data {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Registracijos data negali būti po akademinio laikotarpio pabaigos datos {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Registracijos data negali būti ankstesnė už akademinio laikotarpio pradžios datą {0},
+Future Posting Not Allowed,Ateityje skelbti negalima,
+"To enable Capital Work in Progress Accounting, ",Norėdami įgalinti kapitalo darbo eigą,
+you must select Capital Work in Progress Account in accounts table,sąskaitų lentelėje turite pasirinkti Vykdomo kapitalo darbo sąskaitą,
+You can also set default CWIP account in Company {},Taip pat galite nustatyti numatytąją CWIP paskyrą įmonėje {},
+The Request for Quotation can be accessed by clicking on the following button,Su prašymu pateikti pasiūlymą galima susipažinti spustelėjus šį mygtuką,
+Regards,Pagarbiai,
+Please click on the following button to set your new password,"Norėdami nustatyti naują slaptažodį, spustelėkite šį mygtuką",
+Update Password,Atnaujinti slaptažodį,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},# Eilutė: {} prekės pardavimo rodiklis yra mažesnis nei jos {}. Pardavimas {} turėtų būti mažiausiai {},
+You can alternatively disable selling price validation in {} to bypass this validation.,"Taip pat galite išjungti pardavimo kainos patvirtinimą {}, kad apeitumėte šį patvirtinimą.",
+Invalid Selling Price,Netinkama pardavimo kaina,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,Adresas turi būti susietas su įmone. Lentelėje Nuorodos pridėkite įmonės eilutę.,
+Company Not Linked,Įmonė nesusieta,
+Import Chart of Accounts from CSV / Excel files,Importuoti sąskaitų planą iš CSV / Excel failų,
+Completed Qty cannot be greater than 'Qty to Manufacture',Užpildytas kiekis negali būti didesnis nei „Gamybos kiekis“,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","{0} eilutė: Tiekėjui {1}, norint išsiųsti el. Laišką, būtinas el. Pašto adresas",
+"If enabled, the system will post accounting entries for inventory automatically","Jei įgalinta, sistema automatiškai pateiks atsargų apskaitos įrašus",
+Accounts Frozen Till Date,Sąskaitos užšaldytos iki datos,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"Apskaitos įrašai iki šios dienos yra įšaldyti. Niekas negali kurti ar modifikuoti įrašų, išskyrus toliau nurodytą vaidmenį turinčius vartotojus",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Vaidmuo leidžiamas nustatyti įšaldytas sąskaitas ir redaguoti užšaldytus įrašus,
+Address used to determine Tax Category in transactions,"Adresas, naudojamas nustatant mokesčių kategoriją operacijose",
+"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 ","Procentas, kurį jums leidžiama atsiskaityti daugiau už užsakytą sumą. Pvz., Jei prekės užsakymo vertė yra 100 USD, o leistinas nuokrypis yra 10%, tada leidžiama atsiskaityti iki 110 USD",
+This role is allowed to submit transactions that exceed credit limits,"Šiam vaidmeniui leidžiama pateikti sandorius, viršijančius kredito limitus",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Jei pasirenkama „Mėnesiai“, fiksuota suma bus įrašoma į kiekvieno mėnesio atidėtas pajamas ar išlaidas, neatsižvelgiant į dienų skaičių per mėnesį. Jis bus proporcingas, jei atidėtos pajamos ar išlaidos nebus apskaitomos visą mėnesį",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Jei tai nepažymėta, bus sukurti tiesioginiai GL įrašai atidėtoms pajamoms ar išlaidoms apskaityti",
+Show Inclusive Tax in Print,Rodyti įtraukiantį mokestį spausdintuve,
+Only select this if you have set up the Cash Flow Mapper documents,"Pasirinkite tai tik tuo atveju, jei nustatėte „Cash Flow Mapper“ dokumentus",
+Payment Channel,Mokėjimo kanalas,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Ar norint įsigyti sąskaitą faktūrą ir gauti kvitą reikalingas pirkimo užsakymas?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Ar norint sukurti pirkimo sąskaitą faktūrą reikalingas pirkimo kvitas?,
+Maintain Same Rate Throughout the Purchase Cycle,Palaikykite tą patį tarifą per visą pirkimo ciklą,
+Allow Item To Be Added Multiple Times in a Transaction,Leiskite elementą kelis kartus pridėti prie operacijos,
+Suppliers,Tiekėjai,
+Send Emails to Suppliers,Siųskite el. Laiškus tiekėjams,
+Select a Supplier,Pasirinkite tiekėją,
+Cannot mark attendance for future dates.,Negalima pažymėti lankomumo būsimoms datoms.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Ar norite atnaujinti lankomumą?<br> Pateikti: {0}<br> Nėra: {1},
+Mpesa Settings,„Mpesa“ nustatymai,
+Initiator Name,Iniciatoriaus vardas,
+Till Number,Till Number,
+Sandbox,Smėlio dėžė,
+ Online PassKey,Internetinis „PassKey“,
+Security Credential,Saugos duomenys,
+Get Account Balance,Gaukite sąskaitos balansą,
+Please set the initiator name and the security credential,Nustatykite iniciatoriaus vardą ir saugos kredencialą,
+Inpatient Medication Entry,Stacionarinių vaistų įrašas,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Prekės kodas (vaistas),
+Medication Orders,Vaistų užsakymai,
+Get Pending Medication Orders,Gaukite laukiančius vaistų užsakymus,
+Inpatient Medication Orders,Stacionarinių vaistų užsakymai,
+Medication Warehouse,Vaistų sandėlis,
+Warehouse from where medication stock should be consumed,"Sandėlis, iš kurio reikėtų vartoti vaistų atsargas",
+Fetching Pending Medication Orders,Gaunami laukiantys vaistų užsakymai,
+Inpatient Medication Entry Detail,Stacionarinių vaistų įrašo informacija,
+Medication Details,Išsami informacija apie vaistus,
+Drug Code,Narkotikų kodas,
+Drug Name,Vaisto pavadinimas,
+Against Inpatient Medication Order,Prieš stacionarių vaistų užsakymą,
+Against Inpatient Medication Order Entry,Prieš stacionarių vaistų užsakymo įrašą,
+Inpatient Medication Order,Stacionarinių vaistų užsakymas,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Iš viso užsakymų,
+Completed Orders,Įvykdyti užsakymai,
+Add Medication Orders,Pridėti vaistų užsakymus,
+Adding Order Entries,Pridedami užsakymo įrašai,
+{0} medication orders completed,Užbaigti {0} vaistų užsakymai,
+{0} medication order completed,Užpildytas {0} vaistų užsakymas,
+Inpatient Medication Order Entry,Stacionarinių vaistų užsakymo įrašas,
+Is Order Completed,Ar užsakymas baigtas,
+Employee Records to Be Created By,"Darbuotojų įrašai, kuriuos turi sukurti",
+Employee records are created using the selected field,Darbuotojų įrašai sukuriami naudojant pasirinktą lauką,
+Don't send employee birthday reminders,Nesiųskite darbuotojų gimtadienio priminimų,
+Restrict Backdated Leave Applications,Apriboti pasenusių atostogų paraiškas,
+Sequence ID,Eilės ID,
+Sequence Id,Eilės ID,
+Allow multiple material consumptions against a Work Order,Leiskite daug medžiagų sunaudoti pagal darbo užsakymą,
+Plan time logs outside Workstation working hours,Suplanuokite laiko žurnalus ne darbo vietos darbo laiku,
+Plan operations X days in advance,Planuokite operacijas prieš X dienas,
+Time Between Operations (Mins),Laikas tarp operacijų (minutės),
+Default: 10 mins,Numatytasis: 10 min,
+Overproduction for Sales and Work Order,Pardavimų ir darbo užsakymo perprodukcija,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Automatiškai atnaujinkite BOM kainą per planavimo priemonę, remdamiesi naujausia žaliavų vertinimo norma / kainų sąrašo norma / paskutinio žaliavų pirkimo norma",
+Purchase Order already created for all Sales Order items,Jau sukurtas pirkimo užsakymas visoms pardavimo užsakymo prekėms,
+Select Items,Pasirinkite elementus,
+Against Default Supplier,Prieš numatytąjį tiekėją,
+Auto close Opportunity after the no. of days mentioned above,Automatiškai uždaryti galimybę po Nr. pirmiau minėtų dienų,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Ar kuriant pardavimo sąskaitą faktūrą ir pristatymo lapą reikalingas pardavimo užsakymas?,
+Is Delivery Note Required for Sales Invoice Creation?,Ar kuriant pardavimo sąskaitą būtina pristatymo žiniaraštis?,
+How often should Project and Company be updated based on Sales Transactions?,"Kaip dažnai reikėtų atnaujinti projektą ir įmonę, atsižvelgiant į pardavimo operacijas?",
+Allow User to Edit Price List Rate in Transactions,Leisti vartotojui redaguoti kainų tarifą atliekant operacijas,
+Allow Item to Be Added Multiple Times in a Transaction,Leisti elementą kelis kartus pridėti prie operacijos,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Leisti kelis pardavimo užsakymus kliento pirkimo užsakymui,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,"Patvirtinkite prekės pardavimo kainą, palyginti su pirkimo norma arba vertinimo norma",
+Hide Customer's Tax ID from Sales Transactions,Slėpti kliento mokesčių ID iš pardavimo operacijų,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Procentas, kurį jums leidžiama gauti ar pristatyti daugiau, palyginti su užsakytu kiekiu. Pavyzdžiui, jei užsisakėte 100 vienetų, o jūsų pašalpa yra 10%, tuomet leidžiama gauti 110 vienetų.",
+Action If Quality Inspection Is Not Submitted,"Veiksmas, jei kokybės patikrinimas nepateikiamas",
+Auto Insert Price List Rate If Missing,"Automatiškai įterpti kainoraštį, jei trūksta",
+Automatically Set Serial Nos Based on FIFO,Automatiškai nustatyti serijos numerius pagal FIFO,
+Set Qty in Transactions Based on Serial No Input,Nustatykite operacijų kiekį pagal nuoseklųjį įvestį,
+Raise Material Request When Stock Reaches Re-order Level,"Padidinkite medžiagų užklausą, kai atsargos pasiekia pertvarkymo lygį",
+Notify by Email on Creation of Automatic Material Request,Pranešti el. Paštu apie automatinių medžiagų užklausų kūrimą,
+Allow Material Transfer from Delivery Note to Sales Invoice,Leisti perduoti medžiagą nuo pristatymo pastabos iki pardavimo sąskaitos faktūros,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Leisti perduoti medžiagą iš pirkimo kvito į pirkimo sąskaitą faktūrą,
+Freeze Stocks Older Than (Days),Įšaldyti senesnes nei dienų dienas atsargas,
+Role Allowed to Edit Frozen Stock,Vaidmuo leidžiamas redaguoti įšaldytas atsargas,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Nepaskirta mokėjimo įrašo suma {0} yra didesnė nei nepaskirta banko operacijos suma,
+Payment Received,Apmokėjimas gautas,
+Attendance cannot be marked outside of Academic Year {0},Dalyvavimas negali būti pažymėtas ne mokslo metais {0},
+Student is already enrolled via Course Enrollment {0},Studentas jau yra užsiregistravęs per kursų registraciją {0},
+Attendance cannot be marked for future dates.,Lankomumas negali būti pažymėtas būsimoms datoms.,
+Please add programs to enable admission application.,"Pridėkite programų, kad įgalintumėte priėmimo paraišką.",
+The following employees are currently still reporting to {0}:,Šie darbuotojai šiuo metu vis dar atsiskaito {0}:,
+Please make sure the employees above report to another Active employee.,"Įsitikinkite, kad aukščiau esantys darbuotojai atsiskaito kitam aktyviam darbuotojui.",
+Cannot Relieve Employee,Negaliu palengvinti darbuotojo,
+Please enter {0},Įveskite {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Pasirinkite kitą mokėjimo metodą. „Mpesa“ nepalaiko operacijų valiuta „{0}“,
+Transaction Error,Operacijos klaida,
+Mpesa Express Transaction Error,„Mpesa Express“ operacijos klaida,
+"Issue detected with Mpesa configuration, check the error logs for more details","Aptikta problema naudojant „Mpesa“ konfigūraciją. Jei reikia daugiau informacijos, patikrinkite klaidų žurnalus",
+Mpesa Express Error,„Mpesa Express“ klaida,
+Account Balance Processing Error,Sąskaitos balanso apdorojimo klaida,
+Please check your configuration and try again,Patikrinkite konfigūraciją ir bandykite dar kartą,
+Mpesa Account Balance Processing Error,„Mpesa“ sąskaitos balanso apdorojimo klaida,
+Balance Details,Informacija apie balansą,
+Current Balance,Dabartinis balansas,
+Available Balance,Turimas balansas,
+Reserved Balance,Rezervuotas likutis,
+Uncleared Balance,Neaiškus balansas,
+Payment related to {0} is not completed,Su „{0}“ susijęs mokėjimas nėra baigtas,
+Row #{}: Item Code: {} is not available under warehouse {}.,# Eilutė: {}: prekės kodas: {} nepasiekiamas sandėlyje {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,# Eilutė {}: atsargų kiekio nepakanka prekės kodui: {} po sandėliu {}. Galimas kiekis {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,"# Eilutė: {}: pasirinkite serijos numerį ir paketuokite elementą: {} arba pašalinkite jį, kad užbaigtumėte operaciją.",
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"{0} eilutė: prie elemento nepasirinktas serijos numeris: {}. Pasirinkite vieną arba pašalinkite, kad užbaigtumėte operaciją.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,"# Eilutė: {0} nėra pasirinkta jokių elementų paketų: Norėdami užbaigti operaciją, pasirinkite grupę arba ją pašalinkite.",
+Payment amount cannot be less than or equal to 0,Mokėjimo suma negali būti mažesnė arba lygi 0,
+Please enter the phone number first,Pirmiausia įveskite telefono numerį,
+Row #{}: {} {} does not exist.,# Eilutė: {} {} neegzistuoja.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,{0} eilutė: {1} būtina norint sukurti sąskaitas faktūras „Atidarymas“ {2},
+You had {} errors while creating opening invoices. Check {} for more details,Kurdami atidarymo sąskaitas faktūras turėjote {} klaidų. Daugiau informacijos ieškokite {},
+Error Occured,Įvyko klaida,
+Opening Invoice Creation In Progress,Vykdoma sąskaita faktūros kūrimas,
+Creating {} out of {} {},Kuriama {} iš {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Serijos Nr.: {0}) negalima vartoti, nes jis skirtas užpildyti pardavimo užsakymą {1}.",
+Item {0} {1},{0} {1} elementas,
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Paskutinė prekės {0} sandėlyje {1} sandoris vyko {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,"Prekių, esančių {0} sandėlyje {1}, sandorių negalima paskelbti anksčiau.",
+Posting future stock transactions are not allowed due to Immutable Ledger,Būsimų akcijų sandorių skelbti negalima dėl „Immutable Ledger“,
+A BOM with name {0} already exists for item {1}.,Prekės {1} BOM jau yra su pavadinimu {0}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Ar pervadinote elementą? Susisiekite su administratoriumi / technine pagalba,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},{0} eilutėje: sekos ID {1} negali būti mažesnis nei ankstesnio eilutės sekos ID {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) turi būti lygus {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, atlikite operaciją {1} prieš operaciją {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Neįmanoma užtikrinti pristatymo serijos numeriu, nes prekė {0} pridedama kartu su „Užtikrinti pristatymą serijos numeriu“ ir be jos.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Prekė {0} neturi serijos numerio. Pagal serijos numerį gali būti pristatomi tik serijiniai elementai,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Nerastas aktyvus {0} elemento BOM. Negalima užtikrinti pristatymo serijiniu numeriu,
+No pending medication orders found for selected criteria,Nerasta laukiančių vaistų užsakymų pagal pasirinktus kriterijus,
+From Date cannot be after the current date.,Nuo datos negali būti vėlesnė nei dabartinė data.,
+To Date cannot be after the current date.,Iki datos negali būti po dabartinės datos.,
+From Time cannot be after the current time.,Nuo „Laikas“ negali būti po dabartinio laiko.,
+To Time cannot be after the current time.,Laikas negali būti po dabartinio laiko.,
+Stock Entry {0} created and ,Sukurtas akcijų įrašas {0} ir,
+Inpatient Medication Orders updated successfully,Stacionarinių vaistų užsakymai sėkmingai atnaujinti,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},{0} eilutė: negalima atšaukti stacionarių vaistų užsakymo dėl stacionarių vaistų įrašo {1},
+Row {0}: This Medication Order is already marked as completed,{0} eilutė: šis vaistų užsakymas jau pažymėtas kaip baigtas,
+Quantity not available for {0} in warehouse {1},{0} sandėlyje {1} kiekis nepasiekiamas,
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"Norėdami tęsti, įjunkite „Leisti neigiamą akciją“ akcijų nustatymuose arba sukurkite atsargų įrašą.",
+No Inpatient Record found against patient {0},Nerasta stacionaro įrašo prieš pacientą {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Stacionarių vaistų įsakymas {0} dėl pacientų susidūrimo {1} jau yra.,
+Allow In Returns,Leisti mainais,
+Hide Unavailable Items,Slėpti nepasiekiamus elementus,
+Apply Discount on Discounted Rate,Taikykite nuolaidą nuolaida,
+Therapy Plan Template,Terapijos plano šablonas,
+Fetching Template Details,Gaunama išsami šablono informacija,
+Linked Item Details,Susieto elemento duomenys,
+Therapy Types,Terapijos tipai,
+Therapy Plan Template Detail,Terapijos plano šablono informacija,
+Non Conformance,Neatitikimas,
+Process Owner,Proceso savininkas,
+Corrective Action,Taisomieji veiksmai,
+Preventive Action,Prevencinis veiksmas,
+Problem,Problema,
+Responsible,Atsakingas,
+Completion By,Baigė,
+Process Owner Full Name,Proceso savininko vardas ir pavardė,
+Right Index,Dešinysis indeksas,
+Left Index,Kairysis rodyklė,
+Sub Procedure,Sub procedūra,
+Passed,Praėjo,
+Print Receipt,Spausdinti kvitą,
+Edit Receipt,Redaguoti kvitą,
+Focus on search input,Sutelkite dėmesį į paieškos įvestį,
+Focus on Item Group filter,Susitelkite į elementų grupės filtrą,
+Checkout Order / Submit Order / New Order,Užsakymo užsakymas / pateikiamas užsakymas / naujas užsakymas,
+Add Order Discount,Pridėti užsakymo nuolaidą,
+Item Code: {0} is not available under warehouse {1}.,Prekės kodas: {0} nėra sandėlyje {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Serijos numeriai nepasiekiami {0} sandėlyje {1}. Pabandykite pakeisti sandėlį.,
+Fetched only {0} available serial numbers.,Gauta tik {0} galimi serijos numeriai.,
+Switch Between Payment Modes,Perjungti mokėjimo būdus,
+Enter {0} amount.,Įveskite sumą {0}.,
+You don't have enough points to redeem.,"Jūs neturite pakankamai taškų, kuriuos norite išpirkti.",
+You can redeem upto {0}.,Galite išpirkti iki {0}.,
+Enter amount to be redeemed.,"Įveskite sumą, kurią norite išpirkti.",
+You cannot redeem more than {0}.,Negalite išpirkti daugiau nei {0}.,
+Open Form View,Atidarykite formos rodinį,
+POS invoice {0} created succesfully,POS sąskaita faktūra {0} sukurta sėkmingai,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Prekės kodas nepakanka atsargų kiekiui: {0} sandėlyje {1}. Galimas kiekis {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Serijos numeris: {0} jau buvo perkeltas į kitą POS sąskaitą faktūrą.,
+Balance Serial No,Likutis Serijos Nr,
+Warehouse: {0} does not belong to {1},Sandėlis: {0} nepriklauso {1},
+Please select batches for batched item {0},Pasirinkite paketines paketines prekes {0},
+Please select quantity on row {0},Pasirinkite kiekį {0} eilutėje,
+Please enter serial numbers for serialized item {0},Įveskite serijinės prekės {0} serijos numerius,
+Batch {0} already selected.,{0} paketas jau pasirinktas.,
+Please select a warehouse to get available quantities,"Pasirinkite sandėlį, kad gautumėte galimus kiekius",
+"For transfer from source, selected quantity cannot be greater than available quantity",Perkėlimui iš šaltinio pasirinktas kiekis negali būti didesnis už turimą kiekį,
+Cannot find Item with this Barcode,Nepavyksta rasti elemento su šiuo brūkšniniu kodu,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} yra privalomas. Galbūt valiutos keitimo įrašas nėra sukurtas {1} - {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} pateikė su juo susietą turtą. Norėdami sukurti pirkimo grąžą, turite atšaukti turtą.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Negalima atšaukti šio dokumento, nes jis susietas su pateiktu ištekliu {0}. Norėdami tęsti, atšaukite jį.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,{0} eilutė: serijos Nr. {} Jau buvo perkeltas į kitą POS sąskaitą faktūrą. Pasirinkite galiojantį serijos Nr.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,{0} eilutė: serijos Nr. {} Jau buvo perkeltos į kitą POS sąskaitą faktūrą. Pasirinkite galiojantį serijos Nr.,
+Item Unavailable,Elementas nepasiekiamas,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"{0} eilutė: serijos Nr. {} Negalima grąžinti, nes tai nebuvo padaryta pirminėje sąskaitoje faktūroje {}",
+Please set default Cash or Bank account in Mode of Payment {},Nustatykite numatytąją grynųjų pinigų ar banko sąskaitą mokėjimo režimu {},
+Please set default Cash or Bank account in Mode of Payments {},Mokėjimo režimu nustatykite numatytąją grynųjų pinigų ar banko sąskaitą {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Įsitikinkite, kad {} paskyra yra balanso sąskaita. Galite pakeisti tėvų sąskaitą į balanso sąskaitą arba pasirinkti kitą sąskaitą.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Įsitikinkite, kad „{}“ paskyra yra mokėtina. Pakeiskite sąskaitos tipą į Mokėtinas arba pasirinkite kitą sąskaitą.",
+Row {}: Expense Head changed to {} ,{Eilutė {}: išlaidų antraštė pakeista į {},
+because account {} is not linked to warehouse {} ,nes paskyra {} nesusieta su sandėliu {},
+or it is not the default inventory account,arba tai nėra numatytoji atsargų sąskaita,
+Expense Head Changed,Išlaidų galva pakeista,
+because expense is booked against this account in Purchase Receipt {},nes išlaidos šioje sąskaitoje yra įrašytos pirkimo kvite {},
+as no Purchase Receipt is created against Item {}. ,nes prekei {} nesudaromas pirkimo kvitas.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Tai daroma tvarkant apskaitą tais atvejais, kai pirkimo kvitas sukuriamas po pirkimo sąskaitos faktūros",
+Purchase Order Required for item {},Būtinas prekės {} pirkimo užsakymas,
+To submit the invoice without purchase order please set {} ,"Norėdami pateikti sąskaitą faktūrą be pirkimo užsakymo, nustatykite {}",
+as {} in {},kaip {} {},
+Mandatory Purchase Order,Privalomas pirkimo užsakymas,
+Purchase Receipt Required for item {},Būtinas prekės {} pirkimo kvitas,
+To submit the invoice without purchase receipt please set {} ,"Norėdami pateikti sąskaitą faktūrą be pirkimo kvito, nustatykite {}",
+Mandatory Purchase Receipt,Privalomas pirkimo kvitas,
+POS Profile {} does not belongs to company {},POS profilis {} nepriklauso įmonei {},
+User {} is disabled. Please select valid user/cashier,Vartotojas {} yra išjungtas. Pasirinkite galiojantį vartotoją / kasininką,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,# Eilutė {}: grąžinimo sąskaitos faktūros {} originali sąskaita {} yra {}.,
+Original invoice should be consolidated before or along with the return invoice.,Sąskaitos originalas turėtų būti sujungtas prieš grąžinimo sąskaitą faktūrą arba kartu su ja.,
+You can add original invoice {} manually to proceed.,"Norėdami tęsti, rankiniu būdu galite pridėti sąskaitos faktūrą {} rankiniu būdu.",
+Please ensure {} account is a Balance Sheet account. ,"Įsitikinkite, kad {} paskyra yra balanso sąskaita.",
+You can change the parent account to a Balance Sheet account or select a different account.,Galite pakeisti tėvų sąskaitą į balanso sąskaitą arba pasirinkti kitą sąskaitą.,
+Please ensure {} account is a Receivable account. ,"Įsitikinkite, kad „{}“ paskyra yra gautina.",
+Change the account type to Receivable or select a different account.,Pakeiskite sąskaitos tipą į Gautinas arba pasirinkite kitą sąskaitą.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"„{}“ negalima atšaukti, nes išpirkti uždirbti lojalumo taškai. Pirmiausia atšaukite {} Ne {}",
+already exists,jau egzistuoja,
+POS Closing Entry {} against {} between selected period,POS uždarymo įrašas {} prieš {} tarp pasirinkto laikotarpio,
+POS Invoice is {},POS sąskaita faktūra yra {},
+POS Profile doesn't matches {},POS profilis neatitinka {},
+POS Invoice is not {},POS sąskaita faktūra nėra {},
+POS Invoice isn't created by user {},POS sąskaitą faktūrą sukūrė ne vartotojas {},
+Row #{}: {},# Eilutė {}: {},
+Invalid POS Invoices,Neteisingos POS sąskaitos faktūros,
+Please add the account to root level Company - {},Pridėkite paskyrą prie pagrindinio lygio įmonės - {},
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Kuriant paskyrą vaikų įmonei {0}, tėvų paskyra {1} nerasta. Sukurkite tėvų sąskaitą atitinkamame COA",
+Account Not Found,Paskyra nerasta,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Kuriant paskyros „Child Child“ {0} paskyrą, tėvų paskyra {1} rasta kaip knygos knyga.",
+Please convert the parent account in corresponding child company to a group account.,Perverskite atitinkamos antrinės įmonės tėvų sąskaitą į grupės paskyrą.,
+Invalid Parent Account,Netinkama tėvų sąskaita,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Pervadinti jį leidžiama tik per pagrindinę įmonę {0}, kad būtų išvengta neatitikimų.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Jei {0} {1} prekės kiekius {2}, elementui bus taikoma schema {3}.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Jei {0} {1} verta elemento {2}, elementui bus pritaikyta schema {3}.",
+"As the field {0} is enabled, the field {1} is mandatory.","Kadangi laukas {0} įgalintas, laukas {1} yra privalomas.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Kadangi laukas {0} įgalintas, lauko {1} vertė turėtų būti didesnė nei 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Nepavyksta pateikti serijos Nr. {0} prekės {1}, nes ji rezervuota viso pardavimo užsakymui {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Pardavimo užsakyme {0} yra prekės rezervacija {1}, rezervuotą {1} galite pristatyti tik prieš {0}.",
+{0} Serial No {1} cannot be delivered,{0} Serijos Nr. {1} pristatyti negalima,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},{0} eilutė: žaliavai privalomas subrangos elementas {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Kadangi žaliavų yra pakankamai, sandėliui {0} nereikia pateikti medžiagų užklausų.",
+" If you still want to proceed, please enable {0}.","Jei vis tiek norite tęsti, įgalinkite {0}.",
+The item referenced by {0} - {1} is already invoiced,"Elementas, nurodytas {0} - {1}, jau yra išrašytas",
+Therapy Session overlaps with {0},Terapijos seansas sutampa su {0},
+Therapy Sessions Overlapping,Terapijos seansai sutampa,
+Therapy Plans,Terapijos planai,
+"Item Code, warehouse, quantity are required on row {0}","Prekės kodas, sandėlis, kiekis būtini {0} eilutėje",
+Get Items from Material Requests against this Supplier,Gaukite elementus iš šio tiekėjo materialinių užklausų,
+Enable European Access,Įgalinti Europos prieigą,
+Creating Purchase Order ...,Kuriamas pirkimo užsakymas ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Pasirinkite tiekėją iš toliau nurodytų gaminių iš numatytųjų tiekėjų. Pasirinkus pirkimą, bus sudarytos tik prekės, priklausančios pasirinktam tiekėjui.",
+Row #{}: You must select {} serial numbers for item {}.,# Eilutė {}: turite pasirinkti {} prekės serijos numerius {}.,
diff --git a/erpnext/translations/lv.csv b/erpnext/translations/lv.csv
index 7f5f87d..cbf0485 100644
--- a/erpnext/translations/lv.csv
+++ b/erpnext/translations/lv.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},Faktiskais veids nodokli nevar iekļaut vienības likmes kārtas {0},
Add,Pievienot,
Add / Edit Prices,Pievienot / rediģēt cenas,
-Add All Suppliers,Pievienot visus piegādātājus,
Add Comment,Pievienot komentāru,
Add Customers,Pievienot Klienti,
Add Employees,Pievienot Darbinieki,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',"Nevar atskaitīt, ja kategorija ir "vērtēšanas" vai "Vaulation un Total"",
"Cannot delete Serial No {0}, as it is used in stock transactions","Nevar izdzēst Sērijas Nr {0}, jo tas tiek izmantots akciju darījumiem",
Cannot enroll more than {0} students for this student group.,Nevar uzņemt vairāk nekā {0} studentiem šai studentu grupai.,
-Cannot find Item with this barcode,Nevar atrast vienumu ar šo svītrkodu,
Cannot find active Leave Period,Nevar atrast aktīvo atlikušo periodu,
Cannot produce more Item {0} than Sales Order quantity {1},Nevar ražot vairāk Vienību {0} nekā Pasūtījumu daudzums {1},
Cannot promote Employee with status Left,Nevar reklamēt Darbinieku ar statusu pa kreisi,
Cannot refer row number greater than or equal to current row number for this Charge type,Nevar atsaukties rindu skaits ir lielāks par vai vienāds ar pašreizējo rindu skaitu šim Charge veida,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,"Nav iespējams izvēlēties maksas veidu, kā ""Par iepriekšējo rindu summas"" vai ""Par iepriekšējā rindā Total"" par pirmās rindas",
-Cannot set a received RFQ to No Quote,"Nevar iestatīt saņemto RFQ, ja nav citēta",
Cannot set as Lost as Sales Order is made.,Nevar iestatīt kā Lost kā tiek veikts Sales Order.,
Cannot set authorization on basis of Discount for {0},"Nevar iestatīt atļaujas, pamatojoties uz Atlaide {0}",
Cannot set multiple Item Defaults for a company.,Nevar iestatīt vairākus uzņēmuma vienumu noklusējuma iestatījumus.,
@@ -521,7 +518,6 @@
Chargeble,Maksas,
Charges are updated in Purchase Receipt against each item,Izmaksas tiek atjauninātas pirkuma čeka pret katru posteni,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Maksas tiks izplatīts proporcionāli, pamatojoties uz vienību Daudz vai summu, kā par savu izvēli",
-Chart Of Accounts,Kontu,
Chart of Cost Centers,Shēma izmaksu centriem,
Check all,Pārbaudi visu,
Checkout,Izrakstīšanās,
@@ -581,7 +577,6 @@
Compensatory Off,Kompensējošs Off,
Compensatory leave request days not in valid holidays,Kompensācijas atvaļinājuma pieprasījuma dienas nav derīgas brīvdienās,
Complaint,Sūdzība,
-Completed Qty can not be greater than 'Qty to Manufacture',"Pabeigts Daudz nevar būt lielāks par ""Daudz, lai ražotu""",
Completion Date,Pabeigšana Datums,
Computer,Dators,
Condition,Nosacījums,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Izveidot un pārvaldīt ikdienas, iknedēļas un ikmēneša e-pasta hidrolizātus.",
Create customer quotes,Izveidot klientu citātus,
Create rules to restrict transactions based on values.,"Izveidot noteikumus, lai ierobežotu darījumi, pamatojoties uz vērtībām.",
-Created By,Izveidoja,
Created {0} scorecards for {1} between: ,Izveidoja {0} rādītāju kartes par {1} starp:,
Creating Company and Importing Chart of Accounts,Uzņēmuma izveidošana un kontu plāna importēšana,
Creating Fees,Maksu izveidošana,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Darbinieku pārskaitījumu nevar iesniegt pirms pārskaitījuma datuma,
Employee cannot report to himself.,Darbinieks nevar ziņot sev.,
Employee relieved on {0} must be set as 'Left',"Darbinieku atvieglots par {0} ir jānosaka kā ""Kreisais""",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,"Darbinieka statusu nevar iestatīt uz “kreiso”, jo šādi darbinieki pašlaik ziņo šim darbiniekam:",
Employee {0} already submited an apllication {1} for the payroll period {2},Darbinieks {0} jau ir iesniedzis aplo kāciju {1} algas perioda {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Darbinieks {0} jau ir iesniedzis {1} pieteikumu starp {2} un {3}:,
Employee {0} has no maximum benefit amount,Darbiniekam {0} nav maksimālās labuma summas,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,Rindai {0}: ievadiet plānoto daudzumu,
"For {0}, only credit accounts can be linked against another debit entry","Par {0}, tikai kredīta kontus var saistīt pret citu debeta ierakstu",
"For {0}, only debit accounts can be linked against another credit entry","Par {0}, tikai debeta kontus var saistīt pret citu kredīta ierakstu",
-Form View,Veidlapas skats,
Forum Activity,Foruma aktivitāte,
Free item code is not selected,Bezmaksas preces kods nav atlasīts,
Freight and Forwarding Charges,Kravu un Ekspedīcijas maksājumi,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Atvaļinājumu nevar tikt piešķirts pirms {0}, jo atvaļinājumu bilance jau ir rokas nosūtīja nākotnē atvaļinājumu piešķiršanas ierakstu {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Atstājiet nevar piemērot / atcelts pirms {0}, jo atvaļinājumu bilance jau ir rokas nosūtīja nākotnē atvaļinājumu piešķiršanas ierakstu {1}",
Leave of type {0} cannot be longer than {1},Atvaļinājums tipa {0} nevar būt ilgāks par {1},
-Leave the field empty to make purchase orders for all suppliers,"Atstājiet lauku tukšu, lai veiktu pirkšanas pasūtījumus visiem piegādātājiem",
Leaves,Lapas,
Leaves Allocated Successfully for {0},Lapām Piešķirts Veiksmīgi par {0},
Leaves has been granted sucessfully,Lapas tiek piešķirtas veiksmīgi,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Nav Preces ar Bill materiālu ražošana,
No Items with Bill of Materials.,Nav preču ar materiālu pavadzīmi.,
No Permission,Nav atļaujas,
-No Quote,Nekādu citātu,
No Remarks,Nav Piezīmes,
No Result to submit,Nav iesniegts rezultāts,
No Salary Structure assigned for Employee {0} on given date {1},Darba algas struktūra nav piešķirta darbiniekam {0} noteiktā datumā {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Pārklāšanās apstākļi atrasts starp:,
Owner,Īpašnieks,
PAN,PAN,
-PO already created for all sales order items,PO jau izveidots visiem pārdošanas pasūtījumu posteņiem,
POS,POS,
POS Profile,POS Profile,
POS Profile is required to use Point-of-Sale,"POS profils ir nepieciešams, lai izmantotu pārdošanas vietas",
@@ -2033,7 +2022,6 @@
Please select Charge Type first,"Lūdzu, izvēlieties iekasēšanas veids pirmais",
Please select Company,"Lūdzu, izvēlieties Uzņēmums",
Please select Company and Designation,"Lūdzu, atlasiet Uzņēmums un Apzīmējums",
-Please select Company and Party Type first,"Lūdzu, izvēlieties Uzņēmumu un Party tips pirmais",
Please select Company and Posting Date to getting entries,"Lūdzu, izvēlieties Uzņēmums un Publicēšanas datums, lai saņemtu ierakstus",
Please select Company first,"Lūdzu, izvēlieties Company pirmais",
Please select Completion Date for Completed Asset Maintenance Log,"Lūdzu, atlasiet pabeigtā īpašuma uzturēšanas žurnāla pabeigšanas datumu",
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Row {0}: UOM Conversion Factor ir obligāta,
Row {0}: select the workstation against the operation {1},Rinda {0}: izvēlieties darbstaciju pret operāciju {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Rinda {0}: {1} {2} vienumam ir vajadzīgi sērijas numuri. Jūs esat iesniedzis {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,"Rinda {0}: {1} ir nepieciešama, lai izveidotu atvēršanas {2} rēķinus",
Row {0}: {1} must be greater than 0,Rindai {0}: {1} jābūt lielākam par 0,
Row {0}: {1} {2} does not match with {3},Rinda {0}: {1}{2} nesakrīt ar {3},
Row {0}:Start Date must be before End Date,Rinda {0}: sākuma datumam jābūt pirms beigu datuma,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Nosūtiet Granta pārskata e-pastu,
Send Now,Nosūtīt tagad,
Send SMS,Sūtīt SMS,
-Send Supplier Emails,Nosūtīt Piegādātāja e-pastu,
Send mass SMS to your contacts,Sūtīt masu SMS saviem kontaktiem,
Sensitivity,Jutīgums,
Sent,Nosūtīts,
-Serial #,Sērijas #,
Serial No and Batch,Sērijas Nr un partijas,
Serial No is mandatory for Item {0},Sērijas numurs ir obligāta postenī {0},
Serial No {0} does not belong to Batch {1},Sērijas numurs {0} nepieder partijai {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,"Jūsu uzņēmuma nosaukums, par kuru jums ir izveidot šo sistēmu.",
The number of shares and the share numbers are inconsistent,Akciju skaits un akciju skaits ir pretrunīgi,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Plāna {0} maksājuma vārtejas konts atšķiras no maksājuma vārtejas konta šajā maksājuma pieprasījumā,
-The request for quotation can be accessed by clicking on the following link,"Par citāts pieprasījumu var piekļūt, uzklikšķinot uz šīs saites",
The selected BOMs are not for the same item,Izvēlētie BOMs nav par to pašu posteni,
The selected item cannot have Batch,Izvēlētais objekts nevar būt partijas,
The seller and the buyer cannot be the same,Pārdevējs un pircējs nevar būt vienādi,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Kopējā elastīgā pabalsta komponenta summa {0} nedrīkst būt mazāka par maksimālo pabalstu summu {1},
Total hours: {0},Kopējais stundu skaits: {0},
Total leaves allocated is mandatory for Leave Type {0},Kopējās piešķirtās lapas ir obligātas attiecībā uz atstāšanas veidu {0},
-Total weightage assigned should be 100%. It is {0},Kopā weightage piešķirts vajadzētu būt 100%. Tas ir {0},
Total working hours should not be greater than max working hours {0},Kopējais darba laiks nedrīkst būt lielāks par max darba stundas {0},
Total {0} ({1}),Kopā {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Kopā {0} uz visiem posteņiem ir nulle, var būt jums vajadzētu mainīt "Sadalīt maksa ir atkarīga no"",
@@ -3316,7 +3299,6 @@
What do you need help with?,Kas jums ir nepieciešama palīdzība ar?,
What does it do?,Ko tas dod?,
Where manufacturing operations are carried.,"Gadījumos, kad ražošanas darbības tiek veiktas.",
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Veidojot kontu bērnu uzņēmumam {0}, vecāku konts {1} nav atrasts. Lūdzu, izveidojiet vecāku kontu attiecīgajā COA",
White,Balts,
Wire Transfer,Wire Transfer,
WooCommerce Products,WooCommerce produkti,
@@ -3448,7 +3430,6 @@
{0} variants created.,Izveidoti {0} varianti.,
{0} {1} created,{0} {1} izveidots,
{0} {1} does not exist,{0} {1} neeksistē,
-{0} {1} does not exist.,{0} {1} neeksistē.,
{0} {1} has been modified. Please refresh.,{0}{1} ir mainīta. Lūdzu atsvaidzināt.,
{0} {1} has not been submitted so the action cannot be completed,{0} {1} nav iesniegts tā darbību nevar pabeigt,
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} ir saistīts ar {2}, bet Puses konts ir {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} neeksistē,
{0}: {1} not found in Invoice Details table,{0}: {1} nav atrasta Rēķina informācija tabulā,
{} of {},no {},
+Assigned To,Norīkoti,
Chat,Tērzēšana,
Completed By,Pabeigts ar,
Conditions,Nosacījumi,
@@ -3506,7 +3488,9 @@
Merge with existing,Saplūst ar esošo,
Office,Birojs,
Orientation,orientēšanās,
+Parent,Vecāks,
Passive,Pasīvs,
+Payment Failed,maksājums neizdevās,
Percent,Procents,
Permanent,pastāvīgs,
Personal,Personisks,
@@ -3544,7 +3528,6 @@
Company field is required,Jānorāda uzņēmuma lauks,
Creating Dimensions...,Notiek kategoriju izveidošana ...,
Duplicate entry against the item code {0} and manufacturer {1},Ieraksta dublikāts attiecībā uz preces kodu {0} un ražotāju {1},
-Import Chart Of Accounts from CSV / Excel files,Importējiet kontu diagrammu no CSV / Excel failiem,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Nederīgs GSTIN! Jūsu ievadītā ievade neatbilst GSTIN formātam UIN turētājiem vai nerezidentu OIDAR pakalpojumu sniedzējiem,
Invoice Grand Total,Rēķins kopā,
Last carbon check date cannot be a future date,Pēdējais oglekļa pārbaudes datums nevar būt nākotnes datums,
@@ -3556,6 +3539,7 @@
Show {0},Rādīt {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Speciālās rakstzīmes, izņemot "-", "#", ".", "/", "{" Un "}", kas nav atļautas nosaukuma sērijās",
Target Details,Mērķa informācija,
+{0} already has a Parent Procedure {1}.,{0} jau ir vecāku procedūra {1}.,
API,API,
Annual,Gada,
Approved,Apstiprināts,
@@ -3572,6 +3556,8 @@
No data to export,Nav eksportējamu datu,
Portrait,Portrets,
Print Heading,Print virsraksts,
+Scheduler Inactive,Plānotājs nav aktīvs,
+Scheduler is inactive. Cannot import data.,Plānotājs ir neaktīvs. Nevar importēt datus.,
Show Document,Rādīt dokumentu,
Show Traceback,Rādīt izsekošanu,
Video,Video,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Izveidot kvalitātes pārbaudi priekšmetam {0},
Creating Accounts...,Notiek kontu izveidošana ...,
Creating bank entries...,Notiek bankas ierakstu izveidošana ...,
-Creating {0},{0} izveidošana,
Credit limit is already defined for the Company {0},Kredīta limits uzņēmumam jau ir noteikts {0},
Ctrl + Enter to submit,"Ctrl + Enter, lai iesniegtu",
Ctrl+Enter to submit,"Ctrl + Enter, lai iesniegtu",
@@ -3921,7 +3906,6 @@
Plaid public token error,Plaša publiskā marķiera kļūda,
Plaid transactions sync error,Riska darījuma sinhronizācijas kļūda,
Please check the error log for details about the import errors,"Lūdzu, pārbaudiet kļūdu žurnālu, lai iegūtu sīkāku informāciju par importēšanas kļūdām",
-Please click on the following link to set your new password,"Lūdzu, noklikšķiniet uz šīs saites, lai uzstādītu jauno paroli",
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,"Lūdzu, izveidojiet <b>DATEV iestatījumus</b> uzņēmumam <b>{}</b> .",
Please create adjustment Journal Entry for amount {0} ,"Lūdzu, izveidojiet korekcijas žurnāla ierakstu summai {0}.",
Please do not create more than 500 items at a time,"Lūdzu, neveidojiet vairāk par 500 vienībām vienlaikus",
@@ -3997,6 +3981,7 @@
Release date must be in the future,Izdošanas datumam jābūt nākotnē,
Relieving Date must be greater than or equal to Date of Joining,Atvieglojuma datumam jābūt lielākam vai vienādam ar iestāšanās datumu,
Rename,Pārdēvēt,
+Rename Not Allowed,Pārdēvēt nav atļauts,
Repayment Method is mandatory for term loans,Atmaksas metode ir obligāta termiņa aizdevumiem,
Repayment Start Date is mandatory for term loans,Atmaksas sākuma datums ir obligāts termiņaizdevumiem,
Report Item,Pārskata vienums,
@@ -4043,7 +4028,6 @@
Select All,Izvēlēties visu,
Select Difference Account,Atlasiet Starpības konts,
Select a Default Priority.,Atlasiet noklusējuma prioritāti.,
-Select a Supplier from the Default Supplier List of the items below.,Zemāk esošo vienumu noklusējuma sarakstā atlasiet piegādātāju.,
Select a company,Izvēlieties uzņēmumu,
Select finance book for the item {0} at row {1},Atlasiet {0} posteņa {1} finanšu grāmatu,
Select only one Priority as Default.,Atlasiet tikai vienu prioritāti kā noklusējumu.,
@@ -4247,7 +4231,6 @@
Actual ,Faktisks,
Add to cart,Pievienot grozam,
Budget,Budžets,
-Chart Of Accounts Importer,Importētāja kontu diagramma,
Chart of Accounts,Kontu diagramma,
Customer database.,Klientu datu bāze.,
Days Since Last order,Dienas kopš pēdējā pasūtījuma,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Beigu Datums nevar būt mazāks par sākuma datuma,
For Default Supplier (Optional),Paredzētajam piegādātājam (neobligāti),
From date cannot be greater than To date,No datuma nevar būt lielāka par datumu,
-Get items from,Dabūtu preces no,
Group by,Group By,
In stock,Noliktavā,
Item name,Vienības nosaukums,
@@ -4532,32 +4514,22 @@
Accounts Settings,Konti Settings,
Settings for Accounts,Iestatījumi kontu,
Make Accounting Entry For Every Stock Movement,Padarīt grāmatvedības ieraksts Katrs krājumu aprites,
-"If enabled, the system will post accounting entries for inventory automatically.","Ja ieslēgts, sistēma būs pēc grāmatvedības ierakstus inventāru automātiski.",
-Accounts Frozen Upto,Konti Frozen Līdz pat,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Grāmatvedības ieraksts iesaldēta līdz šim datumam, neviens nevar darīt / mainīt ierakstu izņemot lomu zemāk norādīto.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Loma atļauts noteikt iesaldētos kontus un rediģēt Saldētas Ieraksti,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,"Lietotāji ar šo lomu ir atļauts noteikt iesaldētos kontus, un izveidot / mainīt grāmatvedības ierakstus pret iesaldētos kontus",
Determine Address Tax Category From,No adreses nodokļa kategorijas noteikšana,
-Address used to determine Tax Category in transactions.,"Adrese, kuru izmanto nodokļu kategorijas noteikšanai darījumos.",
Over Billing Allowance (%),Virs norēķinu pabalsts (%),
-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 for $110.,"Procenti, par kuriem jums ir atļauts maksāt vairāk par pasūtīto summu. Piemēram: ja preces pasūtījuma vērtība ir USD 100 un pielaide ir iestatīta kā 10%, tad jums ir atļauts izrakstīt rēķinu par 110 USD.",
Credit Controller,Kredīts Controller,
-Role that is allowed to submit transactions that exceed credit limits set.,"Loma, kas ir atļauts iesniegt darījumus, kas pārsniedz noteiktos kredīta limitus.",
Check Supplier Invoice Number Uniqueness,Pārbaudiet Piegādātājs Rēķina numurs Unikalitāte,
Make Payment via Journal Entry,Veikt maksājumus caur Journal Entry,
Unlink Payment on Cancellation of Invoice,Atsaistītu maksājumu par anulēšana rēķina,
-Unlink Advance Payment on Cancelation of Order,Atsaistiet avansa maksājumu par pasūtījuma atcelšanu,
Book Asset Depreciation Entry Automatically,Grāmatu Aktīvu nolietojums Entry Automātiski,
Automatically Add Taxes and Charges from Item Tax Template,Automātiski pievienojiet nodokļus un nodevas no vienumu nodokļu veidnes,
Automatically Fetch Payment Terms,Automātiski ienest maksājuma noteikumus,
-Show Inclusive Tax In Print,Rādīt iekļaujošu nodokli drukāt,
Show Payment Schedule in Print,Rādīt norēķinu grafiku drukā,
Currency Exchange Settings,Valūtas maiņas iestatījumi,
Allow Stale Exchange Rates,Atļaut mainīt valūtas kursus,
Stale Days,Stale dienas,
Report Settings,Ziņojuma iestatījumi,
Use Custom Cash Flow Format,Izmantojiet pielāgotu naudas plūsmas formātu,
-Only select if you have setup Cash Flow Mapper documents,"Atlasiet tikai tad, ja esat iestatījis naudas plūsmas mapera dokumentus",
Allowed To Transact With,Atļauts veikt darījumus ar,
SWIFT number,SWIFT numurs,
Branch Code,Filiāles kods,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS Klientu Group,
POS Field,POS lauks,
POS Item Group,POS Prece Group,
-[Select],[Izvēlēties],
Company Address,Uzņēmuma adrese,
Update Stock,Update Stock,
Ignore Pricing Rule,Ignorēt cenu veidošanas likumu,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Piegādātājs nosaukšana Līdz,
Default Supplier Group,Noklusējuma piegādātāju grupa,
Default Buying Price List,Default Pirkšana Cenrādis,
-Maintain same rate throughout purchase cycle,Uzturēt pašu likmi visā pirkuma ciklu,
-Allow Item to be added multiple times in a transaction,Atļaut punkts jāpievieno vairākas reizes darījumā,
Backflush Raw Materials of Subcontract Based On,Apakšlīgumu pamatā esošās neapstrādātas izejvielas,
Material Transferred for Subcontract,Materiāls nodots apakšlīgumam,
Over Transfer Allowance (%),Pārskaitījuma pabalsts (%),
@@ -5540,7 +5509,6 @@
Current Stock,Pašreizējā Stock,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,Par individuālo piegādātāja,
-Supplier Detail,piegādātājs Detail,
Link to Material Requests,Saite uz materiālu pieprasījumiem,
Message for Supplier,Vēstījums piegādātājs,
Request for Quotation Item,Pieprasīt Piedāvājuma ITEM,
@@ -6481,7 +6449,6 @@
Appraisal Template,Izvērtēšana Template,
For Employee Name,Par darbinieku Vārds,
Goals,Mērķi,
-Calculate Total Score,Aprēķināt kopējo punktu skaitu,
Total Score (Out of 5),Total Score (no 5),
"Any other remarks, noteworthy effort that should go in the records.","Jebkādas citas piezīmes, ievērības cienīgs piepūles ka jāiet ierakstos.",
Appraisal Goal,Izvērtēšana Goal,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Iemesls Atstājot,
Leave Encashed?,Atvaļinājums inkasēta?,
Encashment Date,Inkasācija Datums,
-Exit Interview Details,Iziet Intervija Details,
-Held On,Notika,
-Reason for Resignation,Iemesls atkāpšanās no amata,
-Better Prospects,Labākas izredzes,
-Health Concerns,Veselības problēmas,
New Workplace,Jaunajā darbavietā,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Atgrieztā summa,
@@ -6740,10 +6702,7 @@
Employee Settings,Darbinieku iestatījumi,
Retirement Age,pensionēšanās vecums,
Enter retirement age in years,Ievadiet pensionēšanās vecumu gados,
-Employee Records to be created by,"Darbinieku Records, kas rada",
-Employee record is created using selected field. ,"Darbinieku ieraksts tiek izveidota, izmantojot izvēlēto laukumu.",
Stop Birthday Reminders,Stop Birthday atgādinājumi,
-Don't send Employee Birthday Reminders,Nesūtiet darbinieku dzimšanas dienu atgādinājumus,
Expense Approver Mandatory In Expense Claim,Izdevumu apstiprinātājs obligāts izdevumu pieprasījumā,
Payroll Settings,Algas iestatījumi,
Leave,Aiziet,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,"Atstājiet apstiprinātāju obligāti, atstājot pieteikumu",
Show Leaves Of All Department Members In Calendar,Rādīt visu departamenta deputātu lapas kalendārā,
Auto Leave Encashment,Automātiska aiziešana no iekasēšanas,
-Restrict Backdated Leave Application,Ierobežot atpakaļejošu atvaļinājuma pieteikumu,
Hiring Settings,Iznomāšanas iestatījumi,
Check Vacancies On Job Offer Creation,Pārbaudiet vakances darba piedāvājuma izveidē,
Identification Document Type,Identifikācijas dokumenta veids,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,Ražošanas iestatījumi,
Raw Materials Consumption,Izejvielu patēriņš,
Allow Multiple Material Consumption,Atļaut vairāku materiālu patēriņu,
-Allow multiple Material Consumption against a Work Order,Atļaut vairāku materiālu patēriņu pret darba kārtību,
Backflush Raw Materials Based On,Backflush izejvielas Based On,
Material Transferred for Manufacture,"Materiāls pārvietoti, lai ražošana",
Capacity Planning,Capacity Planning,
Disable Capacity Planning,Atspējot kapacitātes plānošanu,
Allow Overtime,Atļaut Virsstundas,
-Plan time logs outside Workstation Working Hours.,Plānot laiku ārpus Darba vietas darba laika.,
Allow Production on Holidays,Atļaut Production brīvdienās,
Capacity Planning For (Days),Capacity Planning For (dienas),
-Try planning operations for X days in advance.,Mēģiniet plānojot operācijas X dienas iepriekš.,
-Time Between Operations (in mins),Laiks starp operācijām (Min),
-Default 10 mins,Pēc noklusējuma 10 min,
Default Warehouses for Production,Noklusējuma noliktavas ražošanai,
Default Work In Progress Warehouse,Default nepabeigtie Noliktava,
Default Finished Goods Warehouse,Noklusējuma Gatavās produkcijas noliktava,
Default Scrap Warehouse,Noklusējuma lūžņu noliktava,
-Over Production for Sales and Work Order,Pārmērīga produkcija pārdošanas un pasūtījuma veikšanai,
Overproduction Percentage For Sales Order,Pārprodukcijas procents pārdošanas pasūtījumam,
Overproduction Percentage For Work Order,Pārprodukcijas procents par darba kārtību,
Other Settings,Citi iestatījumi,
Update BOM Cost Automatically,Automātiski atjauniniet BOM izmaksas,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Automātiski atjaunināt BOM izmaksas, izmantojot plānotāju, pamatojoties uz jaunāko novērtēšanas likmi / cenrāžu likmi / izejvielu pēdējo pirkumu likmi.",
Material Request Plan Item,Materiālu pieprasījuma plāna postenis,
Material Request Type,Materiāls Pieprasījuma veids,
Material Issue,Materiāls Issue,
@@ -7603,10 +7554,6 @@
Quality Goal,Kvalitātes mērķis,
Monitoring Frequency,Monitoringa biežums,
Weekday,Nedēļas diena,
-January-April-July-October,Janvāris-aprīlis-jūlijs-oktobris,
-Revision and Revised On,Pārskatīšana un pārskatīšana ieslēgta,
-Revision,Pārskatīšana,
-Revised On,Pārskatīts ieslēgts,
Objectives,Mērķi,
Quality Goal Objective,Kvalitātes mērķis,
Objective,Objektīvs,
@@ -7619,7 +7566,6 @@
Processes,Procesi,
Quality Procedure Process,Kvalitātes procedūras process,
Process Description,Procesa apraksts,
-Child Procedure,Bērna procedūra,
Link existing Quality Procedure.,Saistīt esošo kvalitātes procedūru.,
Additional Information,Papildus informācija,
Quality Review Objective,Kvalitātes pārskata mērķis,
@@ -7787,15 +7733,9 @@
Default Customer Group,Default Klientu Group,
Default Territory,Default Teritorija,
Close Opportunity After Days,Aizvērt Iespēja pēc dienas,
-Auto close Opportunity after 15 days,Auto tuvu Opportunity pēc 15 dienām,
Default Quotation Validity Days,Nokotināšanas cesijas derīguma dienas,
Sales Update Frequency,Pārdošanas atjaunināšanas biežums,
-How often should project and company be updated based on Sales Transactions.,"Cik bieži ir jāuzlabo projekts un uzņēmums, pamatojoties uz pārdošanas darījumiem.",
Each Transaction,Katrs darījums,
-Allow user to edit Price List Rate in transactions,Ļauj lietotājam rediģēt Cenrādi Rate darījumos,
-Allow multiple Sales Orders against a Customer's Purchase Order,Atļaut vairākas pārdošanas pasūtījumos pret Klienta Pirkuma pasūtījums,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Apstiprināt pārdošanas cena posteni pret pirkuma likmes vai vērtēšanas koeficients,
-Hide Customer's Tax Id from Sales Transactions,Slēpt Klienta nodokļu ID no pārdošanas darījumu,
SMS Center,SMS Center,
Send To,Sūtīt,
All Contact,Visi Contact,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Ražotāji izmanto preces,
Limited to 12 characters,Ierobežots līdz 12 simboliem,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Iestatiet noliktavu,
-Sets 'For Warehouse' in each row of the Items table.,Tabulas Items katrā rindā iestata 'For Warehouse'.,
-Requested For,Pieprasīts Par,
Partially Ordered,Daļēji pasūtīts,
Transferred,Pārskaitīts,
% Ordered,% Pasūtīts,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Default Stock UOM,
Sample Retention Warehouse,Paraugu uzglabāšanas noliktava,
Default Valuation Method,Default Vērtēšanas metode,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Procents jums ir atļauts saņemt vai piegādāt vairāk pret pasūtīto daudzumu. Piemēram: Ja esi pasūtījis 100 vienības. un jūsu pabalsts ir, tad jums ir atļauts saņemt 110 vienības 10%.",
-Action if Quality inspection is not submitted,"Rīcība, ja nav iesniegta kvalitātes pārbaude",
Show Barcode Field,Rādīt Svītrkoda Field,
Convert Item Description to Clean HTML,"Konvertēt elementa aprakstu, lai notīrītu HTML",
-Auto insert Price List rate if missing,"Auto ievietot Cenrādis likme, ja trūkst",
Allow Negative Stock,Atļaut negatīvs Stock,
Automatically Set Serial Nos based on FIFO,Automātiski iestata Serial Nos pamatojoties uz FIFO,
-Set Qty in Transactions based on Serial No Input,"Iestatiet daudzumu darījumos, kuru pamatā ir sērijas Nr. Ievade",
Auto Material Request,Auto Materiāls Pieprasījums,
-Raise Material Request when stock reaches re-order level,Paaugstināt Materiālu pieprasījums kad akciju sasniedz atkārtoti pasūtījuma līmeni,
-Notify by Email on creation of automatic Material Request,Paziņot pa e-pastu uz izveidojot automātisku Material pieprasījuma,
Inter Warehouse Transfer Settings,Starp noliktavas pārsūtīšanas iestatījumi,
-Allow Material Transfer From Delivery Note and Sales Invoice,Atļaut materiālu pārsūtīšanu no pavadzīmes un pārdošanas rēķina,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Atļaut materiālu pārsūtīšanu no pirkuma saņemšanas un pirkuma rēķina,
Freeze Stock Entries,Iesaldēt krājumu papildināšanu,
Stock Frozen Upto,Stock Frozen Līdz pat,
-Freeze Stocks Older Than [Days],Iesaldēt Krājumi Vecāki par [dienas],
-Role Allowed to edit frozen stock,Loma Atļauts rediģēt saldētas krājumus,
Batch Identification,Partijas identifikācija,
Use Naming Series,Izmantojiet nosaukumu sēriju,
Naming Series Prefix,Nosaukumu sērijas prefikss,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Pirkuma čeka tendences,
Purchase Register,Pirkuma Reģistrēties,
Quotation Trends,Piedāvājumu tendences,
-Quoted Item Comparison,Citēts Prece salīdzinājums,
Received Items To Be Billed,Saņemtie posteņi ir Jāmaksā,
Qty to Order,Daudz pasūtījuma,
Requested Items To Be Transferred,Pieprasīto pozīcijas jāpārskaita,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Atlasiet noliktavu materiālu pieprasījumiem,
Transfer Materials For Warehouse {0},Materiālu pārsūtīšana noliktavai {0},
Production Plan Material Request Warehouse,Ražošanas plāna materiālu pieprasījumu noliktava,
-Set From Warehouse,Komplekts No noliktavas,
-Source Warehouse (Material Transfer),Avota noliktava (materiālu pārsūtīšana),
Sets 'Source Warehouse' in each row of the items table.,Katrā vienumu tabulas rindā iestata “Avota noliktava”.,
Sets 'Target Warehouse' in each row of the items table.,Katrā vienumu tabulas rindā iestata 'Mērķa noliktava'.,
Show Cancelled Entries,Rādīt atceltos ierakstus,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Pakalpojums saņemts, bet nav rēķins",
Deferred Accounting Settings,Atliktie grāmatvedības iestatījumi,
Book Deferred Entries Based On,Grāmata atlikto ierakstu pamatā,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ja ir atlasīts "Mēneši", fiksētā summa tiks rezervēta kā atliktie ieņēmumi vai izdevumi par katru mēnesi neatkarīgi no dienu skaita mēnesī. Tiks proporcionāls, ja atliktie ieņēmumi vai izdevumi netiks rezervēti uz visu mēnesi.",
Days,Dienas,
Months,Mēneši,
Book Deferred Entries Via Journal Entry,"Grāmatu atliktie ieraksti, izmantojot žurnāla ierakstu",
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Ja šī nav pārbaudīta, tiks izveidoti GL ieraksti, lai rezervētu atliktos ieņēmumus / izdevumus",
Submit Journal Entries,Iesniegt žurnāla ierakstus,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Ja šī nav atzīmēta, žurnāla ieraksti tiks saglabāti melnrakstā un būs jāiesniedz manuāli",
Enable Distributed Cost Center,Iespējot izplatīto izmaksu centru,
@@ -8901,8 +8823,6 @@
Is Inter State,Ir starpvalsts,
Purchase Details,Informācija par pirkumu,
Depreciation Posting Date,Nolietojuma uzskaites datums,
-Purchase Order Required for Purchase Invoice & Receipt Creation,"Nepieciešams pirkuma pasūtījums, lai izveidotu rēķinu un kvīti",
-Purchase Receipt Required for Purchase Invoice Creation,Nepieciešama pirkuma kvīts pirkuma rēķina izveidei,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Pēc noklusējuma piegādātāja nosaukums tiek iestatīts atbilstoši ievadītajam piegādātāja nosaukumam. Ja vēlaties, lai piegādātājus nosauc a",
choose the 'Naming Series' option.,izvēlieties opciju “Nosaukt sēriju”.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,"Konfigurējiet noklusējuma cenrādi, veidojot jaunu pirkuma darījumu. Vienību cenas tiks iegūtas no šī Cenrāža.",
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Ir ienākuma nodokļa sastāvdaļa,
Component properties and references ,Komponentu īpašības un atsauces,
Additional Salary ,Papildalga,
-Condtion and formula,Nosacījums un formula,
Unmarked days,Nezīmētas dienas,
Absent Days,Nebūšanas dienas,
Conditions and Formula variable and example,Nosacījumi un Formulas mainīgais un piemērs,
Feedback By,Atsauksmes Autors,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.GGGG .-. MM .-. DD.-,
Manufacturing Section,Ražošanas nodaļa,
-Sales Order Required for Sales Invoice & Delivery Note Creation,"Nepieciešams pārdošanas pasūtījums, lai izveidotu pārdošanas rēķinu un piegādes piezīmi",
-Delivery Note Required for Sales Invoice Creation,"Piegādes piezīme nepieciešama, lai izveidotu pārdošanas rēķinu",
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Pēc noklusējuma klienta vārds tiek iestatīts atbilstoši ievadītajam vārdam. Ja vēlaties, lai klientus nosauc a",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,"Konfigurējiet noklusējuma cenrādi, veidojot jaunu pārdošanas darījumu. Vienību cenas tiks iegūtas no šī Cenrāža.",
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ja šī opcija ir konfigurēta “Jā”, ERPNext neļaus jums izveidot pārdošanas rēķinu vai piegādes piezīmi, vispirms neizveidojot pārdošanas pasūtījumu. Šo konfigurāciju var ignorēt konkrēts klients, klienta galvenajā ieslēdzot izvēles rūtiņu “Atļaut pārdošanas rēķinu izveidošanu bez pārdošanas pasūtījuma”.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} ir veiksmīgi pievienots visām atlasītajām tēmām.,
Topics updated,Tēmas ir atjauninātas,
Academic Term and Program,Akadēmiskais termins un programma,
-Last Stock Transaction for item {0} was on {1}.,Pēdējais krājuma darījums vienumam {0} bija {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Preces {0} krājumu darījumus nevar izlikt pirms šī laika.,
Please remove this item and try to submit again or update the posting time.,"Lūdzu, noņemiet šo vienumu un mēģiniet iesniegt vēlreiz vai atjauniniet izlikšanas laiku.",
Failed to Authenticate the API key.,Neizdevās autentificēt API atslēgu.,
Invalid Credentials,Nederīgi akreditācijas dati,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,"Lūdzu, pārbaudiet savu Plaid klienta ID un slepenās vērtības",
Bank transaction creation error,Kļūda bankas darījuma izveidē,
Unit of Measurement,Mērvienība,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},#. Rinda: vienuma {} pārdošanas likme ir zemāka par tā {}. Pārdošanas likmei jābūt vismaz {},
Fiscal Year {0} Does Not Exist,Fiskālais gads {0} nepastāv,
Row # {0}: Returned Item {1} does not exist in {2} {3},{0}. Rinda: atgrieztais vienums {1} nepastāv šeit: {2} {3},
Valuation type charges can not be marked as Inclusive,Novērtēšanas veida izmaksas nevar atzīmēt kā iekļaujošas,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Reakcijas laiks {0} prioritātei rindā {1} nevar būt ilgāks par izšķirtspējas laiku.,
{0} is not enabled in {1},Vietne {0} nav iespējota šeit: {1},
Group by Material Request,Grupēt pēc materiāla pieprasījuma,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","{0} rinda: Piegādātājam {0} e-pasta adrese ir nepieciešama, lai nosūtītu e-pastu",
Email Sent to Supplier {0},E-pasts nosūtīts piegādātājam {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Piekļuve pieprasījumam no portāla ir atspējota. Lai atļautu piekļuvi, iespējojiet to portāla iestatījumos.",
Supplier Quotation {0} Created,Piegādātāja piedāvājums {0} izveidots,
Valid till Date cannot be before Transaction Date,Derīgs līdz datumam nevar būt pirms darījuma datuma,
+Unlink Advance Payment on Cancellation of Order,"Atsaistot avansa maksājumu, atceļot pasūtījumu",
+"Simple Python Expression, Example: territory != 'All Territories'","Vienkārša Python izteiksme, piemērs: territorija! = 'Visas teritorijas'",
+Sales Contributions and Incentives,Pārdošanas iemaksas un stimuli,
+Sourced by Supplier,Piegādātājs,
+Total weightage assigned should be 100%.<br>It is {0},Kopējam piešķirtajam svaram jābūt 100%.<br> Tas ir {0},
+Account {0} exists in parent company {1}.,Konts {0} pastāv mātes uzņēmumā {1}.,
+"To overrule this, enable '{0}' in company {1}","Lai to atceltu, iespējojiet “{0}” uzņēmumā {1}",
+Invalid condition expression,Nederīga nosacījuma izteiksme,
+Please Select a Company First,"Lūdzu, vispirms atlasiet uzņēmumu",
+Please Select Both Company and Party Type First,"Lūdzu, vispirms atlasiet gan uzņēmuma, gan ballītes veidu",
+Provide the invoice portion in percent,Norādiet rēķina daļu procentos,
+Give number of days according to prior selection,Norādiet dienu skaitu pēc iepriekšējas izvēles,
+Email Details,E-pasta informācija,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Izvēlieties sveicienu uztvērējam. Piemēram, kungs, kundze utt.",
+Preview Email,Priekšskatīt e-pastu,
+Please select a Supplier,"Lūdzu, izvēlieties piegādātāju",
+Supplier Lead Time (days),Piegādātāja izpildes laiks (dienas),
+"Home, Work, etc.","Mājas, darbs utt.",
+Exit Interview Held On,Izejas intervija notiek,
+Condition and formula,Stāvoklis un formula,
+Sets 'Target Warehouse' in each row of the Items table.,Katrā tabulas Vienumi rindā iestata 'Mērķa noliktava'.,
+Sets 'Source Warehouse' in each row of the Items table.,Katrā tabulas Elementi rindā iestata “Avota noliktava”.,
+POS Register,POS reģistrs,
+"Can not filter based on POS Profile, if grouped by POS Profile","Nevar filtrēt, pamatojoties uz POS profilu, ja tas ir grupēts pēc POS profila",
+"Can not filter based on Customer, if grouped by Customer","Nevar filtrēt, pamatojoties uz klientu, ja tas ir grupēts pēc klienta",
+"Can not filter based on Cashier, if grouped by Cashier","Nevar filtrēt, pamatojoties uz kasieri, ja tos sagrupē kasieris",
+Payment Method,Apmaksas veids,
+"Can not filter based on Payment Method, if grouped by Payment Method","Nevar filtrēt, pamatojoties uz maksājuma veidu, ja tas ir grupēts pēc maksājuma veida",
+Supplier Quotation Comparison,Piegādātāju cenu salīdzinājums,
+Price per Unit (Stock UOM),Vienības cena (krājuma UOM),
+Group by Supplier,Grupēt pēc piegādātāja,
+Group by Item,Grupēt pēc vienumiem,
+Remember to set {field_label}. It is required by {regulation}.,Atcerieties iestatīt {field_label}. To prasa {regulējums}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Reģistrācijas datums nevar būt pirms akadēmiskā gada sākuma datuma {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Reģistrācijas datums nevar būt pēc akadēmiskā termiņa beigu datuma {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Reģistrācijas datums nevar būt pirms akadēmiskā termiņa sākuma datuma {0},
+Future Posting Not Allowed,Turpmākā norīkošana nav atļauta,
+"To enable Capital Work in Progress Accounting, ","Lai iespējotu kapitāla darbu grāmatvedībā,",
+you must select Capital Work in Progress Account in accounts table,kontu tabulā jāatlasa Kapitāla darba process,
+You can also set default CWIP account in Company {},Varat arī iestatīt noklusējuma CWIP kontu uzņēmumā {},
+The Request for Quotation can be accessed by clicking on the following button,"Piedāvājuma pieprasījumam var piekļūt, noklikšķinot uz šīs pogas",
+Regards,Sveicieni,
+Please click on the following button to set your new password,"Lūdzu, noklikšķiniet uz šīs pogas, lai iestatītu jauno paroli",
+Update Password,Atjaunināt paroli,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},#. Rinda: vienuma {} pārdošanas likme ir zemāka par tā {}. Pārdošanai {} jābūt vismaz {},
+You can alternatively disable selling price validation in {} to bypass this validation.,"Varat arī atspējot pārdošanas cenas apstiprināšanu vietnē {}, lai apietu šo validāciju.",
+Invalid Selling Price,Nederīga pārdošanas cena,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,"Adresei jābūt saistītai ar uzņēmumu. Lūdzu, tabulā Saites pievienojiet rindu uzņēmumam Uzņēmums.",
+Company Not Linked,Uzņēmums nav saistīts,
+Import Chart of Accounts from CSV / Excel files,Importēt kontu plānu no CSV / Excel failiem,
+Completed Qty cannot be greater than 'Qty to Manufacture',Pabeigtais daudzums nedrīkst būt lielāks par “Daudzums izgatavošanai”,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email",{0} rinda: piegādātājam {1} e-pasta adreses nosūtīšanai ir nepieciešama e-pasta adrese,
+"If enabled, the system will post accounting entries for inventory automatically","Ja tas ir iespējots, sistēma automātiski grāmato uzskaites ierakstus par krājumiem",
+Accounts Frozen Till Date,Konti iesaldēti līdz datumam,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"Grāmatvedības ieraksti ir iesaldēti līdz šim datumam. Neviens nevar izveidot vai modificēt ierakstus, izņemot lietotājus ar tālāk norādīto lomu",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,"Atļauta loma, lai iestatītu iesaldētus kontus un rediģētu iesaldētos ierakstus",
+Address used to determine Tax Category in transactions,"Adrese, ko izmanto nodokļu kategorijas noteikšanai darījumos",
+"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 ","Procents, par kuru jums ir atļauts izrakstīt vairāk rēķinu pret pasūtīto summu. Piemēram, ja pasūtījuma vērtība ir 100 ASV dolāri vienumam un pielaide ir iestatīta kā 10%, tad jums ir atļauts izrakstīt rēķinu līdz 110 ASV dolāriem",
+This role is allowed to submit transactions that exceed credit limits,"Šai lomai ir atļauts iesniegt darījumus, kas pārsniedz kredītlimitus",
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ja tiek izvēlēts "Mēneši", fiksēta summa tiks rezervēta kā atliktie ieņēmumi vai izdevumi par katru mēnesi neatkarīgi no dienu skaita mēnesī. Tas tiks proporcionāls, ja atliktie ieņēmumi vai izdevumi netiks rezervēti uz visu mēnesi",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Ja tas nav atzīmēts, tiks izveidoti tiešie GL ieraksti atlikto ieņēmumu vai izdevumu uzskaitei",
+Show Inclusive Tax in Print,Parādiet iekļaujošo nodokli drukātā veidā,
+Only select this if you have set up the Cash Flow Mapper documents,"Atlasiet to tikai tad, ja esat iestatījis Cash Flow Mapper dokumentus",
+Payment Channel,Maksājumu kanāls,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Vai pirkuma rēķins un kvīts izveidošanai ir nepieciešams pirkuma pasūtījums?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Vai pirkuma rēķina izveidei ir nepieciešama pirkuma kvīts?,
+Maintain Same Rate Throughout the Purchase Cycle,Uzturiet vienādu likmi visā pirkuma ciklā,
+Allow Item To Be Added Multiple Times in a Transaction,Ļaujiet vienumam vairākas reizes pievienot darījumu,
+Suppliers,Piegādātāji,
+Send Emails to Suppliers,Nosūtiet e-pastus piegādātājiem,
+Select a Supplier,Izvēlieties piegādātāju,
+Cannot mark attendance for future dates.,Nevar atzīmēt apmeklējumu nākamajiem datumiem.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Vai vēlaties atjaunināt apmeklējumu skaitu?<br> Klāt: {0}<br> Nav: {1},
+Mpesa Settings,Mpesa iestatījumi,
+Initiator Name,Iniciatora vārds,
+Till Number,Līdz numuram,
+Sandbox,Smilšu kaste,
+ Online PassKey,Tiešsaistes PassKey,
+Security Credential,Drošības akreditācijas dati,
+Get Account Balance,Saņemt konta atlikumu,
+Please set the initiator name and the security credential,"Lūdzu, iestatiet iniciatora vārdu un drošības akreditācijas datus",
+Inpatient Medication Entry,Stacionāro zāļu ievadīšana,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Preces kods (zāles),
+Medication Orders,Zāļu pasūtījumi,
+Get Pending Medication Orders,Saņemiet neapstiprinātus medikamentu pasūtījumus,
+Inpatient Medication Orders,Stacionārie medikamentu pasūtījumi,
+Medication Warehouse,Zāļu noliktava,
+Warehouse from where medication stock should be consumed,"Noliktava, no kuras jāizlieto zāļu krājumi",
+Fetching Pending Medication Orders,Notiek neapstiprinātu zāļu pasūtījumu saņemšana,
+Inpatient Medication Entry Detail,Stacionāro zāļu ievadīšanas informācija,
+Medication Details,Zāļu informācija,
+Drug Code,Narkotiku kods,
+Drug Name,Zāļu nosaukums,
+Against Inpatient Medication Order,Pret stacionāro zāļu pasūtījumu,
+Against Inpatient Medication Order Entry,Pret stacionāro medikamentu pasūtījumu,
+Inpatient Medication Order,Stacionāro zāļu pasūtījums,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Pasūtījumu kopskaits,
+Completed Orders,Pabeigtie pasūtījumi,
+Add Medication Orders,Pievienojiet zāļu pasūtījumus,
+Adding Order Entries,Pasūtījumu ierakstu pievienošana,
+{0} medication orders completed,Pabeigti {0} zāļu pasūtījumi,
+{0} medication order completed,Pabeigts {0} zāļu pasūtījums,
+Inpatient Medication Order Entry,Stacionāra zāļu pasūtījuma ieraksts,
+Is Order Completed,Vai pasūtījums ir pabeigts,
+Employee Records to Be Created By,"Darbinieku ieraksti, kurus jāizveido",
+Employee records are created using the selected field,"Darbinieku ieraksti tiek veidoti, izmantojot atlasīto lauku",
+Don't send employee birthday reminders,Nesūtiet darbinieku dzimšanas dienas atgādinājumus,
+Restrict Backdated Leave Applications,Ierobežot novecojušo atvaļinājumu pieteikumus,
+Sequence ID,Secības ID,
+Sequence Id,Secības ID,
+Allow multiple material consumptions against a Work Order,Atļaut vairāku materiālu patēriņu pret darba rīkojumu,
+Plan time logs outside Workstation working hours,Plānojiet laika žurnālus ārpus darbstacijas darba laika,
+Plan operations X days in advance,Plānojiet operācijas X dienas iepriekš,
+Time Between Operations (Mins),Laiks starp operācijām (minūtes),
+Default: 10 mins,Noklusējums: 10 minūtes,
+Overproduction for Sales and Work Order,Pārprodukcija pārdošanas un darba pasūtījumiem,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Automātiski atjaunināt BOM izmaksas, izmantojot plānotāju, pamatojoties uz jaunāko izejvielu vērtēšanas likmi / cenu saraksta likmi / pēdējo pirkšanas likmi",
+Purchase Order already created for all Sales Order items,Visiem pārdošanas pasūtījuma priekšmetiem jau ir izveidots pirkuma pasūtījums,
+Select Items,Atlasiet vienumus,
+Against Default Supplier,Pret noklusēto piegādātāju,
+Auto close Opportunity after the no. of days mentioned above,Automātiska aizvēršanas iespēja pēc nr. dienu laikā,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Vai pārdošanas rēķina un piegādes piezīmes izveidei ir nepieciešams pārdošanas pasūtījums?,
+Is Delivery Note Required for Sales Invoice Creation?,Vai pārdošanas rēķina izveidei ir nepieciešama piegādes pavadzīme?,
+How often should Project and Company be updated based on Sales Transactions?,"Cik bieži projekts un uzņēmums ir jāatjaunina, pamatojoties uz pārdošanas darījumiem?",
+Allow User to Edit Price List Rate in Transactions,Atļaut lietotājam rediģēt cenu saraksta likmi darījumos,
+Allow Item to Be Added Multiple Times in a Transaction,Ļaujiet vienumam vairākas reizes pievienot darījumu,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Atļaut vairākus pārdošanas pasūtījumus klienta pirkuma pasūtījumam,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Apstipriniet preces pārdošanas cenu pret pirkuma likmi vai vērtēšanas likmi,
+Hide Customer's Tax ID from Sales Transactions,Paslēpt klienta nodokļu ID no pārdošanas darījumiem,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Procentuālais daudzums, ko atļauts saņemt vai piegādāt vairāk, salīdzinot ar pasūtīto daudzumu. Piemēram, ja esat pasūtījis 100 vienības un jūsu pabalsts ir 10%, tad jums ir atļauts saņemt 110 vienības.",
+Action If Quality Inspection Is Not Submitted,"Rīcība, ja kvalitātes pārbaude nav iesniegta",
+Auto Insert Price List Rate If Missing,"Automātiski ievietot cenu sarakstu, ja trūkst",
+Automatically Set Serial Nos Based on FIFO,"Automātiski iestatīt sērijas numurus, pamatojoties uz FIFO",
+Set Qty in Transactions Based on Serial No Input,"Iestatiet daudzumu darījumos, pamatojoties uz sērijas bez ievades",
+Raise Material Request When Stock Reaches Re-order Level,"Paaugstiniet materiālu pieprasījumu, kad krājums sasniedz atkārtotas pasūtīšanas līmeni",
+Notify by Email on Creation of Automatic Material Request,Paziņot pa e-pastu par automātiska materiāla pieprasījuma izveidošanu,
+Allow Material Transfer from Delivery Note to Sales Invoice,Atļaut materiālu pārsūtīšanu no piegādes paziņojuma līdz pārdošanas rēķinam,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Atļaut materiālu pārsūtīšanu no pirkuma kvīts uz pirkuma rēķinu,
+Freeze Stocks Older Than (Days),"Iesaldēt krājumus, kas vecāki par (dienām)",
+Role Allowed to Edit Frozen Stock,Loma atļauts rediģēt iesaldēto krājumu,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Nepiešķirtā maksājuma ieraksta summa {0} ir lielāka par bankas darījuma nepiešķirto summu,
+Payment Received,Maksājums saņemts,
+Attendance cannot be marked outside of Academic Year {0},Apmeklējumu nevar atzīmēt ārpus akadēmiskā gada {0},
+Student is already enrolled via Course Enrollment {0},"Students jau ir reģistrēts, izmantojot kursu reģistrāciju {0}",
+Attendance cannot be marked for future dates.,Apmeklējumu nevar atzīmēt nākamajiem datumiem.,
+Please add programs to enable admission application.,"Lūdzu, pievienojiet programmas, lai iespējotu uzņemšanas pieteikumu.",
+The following employees are currently still reporting to {0}:,Šie darbinieki joprojām ziņo uzņēmumam {0}:,
+Please make sure the employees above report to another Active employee.,"Lūdzu, pārliecinieties, ka iepriekš minētie darbinieki ziņo citam aktīvam darbiniekam.",
+Cannot Relieve Employee,Nevar atvieglot darbinieku,
+Please enter {0},"Lūdzu, ievadiet {0}",
+Please select another payment method. Mpesa does not support transactions in currency '{0}',"Lūdzu, izvēlieties citu maksājuma veidu. Mpesa neatbalsta darījumus valūtā “{0}”",
+Transaction Error,Darījuma kļūda,
+Mpesa Express Transaction Error,Mpesa Express darījuma kļūda,
+"Issue detected with Mpesa configuration, check the error logs for more details","Ar Mpesa konfigurāciju konstatēta problēma. Lai iegūtu sīkāku informāciju, pārbaudiet kļūdu žurnālus",
+Mpesa Express Error,Mpesa Express kļūda,
+Account Balance Processing Error,Konta atlikuma apstrādes kļūda,
+Please check your configuration and try again,"Lūdzu, pārbaudiet konfigurāciju un mēģiniet vēlreiz",
+Mpesa Account Balance Processing Error,Mpesa konta atlikuma apstrādes kļūda,
+Balance Details,Informācija par atlikumu,
+Current Balance,Pašreizējā bilance,
+Available Balance,Pieejamais atlikums,
+Reserved Balance,Rezervētais atlikums,
+Uncleared Balance,Neskaidrs atlikums,
+Payment related to {0} is not completed,"Maksājums, kas saistīts ar {0}, nav pabeigts",
+Row #{}: Item Code: {} is not available under warehouse {}.,#. Rinda: preces kods: {} nav pieejams noliktavā {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,#. Rinda: krājuma daudzums nav pietiekams preces kodam: {} zem noliktavas {}. Pieejamais daudzums {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,"#. Rinda: Lūdzu, atlasiet sērijas nr. Un sēriju pret vienumu: {} vai noņemiet to, lai pabeigtu darījumu.",
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,"#. Rinda: vienumam nav atlasīts sērijas numurs: {}. Lūdzu, izvēlieties vienu vai noņemiet to, lai pabeigtu darījumu.",
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,"#. Rinda: vienumam nav atlasīta neviena sērija: {}. Lūdzu, atlasiet partiju vai noņemiet to, lai pabeigtu darījumu.",
+Payment amount cannot be less than or equal to 0,Maksājuma summa nevar būt mazāka vai vienāda ar 0,
+Please enter the phone number first,"Lūdzu, vispirms ievadiet tālruņa numuru",
+Row #{}: {} {} does not exist.,#. Rinda: {} {} nepastāv.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,"{0}. Rinda: {1} ir nepieciešama, lai izveidotu rēķinus ar atvēršanas {2}",
+You had {} errors while creating opening invoices. Check {} for more details,"Veidojot sākuma rēķinus, radās {} kļūdas. Plašāku informāciju skatiet vietnē {}",
+Error Occured,Radās kļūda,
+Opening Invoice Creation In Progress,Notiek rēķina atvēršana,
+Creating {} out of {} {},Izveide {} no {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,"(Sērijas numurs: {0}) nevar izmantot, jo tas ir paredzēts pārdošanas pasūtījuma pilnīgai aizpildīšanai {1}.",
+Item {0} {1},Vienums {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Pēdējais krājuma darījums ar preci {0} zem noliktavas {1} notika šādā datumā: {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Preču {0} noliktavā {1} krājumu darījumus nevar izlikt pirms šī laika.,
+Posting future stock transactions are not allowed due to Immutable Ledger,"Turpmāko akciju darījumu publicēšana nav atļauta, pateicoties maināmai virsgrāmatai",
+A BOM with name {0} already exists for item {1}.,Vienumam {1} jau eksistē BOM ar nosaukumu {0}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,"{0} {1} Vai pārdēvējāt vienumu? Lūdzu, sazinieties ar administratoru / tehnisko atbalstu",
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},Rindā # {0}: secības ID {1} nevar būt mazāks par iepriekšējo rindas secības ID {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) jābūt vienādam ar {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, pabeidziet darbību {1} pirms operācijas {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Nevar nodrošināt piegādi ar sērijas numuru, jo prece {0} ir pievienota ar un bez Nodrošināt piegādi ar sērijas numuru.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,"Vienumam {0} nav sērijas numura. Tikai serilizētiem priekšmetiem var būt piegāde, pamatojoties uz sērijas numuru",
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Vienumam {0} nav atrasts aktīvs BOM. Piegādi ar sērijas numuru nevar nodrošināt,
+No pending medication orders found for selected criteria,Atlasītiem kritērijiem nav atrasti neapstiprināti medikamentu pasūtījumi,
+From Date cannot be after the current date.,Sākot no datuma nevar būt pēc pašreizējā datuma.,
+To Date cannot be after the current date.,Līdz datumam nevar būt pēc pašreizējā datuma.,
+From Time cannot be after the current time.,No laika nevar būt pēc pašreizējā laika.,
+To Time cannot be after the current time.,Laiks nevar būt pēc pašreizējā laika.,
+Stock Entry {0} created and ,Krājuma ieraksts {0} ir izveidots un,
+Inpatient Medication Orders updated successfully,Stacionāro zāļu pasūtījumi ir veiksmīgi atjaunināti,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},{0}. Rinda: Nevar izveidot stacionāro zāļu ierakstu pret atceltu stacionāro zāļu pasūtījumu {1},
+Row {0}: This Medication Order is already marked as completed,{0}. Rinda: Šis zāļu pasūtījums jau ir atzīmēts kā pabeigts,
+Quantity not available for {0} in warehouse {1},Daudzums nav pieejams vietnei {0} noliktavā {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,"Lūdzu, iespējojiet opciju Atļaut negatīvo krājumu krājumu iestatījumos vai izveidojiet krājuma ievadi, lai turpinātu.",
+No Inpatient Record found against patient {0},Netika atrasts neviens pacienta stacionāra reģistrs {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Stacionārs zāļu pasūtījums {0} pret pacienta sastapšanos {1} jau pastāv.,
+Allow In Returns,Atļaut pretī,
+Hide Unavailable Items,Paslēpt nepieejamos vienumus,
+Apply Discount on Discounted Rate,Piesakies atlaidi diskontētajai likmei,
+Therapy Plan Template,Terapijas plāna veidne,
+Fetching Template Details,Notiek veidnes detaļu ielāde,
+Linked Item Details,Saistītās preces informācija,
+Therapy Types,Terapijas veidi,
+Therapy Plan Template Detail,Terapijas plāna veidnes detaļas,
+Non Conformance,Nepakļaušanās,
+Process Owner,Procesa īpašnieks,
+Corrective Action,Korektīvie pasākumi,
+Preventive Action,Profilaktiskā darbība,
+Problem,Problēma,
+Responsible,Atbildīgs,
+Completion By,Pabeigšana,
+Process Owner Full Name,Procesa īpašnieka pilns vārds,
+Right Index,Labais indekss,
+Left Index,Kreisais rādītājs,
+Sub Procedure,Apakšprocedūra,
+Passed,Izturēts,
+Print Receipt,Drukāt kvīti,
+Edit Receipt,Rediģēt kvīti,
+Focus on search input,Koncentrējieties uz meklēšanas ievadi,
+Focus on Item Group filter,Koncentrējieties uz vienumu grupas filtru,
+Checkout Order / Submit Order / New Order,Checkout Order / Submit Order / New Order,
+Add Order Discount,Pievienojiet pasūtījuma atlaidi,
+Item Code: {0} is not available under warehouse {1}.,Preces kods: {0} nav pieejams noliktavā {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,"Sērijas numuri nav pieejami vienumam {0} zem noliktavas {1}. Lūdzu, mēģiniet nomainīt noliktavu.",
+Fetched only {0} available serial numbers.,Iegūti tikai {0} pieejamie sērijas numuri.,
+Switch Between Payment Modes,Pārslēgšanās starp maksājumu veidiem,
+Enter {0} amount.,Ievadiet summu {0}.,
+You don't have enough points to redeem.,"Jums nav pietiekami daudz punktu, lai tos izpirktu.",
+You can redeem upto {0}.,Varat izmantot līdz pat {0}.,
+Enter amount to be redeemed.,Ievadiet izpērkamo summu.,
+You cannot redeem more than {0}.,Jūs nevarat izmantot vairāk par {0}.,
+Open Form View,Atvērt veidlapas skatu,
+POS invoice {0} created succesfully,POS rēķins {0} izveidots veiksmīgi,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Krājuma daudzums ir nepietiekams preces kodam: {0} zem noliktavas {1}. Pieejamais daudzums {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Sērijas numurs: {0} jau ir pārskaitīts uz citu POS rēķinu.,
+Balance Serial No,Bilances sērijas Nr,
+Warehouse: {0} does not belong to {1},Noliktava: {0} nepieder pie {1},
+Please select batches for batched item {0},"Lūdzu, atlasiet sērijveida preces partijas {0}",
+Please select quantity on row {0},"Lūdzu, atlasiet daudzumu {0}. Rindā",
+Please enter serial numbers for serialized item {0},"Lūdzu, ievadiet sērijveida preces {0} sērijas numurus",
+Batch {0} already selected.,Partija {0} jau ir atlasīta.,
+Please select a warehouse to get available quantities,"Lūdzu, izvēlieties noliktavu, lai iegūtu pieejamos daudzumus",
+"For transfer from source, selected quantity cannot be greater than available quantity",Pārsūtīšanai no avota izvēlētais daudzums nevar būt lielāks par pieejamo daudzumu,
+Cannot find Item with this Barcode,Nevar atrast vienumu ar šo svītrkodu,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} ir obligāta. Varbūt valūtas maiņas ieraksts nav izveidots no {1} uz {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} ir iesniedzis ar to saistītus īpašumus. Lai izveidotu pirkuma atdevi, jums ir jāatceļ aktīvi.",
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Šo dokumentu nevar atcelt, jo tas ir saistīts ar iesniegto īpašumu {0}. Lūdzu, atceliet to, lai turpinātu.",
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,"#. Rinda: sērijas numurs {} jau ir transakts citā POS rēķinā. Lūdzu, izvēlieties derīgu sērijas nr.",
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,"Rinda Nr. {}: Sērijas numuri {} jau ir pārskaitīti uz citu POS rēķinu. Lūdzu, izvēlieties derīgu sērijas nr.",
+Item Unavailable,Vienums nav pieejams,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"#. Rinda: kārtas numuru {} nevar atgriezt, jo tas netika darīts sākotnējā rēķinā {}",
+Please set default Cash or Bank account in Mode of Payment {},"Lūdzu, norēķinu režīmā iestatiet noklusējuma skaidras naudas vai bankas kontu {}",
+Please set default Cash or Bank account in Mode of Payments {},"Maksājumu režīmā, lūdzu, iestatiet noklusējuma skaidras naudas vai bankas kontu {}",
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,"Lūdzu, pārliecinieties, ka {} konts ir Bilances konts. Varat mainīt vecāku kontu uz Bilances kontu vai izvēlēties citu kontu.",
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,"Lūdzu, pārliecinieties, ka {} konts ir apmaksājams konts. Mainiet konta veidu uz Maksājams vai atlasiet citu kontu.",
+Row {}: Expense Head changed to {} ,{}. Rinda: izdevumu daļa mainīta uz {},
+because account {} is not linked to warehouse {} ,jo konts {} nav saistīts ar noliktavu {},
+or it is not the default inventory account,vai arī tas nav noklusējuma krājumu konts,
+Expense Head Changed,Izdevumu galva mainīta,
+because expense is booked against this account in Purchase Receipt {},jo izdevumi tiek iegrāmatoti šajā kontā pirkuma čekā {},
+as no Purchase Receipt is created against Item {}. ,tā kā pret preci {} netiek izveidota pirkuma kvīts.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,"Tas tiek darīts, lai apstrādātu gadījumus, kad pēc pirkuma rēķina tiek izveidota pirkuma kvīts",
+Purchase Order Required for item {},Obligāts pirkuma pasūtījums vienumam {},
+To submit the invoice without purchase order please set {} ,"Lai iesniegtu rēķinu bez pirkuma pasūtījuma, lūdzu, iestatiet {}",
+as {} in {},kā {},
+Mandatory Purchase Order,Obligāts pirkuma pasūtījums,
+Purchase Receipt Required for item {},Nepieciešama vienuma {} pirkuma kvīts,
+To submit the invoice without purchase receipt please set {} ,"Lai iesniegtu rēķinu bez pirkuma čeka, lūdzu, iestatiet {}",
+Mandatory Purchase Receipt,Obligāta pirkuma kvīts,
+POS Profile {} does not belongs to company {},POS profils {} nepieder uzņēmumam {},
+User {} is disabled. Please select valid user/cashier,"Lietotājs {} ir atspējots. Lūdzu, atlasiet derīgu lietotāju / kasieri",
+Row #{}: Original Invoice {} of return invoice {} is {}. ,#. Rinda: atgriešanas rēķina sākotnējais rēķins {} ir {}.,
+Original invoice should be consolidated before or along with the return invoice.,Rēķina oriģināls jāapvieno pirms atgriešanas rēķina vai kopā ar to.,
+You can add original invoice {} manually to proceed.,"Lai turpinātu, rēķinu oriģinālu varat pievienot {} manuāli.",
+Please ensure {} account is a Balance Sheet account. ,"Lūdzu, pārliecinieties, ka {} konts ir Bilances konts.",
+You can change the parent account to a Balance Sheet account or select a different account.,Varat mainīt vecāku kontu uz Bilances kontu vai izvēlēties citu kontu.,
+Please ensure {} account is a Receivable account. ,"Lūdzu, pārliecinieties, ka {} konts ir debitoru konts.",
+Change the account type to Receivable or select a different account.,Mainiet konta veidu uz Debitori vai atlasiet citu kontu.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},"{} nevar atcelt, jo nopelnītie lojalitātes punkti ir izpirkti. Vispirms atceliet {} Nē {}",
+already exists,jau eksistē,
+POS Closing Entry {} against {} between selected period,POS slēgšanas ieraksts {} pret {} starp atlasīto periodu,
+POS Invoice is {},POS rēķins ir {},
+POS Profile doesn't matches {},POS profils neatbilst {},
+POS Invoice is not {},POS rēķins nav {},
+POS Invoice isn't created by user {},POS rēķinu nav izveidojis lietotājs {},
+Row #{}: {},#. Rinda: {},
+Invalid POS Invoices,Nederīgi POS rēķini,
+Please add the account to root level Company - {},"Lūdzu, pievienojiet kontu saknes līmeņa uzņēmumam - {}",
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Veidojot kontu pakārtotajam uzņēmumam {0}, vecāku konts {1} nav atrasts. Lūdzu, izveidojiet vecāku kontu attiecīgajā COA",
+Account Not Found,Konts nav atrasts,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Veidojot kontu pakārtotajam uzņēmumam {0}, vecāku konts {1} tika atrasts kā virsgrāmatas konts.",
+Please convert the parent account in corresponding child company to a group account.,"Lūdzu, konvertējiet vecāku kontu attiecīgajā pakārtotajā uzņēmumā par grupas kontu.",
+Invalid Parent Account,Nederīgs vecāku konts,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Pārdēvēšana ir atļauta tikai ar mātes uzņēmuma {0} starpniecību, lai izvairītos no neatbilstības.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Ja {0} {1} vienuma daudzumi ir {2}, vienumam tiks piemērota shēma {3}.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ja esat {0} {1} vērts vienumu {2}, vienumam tiks piemērota shēma {3}.",
+"As the field {0} is enabled, the field {1} is mandatory.","Tā kā lauks {0} ir iespējots, lauks {1} ir obligāts.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Tā kā lauks {0} ir iespējots, lauka {1} vērtībai jābūt lielākai par 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Nevar piegādāt preces {1} sērijas numuru {1}, jo tas ir rezervēts pilnas pārdošanas pasūtījumam {2}",
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Pārdošanas pasūtījumā {0} ir rezervācija vienumam {1}, rezervēto {1} varat piegādāt tikai pret {0}.",
+{0} Serial No {1} cannot be delivered,{0} Sērijas Nr. {1} nevar piegādāt,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},{0}. Rinda: izejvielai ir obligāti jānodrošina apakšlīguma priekšmets {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Tā kā izejvielu ir pietiekami daudz, materiālu pieprasījums nav nepieciešams noliktavai {0}.",
+" If you still want to proceed, please enable {0}.","Ja joprojām vēlaties turpināt, lūdzu, iespējojiet {0}.",
+The item referenced by {0} - {1} is already invoiced,"Vienumam, uz kuru atsaucas {0} - {1}, jau ir izrakstīts rēķins",
+Therapy Session overlaps with {0},Terapijas sesija pārklājas ar {0},
+Therapy Sessions Overlapping,Terapijas sesijas pārklājas,
+Therapy Plans,Terapijas plāni,
+"Item Code, warehouse, quantity are required on row {0}","Rindā {0} ir nepieciešams preces kods, noliktava un daudzums",
+Get Items from Material Requests against this Supplier,Iegūstiet preces no materiāliem pieprasījumiem pret šo piegādātāju,
+Enable European Access,Iespējot Eiropas piekļuvi,
+Creating Purchase Order ...,Notiek pirkuma pasūtījuma izveide ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Izvēlieties piegādātāju no tālāk norādīto vienumu noklusējuma piegādātājiem. Pēc izvēles tiks veikts pirkuma pasūtījums tikai par precēm, kas pieder izvēlētajam piegādātājam.",
+Row #{}: You must select {} serial numbers for item {}.,#. Rinda: jums jāizvēlas {} vienuma sērijas numuri {}.,
diff --git a/erpnext/translations/mk.csv b/erpnext/translations/mk.csv
index 99ef866..7008025 100644
--- a/erpnext/translations/mk.csv
+++ b/erpnext/translations/mk.csv
@@ -110,7 +110,6 @@
Actual type tax cannot be included in Item rate in row {0},даноците не може да бидат содржани во ставките во ред {0},
Add,Додавање,
Add / Edit Prices,Додај / Уреди цени,
-Add All Suppliers,Додај ги сите добавувачи,
Add Comment,Додај коментар,
Add Customers,Додади Клиентите,
Add Employees,Додај вработени,
@@ -474,13 +473,11 @@
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',не може да се одбие кога категорија е наменета за "оценка" или "Vaulation и вкупно",
"Cannot delete Serial No {0}, as it is used in stock transactions","Не можат да избришат сериски Не {0}, како што се користи во акции трансакции",
Cannot enroll more than {0} students for this student group.,Не може да се запишат повеќе од {0} студентите за оваа група студенти.,
-Cannot find Item with this barcode,Не можам да ја пронајдам Ставката со овој баркод,
Cannot find active Leave Period,Не може да се најде активен период на напуштање,
Cannot produce more Item {0} than Sales Order quantity {1},Не може да произведе повеќе од ставка {0} од количина {1} во Продажна нарачка,
Cannot promote Employee with status Left,Не може да се промовира вработениот со статус Лево,
Cannot refer row number greater than or equal to current row number for this Charge type,Не може да се однесува ред број е поголема или еднаква на тековниот број на ред за овој тип на полнење,
Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,Не може да го изберете видот на пресметување како 'Износ на претходниот ред' или 'Вкупно на претходниот ред' за првиот ред,
-Cannot set a received RFQ to No Quote,Не може да се постави примена RFQ во Нема Цитат,
Cannot set as Lost as Sales Order is made.,Не може да се постави како изгубени како Продај Побарувања е направен.,
Cannot set authorization on basis of Discount for {0},Не може да се постави овластување врз основа на попуст за {0},
Cannot set multiple Item Defaults for a company.,Не може да се постават повеќекратни преференции на ставка за компанијата.,
@@ -521,7 +518,6 @@
Chargeble,Шаргел,
Charges are updated in Purchase Receipt against each item,Обвиненијата се ажурирани Набавка Потврда против секоја ставка,
"Charges will be distributed proportionately based on item qty or amount, as per your selection","Кривична пријава ќе биде дистрибуиран пропорционално врз основа на точка количество: Контакт лице или количина, како на вашиот избор",
-Chart Of Accounts,Сметковниот план,
Chart of Cost Centers,Шема на трошоците центри,
Check all,Проверете ги сите,
Checkout,Плаќање,
@@ -581,7 +577,6 @@
Compensatory Off,Обесштетување Off,
Compensatory leave request days not in valid holidays,Денови за барање компензаторско отсуство не се во валидни празници,
Complaint,Жалба,
-Completed Qty can not be greater than 'Qty to Manufacture',Завршено Количина не може да биде поголем од "Количина на производство",
Completion Date,Датум на завршување,
Computer,Компјутер,
Condition,Состојба,
@@ -694,7 +689,6 @@
"Create and manage daily, weekly and monthly email digests.","Креирање и управување со дневни, неделни и месечни Е-содржините.",
Create customer quotes,Креирај понуди на клиентите,
Create rules to restrict transactions based on values.,Создаде правила за ограничување на трансакции врз основа на вредности.,
-Created By,Создадена од страна,
Created {0} scorecards for {1} between: ,Создадени {0} броеви за карти за {1} помеѓу:,
Creating Company and Importing Chart of Accounts,Создавање компанија и увоз на табела на сметки,
Creating Fees,Создавање такси,
@@ -936,7 +930,6 @@
Employee Transfer cannot be submitted before Transfer Date ,Преносот на вработените не може да се поднесе пред датумот на пренос,
Employee cannot report to himself.,Вработените не можат да известуваат за себе.,
Employee relieved on {0} must be set as 'Left',Вработен ослободен на {0} мора да биде поставено како "Лево",
-Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ,Статусот на вработениот не може да се постави на „лево“ бидејќи следниве вработени во моментот се пријавуваат кај овој вработен:,
Employee {0} already submited an apllication {1} for the payroll period {2},Вработениот {0} веќе доставил примена {1} за периодот на платен список {2},
Employee {0} has already applied for {1} between {2} and {3} : ,Вработениот {0} веќе аплицираше за {1} помеѓу {2} и {3}:,
Employee {0} has no maximum benefit amount,Вработениот {0} нема максимален износ на корист,
@@ -1083,7 +1076,6 @@
For row {0}: Enter Planned Qty,За ред {0}: Внесете го планираното количество,
"For {0}, only credit accounts can be linked against another debit entry","За {0}, само кредитни сметки може да се поврзат против друг запис дебитна",
"For {0}, only debit accounts can be linked against another credit entry","За {0}, само задолжува сметки може да се поврзат против друга кредитна влез",
-Form View,Преглед на форма,
Forum Activity,Форум активност,
Free item code is not selected,Кодот за бесплатна ставка не е избран,
Freight and Forwarding Charges,Товар и товар пријави,
@@ -1458,7 +1450,6 @@
"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Одмор не може да се одвои пред {0}, како рамнотежа одмор веќе е рачна пренасочат во рекордно идната распределба одмор {1}",
"Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}","Отсуство не може да се примени / откажана пред {0}, како рамнотежа одмор веќе е рачна пренасочат во рекордно идната распределба одмор {1}",
Leave of type {0} cannot be longer than {1},Отсуство од типот {0} не може да биде подолг од {1},
-Leave the field empty to make purchase orders for all suppliers,Оставете го полето празно за да ги направите купувачките нарачки за сите добавувачи,
Leaves,Заминува,
Leaves Allocated Successfully for {0},Остава распределени успешно за {0},
Leaves has been granted sucessfully,Лисјата се дадени успешно,
@@ -1701,7 +1692,6 @@
No Items with Bill of Materials to Manufacture,Нема предмети со Бил на материјали за производство на,
No Items with Bill of Materials.,Нема елементи со Бил материјали.,
No Permission,Нема дозвола,
-No Quote,Не Цитат,
No Remarks,Нема забелешки,
No Result to submit,Нема резултат што треба да се поднесе,
No Salary Structure assigned for Employee {0} on given date {1},Структура за плата доделена за вработените {0} на даден датум {1},
@@ -1858,7 +1848,6 @@
Overlapping conditions found between:,Преклопување состојби помеѓу:,
Owner,Сопственикот,
PAN,PAN,
-PO already created for all sales order items,PO веќе креиран за сите нарачки за нарачки,
POS,POS,
POS Profile,POS Профил,
POS Profile is required to use Point-of-Sale,ПОС профилот е потребен за користење на Point-of-Sale,
@@ -2033,7 +2022,6 @@
Please select Charge Type first,Ве молиме изберете Полнење Тип прв,
Please select Company,Ве молиме изберете ја компанијата,
Please select Company and Designation,Изберете компанија и ознака,
-Please select Company and Party Type first,Ве молиме изберете компанија и Партијата Тип прв,
Please select Company and Posting Date to getting entries,Ве молиме изберете Компанија и Датум на објавување за да добивате записи,
Please select Company first,Ве молиме изберете ја првата компанија,
Please select Completion Date for Completed Asset Maintenance Log,Изберете датум за завршување на дневник за одржување на средствата,
@@ -2505,7 +2493,6 @@
Row {0}: UOM Conversion Factor is mandatory,Ред {0}: UOM конверзија фактор е задолжително,
Row {0}: select the workstation against the operation {1},Ред {0}: изберете работна станица против операцијата {1},
Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.,Ред {0}: {1} Сериски броеви потребни за точка {2}. Вие сте доставиле {3}.,
-Row {0}: {1} is required to create the Opening {2} Invoices,Ред {0}: {1} е потребно да се креираат Отворање {2} фактури,
Row {0}: {1} must be greater than 0,Редот {0}: {1} мора да биде поголем од 0,
Row {0}: {1} {2} does not match with {3},Ред {0}: {1} {2} не се поклопува со {3},
Row {0}:Start Date must be before End Date,Ред {0}: Почеток Датум мора да биде пред Крај Датум,
@@ -2645,11 +2632,9 @@
Send Grant Review Email,Испратете е-пошта за Грант Преглед,
Send Now,Испрати Сега,
Send SMS,Испрати СМС,
-Send Supplier Emails,Испрати Добавувачот пораки,
Send mass SMS to your contacts,Испрати маса SMS порака на вашите контакти,
Sensitivity,Чувствителност,
Sent,Испрати,
-Serial #,Сериски #,
Serial No and Batch,Сериски Не и серија,
Serial No is mandatory for Item {0},Сериски Не е задолжително за Точка {0},
Serial No {0} does not belong to Batch {1},Сериската број {0} не припаѓа на групата {1},
@@ -2980,7 +2965,6 @@
The name of your company for which you are setting up this system.,Името на вашата компанија за која сте за создавање на овој систем.,
The number of shares and the share numbers are inconsistent,Бројот на акции и бројот на акции се недоследни,
The payment gateway account in plan {0} is different from the payment gateway account in this payment request,Сметката за платежна портал во планот {0} е различна од сметката на платежната порта во ова барање за плаќање,
-The request for quotation can be accessed by clicking on the following link,Барањето за прибирање на понуди може да се пристапи со кликнување на следниов линк,
The selected BOMs are not for the same item,Избраните BOMs не се за истата ставка,
The selected item cannot have Batch,На избраната ставка не може да има Batch,
The seller and the buyer cannot be the same,Продавачот и купувачот не можат да бидат исти,
@@ -3130,7 +3114,6 @@
Total flexible benefit component amount {0} should not be less than max benefits {1},Вкупната количина на флексибилен придонес {0} не треба да биде помала од максималната придобивка {1},
Total hours: {0},Вкупно часови: {0},
Total leaves allocated is mandatory for Leave Type {0},Вкупниот износ на лисја е задолжителен за Тип за напуштање {0},
-Total weightage assigned should be 100%. It is {0},Вкупно weightage доделени треба да биде 100%. Тоа е {0},
Total working hours should not be greater than max working hours {0},Вкупно работно време не смее да биде поголема од работното време max {0},
Total {0} ({1}),Вкупно {0} ({1}),
"Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'","Вкупно {0} за сите предмети е нула, може да треба да се менува "Дистрибуирање промени врз основа на"",
@@ -3316,7 +3299,6 @@
What do you need help with?,Што ви треба помош?,
What does it do?,Што да направам?,
Where manufacturing operations are carried.,Каде што се врши производните операции.,
-"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Додека создавате сметка за дете Компанија {0}, сметката за родители {1} не е пронајдена. Ве молиме, креирајте ја матичната сметка во соодветниот ЦОА",
White,Бела,
Wire Transfer,Wire Transfer,
WooCommerce Products,Производи на WooCommerce,
@@ -3448,7 +3430,6 @@
{0} variants created.,{0} создадени варијанти.,
{0} {1} created,{0} {1} создадена,
{0} {1} does not exist,{0} {1} не постои,
-{0} {1} does not exist.,{0} {1} не постои.,
{0} {1} has been modified. Please refresh.,{0} {1} е изменета. Ве молиме да се одмориме.,
{0} {1} has not been submitted so the action cannot be completed,"{0} {1} не е поднесено, па не може да се заврши на акција",
"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} е поврзан со {2}, но партиска сметка е {3}",
@@ -3485,6 +3466,7 @@
{0}: {1} does not exists,{0}: {1} не постои,
{0}: {1} not found in Invoice Details table,{0}: {1} не се најде во Фактура Детали маса,
{} of {},{} од {},
+Assigned To,Доделени,
Chat,Чет,
Completed By,Завршено од,
Conditions,Услови,
@@ -3506,7 +3488,9 @@
Merge with existing,Се спои со постојната,
Office,Канцеларија,
Orientation,ориентација,
+Parent,Родител,
Passive,Пасивни,
+Payment Failed,плаќање успеав,
Percent,Проценти,
Permanent,постојана,
Personal,Лични,
@@ -3544,7 +3528,6 @@
Company field is required,Потребно е поле на компанијата,
Creating Dimensions...,Создавање димензии ...,
Duplicate entry against the item code {0} and manufacturer {1},Дупликат внес против кодот на објектот {0} и производител {1},
-Import Chart Of Accounts from CSV / Excel files,Увези ја табелата на сметки од датотеките CSV / Excel,
Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers,Невалиден GSTIN! Внесот што сте го внеле не се совпаѓа со форматот GSTIN за имателите на UIN или Даватели на услуги што не се резиденти на OIDAR,
Invoice Grand Total,Фактура вкупно,
Last carbon check date cannot be a future date,Последниот датум за проверка на јаглерод не може да биде иден датум,
@@ -3556,6 +3539,7 @@
Show {0},Покажи {0},
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Не се дозволени специјални карактери освен "-", "#", ".", "/", "{" И "}" во сериите за именување",
Target Details,Цели детали,
+{0} already has a Parent Procedure {1}.,{0} веќе има Матична постапка {1}.,
API,API,
Annual,Годишен,
Approved,Одобрени,
@@ -3572,6 +3556,8 @@
No data to export,Нема податоци за извоз,
Portrait,Портрет,
Print Heading,Печати Заглавие,
+Scheduler Inactive,Распоред неактивен,
+Scheduler is inactive. Cannot import data.,Распоредот е неактивен. Не може да се внесат податоци.,
Show Document,Прикажи документ,
Show Traceback,Покажи пребарување,
Video,Видео,
@@ -3697,7 +3683,6 @@
Create Quality Inspection for Item {0},Создадете квалитетна инспекција за производот {0},
Creating Accounts...,Креирање на сметки ...,
Creating bank entries...,Креирање на записи во банка ...,
-Creating {0},Креирање {0},
Credit limit is already defined for the Company {0},Кредитниот лимит е веќе дефиниран за компанијата {0,
Ctrl + Enter to submit,Ctrl + Enter за да се достават,
Ctrl+Enter to submit,Ctrl + Enter за да поднесете,
@@ -3921,7 +3906,6 @@
Plaid public token error,Грешна грешка во карирани јавни знаци,
Plaid transactions sync error,Грешка во синхронизацијата со карирани трансакции,
Please check the error log for details about the import errors,Проверете го дневникот за грешки за детали за грешките при увозот,
-Please click on the following link to set your new password,Ве молиме кликнете на следниот линк за да го поставите нова лозинка,
Please create <b>DATEV Settings</b> for Company <b>{}</b>.,"Ве молиме, креирајте ги <b>поставките DATEV</b> за компанијата <b>{</b> .",
Please create adjustment Journal Entry for amount {0} ,"Ве молиме, креирајте припис за весник за износ amount 0}",
Please do not create more than 500 items at a time,"Ве молиме, не создавајте повеќе од 500 артикли истовремено",
@@ -3997,6 +3981,7 @@
Release date must be in the future,Датумот на објавување мора да биде во иднина,
Relieving Date must be greater than or equal to Date of Joining,Датумот на ослободување мора да биде поголем или еднаков на датумот на придружување,
Rename,Преименувај,
+Rename Not Allowed,Преименување не е дозволено,
Repayment Method is mandatory for term loans,Метод на отплата е задолжителен за заеми со рок,
Repayment Start Date is mandatory for term loans,Датумот на започнување на отплата е задолжителен за заеми со термин,
Report Item,Известување ставка,
@@ -4043,7 +4028,6 @@
Select All,Избери ги сите,
Select Difference Account,Изберете сметка за разлика,
Select a Default Priority.,Изберете Стандарден приоритет.,
-Select a Supplier from the Default Supplier List of the items below.,Изберете снабдувач од списокот со стандардна понудувач на артиклите подолу.,
Select a company,Изберете компанија,
Select finance book for the item {0} at row {1},Изберете книга за финансии за производот {0} по ред {1,
Select only one Priority as Default.,Изберете само еден Приоритет како Стандарден.,
@@ -4247,7 +4231,6 @@
Actual ,Крај,
Add to cart,Додади во кошничка,
Budget,Буџет,
-Chart Of Accounts Importer,Табела на сметки увозник,
Chart of Accounts,Сметка на сметки,
Customer database.,База на податоци за клиентите.,
Days Since Last order,Дена од денот на нарачка,
@@ -4255,7 +4238,6 @@
End date can not be less than start date,Крајниот датум не може да биде помал од датумот на почеток,
For Default Supplier (Optional),За стандарден добавувач (опционално),
From date cannot be greater than To date,Од датумот не може да биде поголем од датум,
-Get items from,Се предмети од,
Group by,Со група,
In stock,На залиха,
Item name,Точка Име,
@@ -4532,32 +4514,22 @@
Accounts Settings,Сметки Settings,
Settings for Accounts,Поставки за сметки,
Make Accounting Entry For Every Stock Movement,Направете влез сметководството за секој берза движење,
-"If enabled, the system will post accounting entries for inventory automatically.","Ако е овозможено, системот ќе ја објавите на сметководствените ставки за попис автоматски.",
-Accounts Frozen Upto,Сметки замрзнати до,
-"Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.","Сметководство влез замрзнати до овој датум, никој не може да се направи / менувате влез освен улога наведени подолу.",
-Role Allowed to Set Frozen Accounts & Edit Frozen Entries,Улогата дозволено да го поставите замрзнати сметки & Уреди Замрзнати записи,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Корисниците со оваа улога може да поставите замрзнати сметки и да се создаде / измени на сметководствените ставки кон замрзнатите сметки,
Determine Address Tax Category From,Одреди ја категоријата Данок на адреса од,
-Address used to determine Tax Category in transactions.,Адреса се користи за да се утврди даночна категорија во трансакции.,
Over Billing Allowance (%),Надоместок за наплата (%),
-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 for $110.,"Процент ви е дозволено да плаќате повеќе во однос на нарачаната сума. На пример: Ако вредноста за нарачката е 100 $ за една ставка и толеранцијата е поставена како 10%, тогаш ќе ви биде дозволено да плаќате за 110 долари.",
Credit Controller,Кредитна контролор,
-Role that is allowed to submit transactions that exceed credit limits set.,Улогата што може да поднесе трансакции кои надминуваат кредитни лимити во собата.,
Check Supplier Invoice Number Uniqueness,Проверете Добавувачот број на фактурата Единственост,
Make Payment via Journal Entry,Се направи исплата преку весник Влегување,
Unlink Payment on Cancellation of Invoice,Прекин на врска плаќање за поништување на Фактура,
-Unlink Advance Payment on Cancelation of Order,Одврзете авансно плаќање за откажување на нарачката,
Book Asset Depreciation Entry Automatically,Книга Асет Амортизација Влегување Автоматски,
Automatically Add Taxes and Charges from Item Tax Template,Автоматски додавајте даноци и такси од образецот за данок на артикали,
Automatically Fetch Payment Terms,Автоматски дополнете услови за плаќање,
-Show Inclusive Tax In Print,Прикажи инклузивен данок во печатење,
Show Payment Schedule in Print,Прикажи го распоредот за исплата во печатење,
Currency Exchange Settings,Подесувања за размена на валута,
Allow Stale Exchange Rates,Дозволи замени стапки на размена,
Stale Days,Стари денови,
Report Settings,Поставувања за извештај,
Use Custom Cash Flow Format,Користете формат за прилагодени парични текови,
-Only select if you have setup Cash Flow Mapper documents,Изберете само ако имате инсталирано документи за прилив на готовински тек,
Allowed To Transact With,Дозволено да се справи со,
SWIFT number,SWIFT број,
Branch Code,Огранок законик,
@@ -4940,7 +4912,6 @@
POS Customer Group,POS клиентите група,
POS Field,Пос поле,
POS Item Group,ПОС Точка група,
-[Select],[Избери],
Company Address,адреса на компанијата,
Update Stock,Ажурирање берза,
Ignore Pricing Rule,Игнорирај Цените Правило,
@@ -5495,8 +5466,6 @@
Supplier Naming By,Добавувачот грабеж на име со,
Default Supplier Group,Стандардна добавувачка група,
Default Buying Price List,Стандардно Купување Ценовник,
-Maintain same rate throughout purchase cycle,Одржување на иста стапка во текот на купувањето циклус,
-Allow Item to be added multiple times in a transaction,Овозможува ставките да се додадат повеќе пати во една трансакција,
Backflush Raw Materials of Subcontract Based On,Backflush суровини на Субконтракт Врз основа,
Material Transferred for Subcontract,Пренесен материјал за поддоговор,
Over Transfer Allowance (%),Премногу надомест за трансфер (%),
@@ -5540,7 +5509,6 @@
Current Stock,Тековни берза,
PUR-RFQ-.YYYY.-,PUR-RFQ-.YYYY.-,
For individual supplier,За индивидуални снабдувач,
-Supplier Detail,добавувачот детали,
Link to Material Requests,Врска до барања за материјали,
Message for Supplier,Порака за Добавувачот,
Request for Quotation Item,Барање за прибирање понуди Точка,
@@ -6481,7 +6449,6 @@
Appraisal Template,Процена Шаблон,
For Employee Name,За име на вработениот,
Goals,Цели,
-Calculate Total Score,Пресметај Вкупен резултат,
Total Score (Out of 5),Вкупен Резултат (Од 5),
"Any other remarks, noteworthy effort that should go in the records.","Било други забелешки, да се спомене напори кои треба да одат во евиденцијата.",
Appraisal Goal,Процена Цел,
@@ -6599,11 +6566,6 @@
Reason for Leaving,Причина за напуштање,
Leave Encashed?,Остави Encashed?,
Encashment Date,Датум на инкасо,
-Exit Interview Details,Излез Интервју Детали за,
-Held On,Одржана на,
-Reason for Resignation,Причина за оставка,
-Better Prospects,Подобри можности,
-Health Concerns,Здравствени проблеми,
New Workplace,Нов работен простор,
HR-EAD-.YYYY.-,HR-EAD-.YYYY.-,
Returned Amount,Врати износ,
@@ -6740,10 +6702,7 @@
Employee Settings,Подесувања на вработените,
Retirement Age,Возраста за пензионирање,
Enter retirement age in years,Внесете пензионирање возраст во години,
-Employee Records to be created by,Вработен евиденција да бидат создадени од страна,
-Employee record is created using selected field. ,Рекорд вработен е креирана преку избрани поле.,
Stop Birthday Reminders,Стоп роденден потсетници,
-Don't send Employee Birthday Reminders,Не праќај вработените роденден потсетници,
Expense Approver Mandatory In Expense Claim,Трошок за одобрување задолжителен во трошок,
Payroll Settings,Settings Даноци,
Leave,Остави,
@@ -6765,7 +6724,6 @@
Leave Approver Mandatory In Leave Application,Оставете одобрение задолжително во апликацијата за напуштање,
Show Leaves Of All Department Members In Calendar,Прикажи листови на сите членови на одделот во календарот,
Auto Leave Encashment,Автоматско напуштање,
-Restrict Backdated Leave Application,Ограничете ја апликацијата за заостаната за заминување,
Hiring Settings,Поставки за вработување,
Check Vacancies On Job Offer Creation,Проверете ги работните места за создавање понуда за работа,
Identification Document Type,Тип на документ за идентификација,
@@ -7299,28 +7257,21 @@
Manufacturing Settings,"Подесување ""Производство""",
Raw Materials Consumption,Потрошувачка на суровини,
Allow Multiple Material Consumption,Дозволи повеќе потрошувачка на материјал,
-Allow multiple Material Consumption against a Work Order,Дозволи повеќе потрошувачка на материјал против работниот налог,
Backflush Raw Materials Based On,Backflush Суровини врз основа на,
Material Transferred for Manufacture,Материјал префрлени за Производство,
Capacity Planning,Планирање на капацитетот,
Disable Capacity Planning,Оневозможи планирање на капацитетот,
Allow Overtime,Дозволете Прекувремена работа,
-Plan time logs outside Workstation Working Hours.,План Време на дневници надвор Workstation работно време.,
Allow Production on Holidays,Овозможете производството за празниците,
Capacity Planning For (Days),Планирање на капацитет за (во денови),
-Try planning operations for X days in advance.,Обидете се планира операции за X дена однапред.,
-Time Between Operations (in mins),Време помеѓу операции (во минути),
-Default 10 mins,Стандардно 10 минути,
Default Warehouses for Production,Стандардни складишта за производство,
Default Work In Progress Warehouse,Стандардно работа во магацин за напредокот,
Default Finished Goods Warehouse,Стандардно готови стоки Магацински,
Default Scrap Warehouse,Стандардна складиште за отпад,
-Over Production for Sales and Work Order,Преку производство за продажба и нарачка за работа,
Overproduction Percentage For Sales Order,Процент на прекумерно производство за редослед на продажба,
Overproduction Percentage For Work Order,Процент на препроизводство за работна нарачка,
Other Settings,други поставувања,
Update BOM Cost Automatically,Ажурирајте го BOM трошокот автоматски,
-"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.","Ажурирајте го БОМ трошокот автоматски преку Распоредувачот, врз основа на најновата проценка за стапката / ценовниот лист / последната стапка на набавка на суровини.",
Material Request Plan Item,Мапа на Барање за материјали,
Material Request Type,Материјал Тип на Барањето,
Material Issue,Материјал Број,
@@ -7603,10 +7554,6 @@
Quality Goal,Цел на квалитетот,
Monitoring Frequency,Фреквенција на набудување,
Weekday,Неделен ден,
-January-April-July-October,Јануари-април-јули-октомври,
-Revision and Revised On,Ревизија и ревидирање на,
-Revision,Ревизија,
-Revised On,Ревидирано на,
Objectives,Цели,
Quality Goal Objective,Цел на квалитетот на целта,
Objective,Цел,
@@ -7619,7 +7566,6 @@
Processes,Процеси,
Quality Procedure Process,Процес на постапка за квалитет,
Process Description,Опис на процесот,
-Child Procedure,Постапка за деца,
Link existing Quality Procedure.,Поврзете ја постојната процедура за квалитет.,
Additional Information,дополнителни информации,
Quality Review Objective,Цел на преглед на квалитетот,
@@ -7787,15 +7733,9 @@
Default Customer Group,Стандардната група на потрошувачи,
Default Territory,Стандардно Територија,
Close Opportunity After Days,Затвори можност по денови,
-Auto close Opportunity after 15 days,Авто блиску можност по 15 дена,
Default Quotation Validity Days,Стандардни дена за валидност на понудата,
Sales Update Frequency,Фреквенција за ажурирање на продажбите,
-How often should project and company be updated based on Sales Transactions.,Колку често треба да се ажурираат проектите и компанијата врз основа на продажните трансакции.,
Each Transaction,Секоја трансакција,
-Allow user to edit Price List Rate in transactions,Им овозможи на корисникот да ги уредувате Ценовник стапка во трансакции,
-Allow multiple Sales Orders against a Customer's Purchase Order,Им овозможи на повеќе Продај Нарачка против нарачка на купувачи,
-Validate Selling Price for Item against Purchase Rate or Valuation Rate,Провери продажна цена за точка против Набавка стапка или вреднување курс,
-Hide Customer's Tax Id from Sales Transactions,Скриј даночен број купувачи од продажбата на трансакции,
SMS Center,SMS центарот,
Send To,Испрати до,
All Contact,Сите Контакт,
@@ -8239,9 +8179,6 @@
Manufacturers used in Items,Производителите користат во Предмети,
Limited to 12 characters,Ограничен на 12 карактери,
MAT-MR-.YYYY.-,MAT-MR-.YYYY.-,
-Set Warehouse,Поставете складиште,
-Sets 'For Warehouse' in each row of the Items table.,Поставува „За магацин“ во секој ред од табелата со Артикли.,
-Requested For,Се бара за,
Partially Ordered,Делумно нарачано,
Transferred,пренесени,
% Ordered,Нареди%,
@@ -8407,24 +8344,14 @@
Default Stock UOM,Стандардно берза UOM,
Sample Retention Warehouse,Магацин за чување примероци,
Default Valuation Method,Метод за проценка стандардно,
-Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.,"Процент ви е дозволено да примате или да испорача повеќе во однос на количината нареди. На пример: Ако го наредил 100 единици. и вашиот додаток е 10%, тогаш ви е дозволено да се добијат 110 единици.",
-Action if Quality inspection is not submitted,Акција ако не е доставена инспекција за квалитет,
Show Barcode Field,Прикажи Баркод поле,
Convert Item Description to Clean HTML,Конвертирај ставка за да го исчистите HTML,
-Auto insert Price List rate if missing,Авто вметнете Ценовник стапка ако недостасува,
Allow Negative Stock,Дозволете негативна состојба,
Automatically Set Serial Nos based on FIFO,Автоматски го менува Сериски броеви врз основа на правилото FIFO,
-Set Qty in Transactions based on Serial No Input,Поставете Кол во трансакции врз основа на сериски број за внесување,
Auto Material Request,Авто материјал Барање,
-Raise Material Request when stock reaches re-order level,Подигне материјал Барање кога акциите достигне нивото повторно цел,
-Notify by Email on creation of automatic Material Request,Да го извести преку е-пошта на создавање на автоматски материјал Барање,
Inter Warehouse Transfer Settings,Поставки за трансфер на складишта Интер,
-Allow Material Transfer From Delivery Note and Sales Invoice,Дозволете трансфер на материјал од испратница и фактура за продажба,
-Allow Material Transfer From Purchase Receipt and Purchase Invoice,Дозволете трансфер на материјал од фактура за прием и набавка,
Freeze Stock Entries,Замрзнување берза записи,
Stock Frozen Upto,Акции Замрзнати до,
-Freeze Stocks Older Than [Days],Замрзнување резерви постари од [Денови],
-Role Allowed to edit frozen stock,Улогата дозволено да ја менувате замрзнати акции,
Batch Identification,Идентификација на серијата,
Use Naming Series,Користете имиња на серии,
Naming Series Prefix,Префикс на именување на серии,
@@ -8621,7 +8548,6 @@
Purchase Receipt Trends,Купување Потврда трендови,
Purchase Register,Купување Регистрирај се,
Quotation Trends,Трендови на Понуди,
-Quoted Item Comparison,Цитирано Точка споредба,
Received Items To Be Billed,Примените предмети да бидат фактурирани,
Qty to Order,Количина да нарачате,
Requested Items To Be Transferred,Бара предмети да бидат префрлени,
@@ -8690,8 +8616,6 @@
Select warehouse for material requests,Изберете магацин за материјални барања,
Transfer Materials For Warehouse {0},Трансфер материјали за магацин {0},
Production Plan Material Request Warehouse,План за производство Магацин за барање материјали,
-Set From Warehouse,Поставен од магацин,
-Source Warehouse (Material Transfer),Извор магацин (трансфер на материјал),
Sets 'Source Warehouse' in each row of the items table.,Поставува „Магацински извор“ во секој ред од табелата со ставки.,
Sets 'Target Warehouse' in each row of the items table.,Поставува „Целен склад“ во секој ред од табелата со ставки.,
Show Cancelled Entries,Покажете откажани записи,
@@ -8752,11 +8676,9 @@
Service Received But Not Billed,"Добиена услуга, но не и наплатена",
Deferred Accounting Settings,Одложени поставки за сметководство,
Book Deferred Entries Based On,Одложени записи за книги засновани на,
-"If ""Months"" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.","Ако е избрано „Месеци“, тогаш фиксниот износ ќе се резервира како одложен приход или трошок за секој месец, без оглед на бројот на денови во еден месец. Beе се проценува ако одложените приходи или расходи не се резервираат цел месец.",
Days,Денови,
Months,Месеци,
Book Deferred Entries Via Journal Entry,Резервирајте ги одложените записи преку списанието,
-If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense,"Доколку ова не е означено, ќе се создадат директни записи за GL да се резервираат одложени приходи / трошоци",
Submit Journal Entries,Поднесете записи во весник,
If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually,"Ако ова не е означено, Записите во весникот ќе бидат зачувани во нацрт-состојба и ќе треба да се достават рачно",
Enable Distributed Cost Center,Овозможете Центар за дистрибуирани трошоци,
@@ -8901,8 +8823,6 @@
Is Inter State,Дали е Интер-држава,
Purchase Details,Детали за набавката,
Depreciation Posting Date,Датум на објавување на амортизација,
-Purchase Order Required for Purchase Invoice & Receipt Creation,Потребна е нарачка за нарачка за фактура за купување и создавање на потврда,
-Purchase Receipt Required for Purchase Invoice Creation,Потребна е потврда за набавка за создавање фактура за набавка,
"By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ","Стандардно, името на добавувачот е поставено според внесеното име на добавувачот. Ако сакате добавувачите да бидат именувани од А.",
choose the 'Naming Series' option.,изберете ја опцијата „Серија за именување“.,
Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.,Конфигурирајте го стандардниот Ценовник при креирање нова трансакција за набавки. Цените на артиклите ќе бидат земени од овој Ценовник.,
@@ -9157,15 +9077,11 @@
Is Income Tax Component,Дали е компонента за данок на доход,
Component properties and references ,Својства на компонентите и препораки,
Additional Salary ,Дополнителна плата,
-Condtion and formula,Состојба и формула,
Unmarked days,Необележани денови,
Absent Days,Отсутни денови,
Conditions and Formula variable and example,Услови и формула променлива и пример,
Feedback By,Повратни информации од,
-MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYYY .-. ММ .-. Д.Д.-,
Manufacturing Section,Секција за производство,
-Sales Order Required for Sales Invoice & Delivery Note Creation,Потребна е нарачка за продажба за фактура за продажба и создавање белешка за достава,
-Delivery Note Required for Sales Invoice Creation,Потребна е белешка за испорака за создавање фактура за продажба,
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ","Стандардно, името на клиентот е поставено според внесеното полно име. Ако сакате клиентите да бидат именувани од а",
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Конфигурирајте го стандардниот ценовник кога креирате нова продажна трансакција. Цените на артиклите ќе бидат земени од овој Ценовник.,
"If this option is configured 'Yes', ERPNext will prevent you from creating a Sales Invoice or Delivery Note without creating a Sales Order first. This configuration can be overridden for a particular Customer by enabling the 'Allow Sales Invoice Creation Without Sales Order' checkbox in the Customer master.","Ако оваа опција е конфигурирана „Да“, ERPNext ќе ве спречи да креирате Фактура за продажба или Белешка за испорака без претходно да креирате Нарачка за продажба. Оваа конфигурација може да се замени за одреден Клиент со овозможување на полето за избор „Дозволи создавање фактура за продажба без нарачка за продажба“ во господарот на потрошувачот.",
@@ -9389,8 +9305,6 @@
{0} {1} has been added to all the selected topics successfully.,{0} {1} е успешно додадена на сите избрани теми.,
Topics updated,Темите се ажурирани,
Academic Term and Program,Академски мандат и програма,
-Last Stock Transaction for item {0} was on {1}.,Последната трансакција со акции за артиклот {0} беше на {1}.,
-Stock Transactions for Item {0} cannot be posted before this time.,Трансакциите со акции за ставката {0} не можат да бидат објавени пред овој пат.,
Please remove this item and try to submit again or update the posting time.,Отстранете ја оваа ставка и обидете се да ја доставите повторно или да го ажурирате времето за објавување.,
Failed to Authenticate the API key.,Не успеа да се провери клучот за API.,
Invalid Credentials,Неважечки акредитиви,
@@ -9444,7 +9358,6 @@
Please check your Plaid client ID and secret values,"Ве молиме, проверете ги ID на клиентот на Plaid и тајните вредности",
Bank transaction creation error,Грешка при создавање банкарска трансакција,
Unit of Measurement,Единица за мерење,
-Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {},Ред # {}: Стапката на продажба за ставка {} е пониска од нејзината {}. Стапката на продажба треба да биде најмала {},
Fiscal Year {0} Does Not Exist,Фискална година {0} Не постои,
Row # {0}: Returned Item {1} does not exist in {2} {3},Ред # {0}: Вратената ставка {1} не постои во {2} {3},
Valuation type charges can not be marked as Inclusive,Наплатата од типот на проценка не може да се означи како инклузивна,
@@ -9598,8 +9511,330 @@
Response Time for {0} priority in row {1} can't be greater than Resolution Time.,Времето на одговор за {0} приоритет во редот {1} не може да биде поголемо од времето за резолуција.,
{0} is not enabled in {1},{0} не е овозможено во {1},
Group by Material Request,Групирај по материјално барање,
-"Row {0}: For Supplier {0}, Email Address is Required to Send Email","Ред {0}: За добавувачот {0}, потребна е адреса за е-пошта за испраќање е-пошта",
Email Sent to Supplier {0},Е-пошта е испратена до добавувачот {0},
"The Access to Request for Quotation From Portal is Disabled. To Allow Access, Enable it in Portal Settings.","Пристапот до барање за понуда од порталот е оневозможен. За да дозволите пристап, овозможете го во Поставките за порталот.",
Supplier Quotation {0} Created,Цитат на добавувач {0} Создаден,
Valid till Date cannot be before Transaction Date,Валидно до датумот не може да биде пред датумот на трансакција,
+Unlink Advance Payment on Cancellation of Order,Одврзете авансно плаќање при откажување на нарачката,
+"Simple Python Expression, Example: territory != 'All Territories'","Едноставно изразување на Пајтон, Пример: територија! = 'Сите територии'",
+Sales Contributions and Incentives,Придонеси и стимулации за продажба,
+Sourced by Supplier,Извори од добавувач,
+Total weightage assigned should be 100%.<br>It is {0},Вкупната тежина назначена треба да биде 100%.<br> Тоа е {0},
+Account {0} exists in parent company {1}.,Сметката {0} постои во матичната компанија {1}.,
+"To overrule this, enable '{0}' in company {1}","За да го надминете ова, овозможете „{0}“ во компанијата {1}",
+Invalid condition expression,Неважечки израз на состојба,
+Please Select a Company First,Прво изберете компанија,
+Please Select Both Company and Party Type First,Прво изберете ги и типот на компанијата и партијата,
+Provide the invoice portion in percent,Обезбедете дел од фактурата во проценти,
+Give number of days according to prior selection,Дајте број на денови според претходниот избор,
+Email Details,Детали за е-пошта,
+"Select a greeting for the receiver. E.g. Mr., Ms., etc.","Изберете честитка за приемникот. На пр. Г-ѓа, г-ѓа, итн.",
+Preview Email,Преглед на е-пошта,
+Please select a Supplier,Ве молиме изберете снабдувач,
+Supplier Lead Time (days),Време на доставување добавувач (денови),
+"Home, Work, etc.","Дом, работа и сл.",
+Exit Interview Held On,Излез за интервју одржано,
+Condition and formula,Состојба и формула,
+Sets 'Target Warehouse' in each row of the Items table.,Поставува „Целен склад“ во секој ред од табелата со Артикли.,
+Sets 'Source Warehouse' in each row of the Items table.,Поставува „Магацински извор“ во секој ред од табелата со Артикли.,
+POS Register,ПОС регистар,
+"Can not filter based on POS Profile, if grouped by POS Profile","Не може да се филтрира врз основа на ПОС-профилот, ако е групирано според ПОС-профилот",
+"Can not filter based on Customer, if grouped by Customer","Не може да се филтрира врз основа на клиент, ако е групирано од клиент",
+"Can not filter based on Cashier, if grouped by Cashier","Не може да се филтрира врз основа на благајник, ако е групирано по благајник",
+Payment Method,Метод за плаќање,
+"Can not filter based on Payment Method, if grouped by Payment Method","Не може да се филтрира врз основа на Начинот на плаќање, ако е групирано според Начинот на плаќање",
+Supplier Quotation Comparison,Споредба на понуди за добавувачи,
+Price per Unit (Stock UOM),Цена по единица (берза УОМ),
+Group by Supplier,Групација по снабдувач,
+Group by Item,Група по точка,
+Remember to set {field_label}. It is required by {regulation}.,Запомнете да ја поставите {field_label}. Тоа го бара {регулативата}.,
+Enrollment Date cannot be before the Start Date of the Academic Year {0},Датумот на запишување не може да биде пред датумот на почеток на академската година {0},
+Enrollment Date cannot be after the End Date of the Academic Term {0},Датумот на запишување не може да биде по датумот на завршување на академскиот термин {0},
+Enrollment Date cannot be before the Start Date of the Academic Term {0},Датумот на запишување не може да биде пред Датумот на започнување на академскиот термин {0},
+Future Posting Not Allowed,Идниното објавување не е дозволено,
+"To enable Capital Work in Progress Accounting, ","За да овозможите капитално работење во тек сметководство,",
+you must select Capital Work in Progress Account in accounts table,мора да изберете сметка за капитална работа во тек во табелата за сметки,
+You can also set default CWIP account in Company {},Може да поставите и стандардна сметка за CWIP во компанијата {},
+The Request for Quotation can be accessed by clicking on the following button,До Барањето за понуда може да се пристапи со кликнување на следното копче,
+Regards,Со почит,
+Please click on the following button to set your new password,Кликнете на следното копче за да ја поставите вашата нова лозинка,
+Update Password,Ажурирајте ја лозинката,
+Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Ред # {}: Стапката на продажба за ставка {} е пониска од нејзината {}. Продажбата {} треба да биде најмалку {},
+You can alternatively disable selling price validation in {} to bypass this validation.,Можете алтернативно да ја оневозможите потврдата на продажната цена во {} за да ја заобиколите оваа валидација.,
+Invalid Selling Price,Невалидна цена за продажба,
+Address needs to be linked to a Company. Please add a row for Company in the Links table.,"Адресата треба да биде поврзана со компанија. Ве молиме, додадете табела за компанијата во табелата Линкови.",
+Company Not Linked,Компанијата не е поврзана,
+Import Chart of Accounts from CSV / Excel files,Увоз на табела на сметки од датотеки CSV / Excel,
+Completed Qty cannot be greater than 'Qty to Manufacture',Комплетираниот количина не може да биде поголем од „Количина за производство“,
+"Row {0}: For Supplier {1}, Email Address is Required to send an email","Ред {0}: За добавувачот {1}, Потребна е адреса за е-пошта за испраќање е-пошта",
+"If enabled, the system will post accounting entries for inventory automatically","Доколку е овозможено, системот автоматски ќе објавува сметководствени записи за залихи",
+Accounts Frozen Till Date,Сметките замрзнати до датумот,
+Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below,"Сметководствените записи се замрзнати до овој датум. Никој не може да креира или менува записи, освен корисниците со улогата наведена подолу",
+Role Allowed to Set Frozen Accounts and Edit Frozen Entries,Дозволена е улога за поставување замрзнати сметки и уредување на замрзнати записи,
+Address used to determine Tax Category in transactions,Адреса што се користи за утврдување на категоријата данок во трансакциите,
+"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 ","Процентот што ви е дозволено да наплаќате повеќе наспроти нарачаната сума. На пример, ако вредноста на нарачката е 100 УСД за одредена ставка и толеранцијата е поставена на 10%, тогаш ви е дозволено да наплатате до 110 УСД",
+This role is allowed to submit transactions that exceed credit limits,Оваа улога е дозволено да поднесува трансакции што ги надминуваат кредитните лимити,
+"If ""Months"" is selected, a fixed amount will be booked as deferred revenue or expense for each month irrespective of the number of days in a month. It will be prorated if deferred revenue or expense is not booked for an entire month","Ако е избрана „Месеци“, фиксниот износ ќе се резервира како одложени приходи или трошоци за секој месец, без оглед на бројот на денови во еден месец. Beе се процени ако одложените приходи или расходи не се резервираат цел месец",
+"If this is unchecked, direct GL entries will be created to book deferred revenue or expense","Ако ова не е означено, ќе се креираат директни записи за GL за да се резервираат одложените приходи или трошоци",
+Show Inclusive Tax in Print,Прикажи вклучен данок во печатење,
+Only select this if you have set up the Cash Flow Mapper documents,Изберете го ова само ако сте ги поставиле документите за мерење на парични текови,
+Payment Channel,Канал за плаќање,
+Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Дали е потребна нарачка за нарачка за фактура за купување и создавање на потврда?,
+Is Purchase Receipt Required for Purchase Invoice Creation?,Дали е потребна потврда за набавка за создавање фактура за набавка?,
+Maintain Same Rate Throughout the Purchase Cycle,Одржувајте иста стапка во текот на целиот циклус на набавки,
+Allow Item To Be Added Multiple Times in a Transaction,Дозволете ставка да се додаде повеќе пати во трансакција,
+Suppliers,Добавувачи,
+Send Emails to Suppliers,Испратете е-пошта до добавувачите,
+Select a Supplier,Изберете снабдувач,
+Cannot mark attendance for future dates.,Не може да се одбележи присуството за идните датуми.,
+Do you want to update attendance? <br> Present: {0} <br> Absent: {1},Дали сакате да ја ажурирате посетеноста?<br> Сегашност: {0}<br> Отсутни: {1},
+Mpesa Settings,Поставки за Мпеса,
+Initiator Name,Име на иницијатор,
+Till Number,До број,
+Sandbox,Кутија со песок,
+ Online PassKey,Он PassKey,
+Security Credential,Уверение за безбедност,
+Get Account Balance,Добијте салдо на сметка,
+Please set the initiator name and the security credential,"Ве молиме, поставете го името на иницијаторот и безбедносните квалификации",
+Inpatient Medication Entry,Влез за стационарни лекови,
+HLC-IME-.YYYY.-,HLC-IME-.YYYY.-,
+Item Code (Drug),Код на артикл (дрога),
+Medication Orders,Нарачки за лекови,
+Get Pending Medication Orders,Добијте нарачки за чекање на лекови,
+Inpatient Medication Orders,Нарачки за стационарни лекови,
+Medication Warehouse,Складиште за лекови,
+Warehouse from where medication stock should be consumed,Складиште од каде треба да се консумира залиха на лекови,
+Fetching Pending Medication Orders,Преземање на нарачки за чекање на лекови,
+Inpatient Medication Entry Detail,Детал за влез во стационарните лекови,
+Medication Details,Детали за лекови,
+Drug Code,Код за лекови,
+Drug Name,Име на лекови,
+Against Inpatient Medication Order,Против наредба за стационарни лекови,
+Against Inpatient Medication Order Entry,Против внесување на нарачки за болнички лекови,
+Inpatient Medication Order,Ред за лекови за стационарни лекови,
+HLC-IMO-.YYYY.-,HLC-IMO-.YYYY.-,
+Total Orders,Вкупно нарачки,
+Completed Orders,Завршени нарачки,
+Add Medication Orders,Додадете наредби за лекови,
+Adding Order Entries,Додавање записи за нарачки,
+{0} medication orders completed,{0} нарачки за лекови се завршени,
+{0} medication order completed,{0} нарачката за лекови е завршена,
+Inpatient Medication Order Entry,Внесување на нарачки за болнички лекови,
+Is Order Completed,Дали нарачката е завршена,
+Employee Records to Be Created By,Записи за вработените што треба да ги креира,
+Employee records are created using the selected field,Евиденцијата на вработените се креира со користење на избраното поле,
+Don't send employee birthday reminders,Не испраќајте потсетници за роденден на вработените,
+Restrict Backdated Leave Applications,Ограничете ги апликациите за напуштени со датум,
+Sequence ID,ID на низата,
+Sequence Id,Ид на низа,
+Allow multiple material consumptions against a Work Order,Дозволете повеќекратни потрошувачки на материјали против налог за работа,
+Plan time logs outside Workstation working hours,Планирајте дневници за време надвор од работното време на работната станица,
+Plan operations X days in advance,Планирајте операции X дена однапред,
+Time Between Operations (Mins),Време помеѓу операциите (мин.),
+Default: 10 mins,Стандардно: 10 мин,
+Overproduction for Sales and Work Order,Хиперпродукција за продажба и нарачка за работа,
+"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Ажурирајте ги трошоците за БОМ автоматски преку распоредувачот, засновани се на последната стапка на проценка / ценовник / стапка на последната набавка на суровини",
+Purchase Order already created for all Sales Order items,Нарачката за набавка е веќе креирана за сите артикли за нарачката за продажба,
+Select Items,Изберете Предмети,
+Against Default Supplier,Против стандардниот снабдувач,
+Auto close Opportunity after the no. of days mentioned above,Автоматско затворање на Можност по бр. на денови споменати погоре,
+Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Дали е потребна нарачка за продажба за креирање на фактура за продажба и белешка за достава?,
+Is Delivery Note Required for Sales Invoice Creation?,Дали е потребна испратница за создавање фактури за продажба?,
+How often should Project and Company be updated based on Sales Transactions?,Колку често Проектот и компанијата треба да се ажурираат врз основа на продажни трансакции?,
+Allow User to Edit Price List Rate in Transactions,Дозволете му на корисникот да ја измени стапката на ценовникот во трансакциите,
+Allow Item to Be Added Multiple Times in a Transaction,Дозволете ставка да се додаде повеќе пати во трансакција,
+Allow Multiple Sales Orders Against a Customer's Purchase Order,Дозволете повеќе налози за продажба против налогот за купување на клиентот,
+Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Потврдете ја цената на продажбата на артиклот наспроти стапката на набавка или стапката на проценка,
+Hide Customer's Tax ID from Sales Transactions,Сокријте го даночниот ID на клиентот од трансакциите во продажба,
+"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Процентот што ви е дозволено да примате или испорачувате повеќе наспроти нарачаната количина. На пример, ако нарачавте 100 единици, а вашиот додаток е 10%, тогаш ви е дозволено да примате 110 единици.",
+Action If Quality Inspection Is Not Submitted,Дејство ако не е доставена проверка на квалитетот,
+Auto Insert Price List Rate If Missing,Автоматско вметнување на ценовник Цена доколку недостасува,
+Automatically Set Serial Nos Based on FIFO,Автоматски поставете сериски броеви засновани на FIFO,
+Set Qty in Transactions Based on Serial No Input,Поставете Количина во трансакции засновани на сериски бр,
+Raise Material Request When Stock Reaches Re-order Level,Подигнете го барањето за материјали кога акциите достигнуваат на ниво на нарачка,
+Notify by Email on Creation of Automatic Material Request,Известете по е-пошта за создавање на барање за автоматско материјали,
+Allow Material Transfer from Delivery Note to Sales Invoice,Дозволете трансфер на материјал од испратница до фактура за продажба,
+Allow Material Transfer from Purchase Receipt to Purchase Invoice,Дозволете трансфер на материјал од потврда за набавка до фактура за набавка,
+Freeze Stocks Older Than (Days),Замрзнете ги акциите постари од (денови),
+Role Allowed to Edit Frozen Stock,Улогата е дозволена за уредување на замрзнатиот фонд,
+The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount,Нераспределениот износ на Уплатата за влез {0} е поголем од нераспределениот износ на банкарската трансакција,
+Payment Received,Уплатата примена,
+Attendance cannot be marked outside of Academic Year {0},Присуството не може да се обележи надвор од Академската година {0},
+Student is already enrolled via Course Enrollment {0},Студентот е веќе запишан преку запишување на курс {0},
+Attendance cannot be marked for future dates.,Присуството не може да се обележи за идните датуми.,
+Please add programs to enable admission application.,"Ве молиме, додадете програми за да овозможите апликација за прием.",
+The following employees are currently still reporting to {0}:,Следните вработени во моментов сè уште пријавуваат на {0}:,
+Please make sure the employees above report to another Active employee.,"Ве молиме, проверете дали вработените погоре се пријавуваат на друг активен вработен.",
+Cannot Relieve Employee,Не може да му олесни на вработениот,
+Please enter {0},Внесете {0},
+Please select another payment method. Mpesa does not support transactions in currency '{0}',Изберете друг начин на плаќање. Мпеса не поддржува трансакции во валута „{0}“,
+Transaction Error,Грешка во трансакцијата,
+Mpesa Express Transaction Error,Грешка во експресната трансакција на Мпеса,
+"Issue detected with Mpesa configuration, check the error logs for more details","Откриено е прашање со конфигурацијата на Мпеса, проверете ги евиденциите за грешки за повеќе детали",
+Mpesa Express Error,Експресна грешка во Мпеса,
+Account Balance Processing Error,Грешка во обработката на билансот на сметка,
+Please check your configuration and try again,Проверете ја вашата конфигурација и обидете се повторно,
+Mpesa Account Balance Processing Error,Грешка во обработката на билансот на сметката Mpesa,
+Balance Details,Детали за билансот,
+Current Balance,Сегашна состојба,
+Available Balance,Расположливо салдо,
+Reserved Balance,Резервиран биланс,
+Uncleared Balance,Нејасен биланс,
+Payment related to {0} is not completed,Плаќањето поврзано со {0} не е завршено,
+Row #{}: Item Code: {} is not available under warehouse {}.,Ред # {}: Шифра на ставка: {} не е достапна под магацин {}.,
+Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Ред # {}: Количината на залиха не е доволна за Кодот на артиклот: {} под магацин {}. Достапна количина {}.,
+Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,"Ред # {}: Ве молиме, изберете сериски број и група против ставка: {} или отстранете ја за да ја завршите трансакцијата.",
+Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.,Ред # {}: Нема избран сериски број наспроти ставката: {}. Изберете една или отстранете ја за да ја завршите трансакцијата.,
+Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.,Ред # {}: Не е избрана серија против ставка: {}. Изберете група или отстранете ја за да ја завршите трансакцијата.,
+Payment amount cannot be less than or equal to 0,Износот на плаќањето не може да биде помал или еднаков на 0,
+Please enter the phone number first,Прво внесете го телефонскиот број,
+Row #{}: {} {} does not exist.,Ред # {}: {} {} не постои.,
+Row #{0}: {1} is required to create the Opening {2} Invoices,Ред # {0}: Потребен е {1} за создавање на {2} Фактури за отворање,
+You had {} errors while creating opening invoices. Check {} for more details,Имавте {} грешки при креирање на фактури за отворање. Проверете {} за повеќе детали,
+Error Occured,Настана грешка,
+Opening Invoice Creation In Progress,Во тек е создавање на креирање на фактури,
+Creating {} out of {} {},Создавање {} од {} {},
+(Serial No: {0}) cannot be consumed as it's reserverd to fullfill Sales Order {1}.,(Сериски број: {0}) не може да се потроши бидејќи е резервен за да се изврши пополнување на налогот за продажба {1}.,
+Item {0} {1},Предмет {0} {1},
+Last Stock Transaction for item {0} under warehouse {1} was on {2}.,Последната трансакција на акции за ставка {0} под магацин {1} беше на {2}.,
+Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.,Трансакциите со акции за ставката {0} под магацин {1} не можат да бидат објавени пред овој пат.,
+Posting future stock transactions are not allowed due to Immutable Ledger,Објавувањето на идните трансакции со акции не е дозволено поради непроменливиот Леџер,
+A BOM with name {0} already exists for item {1}.,БОМ со име {0} веќе постои за ставката {1}.,
+{0}{1} Did you rename the item? Please contact Administrator / Tech support,{0} {1} Дали ја преименувавте ставката? Ве молиме контактирајте ја администраторот / техничката поддршка,
+At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2},На редот број {0}: ID-то на низата {1} не може да биде помало од претходниот ID на низата на претходниот ред {2},
+The {0} ({1}) must be equal to {2} ({3}),{0} ({1}) мора да биде еднакво на {2} ({3}),
+"{0}, complete the operation {1} before the operation {2}.","{0}, завршете ја операцијата {1} пред операцијата {2}.",
+Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No.,"Не може да се обезбеди испорака до сериски број, бидејќи ставката {0} е додадена со и без Обезбедете испорака од серискиот број.",
+Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No,Предметот {0} нема сериски број. Само сериски направените производи можат да имаат испорака врз основа на серискиот број,
+No active BOM found for item {0}. Delivery by Serial No cannot be ensured,Не е пронајден активен БОМ за ставката {0}. Испораката со сериски бр не може да се обезбеди,
+No pending medication orders found for selected criteria,Не се пронајдени наредби за чекање на лекови за избрани критериуми,
+From Date cannot be after the current date.,Од Датум не може да биде после тековниот датум.,
+To Date cannot be after the current date.,Датумот не може да биде после тековниот датум.,
+From Time cannot be after the current time.,Од Време не може да биде по тековното време.,
+To Time cannot be after the current time.,To Time не може да биде по тековното време.,
+Stock Entry {0} created and ,Внесувањето на акциите {0} е создадено и,
+Inpatient Medication Orders updated successfully,Нарачките за лекови во стационарните успешно се ажурираат,
+Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1},Ред {0}: Не можам да создадам упис за стационарни лекови против откажана наредба за лекови за стационарни пациенти {1},
+Row {0}: This Medication Order is already marked as completed,Ред {0}: Оваа наредба за лекови е веќе означена како завршена,
+Quantity not available for {0} in warehouse {1},Количината не е достапна за {0} во магацин {1},
+Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Овозможете Дозволете негативна залиха во поставките на акциите или создадете упис на акции за да продолжите.,
+No Inpatient Record found against patient {0},Не е пронајден запис за пациенти против пациент {0},
+An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Наредба за стационарни лекови {0} против средба со пациенти {1} веќе постои.,
+Allow In Returns,Дозволи за возврат,
+Hide Unavailable Items,Сокриј ги недостапните ставки,
+Apply Discount on Discounted Rate,Примени попуст на попуст,
+Therapy Plan Template,Шаблон на план за терапија,
+Fetching Template Details,Преземање на детали за образецот,
+Linked Item Details,Детали за поврзаната ставка,
+Therapy Types,Видови на терапија,
+Therapy Plan Template Detail,Детал за образецот на планот за терапија,
+Non Conformance,Не се усогласи,
+Process Owner,Сопственик на процес,
+Corrective Action,Поправна акција,
+Preventive Action,Превентивна акција,
+Problem,Проблем,
+Responsible,Одговорен,
+Completion By,Завршување од,
+Process Owner Full Name,Целосно име на сопственикот на процесот,
+Right Index,Десен индекс,
+Left Index,Лев индекс,
+Sub Procedure,Подпроцедура,
+Passed,Помина,
+Print Receipt,Потврда за печатење,
+Edit Receipt,Уредете ја потврдата,
+Focus on search input,Фокусирајте се на влезот за пребарување,
+Focus on Item Group filter,Фокусирајте се на филтерот за група ставки,
+Checkout Order / Submit Order / New Order,Нарачка за исплата / Доставете порачка / Нова нарачка,
+Add Order Discount,Додадете попуст на нарачката,
+Item Code: {0} is not available under warehouse {1}.,Код на ставка: {0} не е достапен под складиштето {1}.,
+Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,"Сериските броеви се недостапни за Точката {0} под магацин {1}. Ве молиме, обидете се да го смените складиштето.",
+Fetched only {0} available serial numbers.,Набавени се само {0} достапни сериски броеви.,
+Switch Between Payment Modes,Префрлување помеѓу режимите на плаќање,
+Enter {0} amount.,Внесете {0} износ.,
+You don't have enough points to redeem.,Немате доволно поени за откуп.,
+You can redeem upto {0}.,Може да активирате до {0}.,
+Enter amount to be redeemed.,Внесете износ што треба да се откупи.,
+You cannot redeem more than {0}.,Не можете да откупите повеќе од {0}.,
+Open Form View,Отворете го Погледот на формата,
+POS invoice {0} created succesfully,ПОС-фактурата {0} е создадена успешно,
+Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Количината на залиха не е доволна за кодот на артиклот: {0} под магацин {1}. Достапна количина {2}.,
+Serial No: {0} has already been transacted into another POS Invoice.,Сериски број: {0} веќе е пренесен во друга ПОС-фактура.,
+Balance Serial No,Биланс Сериски бр,
+Warehouse: {0} does not belong to {1},Складиште: {0} не припаѓа на {1},
+Please select batches for batched item {0},"Ве молиме, изберете серии за сериската ставка {0}",
+Please select quantity on row {0},Изберете ја количината на редот {0},
+Please enter serial numbers for serialized item {0},Внесете сериски броеви за сериската ставка {0},
+Batch {0} already selected.,Серијата {0} е веќе избрана.,
+Please select a warehouse to get available quantities,Ве молиме изберете магацин за да добиете достапни количини,
+"For transfer from source, selected quantity cannot be greater than available quantity","За пренос од извор, избраната количина не може да биде поголема од достапната количина",
+Cannot find Item with this Barcode,Не можам да ја пронајдам ставката со овој баркод,
+{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} е задолжително. Можеби записот за размена на валути не е создаден за {1} до {2},
+{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,{} достави средства поврзани со него. Треба да ги откажете средствата за да создадете поврат на набавката.,
+Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,Не може да се откаже овој документ бидејќи е поврзан со доставеното средство {0}. Откажете го за да продолжите.,
+Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ред # {}: Серискиот број {} веќе е пренесен во друга ПОС-фактура. Ве молиме изберете важечки сериски бр.,
+Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ред # {}: Бројот на сериите. {} Веќе е пренесен во друга ПОС-фактура. Ве молиме изберете важечки сериски бр.,
+Item Unavailable,Ставката е недостапна,
+Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},Ред # {}: Серискиот број {} не може да се врати бидејќи не е извршен во оригиналната фактура {},
+Please set default Cash or Bank account in Mode of Payment {},Поставете стандардна готовина или банкарска сметка во начинот на плаќање {},
+Please set default Cash or Bank account in Mode of Payments {},Поставете стандардна готовина или банкарска сметка во начинот на плаќање {},
+Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Уверете се дека сметката {} е сметка за Биланс на состојба. Може да ја смените матичната сметка во сметка на Биланс на состојба или да изберете друга сметка.,
+Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Уверете се дека сметката {} е сметка за плаќање. Променете го типот на сметката во Платено или изберете друга сметка.,
+Row {}: Expense Head changed to {} ,Ред {}: Главата на трошоците е сменета во {},
+because account {} is not linked to warehouse {} ,бидејќи сметката {} не е поврзана со магацин {},
+or it is not the default inventory account,или не е стандардна сметка за залихи,
+Expense Head Changed,Главата на трошоците е сменета,
+because expense is booked against this account in Purchase Receipt {},бидејќи трошокот е резервиран наспроти оваа сметка во Потврда за набавка {},
+as no Purchase Receipt is created against Item {}. ,бидејќи не е создадена потврда за набавка наспроти ставката {}.,
+This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Ова е направено за да се справи со сметководството за случаите кога Потврдата за набавка е креирана по Фактурата за набавка,
+Purchase Order Required for item {},Потребна е нарачка за набавка за ставка {},
+To submit the invoice without purchase order please set {} ,"За да ја доставите фактурата без нарачка, поставете {}",
+as {} in {},како во {},
+Mandatory Purchase Order,Задолжителен налог за набавка,
+Purchase Receipt Required for item {},Потребна е потврда за набавка за ставка {},
+To submit the invoice without purchase receipt please set {} ,"За да ја доставите фактурата без потврда за набавка, поставете {}",
+Mandatory Purchase Receipt,Потврда за задолжителна набавка,
+POS Profile {} does not belongs to company {},ПОС-профилот {} не припаѓа на компанијата {},
+User {} is disabled. Please select valid user/cashier,Корисникот {} е оневозможен. Ве молиме изберете валиден корисник / благајник,
+Row #{}: Original Invoice {} of return invoice {} is {}. ,Ред # {}: Оригиналната фактура {} на фактурата за поврат {} е {}.,
+Original invoice should be consolidated before or along with the return invoice.,Оригиналната фактура треба да се консолидира пред или заедно со повратната фактура.,
+You can add original invoice {} manually to proceed.,Можете да додадете оригинална фактура {} рачно за да продолжите.,
+Please ensure {} account is a Balance Sheet account. ,Уверете се дека сметката {} е сметка за Биланс на состојба.,
+You can change the parent account to a Balance Sheet account or select a different account.,Може да ја смените матичната сметка во сметка на Биланс на состојба или да изберете друга сметка.,
+Please ensure {} account is a Receivable account. ,Уверете се дека сметката {} е сметка за побарување.,
+Change the account type to Receivable or select a different account.,Променете го типот на сметка во Побарување или изберете друга сметка.,
+{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} не може да се откаже бидејќи се откупени заработените поени на лојалност. Прво откажете го {} Не {},
+already exists,веќе постои,
+POS Closing Entry {} against {} between selected period,Влез за затворање ПОС {} против {} помеѓу избраниот период,
+POS Invoice is {},ПОС-фактурата е {},
+POS Profile doesn't matches {},ПОС-профилот не се совпаѓа со {},
+POS Invoice is not {},ПОС-фактурата не е {},
+POS Invoice isn't created by user {},ПОС-фактурата не е креирана од корисникот {},
+Row #{}: {},Ред # {}: {},
+Invalid POS Invoices,Неважечки ПОС-фактури,
+Please add the account to root level Company - {},"Ве молиме, додајте ја сметката на ниво на корен - {}",
+"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Додека создавате сметка за Детска компанија {0}, родителската сметка {1} не е пронајдена. Ве молиме, креирајте ја матичната сметка во соодветната СОA",
+Account Not Found,Сметката не е пронајдена,
+"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Додека создавате сметка за Детска компанија {0}, родителската сметка {1} се најде како главна сметка.",
+Please convert the parent account in corresponding child company to a group account.,"Ве молиме, претворете ја матичната сметка во соодветната компанија за деца во групна сметка.",
+Invalid Parent Account,Невалидна родителска сметка,
+"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Преименувањето е дозволено само преку матичната компанија {0}, за да се избегне несовпаѓање.",
+"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","Ако {0} {1} количини на ставката {2} имате, шемата {3} ќе се примени на артиклот.",
+"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","Ако {0} {1} вреди ставка {2}, шемата {3} ќе се примени на ставката.",
+"As the field {0} is enabled, the field {1} is mandatory.","Бидејќи полето {0} е овозможено, полето {1} е задолжително.",
+"As the field {0} is enabled, the value of the field {1} should be more than 1.","Бидејќи полето {0} е овозможено, вредноста на полето {1} треба да биде повеќе од 1.",
+Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},Не може да се достави серискиот број {0} од ставката {1} бидејќи е резервиран за целосна пополнување на нарачката за продажба {2},
+"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.","Нарачката за продажба {0} има резервација за ставката {1}, може да доставите резервирани само {1} наспроти {0}.",
+{0} Serial No {1} cannot be delivered,{0} Серискиот број {1} не може да се испорача,
+Row {0}: Subcontracted Item is mandatory for the raw material {1},Ред {0}: Поткажаната ставка е задолжителна за суровината {1},
+"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Бидејќи има доволно суровини, материјалното барање не е потребно за складиштето {0}.",
+" If you still want to proceed, please enable {0}.","Ако сè уште сакате да продолжите, овозможете {0}.",
+The item referenced by {0} - {1} is already invoiced,Ставката на која се повикуваат {0} - {1} е веќе фактурирана,
+Therapy Session overlaps with {0},Сесијата за терапија се преклопува со {0},
+Therapy Sessions Overlapping,Сесии за терапија што се преклопуваат,
+Therapy Plans,Планови за терапија,
+"Item Code, warehouse, quantity are required on row {0}","Кодот на објектот, складиштето, количината се потребни на редот {0}",
+Get Items from Material Requests against this Supplier,Набавете предмети од материјални барања против овој добавувач,
+Enable European Access,Овозможете европски пристап,
+Creating Purchase Order ...,Создавање налог за набавка ...,
+"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Изберете снабдувач од Стандардните добавувачи на ставките подолу. При избор, ќе се изврши Нарачка за набавка само на предмети што припаѓаат на избраниот Добавувач.",
+Row #{}: You must select {} serial numbers for item {}.,Ред # {}: Мора да изберете {} сериски броеви за ставка {}.,