diff --git a/.github/helper/install.sh b/.github/helper/install.sh new file mode 100644 index 0000000000..253ad70198 --- /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}" --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 \ No newline at end of file diff --git a/.travis/site_config.json b/.github/helper/site_config.json similarity index 89% rename from .travis/site_config.json rename to .github/helper/site_config.json index 572bbd0853..60ef80cbad 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", diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml new file mode 100644 index 0000000000..2a1db14d95 --- /dev/null +++ b/.github/workflows/ci-tests.yml @@ -0,0 +1,96 @@ +name: CI + +on: + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + + 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/.travis.yml b/.travis.yml deleted file mode 100644 index 77d427e5a5..0000000000 --- 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/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index 297dd4333f..10f660a140 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -8,6 +8,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { return { filters: { company: ["in", frm.doc.company], + 'is_company_account': 1 }, }; }); 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 cb5b3a58fe..0023a84a46 100644 --- a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py +++ b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py @@ -20,15 +20,16 @@ class POSOpeningEntry(StatusUpdater): if not cint(frappe.db.get_value("User", self.user, "enabled")): 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: - invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment)) - + 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 {}") diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index d08a854142..33771645fe 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -357,7 +357,6 @@ "reqd": 1 }, { - "depends_on": "eval: doc.selling == 1", "fieldname": "margin", "fieldtype": "Section Break", "label": "Margin" @@ -565,7 +564,7 @@ "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2020-12-04 00:36:24.698219", + "modified": "2021-03-01 23:18:38.717613", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", 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 07e75acb41..96ad0fd785 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -28,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", @@ -789,6 +795,7 @@ "fieldname": "stock_uom_rate", "fieldtype": "Currency", "label": "Rate of Stock UOM", + "no_copy": 1, "options": "currency", "read_only": 1 }, @@ -799,12 +806,54 @@ "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, "links": [], - "modified": "2021-01-30 21:43:21.488258", + "modified": "2021-02-23 00:59:52.614805", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", 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 b403c7b237..8e6952a93c 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -818,6 +818,7 @@ "fieldname": "stock_uom_rate", "fieldtype": "Currency", "label": "Rate of Stock UOM", + "no_copy": 1, "options": "currency", "read_only": 1 } @@ -825,7 +826,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-01-30 21:42:37.796771", + "modified": "2021-02-23 01:05:22.123527", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", 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 75b2954ddd..5baf6939cd 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -27,11 +27,17 @@ "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", @@ -733,15 +739,59 @@ "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": "2021-01-30 21:44:41.816974", + "modified": "2021-02-23 01:00:27.132705", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 10271cbcc9..aab5770a94 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -109,7 +109,7 @@ class calculate_taxes_and_totals(object): 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', 'POS 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")) 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 30fa23cfb4..74ad456ea6 100644 --- a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py +++ b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py @@ -17,8 +17,7 @@ class ShopifySettings(unittest.TestCase): frappe.set_user("Administrator") # 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") diff --git a/erpnext/hooks.py b/erpnext/hooks.py index f87769c182..4b3597afd7 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -361,13 +361,13 @@ scheduler_events = { "erpnext.hr.utils.generate_leave_encashment", "erpnext.hr.utils.allocate_earned_leaves", "erpnext.hr.utils.grant_leaves_automatically", - "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.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.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" ] } diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 7289933d99..143a306eb3 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -246,7 +246,7 @@ class TestSalarySlip(unittest.TestCase): make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR', payroll_period=payroll_period) - frappe.db.sql("""delete from `tabLoan""") + 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() diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index c96386611b..67b12fbca4 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -141,29 +141,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ 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; diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 9351f6d206..1c0abdffcf 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -649,6 +649,40 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }, + 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 = { @@ -1030,7 +1064,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, 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") { @@ -1280,10 +1314,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ 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", "stock_uom_rate"], + 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"]) { @@ -1321,7 +1355,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ // 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); }); @@ -1468,7 +1502,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }); // 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; } diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index a6785f709a..8b53902d32 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -641,6 +641,7 @@ "fieldname": "stock_uom_rate", "fieldtype": "Currency", "label": "Rate of Stock UOM", + "no_copy": 1, "options": "currency", "read_only": 1 } @@ -648,7 +649,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-01-30 21:39:40.174551", + "modified": "2021-02-23 01:13:54.670763", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", 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 37e47a9d41..1e5590e748 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -786,6 +786,7 @@ "fieldname": "stock_uom_rate", "fieldtype": "Currency", "label": "Rate of Stock UOM", + "no_copy": 1, "options": "currency", "read_only": 1 } @@ -793,7 +794,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-01-30 21:35:07.617320", + "modified": "2021-02-23 01:15:05.803091", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 74b4bb085b..278821e392 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -93,6 +93,10 @@ erpnext.PointOfSale.Controller = class { }) return frappe.utils.play_sound("error"); } + + // 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); diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index ce084646e1..04285735ab 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -127,20 +127,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ 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; @@ -353,26 +339,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ 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) { 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 17996247c5..b05090a237 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -750,6 +750,7 @@ "fieldname": "stock_uom_rate", "fieldtype": "Currency", "label": "Rate of Stock UOM", + "no_copy": 1, "options": "currency", "read_only": 1 } @@ -758,7 +759,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-01-30 21:42:03.767968", + "modified": "2021-02-23 01:04:08.588104", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", 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 8974ad9318..efe3642d23 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -37,10 +37,16 @@ "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", @@ -880,6 +886,7 @@ "fieldname": "stock_uom_rate", "fieldtype": "Currency", "label": "Rate of Stock UOM", + "no_copy": 1, "options": "currency", "read_only": 1 }, @@ -890,12 +897,55 @@ "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": "2021-01-30 21:44:06.918515", + "modified": "2021-02-23 00:59:14.360847", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item",