mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-18 09:05:00 +00:00
Merge pull request #31524 from frappe/version-13-hotfix
chore: weekly version-13 release
This commit is contained in:
1
.github/helper/.flake8_strict
vendored
1
.github/helper/.flake8_strict
vendored
@@ -66,6 +66,7 @@ ignore =
|
||||
F841,
|
||||
E713,
|
||||
E712,
|
||||
B023
|
||||
|
||||
|
||||
max-line-length = 200
|
||||
|
||||
2
.github/workflows/server-tests.yml
vendored
2
.github/workflows/server-tests.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
container: [1, 2, 3]
|
||||
container: [1, 2]
|
||||
|
||||
name: Python Unit Tests
|
||||
|
||||
|
||||
117
.github/workflows/ui-tests.yml
vendored
117
.github/workflows/ui-tests.yml
vendored
@@ -1,117 +0,0 @@
|
||||
name: UI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ui-v13-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
name: UI Tests (Cypress)
|
||||
|
||||
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.7
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
check-latest: true
|
||||
|
||||
- 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: Cache cypress binary
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache
|
||||
key: ${{ runner.os }}-cypress-
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cypress-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Install
|
||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||
env:
|
||||
DB: mariadb
|
||||
TYPE: ui
|
||||
|
||||
- name: Site Setup
|
||||
run: cd ~/frappe-bench/ && bench --site test_site execute erpnext.setup.utils.before_tests
|
||||
|
||||
- name: cypress pre-requisites
|
||||
run: cd ~/frappe-bench/apps/frappe && yarn add cypress-file-upload@^5 @testing-library/cypress@^8 --no-lockfile
|
||||
|
||||
|
||||
- name: Build Assets
|
||||
run: cd ~/frappe-bench/ && bench build
|
||||
env:
|
||||
CI: Yes
|
||||
|
||||
- name: UI Tests
|
||||
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: 60a8e3bf-08f5-45b1-9269-2b207d7d30cd
|
||||
|
||||
- name: Show bench console if tests failed
|
||||
if: ${{ failure() }}
|
||||
run: cat ~/frappe-bench/bench_run_logs.txt
|
||||
36
CODEOWNERS
36
CODEOWNERS
@@ -3,33 +3,35 @@
|
||||
# These owners will be the default owners for everything in
|
||||
# the repo. Unless a later match takes precedence,
|
||||
|
||||
erpnext/accounts/ @nextchamp-saqib @deepeshgarg007
|
||||
erpnext/assets/ @nextchamp-saqib @deepeshgarg007
|
||||
erpnext/accounts/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/assets/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/erpnext_integrations/ @nextchamp-saqib
|
||||
erpnext/loan_management/ @nextchamp-saqib @deepeshgarg007
|
||||
erpnext/regional @nextchamp-saqib @deepeshgarg007
|
||||
erpnext/selling @nextchamp-saqib @deepeshgarg007
|
||||
erpnext/regional @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/selling @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/support/ @nextchamp-saqib @deepeshgarg007
|
||||
pos* @nextchamp-saqib
|
||||
|
||||
erpnext/buying/ @marination @rohitwaghchaure @ankush
|
||||
erpnext/buying/ @marination @rohitwaghchaure @s-aga-r
|
||||
erpnext/e_commerce/ @marination
|
||||
erpnext/maintenance/ @marination @rohitwaghchaure
|
||||
erpnext/manufacturing/ @marination @rohitwaghchaure @ankush
|
||||
erpnext/maintenance/ @marination @rohitwaghchaure @s-aga-r
|
||||
erpnext/manufacturing/ @marination @rohitwaghchaure @s-aga-r
|
||||
erpnext/portal/ @marination
|
||||
erpnext/quality_management/ @marination @rohitwaghchaure
|
||||
erpnext/quality_management/ @marination @rohitwaghchaure @s-aga-r
|
||||
erpnext/shopping_cart/ @marination
|
||||
erpnext/stock/ @marination @rohitwaghchaure @ankush
|
||||
erpnext/stock/ @marination @rohitwaghchaure @s-aga-r
|
||||
|
||||
erpnext/crm/ @ruchamahabal @pateljannat
|
||||
erpnext/education/ @ruchamahabal @pateljannat
|
||||
erpnext/healthcare/ @ruchamahabal @pateljannat @chillaranand
|
||||
erpnext/hr/ @ruchamahabal @pateljannat
|
||||
erpnext/crm/ @NagariaHussain
|
||||
erpnext/education/ @rutwikhdev
|
||||
erpnext/healthcare/ @chillaranand
|
||||
erpnext/hr/ @ruchamahabal
|
||||
erpnext/non_profit/ @ruchamahabal
|
||||
erpnext/payroll @ruchamahabal @pateljannat
|
||||
erpnext/projects/ @ruchamahabal @pateljannat
|
||||
erpnext/payroll @ruchamahabal
|
||||
erpnext/projects/ @ruchamahabal
|
||||
|
||||
erpnext/controllers @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination
|
||||
erpnext/patches/ @deepeshgarg007 @nextchamp-saqib @marination rohitwaghchaure
|
||||
erpnext/public/ @nextchamp-saqib @marination
|
||||
|
||||
.github/ @surajshetty3416 @ankush
|
||||
requirements.txt @gavindsouza
|
||||
.github/ @ankush
|
||||
requirements.txt @gavindsouza @ankush
|
||||
|
||||
@@ -476,7 +476,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
});
|
||||
this.frm.trigger("calculate_timesheet_totals");
|
||||
}
|
||||
},
|
||||
|
||||
is_cash_or_non_trade_discount() {
|
||||
this.frm.set_df_property("additional_discount_account", "hidden", 1 - this.frm.doc.is_cash_or_non_trade_discount);
|
||||
if (!this.frm.doc.is_cash_or_non_trade_discount) {
|
||||
this.frm.set_value("additional_discount_account", "");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"loyalty_redemption_cost_center",
|
||||
"section_break_49",
|
||||
"apply_discount_on",
|
||||
"is_cash_or_non_trade_discount",
|
||||
"base_discount_amount",
|
||||
"additional_discount_account",
|
||||
"column_break_51",
|
||||
@@ -1790,8 +1791,6 @@
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"fetch_from": "sales_partner.commission_rate",
|
||||
"fetch_if_empty": 1,
|
||||
"fieldname": "commission_rate",
|
||||
"fieldtype": "Float",
|
||||
"hide_days": 1,
|
||||
@@ -1990,7 +1989,7 @@
|
||||
{
|
||||
"fieldname": "additional_discount_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Additional Discount Account",
|
||||
"label": "Discount Account",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
@@ -2028,6 +2027,13 @@
|
||||
"fieldtype": "Currency",
|
||||
"label": "Amount Eligible for Commission",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval: doc.apply_discount_on == \"Grand Total\"",
|
||||
"fieldname": "is_cash_or_non_trade_discount",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Cash or Non Trade Discount"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
@@ -2040,7 +2046,7 @@
|
||||
"link_fieldname": "consolidated_invoice"
|
||||
}
|
||||
],
|
||||
"modified": "2022-06-10 03:52:51.409913",
|
||||
"modified": "2022-06-16 16:22:44.870575",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -1040,7 +1040,7 @@ class SalesInvoice(SellingController):
|
||||
)
|
||||
|
||||
if grand_total and not self.is_internal_transfer():
|
||||
# Didnot use base_grand_total to book rounding loss gle
|
||||
# Did not use base_grand_total to book rounding loss gle
|
||||
gl_entries.append(
|
||||
self.get_gl_dict(
|
||||
{
|
||||
@@ -1065,6 +1065,22 @@ class SalesInvoice(SellingController):
|
||||
)
|
||||
)
|
||||
|
||||
if self.apply_discount_on == "Grand Total" and self.get("is_cash_or_discount_account"):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict(
|
||||
{
|
||||
"account": self.additional_discount_account,
|
||||
"against": self.debit_to,
|
||||
"debit": self.base_discount_amount,
|
||||
"debit_in_account_currency": self.discount_amount,
|
||||
"cost_center": self.cost_center,
|
||||
"project": self.project,
|
||||
},
|
||||
self.currency,
|
||||
item=self,
|
||||
)
|
||||
)
|
||||
|
||||
def make_tax_gl_entries(self, gl_entries):
|
||||
for tax in self.get("taxes"):
|
||||
amount, base_amount = self.get_tax_amounts(tax, self.enable_discount_accounting)
|
||||
@@ -2163,6 +2179,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
source_document_warehouse_field = "from_warehouse"
|
||||
target_document_warehouse_field = "target_warehouse"
|
||||
|
||||
received_items = get_received_items(source_name, target_doctype, target_detail_field)
|
||||
|
||||
validate_inter_company_transaction(source_doc, doctype)
|
||||
details = get_inter_company_details(source_doc, doctype)
|
||||
|
||||
@@ -2227,12 +2245,17 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
shipping_address_name=target_doc.shipping_address_name,
|
||||
)
|
||||
|
||||
def update_item(source, target, source_parent):
|
||||
target.qty = flt(source.qty) - received_items.get(source.name, 0.0)
|
||||
|
||||
item_field_map = {
|
||||
"doctype": target_doctype + " Item",
|
||||
"field_no_map": ["income_account", "expense_account", "cost_center", "warehouse"],
|
||||
"field_map": {
|
||||
"rate": "rate",
|
||||
},
|
||||
"postprocess": update_item,
|
||||
"condition": lambda doc: doc.qty > 0,
|
||||
}
|
||||
|
||||
if doctype in ["Sales Invoice", "Sales Order"]:
|
||||
@@ -2270,6 +2293,28 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
return doclist
|
||||
|
||||
|
||||
def get_received_items(reference_name, doctype, reference_fieldname):
|
||||
target_doctypes = frappe.get_all(
|
||||
doctype,
|
||||
filters={"inter_company_invoice_reference": reference_name, "docstatus": 1},
|
||||
as_list=True,
|
||||
)
|
||||
|
||||
if target_doctypes:
|
||||
target_doctypes = list(target_doctypes[0])
|
||||
|
||||
received_items_map = frappe._dict(
|
||||
frappe.get_all(
|
||||
doctype + " Item",
|
||||
filters={"parent": ("in", target_doctypes)},
|
||||
fields=[reference_fieldname, "qty"],
|
||||
as_list=1,
|
||||
)
|
||||
)
|
||||
|
||||
return received_items_map
|
||||
|
||||
|
||||
def set_purchase_references(doc):
|
||||
# add internal PO or PR links if any
|
||||
if doc.is_internal_transfer():
|
||||
|
||||
@@ -11,6 +11,7 @@ def get_data():
|
||||
"Payment Request": "reference_name",
|
||||
"Sales Invoice": "return_against",
|
||||
"Auto Repeat": "reference_document",
|
||||
"Purchase Invoice": "inter_company_invoice_reference",
|
||||
},
|
||||
"internal_links": {
|
||||
"Sales Order": ["items", "sales_order"],
|
||||
@@ -30,5 +31,6 @@ def get_data():
|
||||
{"label": _("Reference"), "items": ["Timesheet", "Delivery Note", "Sales Order"]},
|
||||
{"label": _("Returns"), "items": ["Sales Invoice"]},
|
||||
{"label": _("Subscription"), "items": ["Auto Repeat"]},
|
||||
{"label": _("Internal Transfers"), "items": ["Purchase Invoice"]},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -2620,6 +2620,63 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
einvoice = make_einvoice(si)
|
||||
validate_totals(einvoice)
|
||||
|
||||
def test_einvoice_discounts(self):
|
||||
from erpnext.regional.india.e_invoice.utils import make_einvoice, validate_totals
|
||||
|
||||
# Normal Itemized Discount
|
||||
si = get_sales_invoice_for_e_invoice()
|
||||
si.apply_discount_on = ""
|
||||
si.items[0].discount_amount = 4000
|
||||
si.items[1].discount_amount = 300
|
||||
si.save()
|
||||
|
||||
einvoice = make_einvoice(si)
|
||||
validate_totals(einvoice)
|
||||
|
||||
self.assertEqual(einvoice["ItemList"][0]["Discount"], 4000)
|
||||
self.assertEqual(einvoice["ItemList"][1]["Discount"], 300)
|
||||
self.assertEqual(einvoice["ValDtls"]["Discount"], 0)
|
||||
|
||||
# Invoice Discount on net total
|
||||
si = get_sales_invoice_for_e_invoice()
|
||||
si.apply_discount_on = "Net Total"
|
||||
si.discount_amount = 400
|
||||
si.save()
|
||||
|
||||
einvoice = make_einvoice(si)
|
||||
validate_totals(einvoice)
|
||||
|
||||
self.assertEqual(einvoice["ItemList"][0]["Discount"], 316.83)
|
||||
self.assertEqual(einvoice["ItemList"][1]["Discount"], 83.17)
|
||||
self.assertEqual(einvoice["ValDtls"]["Discount"], 0)
|
||||
|
||||
# Invoice Discount on grand total (Itemized Discount)
|
||||
si = get_sales_invoice_for_e_invoice()
|
||||
si.apply_discount_on = "Grand Total"
|
||||
si.discount_amount = 400
|
||||
si.save()
|
||||
|
||||
einvoice = make_einvoice(si)
|
||||
validate_totals(einvoice)
|
||||
|
||||
self.assertEqual(einvoice["ItemList"][0]["Discount"], 268.5)
|
||||
self.assertEqual(einvoice["ItemList"][1]["Discount"], 70.48)
|
||||
self.assertEqual(einvoice["ValDtls"]["Discount"], 0)
|
||||
|
||||
# Invoice Discount on grand total (Cash/Non-Trade Discount)
|
||||
si = get_sales_invoice_for_e_invoice()
|
||||
si.apply_discount_on = "Grand Total"
|
||||
si.is_cash_or_non_trade_discount = 1
|
||||
si.discount_amount = 400
|
||||
si.save()
|
||||
|
||||
einvoice = make_einvoice(si)
|
||||
validate_totals(einvoice)
|
||||
|
||||
self.assertEqual(einvoice["ItemList"][0]["Discount"], 0)
|
||||
self.assertEqual(einvoice["ItemList"][1]["Discount"], 0)
|
||||
self.assertEqual(einvoice["ValDtls"]["Discount"], 400)
|
||||
|
||||
def test_item_tax_net_range(self):
|
||||
item = create_item("T Shirt")
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
company: me.frm.doc.company
|
||||
},
|
||||
allow_child_item_selection: true,
|
||||
child_fielname: "items",
|
||||
child_fieldname: "items",
|
||||
child_columns: ["item_code", "qty"]
|
||||
})
|
||||
}, __("Get Items From"));
|
||||
|
||||
@@ -500,6 +500,9 @@ class calculate_taxes_and_totals(object):
|
||||
else:
|
||||
self.doc.grand_total = flt(self.doc.net_total)
|
||||
|
||||
if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
|
||||
self.doc.grand_total -= self.doc.discount_amount
|
||||
|
||||
if self.doc.get("taxes"):
|
||||
self.doc.total_taxes_and_charges = flt(
|
||||
self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment),
|
||||
@@ -594,6 +597,12 @@ class calculate_taxes_and_totals(object):
|
||||
if not self.doc.apply_discount_on:
|
||||
frappe.throw(_("Please select Apply Discount On"))
|
||||
|
||||
if self.doc.apply_discount_on == "Grand Total" and self.doc.get(
|
||||
"is_cash_or_non_trade_discount"
|
||||
):
|
||||
self.discount_amount_applied = True
|
||||
return
|
||||
|
||||
self.doc.base_discount_amount = flt(
|
||||
self.doc.discount_amount * self.doc.conversion_rate, self.doc.precision("base_discount_amount")
|
||||
)
|
||||
|
||||
@@ -461,6 +461,14 @@ scheduler_events = {
|
||||
"0/30 * * * *": [
|
||||
"erpnext.utilities.doctype.video.video.update_youtube_data",
|
||||
],
|
||||
# Hourly but offset by 30 minutes
|
||||
"30 * * * *": [
|
||||
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
|
||||
],
|
||||
# Daily but offset by 45 minutes
|
||||
"45 0 * * *": [
|
||||
"erpnext.stock.reorder_item.reorder_item",
|
||||
],
|
||||
},
|
||||
"all": [
|
||||
"erpnext.projects.doctype.project.project.project_status_update_reminder",
|
||||
@@ -472,7 +480,6 @@ scheduler_events = {
|
||||
"erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails",
|
||||
"erpnext.accounts.doctype.subscription.subscription.process_all",
|
||||
"erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
|
||||
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
|
||||
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization",
|
||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||
"erpnext.projects.doctype.project.project.collect_project_status",
|
||||
@@ -484,7 +491,6 @@ scheduler_events = {
|
||||
"erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries"
|
||||
],
|
||||
"daily": [
|
||||
"erpnext.stock.reorder_item.reorder_item",
|
||||
"erpnext.support.doctype.issue.issue.auto_close_tickets",
|
||||
"erpnext.crm.doctype.opportunity.opportunity.auto_close_opportunity",
|
||||
"erpnext.controllers.accounts_controller.update_invoice_status",
|
||||
|
||||
@@ -1223,9 +1223,25 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
},
|
||||
|
||||
is_a_mapped_document(item) {
|
||||
const mapped_item_field_map = {
|
||||
"Delivery Note Item": ["si_detail", "so_detail", "dn_detail"],
|
||||
"Sales Invoice Item": ["dn_detail", "so_detail", "sales_invoice_item"],
|
||||
"Purchase Receipt Item": ["purchase_order_item", "purchase_invoice_item", "purchase_receipt_item"],
|
||||
"Purchase Invoice Item": ["purchase_order_item", "pr_detail", "po_detail"],
|
||||
};
|
||||
const mappped_fields = mapped_item_field_map[item.doctype] || [];
|
||||
|
||||
return mappped_fields
|
||||
.map((field) => item[field])
|
||||
.filter(Boolean).length > 0;
|
||||
},
|
||||
|
||||
batch_no: function(doc, cdt, cdn) {
|
||||
let item = frappe.get_doc(cdt, cdn);
|
||||
this.apply_price_list(item, true);
|
||||
if (!this.is_a_mapped_document(item)) {
|
||||
this.apply_price_list(item, true);
|
||||
}
|
||||
},
|
||||
|
||||
toggle_conversion_factor: function(item) {
|
||||
|
||||
@@ -713,7 +713,7 @@ erpnext.utils.map_current_doc = function(opts) {
|
||||
get_query: opts.get_query,
|
||||
add_filters_group: 1,
|
||||
allow_child_item_selection: opts.allow_child_item_selection,
|
||||
child_fieldname: opts.child_fielname,
|
||||
child_fieldname: opts.child_fieldname,
|
||||
child_columns: opts.child_columns,
|
||||
size: opts.size,
|
||||
action: function(selections, args) {
|
||||
|
||||
@@ -272,14 +272,14 @@ def get_item_list(invoice):
|
||||
item.description = sanitize_for_json(d.item_name)
|
||||
|
||||
item.qty = abs(item.qty)
|
||||
if flt(item.qty) != 0.0:
|
||||
item.unit_rate = abs(item.taxable_value / item.qty)
|
||||
else:
|
||||
item.unit_rate = abs(item.taxable_value)
|
||||
item.gross_amount = abs(item.taxable_value)
|
||||
item.taxable_value = abs(item.taxable_value)
|
||||
item.discount_amount = 0
|
||||
|
||||
if invoice.get("apply_discount_on"):
|
||||
item.discount_amount = item.base_amount - item.base_net_amount
|
||||
|
||||
item.unit_rate = abs(item.taxable_value - item.discount_amount) / item.qty
|
||||
|
||||
item.gross_amount = abs(item.taxable_value) + item.discount_amount
|
||||
item.taxable_value = abs(item.taxable_value)
|
||||
item.is_service_item = "Y" if item.gst_hsn_code and item.gst_hsn_code[:2] == "99" else "N"
|
||||
item.serial_no = ""
|
||||
|
||||
@@ -353,7 +353,14 @@ def update_item_taxes(invoice, item):
|
||||
def get_invoice_value_details(invoice):
|
||||
invoice_value_details = frappe._dict(dict())
|
||||
invoice_value_details.base_total = abs(sum([i.taxable_value for i in invoice.get("items")]))
|
||||
invoice_value_details.invoice_discount_amt = 0
|
||||
if (
|
||||
invoice.apply_discount_on == "Grand Total"
|
||||
and invoice.discount_amount
|
||||
and invoice.get("is_cash_or_non_trade_discount")
|
||||
):
|
||||
invoice_value_details.invoice_discount_amt = invoice.discount_amount
|
||||
else:
|
||||
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(
|
||||
|
||||
@@ -1061,8 +1061,16 @@ def update_taxable_values(doc, method):
|
||||
considered_rows.append(prev_row_id)
|
||||
|
||||
for item in doc.get("items"):
|
||||
proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
|
||||
total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
|
||||
if (
|
||||
doc.apply_discount_on == "Grand Total"
|
||||
and doc.discount_amount
|
||||
and doc.get("is_cash_or_non_trade_discount")
|
||||
):
|
||||
proportionate_value = item.base_amount if doc.base_total else item.qty
|
||||
total_value = doc.base_total if doc.base_total else doc.total_qty
|
||||
else:
|
||||
proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
|
||||
total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
|
||||
|
||||
applicable_charges = flt(
|
||||
flt(
|
||||
|
||||
Reference in New Issue
Block a user