Merge branch 'develop' into payment-reconc-party-validation-fix
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 1be2fbf..f763df0 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -230,7 +230,7 @@
if self.check_gle_exists():
throw(_("Account with existing transaction can not be converted to group."))
elif self.account_type and not self.flags.exclude_account_type_check:
- throw(_("Cannot covert to Group because Account Type is selected."))
+ throw(_("Cannot convert to Group because Account Type is selected."))
else:
self.is_group = 1
self.save()
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 703e93c..7bcc6ee 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -10,6 +10,7 @@
"accounts_transactions_settings_section",
"over_billing_allowance",
"role_allowed_to_over_bill",
+ "credit_controller",
"make_payment_via_journal_entry",
"column_break_11",
"check_supplier_invoice_uniqueness",
@@ -27,7 +28,6 @@
"acc_frozen_upto",
"frozen_accounts_modifier",
"column_break_4",
- "credit_controller",
"deferred_accounting_settings_section",
"book_deferred_entries_based_on",
"column_break_18",
@@ -73,11 +73,10 @@
"fieldtype": "Column Break"
},
{
- "description": "This role is allowed to submit transactions that exceed credit limits",
"fieldname": "credit_controller",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "Credit Controller",
+ "label": "Role allowed to bypass Credit Limit",
"options": "Role"
},
{
@@ -268,7 +267,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-06-17 20:26:03.721202",
+ "modified": "2021-08-09 13:08:01.335416",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 603e21e..6c25f00 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -249,7 +249,7 @@
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
if budget_against_field == "project":
- budget_against = "_Test Project"
+ budget_against = frappe.db.get_value("Project", {"project_name": "_Test Project"})
else:
budget_against = budget_against_CC or "_Test Cost Center - _TC"
@@ -275,7 +275,7 @@
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
elif budget_against_field == "project":
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
+ "_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project=budget_against, posting_date=nowdate())
def make_budget(**args):
args = frappe._dict(args)
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 428989a..0be41b4 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -558,7 +558,8 @@
"description": "Simple Python Expression, Example: territory != 'All Territories'",
"fieldname": "condition",
"fieldtype": "Code",
- "label": "Condition"
+ "label": "Condition",
+ "options": "PythonExpression"
},
{
"fieldname": "column_break_42",
@@ -575,7 +576,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
- "modified": "2021-03-06 22:01:24.840422",
+ "modified": "2021-08-06 15:10:04.219321",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 7562418..bda9f41 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -134,7 +134,7 @@
},
get_query_filters: {
docstatus: 1,
- status: ["not in", ["Closed", "Completed"]],
+ status: ["not in", ["Closed", "Completed", "Return Issued"]],
company: me.frm.doc.company,
is_return: 0
}
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index bf4ab1a..9e2e596 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1507,7 +1507,7 @@
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 add_taxes_from_tax_template(child_item, parent_doc):
+def add_taxes_from_tax_template(child_item, parent_doc, db_insert=True):
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:
@@ -1530,7 +1530,8 @@
"category" : "Total",
"add_deduct_tax" : "Add"
})
- tax_row.db_insert()
+ if db_insert:
+ tax_row.db_insert()
def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item):
"""
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index 43e1b99..e9a7a95 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -53,6 +53,13 @@
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
},
+ status:function(frm){
+ if (frm.doc.status == "Lost"){
+ frm.trigger('set_as_lost_dialog');
+ }
+
+ },
+
customer_address: function(frm, cdt, cdn) {
erpnext.utils.get_address_display(frm, 'customer_address', 'address_display', false);
},
@@ -91,11 +98,6 @@
frm.add_custom_button(__('Quotation'),
cur_frm.cscript.create_quotation, __('Create'));
- if(doc.status!=="Quotation") {
- frm.add_custom_button(__('Lost'), () => {
- frm.trigger('set_as_lost_dialog');
- });
- }
}
if(!frm.doc.__islocal && frm.perm[0].write && frm.doc.docstatus==0) {
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 4e93fc6..0ba8507 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -717,9 +717,8 @@
"ignore_conversion_rate": True
})
item_doc = frappe.get_cached_doc("Item", args.get("item_code"))
- out = frappe._dict()
- get_price_list_rate(bom_args, item_doc, out)
- rate = out.price_list_rate
+ price_list_data = get_price_list_rate(bom_args, item_doc)
+ rate = price_list_data.price_list_rate
return rate
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 69c7f5c..66e2394 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -608,6 +608,11 @@
target.set_missing_values()
target.set_stock_entry_type()
+ wo_allows_alternate_item = frappe.db.get_value("Work Order", target.work_order, "allow_alternative_item")
+ for item in target.items:
+ item.allow_alternative_item = int(wo_allows_alternate_item and
+ frappe.get_cached_value("Item", item.item_code, "allow_alternative_item"))
+
doclist = get_mapped_doc("Job Card", source_name, {
"Job Card": {
"doctype": "Stock Entry",
@@ -698,4 +703,4 @@
}
}, target_doc, set_missing_values)
- return doclist
\ No newline at end of file
+ return doclist
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 04f05ed..35b248c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -294,7 +294,8 @@
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
+erpnext.patches.v13_0.delete_orphaned_tables
erpnext.patches.v13_0.update_export_type_for_gst
erpnext.patches.v13_0.update_tds_check_field #3
-erpnext.patches.v13_0.add_custom_field_for_south_africa
+erpnext.patches.v13_0.add_custom_field_for_south_africa #2
erpnext.patches.v13_0.shopify_deprecation_warning
diff --git a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
index f882fde..73ff1ca 100644
--- a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
+++ b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from erpnext.regional.south_africa.setup import make_custom_fields
+from erpnext.regional.south_africa.setup import make_custom_fields, add_permissions
def execute():
company = frappe.get_all('Company', filters = {'country': 'South Africa'})
@@ -11,3 +11,4 @@
return
make_custom_fields()
+ add_permissions()
diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py
new file mode 100644
index 0000000..1d6eebe
--- /dev/null
+++ b/erpnext/patches/v13_0/delete_orphaned_tables.py
@@ -0,0 +1,69 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.utils import getdate
+
+def execute():
+ frappe.reload_doc('setup', 'doctype', 'transaction_deletion_record')
+
+ if has_deleted_company_transactions():
+ child_doctypes = get_child_doctypes_whose_parent_doctypes_were_affected()
+
+ for doctype in child_doctypes:
+ docs = frappe.get_all(doctype, fields=['name', 'parent', 'parenttype', 'creation'])
+
+ for doc in docs:
+ if not frappe.db.exists(doc['parenttype'], doc['parent']):
+ frappe.db.delete(doctype, {'name': doc['name']})
+
+ elif check_for_new_doc_with_same_name_as_deleted_parent(doc):
+ frappe.db.delete(doctype, {'name': doc['name']})
+
+def has_deleted_company_transactions():
+ return frappe.get_all('Transaction Deletion Record')
+
+def get_child_doctypes_whose_parent_doctypes_were_affected():
+ parent_doctypes = get_affected_doctypes()
+ child_doctypes = frappe.get_all(
+ 'DocField',
+ filters={
+ 'fieldtype': 'Table',
+ 'parent':['in', parent_doctypes]
+ }, pluck='options')
+
+ return child_doctypes
+
+def get_affected_doctypes():
+ affected_doctypes = []
+ tdr_docs = frappe.get_all('Transaction Deletion Record', pluck="name")
+
+ for tdr in tdr_docs:
+ tdr_doc = frappe.get_doc("Transaction Deletion Record", tdr)
+
+ for doctype in tdr_doc.doctypes:
+ if is_not_child_table(doctype.doctype_name):
+ affected_doctypes.append(doctype.doctype_name)
+
+ affected_doctypes = remove_duplicate_items(affected_doctypes)
+ return affected_doctypes
+
+def is_not_child_table(doctype):
+ return not bool(frappe.get_value('DocType', doctype, 'istable'))
+
+def remove_duplicate_items(affected_doctypes):
+ return list(set(affected_doctypes))
+
+def check_for_new_doc_with_same_name_as_deleted_parent(doc):
+ """
+ Compares creation times of parent and child docs.
+ Since Transaction Deletion Record resets the naming series after deletion,
+ it allows the creation of new docs with the same names as the deleted ones.
+ """
+
+ parent_creation_time = frappe.db.get_value(doc['parenttype'], doc['parent'], 'creation')
+ child_creation_time = doc['creation']
+
+ return getdate(parent_creation_time) > getdate(child_creation_time)
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index b39cef8..f0ca64f 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -647,10 +647,13 @@
continue
if (
- (not d.additional_salary
- and (not additional_salary or additional_salary.overwrite))
- or (additional_salary
- and additional_salary.name == d.additional_salary)
+ (
+ 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
break
@@ -679,8 +682,12 @@
if additional_salary:
component_row.is_recurring_additional_salary = is_recurring
- component_row.default_amount = 0
- component_row.additional_amount = amount
+ if additional_salary.overwrite:
+ component_row.additional_amount = flt(flt(amount) - flt(component_row.get("default_amount", 0)),
+ component_row.precision("additional_amount"))
+ else:
+ 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
diff --git a/erpnext/regional/address_template/templates/france.html b/erpnext/regional/address_template/templates/france.html
new file mode 100644
index 0000000..752331e
--- /dev/null
+++ b/erpnext/regional/address_template/templates/france.html
@@ -0,0 +1,5 @@
+{% if address_line1 %}{{ address_line1 }}{% endif -%}
+{% if address_line2 %}<br>{{ address_line2 }}{% endif -%}
+{% if pincode %}<br>{{ pincode }}{% endif -%}
+{% if city %} {{ city }}{% endif -%}
+{% if country %}<br>{{ country }}{% endif -%}
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index f8a230d..4276946 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -316,10 +316,6 @@
))
def get_return_doc_reference(invoice):
- if not invoice.return_against:
- frappe.throw(_('For generating IRN, reference to the original invoice is mandatory for a credit note. Please set {} field to generate e-invoice.')
- .format(frappe.bold('Return Against')), title=_('Missing Field'))
-
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')
@@ -438,7 +434,7 @@
if invoice.is_pos and invoice.base_paid_amount:
payment_details = get_payment_details(invoice)
- if invoice.is_return:
+ if invoice.is_return and invoice.return_against:
prev_doc_details = get_return_doc_reference(invoice)
if invoice.transporter and not invoice.is_return:
@@ -932,7 +928,7 @@
def set_einvoice_data(self, res):
enc_signed_invoice = res.get('SignedInvoice')
- dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
+ dec_signed_invoice = jwt.decode(enc_signed_invoice, options={"verify_signature": False})['data']
self.invoice.irn = res.get('Irn')
self.invoice.ewaybill = res.get('EwbNo')
@@ -1130,4 +1126,4 @@
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
+ return True
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.json b/erpnext/regional/report/vat_audit_report/vat_audit_report.json
index 8917e8f..a8be7bf 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.json
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.json
@@ -18,15 +18,5 @@
"ref_doctype": "GL Entry",
"report_name": "VAT Audit Report",
"report_type": "Script Report",
- "roles": [
- {
- "role": "Accounts User"
- },
- {
- "role": "Accounts Manager"
- },
- {
- "role": "Auditor"
- }
- ]
+ "roles": []
}
\ No newline at end of file
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
index f45ba01..292605e 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
@@ -189,6 +189,8 @@
row["posting_date"] = formatdate(inv_data.get("posting_date"), "dd-mm-yyyy")
row["voucher_type"] = doctype
row["voucher_no"] = inv
+ row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
+ row["party"] = inv_data.get("party")
row["remarks"] = inv_data.get("remarks")
row["gross_amount"]= item_details[0].get("gross_amount")
row["tax_amount"]= item_details[0].get("tax_amount")
@@ -227,6 +229,20 @@
"width": 150
},
{
+ "fieldname": "party_type",
+ "label": "Party Type",
+ "fieldtype": "Data",
+ "width": 140,
+ "hidden": 1
+ },
+ {
+ "fieldname": "party",
+ "label": "Party",
+ "fieldtype": "Dynamic Link",
+ "options": "party_type",
+ "width": 150
+ },
+ {
"fieldname": "remarks",
"label": "Details",
"fieldtype": "Data",
@@ -236,18 +252,18 @@
"fieldname": "net_amount",
"label": "Net Amount",
"fieldtype": "Currency",
- "width": 150
+ "width": 130
},
{
"fieldname": "tax_amount",
"label": "Tax Amount",
"fieldtype": "Currency",
- "width": 150
+ "width": 130
},
{
"fieldname": "gross_amount",
"label": "Gross Amount",
"fieldtype": "Currency",
- "width": 150
+ "width": 130
},
]
diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py
index ac783b8..4657ff8 100644
--- a/erpnext/regional/south_africa/setup.py
+++ b/erpnext/regional/south_africa/setup.py
@@ -3,11 +3,12 @@
from __future__ import unicode_literals
-# import frappe, os, json
+import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
def setup(company=None, patch=True):
+ make_custom_fields()
add_permissions()
def make_custom_fields(update=True):
@@ -27,10 +28,23 @@
create_custom_fields(custom_fields, update=update)
def add_permissions():
- """Add Permissions for South Africa VAT Settings and South Africa VAT Account"""
+ """Add Permissions for South Africa VAT Settings and South Africa VAT Account
+ and VAT Audit Report"""
for doctype in ('South Africa VAT Settings', 'South Africa 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)
\ No newline at end of file
+ update_permission_property(doctype, role, 0, 'create', 1)
+
+
+ if not frappe.db.get_value('Custom Role', dict(report="VAT Audit Report")):
+ frappe.get_doc(dict(
+ doctype='Custom Role',
+ report="VAT Audit Report",
+ roles= [
+ dict(role='Accounts User'),
+ dict(role='Accounts Manager'),
+ dict(role='Auditor')
+ ]
+ )).insert()
\ 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 f01934b..717fd9b 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -6,24 +6,31 @@
"document_type": "Other",
"engine": "InnoDB",
"field_order": [
+ "customer_defaults_section",
"cust_master_name",
- "campaign_naming_by",
"customer_group",
+ "column_break_4",
"territory",
- "selling_price_list",
- "close_opportunity_after_days",
+ "crm_settings_section",
+ "campaign_naming_by",
"default_valid_till",
- "column_break_5",
+ "column_break_9",
+ "close_opportunity_after_days",
+ "item_price_settings_section",
+ "selling_price_list",
+ "column_break_15",
+ "maintain_same_sales_rate",
+ "maintain_same_rate_action",
+ "editable_price_list_rate",
+ "validate_selling_price",
+ "sales_transactions_settings_section",
"so_required",
"dn_required",
"sales_update_frequency",
- "maintain_same_sales_rate",
- "maintain_same_rate_action",
+ "column_break_5",
"role_to_override_stop_action",
- "editable_price_list_rate",
"allow_multiple_items",
"allow_against_multiple_purchase_orders",
- "validate_selling_price",
"hide_tax_id"
],
"fields": [
@@ -116,7 +123,7 @@
"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",
@@ -142,7 +149,7 @@
"description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
"fieldname": "maintain_same_rate_action",
"fieldtype": "Select",
- "label": "Action If Same Rate is Not Maintained",
+ "label": "Action if Same Rate is Not Maintained",
"mandatory_depends_on": "maintain_same_sales_rate",
"options": "Stop\nWarn"
},
@@ -152,6 +159,38 @@
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
+ },
+ {
+ "fieldname": "customer_defaults_section",
+ "fieldtype": "Section Break",
+ "label": "Customer Defaults"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "crm_settings_section",
+ "fieldtype": "Section Break",
+ "label": "CRM Settings"
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "item_price_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Item Price Settings"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "sales_transactions_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Transaction Settings"
}
],
"icon": "fa fa-cog",
@@ -159,7 +198,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-04-04 20:18:12.814624",
+ "modified": "2021-08-06 22:25:50.119458",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index f1a166b..63306ad 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -198,6 +198,7 @@
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').css('display', 'grid');
+ this.render_payment_mode_dom();
});
frappe.ui.form.on('POS Invoice', 'loyalty_amount', (frm) => {
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
index 9313f95..23e5947 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -54,7 +54,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-08 23:13:48.049879",
+ "modified": "2021-08-04 20:15:59.071493",
"modified_by": "Administrator",
"module": "Setup",
"name": "Transaction Deletion Record",
@@ -70,6 +70,7 @@
"report": 1,
"role": "System Manager",
"share": 1,
+ "submit": 1,
"write": 1
}
],
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index cbd272d..a85a022 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -269,11 +269,14 @@
batch2 = create_batch('_Test Batch Price Item', 300, 1)
batch3 = create_batch('_Test Batch Price Item', 400, 0)
+ company = "_Test Company with perpetual inventory"
+ currency = frappe.get_cached_value("Company", company, "default_currency")
+
args = frappe._dict({
"item_code": "_Test Batch Price Item",
- "company": "_Test Company with perpetual inventory",
+ "company": company,
"price_list": "_Test Price List",
- "currency": "_Test Currency",
+ "currency": currency,
"doctype": "Sales Invoice",
"conversion_rate": 1,
"price_list_currency": "_Test Currency",
@@ -333,4 +336,4 @@
except frappe.DuplicateEntryError:
batch = frappe.get_doc("Batch", args.batch_id)
- return batch
\ No newline at end of file
+ return batch
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 922049f..7a9985d 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -83,14 +83,17 @@
make_test_objects("Item Price")
+ company = "_Test Company"
+ currency = frappe.get_cached_value("Company", company, "default_currency")
+
details = get_item_details({
"item_code": "_Test Item",
- "company": "_Test Company",
+ "company": company,
"price_list": "_Test Price List",
- "currency": "_Test Currency",
+ "currency": currency,
"doctype": "Sales Order",
"conversion_rate": 1,
- "price_list_currency": "_Test Currency",
+ "price_list_currency": currency,
"plc_conversion_rate": 1,
"order_type": "Sales",
"customer": "_Test Customer",
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 9b1a47e..5de45cb 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
@@ -47,7 +47,8 @@
"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"
+ "label": "Acceptance Criteria Formula",
+ "options": "PythonExpression"
},
{
"default": "0",
@@ -89,7 +90,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-02-04 18:50:02.056173",
+ "modified": "2021-08-06 15:08:20.911338",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Quality Inspection Parameter",
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 32b08f6..128a2ab 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
@@ -11,6 +11,7 @@
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
+from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item
class TestLandedCostVoucher(unittest.TestCase):
def test_landed_cost_voucher(self):
@@ -250,6 +251,38 @@
self.assertEqual(entry.credit, amounts[0])
self.assertEqual(entry.credit_in_account_currency, amounts[1])
+ def test_asset_lcv(self):
+ "Check if LCV for an Asset updates the Assets Gross Purchase Amount correctly."
+ if not frappe.db.exists("Asset Category", "Computers"):
+ create_asset_category()
+
+ if not frappe.db.exists("Item", "Macbook Pro"):
+ create_fixed_asset_item()
+
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=50000)
+
+ # check if draft asset was created
+ assets = frappe.db.get_all('Asset', filters={'purchase_receipt': pr.name})
+ self.assertEqual(len(assets), 1)
+
+ frappe.db.set_value("Company", pr.company, "capital_work_in_progress_account", "CWIP Account - _TC")
+ lcv = make_landed_cost_voucher(
+ company = pr.company,
+ receipt_document_type = "Purchase Receipt",
+ receipt_document=pr.name,
+ charges=80,
+ expense_account="Expenses Included In Valuation - _TC")
+
+ lcv.save()
+ lcv.submit()
+
+ # lcv updates amount in draft asset
+ self.assertEqual(frappe.db.get_value("Asset", assets[0].name, "gross_purchase_amount"), 50080)
+
+ # tear down
+ lcv.cancel()
+ pr.cancel()
+
def make_landed_cost_voucher(** args):
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
@@ -268,7 +301,7 @@
lcv.set("taxes", [{
"description": "Shipping Charges",
- "expense_account": "Expenses Included In Valuation - TCP1",
+ "expense_account": args.expense_account or "Expenses Included In Valuation - TCP1",
"amount": args.charges
}])
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 899d7e8..bcf6052 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -290,8 +290,16 @@
and warehouse_account_name == supplier_warehouse_account:
continue
- self.add_gl_entry(gl_entries, warehouse_account_name, d.cost_center, stock_value_diff, 0.0, remarks,
- stock_rbnb, account_currency=warehouse_account_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=warehouse_account_name,
+ cost_center=d.cost_center,
+ debit=stock_value_diff,
+ credit=0.0,
+ remarks=remarks,
+ against_account=stock_rbnb,
+ account_currency=warehouse_account_currency,
+ item=d)
# GL Entry for from warehouse or Stock Received but not billed
# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
@@ -304,9 +312,17 @@
account = warehouse_account[d.from_warehouse]['account'] \
if d.from_warehouse else stock_rbnb
- self.add_gl_entry(gl_entries, account, d.cost_center,
- -1 * flt(d.base_net_amount, d.precision("base_net_amount")), 0.0, remarks, warehouse_account_name,
- debit_in_account_currency=-1 * credit_amount, account_currency=credit_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=d.cost_center,
+ debit=-1 * flt(d.base_net_amount, d.precision("base_net_amount")),
+ credit=0.0,
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ debit_in_account_currency=-1 * credit_amount,
+ account_currency=credit_currency,
+ item=d)
# check if the exchange rate has changed
if d.get('purchase_invoice'):
@@ -317,13 +333,29 @@
discrepancy_caused_by_exchange_rate_difference = (d.qty * d.net_rate) * \
(exchange_rate_map[d.purchase_invoice] - self.conversion_rate)
- self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, discrepancy_caused_by_exchange_rate_difference,
- remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
- account_currency=credit_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=discrepancy_caused_by_exchange_rate_difference,
+ remarks=remarks,
+ against_account=self.supplier,
+ debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
+ account_currency=credit_currency,
+ item=d)
- self.add_gl_entry(gl_entries, self.get_company_default("exchange_gain_loss_account"), d.cost_center, discrepancy_caused_by_exchange_rate_difference, 0.0,
- remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
- account_currency=credit_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=self.get_company_default("exchange_gain_loss_account"),
+ cost_center=d.cost_center,
+ debit=discrepancy_caused_by_exchange_rate_difference,
+ credit=0.0,
+ remarks=remarks,
+ against_account=self.supplier,
+ debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
+ account_currency=credit_currency,
+ item=d)
# Amount added through landed-cos-voucher
if d.landed_cost_voucher_amount and landed_cost_entries:
@@ -332,14 +364,31 @@
credit_amount = (flt(amount["base_amount"]) if (amount["base_amount"] or
account_currency!=self.company_currency) else flt(amount["amount"]))
- self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, credit_amount, remarks,
- warehouse_account_name, credit_in_account_currency=flt(amount["amount"]),
- account_currency=account_currency, project=d.project, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=credit_amount,
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ credit_in_account_currency=flt(amount["amount"]),
+ account_currency=account_currency,
+ project=d.project,
+ item=d)
# sub-contracting warehouse
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
- self.add_gl_entry(gl_entries, supplier_warehouse_account, d.cost_center, 0.0, flt(d.rm_supp_cost),
- remarks, warehouse_account_name, account_currency=supplier_warehouse_account_currency, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=supplier_warehouse_account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=flt(d.rm_supp_cost),
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ account_currency=supplier_warehouse_account_currency,
+ item=d)
# divisional loss adjustment
valuation_amount_as_per_doc = flt(d.base_net_amount, d.precision("base_net_amount")) + \
@@ -356,8 +405,17 @@
cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
- self.add_gl_entry(gl_entries, loss_account, cost_center, divisional_loss, 0.0, remarks,
- warehouse_account_name, account_currency=credit_currency, project=d.project, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=loss_account,
+ cost_center=cost_center,
+ debit=divisional_loss,
+ credit=0.0,
+ remarks=remarks,
+ against_account=warehouse_account_name,
+ account_currency=credit_currency,
+ project=d.project,
+ item=d)
elif d.warehouse not in warehouse_with_no_account or \
d.rejected_warehouse not in warehouse_with_no_account:
@@ -368,12 +426,30 @@
debit_currency = get_account_currency(d.expense_account)
remarks = self.get("remarks") or _("Accounting Entry for Service")
- self.add_gl_entry(gl_entries, service_received_but_not_billed_account, d.cost_center, 0.0, d.amount,
- remarks, d.expense_account, account_currency=credit_currency, project=d.project,
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=service_received_but_not_billed_account,
+ cost_center=d.cost_center,
+ debit=0.0,
+ credit=d.amount,
+ remarks=remarks,
+ against_account=d.expense_account,
+ account_currency=credit_currency,
+ project=d.project,
voucher_detail_no=d.name, item=d)
- self.add_gl_entry(gl_entries, d.expense_account, d.cost_center, d.amount, 0.0, remarks, service_received_but_not_billed_account,
- account_currency = debit_currency, project=d.project, voucher_detail_no=d.name, item=d)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=d.expense_account,
+ cost_center=d.cost_center,
+ debit=d.amount,
+ credit=0.0,
+ remarks=remarks,
+ against_account=service_received_but_not_billed_account,
+ account_currency = debit_currency,
+ project=d.project,
+ voucher_detail_no=d.name,
+ item=d)
if warehouse_with_no_account:
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
@@ -423,8 +499,15 @@
applicable_amount = negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
amount_including_divisional_loss -= applicable_amount
- self.add_gl_entry(gl_entries, account, tax.cost_center, 0.0, applicable_amount, self.remarks or _("Accounting Entry for Stock"),
- against_account, item=tax)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=tax.cost_center,
+ debit=0.0,
+ credit=applicable_amount,
+ remarks=self.remarks or _("Accounting Entry for Stock"),
+ against_account=against_account,
+ item=tax)
i += 1
@@ -477,15 +560,31 @@
# debit cwip account
debit_in_account_currency = (base_asset_amount
if cwip_account_currency == self.company_currency else asset_amount)
- self.add_gl_entry(gl_entries, cwip_account, item.cost_center, base_asset_amount, 0.0, remarks,
- arbnb_account, debit_in_account_currency=debit_in_account_currency, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=cwip_account,
+ cost_center=item.cost_center,
+ debit=base_asset_amount,
+ credit=0.0,
+ remarks=remarks,
+ against_account=arbnb_account,
+ debit_in_account_currency=debit_in_account_currency,
+ item=item)
asset_rbnb_currency = get_account_currency(arbnb_account)
# credit arbnb account
credit_in_account_currency = (base_asset_amount
if asset_rbnb_currency == self.company_currency else asset_amount)
- self.add_gl_entry(gl_entries, arbnb_account, item.cost_center, 0.0, base_asset_amount, remarks,
- cwip_account, credit_in_account_currency=credit_in_account_currency, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=arbnb_account,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=base_asset_amount,
+ remarks=remarks,
+ against_account=cwip_account,
+ credit_in_account_currency=credit_in_account_currency,
+ item=item)
def add_lcv_gl_entries(self, item, gl_entries):
expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
@@ -498,11 +597,27 @@
remarks = self.get("remarks") or _("Accounting Entry for Stock")
- self.add_gl_entry(gl_entries, expenses_included_in_asset_valuation, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
- remarks, asset_account, project=item.project, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=expenses_included_in_asset_valuation,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=flt(item.landed_cost_voucher_amount),
+ remarks=remarks,
+ against_account=asset_account,
+ project=item.project,
+ item=item)
- self.add_gl_entry(gl_entries, asset_account, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
- remarks, expenses_included_in_asset_valuation, project=item.project, item=item)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=asset_account,
+ cost_center=item.cost_center,
+ debit=flt(item.landed_cost_voucher_amount),
+ credit=0.0,
+ remarks=remarks,
+ against_account=expenses_included_in_asset_valuation,
+ project=item.project,
+ item=item)
def update_assets(self, item, valuation_rate):
assets = frappe.db.get_all('Asset',
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 82461cb..d40d781 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -23,9 +23,7 @@
def test_reverse_purchase_receipt_sle(self):
- frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 0)
-
- pr = make_purchase_receipt(qty=0.5)
+ pr = make_purchase_receipt(qty=0.5, item_code="_Test Item Home Desktop 200")
sl_entry = frappe.db.get_all("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
"voucher_no": pr.name}, ['actual_qty'])
@@ -41,8 +39,6 @@
self.assertEqual(len(sl_entry_cancelled), 2)
self.assertEqual(sl_entry_cancelled[1].actual_qty, -0.5)
- 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({
@@ -328,21 +324,8 @@
pr1.submit()
self.assertRaises(frappe.ValidationError, pr2.submit)
+ frappe.db.rollback()
- pr1.cancel()
- se.cancel()
- se1.cancel()
- se2.cancel()
- se3.cancel()
- po.reload()
- pr2.load_from_db()
-
- if pr2.docstatus == 1 and frappe.db.get_value('Stock Ledger Entry',
- {'voucher_no': pr2.name, 'is_cancelled': 0}, 'name'):
- pr2.cancel()
-
- po.load_from_db()
- po.cancel()
def test_serial_no_supplier(self):
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 2ed7a04..be8508a 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -74,8 +74,7 @@
update_party_blanket_order(args, out)
-
- get_price_list_rate(args, item, out)
+ out.update(get_price_list_rate(args, item))
if args.customer and cint(args.is_pos):
out.update(get_pos_profile_item_details(args.company, args, update_data=True))
@@ -638,7 +637,10 @@
or item_group.get("default_supplier")
or brand.get("default_supplier"))
-def get_price_list_rate(args, item_doc, out):
+def get_price_list_rate(args, item_doc, out=None):
+ if out is None:
+ out = frappe._dict()
+
meta = frappe.get_meta(args.parenttype or args.doctype)
if meta.get_field("currency") or args.get('currency'):
@@ -651,17 +653,17 @@
if meta.get_field("currency"):
validate_conversion_rate(args, meta)
- price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0
+ price_list_rate = get_price_list_rate_for(args, item_doc.name)
# variant
- if not price_list_rate and item_doc.variant_of:
+ if price_list_rate is None and item_doc.variant_of:
price_list_rate = get_price_list_rate_for(args, item_doc.variant_of)
# insert in database
- if not price_list_rate:
+ if price_list_rate is None:
if args.price_list and args.rate:
insert_item_price(args)
- return {}
+ return out
out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \
/ flt(args.conversion_rate)
@@ -671,6 +673,8 @@
out.update(get_last_purchase_details(item_doc.name,
args.name, args.conversion_rate))
+ return out
+
def insert_item_price(args):
"""Insert Item Price if Price List and Price List Rate are specified and currency is the same"""
if frappe.db.get_value("Price List", args.price_list, "currency", cache=True) == args.currency \
@@ -1073,9 +1077,8 @@
}
def apply_price_list_on_item(args):
- item_details = frappe._dict()
item_doc = frappe.get_doc("Item", args.item_code)
- get_price_list_rate(args, item_doc, item_details)
+ item_details = get_price_list_rate(args, item_doc)
item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))