Merge pull request #19973 from deepeshgarg007/budget_variance_dimension
feat: Dynamic filters for dimensions in budget variance report
diff --git a/README.md b/README.md
index 64f8d67..ed57a17 100644
--- a/README.md
+++ b/README.md
@@ -13,9 +13,26 @@
</div>
-Includes: Accounting, Inventory, Manufacturing, CRM, Sales, Purchase, Project Management, HRMS. Requires MariaDB.
+ERPNext as a monolith includes the following areas for managing businesses:
-ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.
+1. [Accounting](https://erpnext.com/docs/user/manual/en/accounts)
+1. [Inventory](https://erpnext.com/docs/user/manual/en/stock)
+1. [CRM](https://erpnext.com/docs/user/manual/en/CRM)
+1. [Sales](https://erpnext.com/docs/user/manual/en/selling)
+1. [Purchase](https://erpnext.com/docs/user/manual/en/buying)
+1. [HRMS](https://erpnext.com/docs/user/manual/en/human-resources)
+1. [Project Management](https://erpnext.com/docs/user/manual/en/projects)
+1. [Support](https://erpnext.com/docs/user/manual/en/support)
+1. [Asset Management](https://erpnext.com/docs/user/manual/en/asset)
+1. [Quality Management](https://erpnext.com/docs/user/manual/en/quality-management)
+1. [Manufacturing](https://erpnext.com/docs/user/manual/en/manufacturing)
+1. [Website Management](https://erpnext.com/docs/user/manual/en/website)
+1. [Customize ERPNext](https://erpnext.com/docs/user/manual/en/customize-erpnext)
+1. [And More](https://erpnext.com/docs/user/manual/en/)
+
+ERPNext requires MariaDB.
+
+ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript.
- [User Guide](https://erpnext.com/docs/user)
- [Discussion Forum](https://discuss.erpnext.com/)
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 078e058..041e419 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -29,7 +29,6 @@
self.validate_and_set_fiscal_year()
self.pl_must_have_cost_center()
self.validate_cost_center()
- self.validate_dimensions_for_pl_and_bs()
if not self.flags.from_repost:
self.check_pl_account()
@@ -39,6 +38,7 @@
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
if not from_repost:
self.validate_account_details(adv_adj)
+ self.validate_dimensions_for_pl_and_bs()
check_freezing_date(self.posting_date, adv_adj)
validate_frozen_account(self.account, adv_adj)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index d6236cd..3604b60 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -190,7 +190,6 @@
if(jvd.reference_type==="Employee Advance") {
return {
filters: {
- 'status': ['=', 'Unpaid'],
'docstatus': 1
}
};
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index e25942c..8897337 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -968,7 +968,7 @@
# The date used to retreive the exchange rate here is the date passed
# in as an argument to this function.
- elif (not exchange_rate or exchange_rate==1) and account_currency and posting_date:
+ elif (not exchange_rate or flt(exchange_rate)==1) and account_currency and posting_date:
exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
else:
exchange_rate = 1
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index adf47ed..2192b7b 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -652,14 +652,16 @@
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
) {
if(total_positive_outstanding > total_negative_outstanding)
- frm.set_value("paid_amount",
- total_positive_outstanding - total_negative_outstanding);
+ if (!frm.doc.paid_amount)
+ frm.set_value("paid_amount",
+ total_positive_outstanding - total_negative_outstanding);
} else if (
total_negative_outstanding &&
total_positive_outstanding < total_negative_outstanding
) {
- frm.set_value("received_amount",
- total_negative_outstanding - total_positive_outstanding);
+ if (!frm.doc.received_amount)
+ frm.set_value("received_amount",
+ total_negative_outstanding - total_positive_outstanding);
}
}
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index f73fb10..29d8378 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -1,5 +1,4 @@
{
- "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:title",
@@ -390,8 +389,7 @@
"fieldname": "rate_or_discount",
"fieldtype": "Select",
"label": "Rate or Discount",
- "options": "\nRate\nDiscount Percentage\nDiscount Amount",
- "reqd": 1
+ "options": "\nRate\nDiscount Percentage\nDiscount Amount"
},
{
"default": "Grand Total",
@@ -440,7 +438,7 @@
},
{
"default": "0",
- "depends_on": "eval:!doc.mixed_conditions && doc.price_or_product_discount == 'Price'",
+ "depends_on": "eval:!doc.mixed_conditions && doc.apply_on != 'Transaction'",
"fieldname": "same_item",
"fieldtype": "Check",
"label": "Same Item"
@@ -556,8 +554,7 @@
],
"icon": "fa fa-gift",
"idx": 1,
- "links": [],
- "modified": "2019-12-13 15:48:48.331495",
+ "modified": "2019-12-18 17:29:22.957077",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index b99c07e..3c14819 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -47,6 +47,9 @@
if tocheck and not self.get(tocheck):
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
+ if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
+ throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
+
def validate_applicable_for_selling_or_buying(self):
if not self.selling and not self.buying:
throw(_("Atleast one of the Selling or Buying must be selected"))
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index d7e64cf..643de7d 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -382,21 +382,11 @@
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
// filter on Account
- if (doc.supplier) {
- return {
- filters: {
- 'account_type': 'Payable',
- 'is_group': 0,
- 'company': doc.company
- }
- }
- } else {
- return {
- filters: {
- 'report_type': 'Balance Sheet',
- 'is_group': 0,
- 'company': doc.company
- }
+ return {
+ filters: {
+ 'account_type': 'Payable',
+ 'is_group': 0,
+ 'company': doc.company
}
}
}
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 7f4ae3c..db6ac55 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -556,22 +556,11 @@
}
cur_frm.set_query("debit_to", function(doc) {
- // filter on Account
- if (doc.customer) {
- return {
- filters: {
- 'account_type': 'Receivable',
- 'is_group': 0,
- 'company': doc.company
- }
- }
- } else {
- return {
- filters: {
- 'report_type': 'Balance Sheet',
- 'is_group': 0,
- 'company': doc.company
- }
+ return {
+ filters: {
+ 'account_type': 'Receivable',
+ 'is_group': 0,
+ 'company': doc.company
}
}
});
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.json b/erpnext/accounts/doctype/share_transfer/share_transfer.json
index f17bf04..59a3053 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.json
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.json
@@ -188,7 +188,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-11-07 13:31:17.999744",
+ "modified": "2019-12-20 14:48:01.990600",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Share Transfer",
@@ -196,6 +196,7 @@
"permissions": [
{
"amend": 1,
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -221,6 +222,7 @@
"write": 1
},
{
+ "cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -230,6 +232,7 @@
"report": 1,
"role": "Accounts Manager",
"share": 1,
+ "submit": 1,
"write": 1
}
],
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index feb598a..bb1b7e3 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -90,8 +90,12 @@
else:
merged_gl_map.append(entry)
+ company = gl_map[0].company if gl_map else erpnext.get_default_company()
+ company_currency = erpnext.get_company_currency(company)
+ precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
+
# filter zero debit and credit entries
- merged_gl_map = filter(lambda x: flt(x.debit, 9)!=0 or flt(x.credit, 9)!=0, merged_gl_map)
+ merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map)
merged_gl_map = list(merged_gl_map)
return merged_gl_map
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 2c53f6e..f82146a 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -171,7 +171,7 @@
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
row.invoice_grand_total = row.invoiced
- if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
+ if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
# non-zero oustanding, we must consider this row
if self.is_invoice(row) and self.filters.based_on_payment_terms:
@@ -285,7 +285,7 @@
def set_party_details(self, row):
# customer / supplier name
- party_details = self.get_party_details(row.party)
+ party_details = self.get_party_details(row.party) or {}
row.update(party_details)
if self.filters.get(scrub(self.filters.party_type)):
row.currency = row.account_currency
diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py
index 0e2821a..afdd31d 100644
--- a/erpnext/accounts/report/sales_register/sales_register.py
+++ b/erpnext/accounts/report/sales_register/sales_register.py
@@ -38,32 +38,46 @@
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
- row = [
- inv.name, inv.posting_date, inv.customer, inv.customer_name
- ]
+ row = {
+ 'invoice': inv.name,
+ 'posting_date': inv.posting_date,
+ 'customer': inv.customer,
+ 'customer_name': inv.customer_name
+ }
if additional_query_columns:
for col in additional_query_columns:
- row.append(inv.get(col))
+ row.update({
+ col: inv.get(col)
+ })
- row +=[
- inv.get("customer_group"),
- inv.get("territory"),
- inv.get("tax_id"),
- inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])),
- inv.project, inv.owner, inv.remarks,
- ", ".join(sales_order), ", ".join(delivery_note),", ".join(cost_center),
- ", ".join(warehouse), company_currency
- ]
+ row.update({
+ 'customer_group': inv.get("customer_group"),
+ 'territory': inv.get("territory"),
+ 'tax_id': inv.get("tax_id"),
+ 'receivable_account': inv.debit_to,
+ 'mode_of_payment': ", ".join(mode_of_payments.get(inv.name, [])),
+ 'project': inv.project,
+ 'owner': inv.owner,
+ 'remarks': inv.remarks,
+ 'sales_order': ", ".join(sales_order),
+ 'delivery_note': ", ".join(delivery_note),
+ 'cost_center': ", ".join(cost_center),
+ 'warehouse': ", ".join(warehouse),
+ 'currency': company_currency
+ })
+
# map income values
base_net_total = 0
for income_acc in income_accounts:
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
base_net_total += income_amount
- row.append(income_amount)
+ row.update({
+ frappe.scrub(income_acc): income_amount
+ })
# net total
- row.append(base_net_total or inv.base_net_total)
+ row.update({'net_total': base_net_total or inv.base_net_total})
# tax account
total_tax = 0
@@ -72,10 +86,18 @@
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
total_tax += tax_amount
- row.append(tax_amount)
+ row.update({
+ frappe.scrub(tax_acc): tax_amount
+ })
# total tax, grand total, outstanding amount & rounded total
- row += [total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount]
+
+ row.update({
+ 'tax_total': total_tax,
+ 'grand_total': inv.base_grand_total,
+ 'rounded_total': inv.base_rounded_total,
+ 'outstanding_amount': inv.outstanding_amount
+ })
data.append(row)
@@ -84,19 +106,118 @@
def get_columns(invoice_list, additional_table_columns):
"""return columns based on filters"""
columns = [
- _("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
- _("Customer") + ":Link/Customer:120", _("Customer Name") + "::120"
+ {
+ 'label': _("Invoice"),
+ 'fieldname': 'invoice',
+ 'fieldtype': 'Link',
+ 'options': 'Sales Invoice',
+ 'width': 120
+ },
+ {
+ 'label': _("Posting Date"),
+ 'fieldname': 'posting_date',
+ 'fieldtype': 'Date',
+ 'width': 80
+ },
+ {
+ 'label': _("Customer"),
+ 'fieldname': 'customer',
+ 'fieldtype': 'Link',
+ 'options': 'Customer',
+ 'width': 120
+ },
+ {
+ 'label': _("Customer Name"),
+ 'fieldname': 'customer_name',
+ 'fieldtype': 'Data',
+ 'width': 120
+ },
]
if additional_table_columns:
columns += additional_table_columns
columns +=[
- _("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
- _("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
- _("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150",
- _("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
- _("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100",
+ {
+ 'label': _("Custmer Group"),
+ 'fieldname': 'customer_group',
+ 'fieldtype': 'Link',
+ 'options': 'Customer Group',
+ 'width': 120
+ },
+ {
+ 'label': _("Territory"),
+ 'fieldname': 'territory',
+ 'fieldtype': 'Link',
+ 'options': 'Territory',
+ 'width': 80
+ },
+ {
+ 'label': _("Tax Id"),
+ 'fieldname': 'tax_id',
+ 'fieldtype': 'Data',
+ 'width': 120
+ },
+ {
+ 'label': _("Receivable Account"),
+ 'fieldname': 'receivable_account',
+ 'fieldtype': 'Link',
+ 'options': 'Account',
+ 'width': 80
+ },
+ {
+ 'label': _("Mode Of Payment"),
+ 'fieldname': 'mode_of_payment',
+ 'fieldtype': 'Data',
+ 'width': 120
+ },
+ {
+ 'label': _("Project"),
+ 'fieldname': 'project',
+ 'fieldtype': 'Link',
+ 'options': 'project',
+ 'width': 80
+ },
+ {
+ 'label': _("Owner"),
+ 'fieldname': 'owner',
+ 'fieldtype': 'Data',
+ 'width': 150
+ },
+ {
+ 'label': _("Remarks"),
+ 'fieldname': 'remarks',
+ 'fieldtype': 'Data',
+ 'width': 150
+ },
+ {
+ 'label': _("Sales Order"),
+ 'fieldname': 'sales_order',
+ 'fieldtype': 'Link',
+ 'options': 'Sales Order',
+ 'width': 100
+ },
+ {
+ 'label': _("Delivery Note"),
+ 'fieldname': 'delivery_note',
+ 'fieldtype': 'Link',
+ 'options': 'Delivery Note',
+ 'width': 100
+ },
+ {
+ 'label': _("Cost Center"),
+ 'fieldname': 'cost_center',
+ 'fieldtype': 'Link',
+ 'options': 'Cost Center',
+ 'width': 100
+ },
+ {
+ 'label': _("Warehouse"),
+ 'fieldname': 'warehouse',
+ 'fieldtype': 'Link',
+ 'options': 'Warehouse',
+ 'width': 100
+ },
{
"fieldname": "currency",
"label": _("Currency"),
@@ -105,7 +226,10 @@
}
]
- income_accounts = tax_accounts = income_columns = tax_columns = []
+ income_accounts = []
+ tax_accounts = []
+ income_columns = []
+ tax_columns = []
if invoice_list:
income_accounts = frappe.db.sql_list("""select distinct income_account
@@ -119,14 +243,65 @@
and parent in (%s) order by account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
- income_columns = [(account + ":Currency/currency:120") for account in income_accounts]
+ for account in income_accounts:
+ income_columns.append({
+ "label": account,
+ "fieldname": frappe.scrub(account),
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ })
+
for account in tax_accounts:
if account not in income_accounts:
- tax_columns.append(account + ":Currency/currency:120")
+ tax_columns.append({
+ "label": account,
+ "fieldname": frappe.scrub(account),
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ })
- columns = columns + income_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
- [_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
- _("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
+ net_total_column = [{
+ "label": _("Net Total"),
+ "fieldname": "net_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ }]
+
+ total_columns = [
+ {
+ "label": _("Tax Total"),
+ "fieldname": "tax_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ },
+ {
+ "label": _("Grand Total"),
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ },
+ {
+ "label": _("Rounded Total"),
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ },
+ {
+ "label": _("Outstanding Amount"),
+ "fieldname": "outstanding_amount",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ }
+ ]
+
+ columns = columns + income_columns + net_total_column + tax_columns + total_columns
return columns, income_accounts, tax_accounts
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py
index 4e1822b..3a08baa 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.py
@@ -110,7 +110,7 @@
ORDER BY
asm.transaction_date asc
""", (d.asset, self.company, 'Receipt'), as_dict=1)
- if auto_gen_movement_entry[0].get('name') == self.name:
+ if auto_gen_movement_entry and auto_gen_movement_entry[0].get('name') == self.name:
frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \
auto generated for Asset {1}').format(self.name, d.asset))
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 5dce349..8cd44c7 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
@@ -47,6 +48,7 @@
"ignore_pricing_rule",
"sec_warehouse",
"set_warehouse",
+ "set_reserve_warehouse",
"col_break_warehouse",
"is_subcontracted",
"supplier_warehouse",
@@ -1039,12 +1041,20 @@
"fieldtype": "Link",
"label": "Tax Category",
"options": "Tax Category"
+ },
+ {
+ "depends_on": "supplied_items",
+ "fieldname": "set_reserve_warehouse",
+ "fieldtype": "Link",
+ "label": "Set Reserve Warehouse",
+ "options": "Warehouse"
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
- "modified": "2019-07-11 18:25:49.509343",
+ "links": [],
+ "modified": "2019-12-18 13:13:22.852412",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
index 9e201e3..af109ba 100644
--- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
@@ -138,7 +138,7 @@
# Check to see if any new scorecard periods are created
if make_all_scorecards(sc.name) > 0:
# Save the scorecard to update the score and standings
- sc.save()
+ frappe.get_doc('Supplier Scorecard', sc.name).save()
@frappe.whitelist()
diff --git a/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json
index d3adcb7..ce3d8cf 100644
--- a/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json
+++ b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json
@@ -12,9 +12,10 @@
}
],
"idx": 0,
- "image_src": "/assets/erpnext/images/illustrations/supplier-onboard.png",
+ "image_src": "",
+ "is_completed": 0,
"max_count": 3,
- "modified": "2019-12-03 22:53:50.552445",
+ "modified": "2019-12-09 17:54:18.452038",
"modified_by": "Administrator",
"name": "Add A Few Suppliers",
"owner": "Administrator",
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 3ec7aff..75b896b 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -265,16 +265,17 @@
fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
- raw_material_data = backflushed_raw_materials_map.get(item_key, {})
-
- consumed_qty = raw_material_data.get('qty', 0)
- consumed_serial_nos = raw_material_data.get('serial_nos', '')
- consumed_batch_nos = raw_material_data.get('batch_nos', '')
-
transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
for raw_material in transferred_raw_materials + non_stock_items:
+ rm_item_key = '{}{}'.format(raw_material.rm_item_code, item.purchase_order)
+ raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
+
+ consumed_qty = raw_material_data.get('qty', 0)
+ consumed_serial_nos = raw_material_data.get('serial_nos', '')
+ consumed_batch_nos = raw_material_data.get('batch_nos', '')
+
transferred_qty = raw_material.qty
rm_qty_to_be_consumed = transferred_qty - consumed_qty
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 7b4a4c9..5c31900 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -311,6 +311,7 @@
and sle.item_code = %(item_code)s
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
+ or batch.expiry_date like %(txt)s
or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2
{cond}
@@ -329,6 +330,7 @@
where batch.disabled = 0
and item = %(item_code)s
and (name like %(txt)s
+ or expiry_date like %(txt)s
or manufacturing_date like %(txt)s)
and docstatus < 2
{0}
diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py
index b6c4c47..f502930 100644
--- a/erpnext/crm/doctype/appointment/appointment.py
+++ b/erpnext/crm/doctype/appointment/appointment.py
@@ -11,7 +11,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import get_url
+from frappe.utils import get_url, getdate
from frappe.utils.verified_command import verify_request, get_signed_params
@@ -117,7 +117,7 @@
if self._assign:
return
available_agents = _get_agents_sorted_by_asc_workload(
- self.scheduled_time.date())
+ getdate(self.scheduled_time))
for agent in available_agents:
if(_check_agent_availability(agent, self.scheduled_time)):
agent = agent[0]
@@ -189,7 +189,7 @@
assigned_to = frappe.parse_json(appointment._assign)
if not assigned_to:
continue
- if (assigned_to[0] in agent_list) and appointment.scheduled_time.date() == date:
+ if (assigned_to[0] in agent_list) and getdate(appointment.scheduled_time) == date:
appointment_counter[assigned_to[0]] += 1
sorted_agent_list = appointment_counter.most_common()
sorted_agent_list.reverse()
diff --git a/erpnext/education/doctype/student/student.js b/erpnext/education/doctype/student/student.js
index b6e741c..1936dcb 100644
--- a/erpnext/education/doctype/student/student.js
+++ b/erpnext/education/doctype/student/student.js
@@ -31,7 +31,7 @@
frappe.ui.form.on('Student Guardian', {
guardians_add: function(frm){
frm.fields_dict['guardians'].grid.get_field('guardian').get_query = function(doc){
- var guardian_list = [];
+ let guardian_list = [];
if(!doc.__islocal) guardian_list.push(doc.guardian);
$.each(doc.guardians, function(idx, val){
if (val.guardian) guardian_list.push(val.guardian);
@@ -40,3 +40,18 @@
};
}
});
+
+
+frappe.ui.form.on('Student Sibling', {
+ siblings_add: function(frm){
+ frm.fields_dict['siblings'].grid.get_field('student').get_query = function(doc){
+ let sibling_list = [frm.doc.name];
+ $.each(doc.siblings, function(idx, val){
+ if (val.student && val.studying_in_same_institute == 'YES') {
+ sibling_list.push(val.student);
+ }
+ });
+ return { filters: [['Student', 'name', 'not in', sibling_list]] };
+ };
+ }
+});
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 2a5e6d8..c99ae7d 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -180,6 +180,7 @@
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"},
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"},
{"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"},
+ {"title": _("Appointment Booking"), "route": "/book_appointment"},
]
default_roles = [
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index 9291820..a45b41d 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -232,7 +232,6 @@
"reqd": 1
},
{
- "description": "You can enter any date manually",
"fieldname": "date_of_birth",
"fieldtype": "Date",
"label": "Date of Birth",
@@ -831,4 +830,4 @@
"sort_order": "DESC",
"title_field": "employee_name",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js
index 77a2bbc..ba62853 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.js
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.js
@@ -34,7 +34,7 @@
}
else if (
frm.doc.docstatus === 1
- && flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount)
+ && flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount)
&& frappe.model.can_create("Expense Claim")
) {
frm.add_custom_button(
@@ -45,6 +45,15 @@
__('Create')
);
}
+
+ if (frm.doc.docstatus === 1
+ && (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount))
+ && frappe.model.can_create("Journal Entry")) {
+
+ frm.add_custom_button(__("Return"), function() {
+ frm.trigger('make_return_entry');
+ }, __('Create'));
+ }
},
make_payment_entry: function(frm) {
@@ -83,6 +92,24 @@
});
},
+ make_return_entry: function(frm) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.employee_advance.employee_advance.make_return_entry',
+ args: {
+ 'employee_name': frm.doc.employee,
+ 'company': frm.doc.company,
+ 'employee_advance_name': frm.doc.name,
+ 'return_amount': flt(frm.doc.paid_amount - frm.doc.claimed_amount),
+ 'mode_of_payment': frm.doc.mode_of_payment,
+ 'advance_account': frm.doc.advance_account
+ },
+ callback: function(r) {
+ const doclist = frappe.model.sync(r.message);
+ frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
+ }
+ });
+ },
+
employee: function (frm) {
if (frm.doc.employee) {
return frappe.call({
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json
index 3597e76..d233a2b 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.json
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.json
@@ -1,737 +1,213 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2017-10-09 14:26:29.612365",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2017-10-09 14:26:29.612365",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "column_break_4",
+ "posting_date",
+ "department",
+ "section_break_8",
+ "purpose",
+ "column_break_11",
+ "advance_amount",
+ "paid_amount",
+ "due_advance_amount",
+ "claimed_amount",
+ "return_amount",
+ "section_break_7",
+ "status",
+ "company",
+ "amended_from",
+ "column_break_18",
+ "advance_account",
+ "mode_of_payment"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 0,
- "options": "HR-EAD-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "HR-EAD-.YYYY.-"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "label": "Employee Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Posting Date",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purpose",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Purpose",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "purpose",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Purpose",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "advance_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Advance Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "advance_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Advance Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "paid_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Paid Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "paid_amount",
+ "fieldtype": "Currency",
+ "label": "Paid Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:cur_frm.doc.employee",
- "fieldname": "due_advance_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Due Advance Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:cur_frm.doc.employee",
+ "fieldname": "due_advance_amount",
+ "fieldtype": "Currency",
+ "label": "Due Advance Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "claimed_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Claimed Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "claimed_amount",
+ "fieldtype": "Currency",
+ "label": "Claimed Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_7",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Employee Advance",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Employee Advance",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_18",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "advance_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Advance Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "advance_account",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Advance Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mode_of_payment",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mode of Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Mode of Payment",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment"
+ },
+ {
+ "fieldname": "return_amount",
+ "fieldtype": "Currency",
+ "label": "Returned Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-30 11:28:15.529649",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Employee Advance",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-15 19:04:07.044505",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Advance",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Expense Approver",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Expense Approver",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "employee,employee_name",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
+ ],
+ "search_fields": "employee,employee_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index 7813da7..7fe2ebc 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -7,6 +7,7 @@
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt, nowdate
+from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
class EmployeeAdvanceOverPayment(frappe.ValidationError):
pass
@@ -53,11 +54,25 @@
and party = %s
""", (self.name, self.employee), as_dict=1)[0].paid_amount
+ return_amount = frappe.db.sql("""
+ select name, ifnull(sum(credit_in_account_currency), 0) as return_amount
+ from `tabGL Entry`
+ where against_voucher_type = 'Employee Advance'
+ and voucher_type != 'Expense Claim'
+ and against_voucher = %s
+ and party_type = 'Employee'
+ and party = %s
+ """, (self.name, self.employee), as_dict=1)[0].return_amount
+
if flt(paid_amount) > self.advance_amount:
frappe.throw(_("Row {0}# Paid Amount cannot be greater than requested advance amount"),
EmployeeAdvanceOverPayment)
+ if flt(return_amount) > self.paid_amount - self.claimed_amount:
+ frappe.throw(_("Return amount cannot be greater unclaimed amount"))
+
self.db_set("paid_amount", paid_amount)
+ self.db_set("return_amount", return_amount)
self.set_status()
frappe.db.set_value("Employee Advance", self.name , "status", self.status)
@@ -88,8 +103,6 @@
@frappe.whitelist()
def make_bank_entry(dt, dn):
- from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
-
doc = frappe.get_doc(dt, dn)
payment_account = get_default_bank_cash_account(doc.company, account_type="Cash",
mode_of_payment=doc.mode_of_payment)
@@ -118,3 +131,33 @@
})
return je.as_dict()
+
+@frappe.whitelist()
+def make_return_entry(employee_name, company, employee_advance_name, return_amount, mode_of_payment, advance_account):
+ return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
+ je = frappe.new_doc('Journal Entry')
+ je.posting_date = nowdate()
+ je.voucher_type = 'Bank Entry'
+ je.company = company
+ je.remark = 'Return against Employee Advance: ' + employee_advance_name
+
+ je.append('accounts', {
+ 'account': advance_account,
+ 'credit_in_account_currency': return_amount,
+ 'reference_type': 'Employee Advance',
+ 'reference_name': employee_advance_name,
+ 'party_type': 'Employee',
+ 'party': employee_name,
+ 'is_advance': 'Yes'
+ })
+
+ je.append("accounts", {
+ "account": return_account.account,
+ "debit_in_account_currency": return_amount,
+ "account_currency": return_account.account_currency,
+ "account_type": return_account.account_type
+ })
+
+ return je.as_dict()
+
+
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
new file mode 100644
index 0000000..c3b4a3a
--- /dev/null
+++ b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
@@ -0,0 +1,19 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'employee_advance',
+ 'non_standard_fieldnames': {
+ 'Payment Entry': 'reference_name',
+ 'Journal Entry': 'reference_name'
+ },
+ 'transactions': [
+ {
+ 'items': ['Expense Claim']
+ },
+ {
+ 'items': ['Payment Entry', 'Journal Entry']
+ }
+ ]
+ }
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
index 996dcdf..c128567 100644
--- a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
@@ -7,6 +7,14 @@
frm.add_fetch("employee_onboarding_template", "department", "department");
frm.add_fetch("employee_onboarding_template", "designation", "designation");
frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
+
+ frm.set_query('job_offer', function () {
+ return {
+ filters: {
+ 'job_applicant': frm.doc.job_applicant
+ }
+ };
+ });
},
refresh: function(frm) {
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 570f2ef..e0bfc83 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -243,11 +243,11 @@
update_employee_advance_claimed_amount: function(frm) {
let amount_to_be_allocated = frm.doc.grand_total;
- $.each(frm.doc.advances || [], function(i, advance){
- if (amount_to_be_allocated >= advance.unclaimed_amount){
+ $.each(frm.doc.advances || [], function(i, advance) {
+ if (amount_to_be_allocated >= advance.unclaimed_amount) {
frm.doc.advances[i].allocated_amount = frm.doc.advances[i].unclaimed_amount;
amount_to_be_allocated -= advance.allocated_amount;
- } else{
+ } else {
frm.doc.advances[i].allocated_amount = amount_to_be_allocated;
amount_to_be_allocated = 0;
}
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index b5b6823..96baaab 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:14",
@@ -43,6 +44,7 @@
"accounting_dimensions_section",
"project",
"dimension_col_break",
+ "cost_center",
"more_details",
"status",
"amended_from",
@@ -365,7 +367,8 @@
"icon": "fa fa-money",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-11-09 14:13:08.964547",
+ "links": [],
+ "modified": "2019-12-14 23:52:05.388458",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim",
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index dfb0bb9..e01e7a4 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -43,9 +43,9 @@
}[cstr(self.docstatus or 0)]
paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount)
- precision = self.precision("total_sanctioned_amount")
+ precision = self.precision("grand_total")
if (self.is_paid or (flt(self.total_sanctioned_amount) > 0
- and flt(self.total_sanctioned_amount, precision) == flt(paid_amount, precision))) \
+ and flt(self.grand_total, precision) == flt(paid_amount, precision))) \
and self.docstatus == 1 and self.approval_status == 'Approved':
self.status = "Paid"
elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
@@ -322,7 +322,7 @@
@frappe.whitelist()
def get_advances(employee, advance_id=None):
if not advance_id:
- condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount'.format(frappe.db.escape(employee))
+ condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount + return_amount'.format(frappe.db.escape(employee))
else:
condition = 'name={0}'.format(frappe.db.escape(advance_id))
diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js
index c487797..d007e1a 100644
--- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js
+++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js
@@ -2,10 +2,10 @@
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Expense Claim Type", {
- refresh: function(frm){
- frm.fields_dict["accounts"].grid.get_field("default_account").get_query = function(frm, cdt, cdn){
+ refresh: function(frm) {
+ frm.fields_dict["accounts"].grid.get_field("default_account").get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
- return{
+ return {
filters: {
"is_group": 0,
"root_type": frm.doc.deferred_expense_account ? "Asset" : "Expense",
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 915cea1..5222712 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -54,9 +54,11 @@
self.create_leave_ledger_entry()
self.reload()
+ def before_cancel(self):
+ self.status = "Cancelled"
+
def on_cancel(self):
self.create_leave_ledger_entry(submit=False)
- self.status = "Cancelled"
# notify leave applier about cancellation
self.notify_employee()
self.cancel_attendance()
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index 2de01e6..dfd38eb 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -163,7 +163,7 @@
"""
cond = self.get_filter_condition()
return frappe.db.sql(""" select eld.loan_account, eld.loan,
- eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment
+ eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment,t1.employee
from
`tabSalary Slip` t1, `tabSalary Slip Loan` eld
where
@@ -246,6 +246,7 @@
accounts.append({
"account": acc,
"debit_in_account_currency": flt(amount, precision),
+ "party_type": '',
"cost_center": self.cost_center,
"project": self.project
})
@@ -257,6 +258,7 @@
"account": acc,
"credit_in_account_currency": flt(amount, precision),
"cost_center": self.cost_center,
+ "party_type": '',
"project": self.project
})
@@ -264,7 +266,9 @@
for data in loan_details:
accounts.append({
"account": data.loan_account,
- "credit_in_account_currency": data.principal_amount
+ "credit_in_account_currency": data.principal_amount,
+ "party_type": "Employee",
+ "party": data.employee
})
if data.interest_amount and not data.interest_income_account:
@@ -275,14 +279,17 @@
"account": data.interest_income_account,
"credit_in_account_currency": data.interest_amount,
"cost_center": self.cost_center,
- "project": self.project
+ "project": self.project,
+ "party_type": "Employee",
+ "party": data.employee
})
payable_amount -= flt(data.total_payment, precision)
# Payable amount
accounts.append({
"account": default_payroll_payable_account,
- "credit_in_account_currency": flt(payable_amount, precision)
+ "credit_in_account_currency": flt(payable_amount, precision),
+ "party_type": '',
})
journal_entry.set("accounts", accounts)
@@ -546,7 +553,6 @@
count += 1
if publish_progress:
frappe.publish_progress(count*100/len(salary_slips), title = _("Submitting Salary Slips..."))
-
if submitted_ss:
payroll_entry.make_accrual_jv_entry()
frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}")
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index dd34ef2..9f42c91 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -46,7 +46,7 @@
frm.trigger("toggle_fields");
frm.fields_dict['earnings'].grid.set_column_disp("default_amount", false);
frm.fields_dict['deductions'].grid.set_column_disp("default_amount", false);
-
+
if(frm.doc.docstatus === 1) {
frm.add_custom_button(__("Preview Salary Slip"), function() {
frm.trigger('preview_salary_slip');
@@ -119,47 +119,52 @@
},
callback: function(r) {
var employees = r.message;
- var d = new frappe.ui.Dialog({
- title: __("Preview Salary Slip"),
- fields: [
- {
- "label":__("Employee"),
- "fieldname":"employee",
- "fieldtype":"Select",
- "reqd": true,
- options: employees
- }, {
- fieldname:"fetch",
- "label":__("Show Salary Slip"),
- "fieldtype":"Button"
- }
- ]
- });
- d.get_input("fetch").on("click", function() {
- var values = d.get_values();
- if(!values) return;
- var print_format;
- frm.doc.salary_slip_based_on_timesheet ?
- print_format="Salary Slip based on Timesheet" :
- print_format="Salary Slip Standard";
-
- frappe.call({
- method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip",
- args: {
- source_name: frm.doc.name,
- employee: values.employee,
- as_print: 1,
- print_format: print_format,
- for_preview: 1
- },
- callback: function(r) {
- var new_window = window.open();
- new_window.document.write(r.message);
- // frappe.msgprint(r.message);
- }
+ if(!employees) return;
+ if (employees.length == 1){
+ frm.events.open_salary_slip(frm, employees[0]);
+ } else {
+ var d = new frappe.ui.Dialog({
+ title: __("Preview Salary Slip"),
+ fields: [
+ {
+ "label":__("Employee"),
+ "fieldname":"employee",
+ "fieldtype":"Select",
+ "reqd": true,
+ options: employees
+ }, {
+ fieldname:"fetch",
+ "label":__("Show Salary Slip"),
+ "fieldtype":"Button"
+ }
+ ]
});
- });
- d.show();
+ d.get_input("fetch").on("click", function() {
+ var values = d.get_values();
+ if(!values) return;
+ frm.events.open_salary_slip(frm, values.employee)
+
+ });
+ d.show();
+ }
+ }
+ });
+ },
+
+ open_salary_slip: function(frm, employee){
+ var print_format = frm.doc.salary_slip_based_on_timesheet ? "Salary Slip based on Timesheet" : "Salary Slip Standard";
+ frappe.call({
+ method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip",
+ args: {
+ source_name: frm.doc.name,
+ employee: employee,
+ as_print: 1,
+ print_format: print_format,
+ for_preview: 1
+ },
+ callback: function(r) {
+ var new_window = window.open();
+ new_window.document.write(r.message);
}
});
},
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.html b/erpnext/hr/notification/training_scheduled/training_scheduled.html
index b1aeb2c..374038a 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.html
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.html
@@ -1,9 +1,44 @@
-<h3>{{_("Training Event")}}</h3>
+<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div class="text-medium text-muted">
+ <span>{{_("Training Event:")}} {{ doc.event_name }}</span>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
-<p>{{ doc.introduction }}</p>
-
-<h4>{{_("Details")}}</h4>
-{{_("Event Name")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
-<br>{{_("Event Location")}}: {{ doc.location }}
-<br>{{_("Start Time")}}: {{ doc.start_time }}
-<br>{{_("End Time")}}: {{ doc.end_time }}
+<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div>
+ {{ doc.introduction }}
+ <ul class="list-unstyled" style="line-height: 1.7">
+ <li>{{_("Event Location")}}: <b>{{ doc.location }}</b></li>
+ {% set start = frappe.utils.get_datetime(doc.start_time) %}
+ {% set end = frappe.utils.get_datetime(doc.end_time) %}
+ {% if start.date() == end.date() %}
+ <li>{{_("Date")}}: <b>{{ start.strftime("%A, %d %b %Y") }}</b></li>
+ <li>
+ {{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
+ </li>
+ {% else %}
+ <li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ <li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ {% endif %}
+ <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
+ </ul>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
\ No newline at end of file
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.json b/erpnext/hr/notification/training_scheduled/training_scheduled.json
index c07e1a6..966b887 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.json
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.json
@@ -1,5 +1,7 @@
{
"attach_print": 0,
+ "channel": "Email",
+ "condition": "",
"creation": "2017-08-11 03:13:40.519614",
"days_in_advance": 0,
"docstatus": 0,
@@ -9,8 +11,8 @@
"event": "Submit",
"idx": 0,
"is_standard": 1,
- "message": "<h3>{{_(\"Training Event\")}}</h3>\n\n<p>{{ doc.introduction }}</p>\n\n<h4>{{_(\"Details\")}}</h4>\n{{_(\"Event Name\")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n<br>{{_(\"Event Location\")}}: {{ doc.location }}\n<br>{{_(\"Start Time\")}}: {{ doc.start_time }}\n<br>{{_(\"End Time\")}}: {{ doc.end_time }}\n",
- "modified": "2017-08-13 22:49:42.338881",
+ "message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div class=\"text-medium text-muted\">\n <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div>\n <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n <li>{{ doc.introduction }}</li>\n <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n <li>\n {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n </li>\n {% else %}\n <li>{{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n {% endif %}\n </ul>\n {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>",
+ "modified": "2019-11-29 15:38:31.805409",
"modified_by": "Administrator",
"module": "HR",
"name": "Training Scheduled",
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.md b/erpnext/hr/notification/training_scheduled/training_scheduled.md
index bcadf7d..374038a 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.md
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.md
@@ -1,9 +1,44 @@
-<h3>{{_("Training Event")}}</h3>
-<p>{{ message }}</p>
+<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div class="text-medium text-muted">
+ <span>{{_("Training Event:")}} {{ doc.event_name }}</span>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
-<h4>{{_("Details")}}</h4>
-{{_("Event Name")}}: <a href="{{ event_link }}">{{ name }}</a>
-<br>{{_("Event Location")}}: {{ location }}
-<br>{{_("Start Time")}}: {{ start_time }}
-<br>{{_("End Time")}}: {{ end_time }}
-<br>{{_("Attendance")}}: {{ attendance }}
+<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div>
+ {{ doc.introduction }}
+ <ul class="list-unstyled" style="line-height: 1.7">
+ <li>{{_("Event Location")}}: <b>{{ doc.location }}</b></li>
+ {% set start = frappe.utils.get_datetime(doc.start_time) %}
+ {% set end = frappe.utils.get_datetime(doc.end_time) %}
+ {% if start.date() == end.date() %}
+ <li>{{_("Date")}}: <b>{{ start.strftime("%A, %d %b %Y") }}</b></li>
+ <li>
+ {{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
+ </li>
+ {% else %}
+ <li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ <li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ {% endif %}
+ <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
+ </ul>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index 8ca8917..176ca2e 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -605,6 +605,8 @@
description: __('Max: {0}', [max]),
default: max
}, data => {
+ max += (max * (frm.doc.__onload.overproduction_percentage || 0.0)) / 100;
+
if (data.qty > max) {
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
reject();
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 227ef78..c4238ac 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -38,7 +38,7 @@
ms = frappe.get_doc("Manufacturing Settings")
self.set_onload("material_consumption", ms.material_consumption)
self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on)
-
+ self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
def validate(self):
self.validate_production_item()
@@ -657,8 +657,9 @@
wo_doc = frappe.new_doc("Work Order")
wo_doc.production_item = item
wo_doc.update(item_details)
- if qty > 0:
- wo_doc.qty = qty
+
+ if flt(qty) > 0:
+ wo_doc.qty = flt(qty)
wo_doc.get_items_and_operations_from_bom()
return wo_doc
diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
index c565b7e..5bb6e3f 100644
--- a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
+++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
@@ -27,6 +27,8 @@
tax_category = inter_state_category.name
for doctype in ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template'):
+ if not frappe.get_meta(doctype).has_field('is_inter_state'): continue
+
template = frappe.db.get_value(doctype, {'is_inter_state': 1, 'disabled': 0}, ['name'])
if template:
frappe.db.set_value(doctype, template, 'tax_category', tax_category)
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index 3a373a4..0993e69 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -52,7 +52,6 @@
def get_products_for_website(field_filters=None, attribute_filters=None, search=None):
-
if attribute_filters:
item_codes = get_item_codes_by_attributes(attribute_filters)
items_by_attributes = get_items([['name', 'in', item_codes]])
@@ -302,6 +301,8 @@
if isinstance(filters, dict):
filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()]
+ enabled_items_filter = get_conditions({ 'disabled': 0 }, 'and')
+
show_in_website_condition = ''
if products_settings.hide_variants:
show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and')
@@ -337,7 +338,8 @@
filter_condition = get_conditions(filters, 'and')
where_conditions = ' and '.join(
- [condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition]
+ [condition for condition in [enabled_items_filter, show_in_website_condition, \
+ search_condition, filter_condition] if condition]
)
left_joins = []
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 7083d69..45f2681 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -47,11 +47,11 @@
if not self.project or frappe.flags.in_test:
return
- expected_end_date = getdate(frappe.db.get_value("Project", self.project, "expected_end_date"))
+ expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date")
if expected_end_date:
- validate_project_dates(expected_end_date, self, "exp_start_date", "exp_end_date", "Expected")
- validate_project_dates(expected_end_date, self, "act_start_date", "act_end_date", "Actual")
+ validate_project_dates(getdate(expected_end_date), self, "exp_start_date", "exp_end_date", "Expected")
+ validate_project_dates(getdate(expected_end_date), self, "act_start_date", "act_end_date", "Actual")
def validate_status(self):
if self.status!=self.get_db_value("status") and self.status == "Completed":
@@ -278,4 +278,4 @@
frappe.throw(_("Task's {0} Start Date cannot be after Project's End Date.").format(actual_or_expected_date))
if task.get(task_end) and date_diff(project_end_date, getdate(task.get(task_end))) < 0:
- frappe.throw(_("Task's {0} End Date cannot be after Project's End Date.").format(actual_or_expected_date))
\ No newline at end of file
+ frappe.throw(_("Task's {0} End Date cannot be after Project's End Date.").format(actual_or_expected_date))
diff --git a/erpnext/public/images/illustrations/customers-onboard.png b/erpnext/public/images/illustrations/customers-onboard.png
deleted file mode 100644
index 4a517bd..0000000
--- a/erpnext/public/images/illustrations/customers-onboard.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/illustrations/desk-onboard.png b/erpnext/public/images/illustrations/desk-onboard.png
deleted file mode 100644
index 74b632d..0000000
--- a/erpnext/public/images/illustrations/desk-onboard.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/illustrations/letterhead-onboard.png b/erpnext/public/images/illustrations/letterhead-onboard.png
deleted file mode 100644
index fdfd16a..0000000
--- a/erpnext/public/images/illustrations/letterhead-onboard.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/illustrations/products-onboard.png b/erpnext/public/images/illustrations/products-onboard.png
deleted file mode 100644
index 2dee203..0000000
--- a/erpnext/public/images/illustrations/products-onboard.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/illustrations/supplier-onboard.png b/erpnext/public/images/illustrations/supplier-onboard.png
deleted file mode 100644
index 30335f2..0000000
--- a/erpnext/public/images/illustrations/supplier-onboard.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 1be4f27..6ca0958 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -500,6 +500,9 @@
() => {
var d = locals[cdt][cdn];
me.add_taxes_from_item_tax_template(d.item_tax_rate);
+ if (d.free_item_data) {
+ me.apply_product_discount(d.free_item_data);
+ }
},
() => me.frm.script_manager.trigger("price_list_rate", cdt, cdn),
() => me.toggle_conversion_factor(item),
@@ -1772,14 +1775,28 @@
}
},
+ set_reserve_warehouse: function() {
+ this.autofill_warehouse("reserve_warehouse");
+ },
+
set_warehouse: function() {
+ this.autofill_warehouse("warehouse");
+ },
+
+ autofill_warehouse : function (warehouse_field) {
+ // set warehouse in all child table rows
var me = this;
- if(this.frm.doc.set_warehouse) {
- $.each(this.frm.doc.items || [], function(i, item) {
- frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
+ let warehouse = (warehouse_field === "warehouse") ? me.frm.doc.set_warehouse : me.frm.doc.set_reserve_warehouse;
+ let child_table = (warehouse_field === "warehouse") ? me.frm.doc.items : me.frm.doc.supplied_items;
+ let doctype = (warehouse_field === "warehouse") ? (me.frm.doctype + " Item") : (me.frm.doctype + " Item Supplied");
+
+ if(warehouse) {
+ $.each(child_table || [], function(i, item) {
+ frappe.model.set_value(doctype, item.name, warehouse_field, warehouse);
});
}
},
+
coupon_code: function() {
var me = this;
frappe.run_serially([
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index d5a78d4..f363999 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -501,6 +501,7 @@
frm.doc[opts.child_docname].forEach(d => {
dialog.fields_dict.trans_items.df.data.push({
"docname": d.name,
+ "name": d.name,
"item_code": d.item_code,
"qty": d.qty,
"rate": d.rate,
diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py
index a362269..f326fe0 100644
--- a/erpnext/regional/report/gstr_2/gstr_2.py
+++ b/erpnext/regional/report/gstr_2/gstr_2.py
@@ -44,12 +44,16 @@
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
for rate, items in items_based_on_rate.items():
- row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
- tax_amount = taxable_value * rate / 100
- if inv in self.igst_invoices:
- row += [tax_amount, 0, 0]
+ if inv not in self.igst_invoices:
+ rate = rate / 2
+ row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
+ tax_amount = taxable_value * rate / 100
+ row += [0, tax_amount, tax_amount]
else:
- row += [0, tax_amount / 2, tax_amount / 2]
+ row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
+ tax_amount = taxable_value * rate / 100
+ row += [tax_amount, 0, 0]
+
row += [
self.invoice_cess.get(inv),
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index cca8efe..aa1b92f 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -5,13 +5,13 @@
setup: function(frm) {
frm.make_methods = {
- 'Quotation': () => erpnext.utils.create_new_doc('Quotation', {
- 'quotation_to': frm.doc.doctype,
- 'party_name': frm.doc.name
+ 'Quotation': () => frappe.model.open_mapped_doc({
+ method: "erpnext.selling.doctype.customer.customer.make_quotation",
+ frm: cur_frm
}),
- 'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', {
- 'opportunity_from': frm.doc.doctype,
- 'party_name': frm.doc.name
+ 'Opportunity': () => frappe.model.open_mapped_doc({
+ method: "erpnext.selling.doctype.customer.customer.make_opportunity",
+ frm: cur_frm
})
}
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 57308ce..136236c 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -12,6 +12,7 @@
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
from frappe.model.rename_doc import update_linked_doctypes
+from frappe.model.mapper import get_mapped_doc
class Customer(TransactionBase):
def get_feed(self):
@@ -239,6 +240,66 @@
contact.insert()
@frappe.whitelist()
+def make_quotation(source_name, target_doc=None):
+
+ def set_missing_values(source, target):
+ _set_missing_values(source, target)
+
+ target_doc = get_mapped_doc("Customer", source_name,
+ {"Customer": {
+ "doctype": "Quotation",
+ "field_map": {
+ "name":"party_name"
+ }
+ }}, target_doc, set_missing_values)
+
+ target_doc.quotation_to = "Customer"
+ target_doc.run_method("set_missing_values")
+ target_doc.run_method("set_other_charges")
+ target_doc.run_method("calculate_taxes_and_totals")
+
+ price_list = frappe.get_value("Customer", source_name, 'default_price_list')
+ if price_list:
+ target_doc.selling_price_list = price_list
+
+ return target_doc
+
+@frappe.whitelist()
+def make_opportunity(source_name, target_doc=None):
+ def set_missing_values(source, target):
+ _set_missing_values(source, target)
+
+ target_doc = get_mapped_doc("Customer", source_name,
+ {"Customer": {
+ "doctype": "Opportunity",
+ "field_map": {
+ "name": "party_name",
+ "doctype": "opportunity_from",
+ }
+ }}, target_doc, set_missing_values)
+
+ return target_doc
+
+def _set_missing_values(source, target):
+ address = frappe.get_all('Dynamic Link', {
+ 'link_doctype': source.doctype,
+ 'link_name': source.name,
+ 'parenttype': 'Address',
+ }, ['parent'], limit=1)
+
+ contact = frappe.get_all('Dynamic Link', {
+ 'link_doctype': source.doctype,
+ 'link_name': source.name,
+ 'parenttype': 'Contact',
+ }, ['parent'], limit=1)
+
+ if address:
+ target.customer_address = address[0].parent
+
+ if contact:
+ target.contact_person = contact[0].parent
+
+@frappe.whitelist()
def get_loyalty_programs(doc):
''' returns applicable loyalty programs for a customer '''
from frappe.desk.treeview import get_children
diff --git a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
index f39fea4..92d00bc 100644
--- a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
+++ b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
@@ -12,9 +12,10 @@
}
],
"idx": 0,
- "image_src": "/assets/erpnext/images/illustrations/customers-onboard.png",
+ "image_src": "",
+ "is_completed": 0,
"max_count": 3,
- "modified": "2019-12-03 22:54:28.959549",
+ "modified": "2019-12-09 17:54:01.686006",
"modified_by": "Administrator",
"name": "Add A Few Customers",
"owner": "Administrator",
diff --git a/erpnext/setup/doctype/company/company_list.js b/erpnext/setup/doctype/company/company_list.js
new file mode 100644
index 0000000..0172865
--- /dev/null
+++ b/erpnext/setup/doctype/company/company_list.js
@@ -0,0 +1,10 @@
+frappe.listview_settings['Company'] = {
+ onload: () => {
+ frappe.breadcrumbs.add({
+ type: 'Custom',
+ module: __('Accounts'),
+ label: __('Accounts'),
+ route: '#modules/Accounts'
+ });
+ }
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index 637e655..1503adb 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -106,7 +106,10 @@
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
def delete_communications(doctype, company_name, company_fieldname):
- frappe.db.sql("""
- DELETE FROM `tabCommunication` WHERE reference_doctype = %s AND
- EXISTS (SELECT name FROM `tab{0}` WHERE {1} = %s AND `tabCommunication`.reference_name = name)
- """.format(doctype, company_fieldname), (doctype, company_name))
+ reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
+ reference_doc_names = [r.name for r in reference_docs]
+
+ communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
+ communication_names = [c.name for c in communications]
+
+ frappe.delete_doc("Communication", communication_names)
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 8d9c23a..1664b66 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -88,6 +88,57 @@
self.delete_mode_of_payment(template)
frappe.delete_doc("Company", template)
+ def test_delete_communication(self):
+ from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
+ company = create_child_company()
+ lead = create_test_lead_in_company(company)
+ communication = create_company_communication("Lead", lead)
+ delete_communications("Lead", "Test Company", "company")
+ self.assertFalse(frappe.db.exists("Communcation", communication))
+ self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
+
def delete_mode_of_payment(self, company):
frappe.db.sql(""" delete from `tabMode of Payment Account`
where company =%s """, (company))
+
+def create_company_communication(doctype, docname):
+ comm = frappe.get_doc({
+ "doctype": "Communication",
+ "communication_type": "Communication",
+ "content": "Deduplication of Links",
+ "communication_medium": "Email",
+ "reference_doctype":doctype,
+ "reference_name":docname
+ })
+ comm.insert()
+
+def create_child_company():
+ child_company = frappe.db.exists("Company", "Test Company")
+ if not child_company:
+ child_company = frappe.get_doc({
+ "doctype":"Company",
+ "company_name":"Test Company",
+ "abbr":"test_company",
+ "default_currency":"INR"
+ })
+ child_company.insert()
+ else:
+ child_company = frappe.get_doc("Company", child_company)
+
+ return child_company.name
+
+def create_test_lead_in_company(company):
+ lead = frappe.db.exists("Lead", "Test Lead in new company")
+ if not lead:
+ lead = frappe.get_doc({
+ "doctype": "Lead",
+ "lead_name": "Test Lead in new company",
+ "scompany": company
+ })
+ lead.insert()
+ else:
+ lead = frappe.get_doc("Lead", lead)
+ lead.company = company
+ lead.save()
+ return lead.name
+
diff --git "a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json" "b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json"
index bf330d0..f00dc94 100644
--- "a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json"
+++ "b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json"
@@ -7,10 +7,10 @@
"domains": [],
"help_links": [],
"idx": 0,
- "image_src": "/assets/erpnext/images/illustrations/desk-onboard.png",
+ "image_src": "",
"is_completed": 0,
"max_count": 3,
- "modified": "2019-12-04 19:21:39.995776",
+ "modified": "2019-12-09 17:53:53.849953",
"modified_by": "Administrator",
"name": "Welcome back to ERPNext!",
"owner": "Administrator",
diff --git "a/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json" "b/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json"
index 4ea6985..37eb67b 100644
--- "a/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json"
+++ "b/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json"
@@ -7,13 +7,14 @@
"domains": [],
"help_links": [],
"idx": 0,
- "image_src": "/assets/erpnext/images/illustrations/desk-onboard.png",
+ "image_src": "",
+ "is_completed": 0,
"max_count": 0,
- "modified": "2019-12-03 22:49:12.871260",
+ "modified": "2019-12-22 21:26:28.414597",
"modified_by": "Administrator",
"name": "Welcome to ERPNext!",
"owner": "Administrator",
- "slide_desc": "Setting up an ERP can be overwhelming. But don't worry, we have got your back!\nLet's setup your company.\nThis wizard will help you onboard to ERPNext in a short time!",
+ "slide_desc": "<div class=\"text center\">Setting up an ERP can be overwhelming. But don't worry, we have got your back! This wizard will help you onboard to ERPNext in a short time!</div>",
"slide_fields": [],
"slide_module": "Setup",
"slide_order": 1,
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 3e890b4..1149254 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -261,15 +261,14 @@
def get_batches(item_code, warehouse, qty=1, throw=False):
- batches = frappe.db.sql(
- 'select batch_id, sum(actual_qty) as qty from `tabBatch` join `tabStock Ledger Entry` ignore index (item_code, warehouse) '
- 'on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )'
- 'where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s '
- 'and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
- 'group by batch_id '
- 'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
- (item_code, warehouse),
- as_dict=True
- )
- return batches
+ return frappe.db.sql("""
+ select batch_id, sum(`tabStock Ledger Entry`.actual_qty) as qty
+ from `tabBatch`
+ join `tabStock Ledger Entry` ignore index (item_code, warehouse)
+ on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )
+ where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s
+ and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)
+ group by batch_id
+ order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC'
+ """, (item_code, warehouse), as_dict=True)
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 060175f..691f92f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -88,7 +88,7 @@
if getdate(self.posting_date) > getdate(nowdate()):
throw(_("Posting Date cannot be future date"))
-
+
def validate_cwip_accounts(self):
for item in self.get('items'):
if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
@@ -362,7 +362,7 @@
# valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item
self.update_assets(item, item.valuation_rate)
return gl_entries
-
+
def add_asset_gl_entries(self, item, gl_entries):
arbnb_account = self.get_company_default("asset_received_but_not_billed")
# This returns category's cwip account if not then fallback to company's default cwip account
@@ -395,7 +395,7 @@
"credit_in_account_currency": (base_asset_amount
if asset_rbnb_currency == self.company_currency else asset_amount)
}, 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")
if not is_cwip_accounting_enabled(item.asset_category):
@@ -404,7 +404,7 @@
else:
# This returns company's default cwip account
asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
-
+
gl_entries.append(self.get_gl_dict({
"account": expenses_included_in_asset_valuation,
"against": asset_account,
@@ -424,7 +424,7 @@
}, item=item))
def update_assets(self, item, valuation_rate):
- assets = frappe.db.get_all('Asset',
+ assets = frappe.db.get_all('Asset',
filters={ 'purchase_receipt': self.name, 'item_code': item.item_code }
)
@@ -610,27 +610,36 @@
return doclist
def get_item_account_wise_additional_cost(purchase_document):
- landed_cost_voucher = frappe.get_value("Landed Cost Purchase Receipt",
- {"receipt_document": purchase_document, "docstatus": 1}, "parent")
+ landed_cost_vouchers = frappe.get_all("Landed Cost Purchase Receipt", fields=["parent"],
+ filters = {"receipt_document": purchase_document, "docstatus": 1})
- if not landed_cost_voucher:
+ if not landed_cost_vouchers:
return
total_item_cost = 0
item_account_wise_cost = {}
- landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", landed_cost_voucher)
- based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+ item_cost_allocated = []
- for item in landed_cost_voucher_doc.items:
- total_item_cost += item.get(based_on_field)
+ for lcv in landed_cost_vouchers:
+ landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
+ based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
- for item in landed_cost_voucher_doc.items:
- if item.receipt_document == purchase_document:
- for account in landed_cost_voucher_doc.taxes:
- item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
- item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
- item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
- account.amount * item.get(based_on_field) / total_item_cost
+ for item in landed_cost_voucher_doc.items:
+ if item.purchase_receipt_item not in item_cost_allocated:
+ total_item_cost += item.get(based_on_field)
+ item_cost_allocated.append(item.purchase_receipt_item)
+
+ for lcv in landed_cost_vouchers:
+ landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
+ based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
+ for item in landed_cost_voucher_doc.items:
+ if item.receipt_document == purchase_document:
+ for account in landed_cost_voucher_doc.taxes:
+ item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
+ account.amount * item.get(based_on_field) / total_item_cost
return item_account_wise_cost
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 00d27ef..1b9660e 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -372,7 +372,7 @@
elif d.t_warehouse and not d.basic_rate:
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
self.doctype, self.name, d.allow_zero_valuation_rate,
- currency=erpnext.get_company_currency(self.company))
+ currency=erpnext.get_company_currency(self.company), company=self.company)
def set_actual_qty(self):
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
diff --git a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
index 27a3062..5ee3167 100644
--- a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
+++ b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
@@ -7,9 +7,10 @@
"domains": [],
"help_links": [],
"idx": 0,
- "image_src": "/assets/erpnext/images/illustrations/products-onboard.png",
+ "image_src": "",
+ "is_completed": 0,
"max_count": 3,
- "modified": "2019-12-03 22:54:07.558632",
+ "modified": "2019-12-09 17:54:09.602885",
"modified_by": "Administrator",
"name": "Add A Few Products You Buy Or Sell",
"owner": "Administrator",
diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js
index c8dd501..262e31b 100644
--- a/erpnext/www/book_appointment/index.js
+++ b/erpnext/www/book_appointment/index.js
@@ -24,20 +24,15 @@
}
function setup_timezone_selector() {
- /**
- * window.timezones is a dictionary with the following structure
- * { IANA name: Pretty name}
- * For example : { Asia/Kolkata : "India Time - Asia/Kolkata"}
- */
let timezones_element = document.getElementById('appointment-timezone');
- let offset = new Date().getTimezoneOffset();
- Object.keys(window.timezones).forEach((timezone) => {
+ let local_timezone = moment.tz.guess()
+ window.timezones.forEach(timezone => {
let opt = document.createElement('option');
opt.value = timezone;
- if (timezone == moment.tz.guess()) {
+ if (timezone == local_timezone) {
opt.selected = true;
}
- opt.innerHTML = window.timezones[timezone]
+ opt.innerHTML = timezone;
timezones_element.appendChild(opt)
});
}
@@ -114,7 +109,7 @@
timeslot_div.classList.add('unavailable')
}
timeslot_div.innerHTML = get_slot_layout(start_time);
- timeslot_div.id = timeslot.time.substr(11, 20);
+ timeslot_div.id = timeslot.time.substring(11, 19);
timeslot_div.addEventListener('click', select_time);
return timeslot_div
}
diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py
index 5b60dd5..7bfac89 100644
--- a/erpnext/www/book_appointment/index.py
+++ b/erpnext/www/book_appointment/index.py
@@ -25,18 +25,8 @@
@frappe.whitelist(allow_guest=True)
def get_timezones():
- from babel.dates import get_timezone, get_timezone_name, Locale
- from frappe.utils.momentjs import get_all_timezones
-
- translated_dict = {}
- locale = Locale.parse(frappe.local.lang, sep="-")
-
- for tz in get_all_timezones():
- timezone_name = get_timezone_name(get_timezone(tz), locale=locale, width='short')
- if timezone_name:
- translated_dict[tz] = timezone_name + ' - ' + tz
-
- return translated_dict
+ import pytz
+ return pytz.all_timezones
@frappe.whitelist(allow_guest=True)
def get_appointment_slots(date, timezone):
@@ -90,7 +80,7 @@
@frappe.whitelist(allow_guest=True)
def create_appointment(date, time, tz, contact):
- format_string = '%Y-%m-%d %H:%M:%S%z'
+ format_string = '%Y-%m-%d %H:%M:%S'
scheduled_time = datetime.datetime.strptime(date + " " + time, format_string)
# Strip tzinfo from datetime objects since it's handled by the doctype
scheduled_time = scheduled_time.replace(tzinfo = None)