diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index ce1ed336d0c..81ff6a52db1 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -50,13 +50,15 @@ class AccountingDimension(Document): if frappe.flags.in_test: make_dimension_in_accounting_doctypes(doc=self) else: - frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self, queue="long") + frappe.enqueue( + make_dimension_in_accounting_doctypes, doc=self, queue="long", enqueue_after_commit=True + ) def on_trash(self): if frappe.flags.in_test: delete_accounting_dimension(doc=self) else: - frappe.enqueue(delete_accounting_dimension, doc=self, queue="long") + frappe.enqueue(delete_accounting_dimension, doc=self, queue="long", enqueue_after_commit=True) def set_fieldname_and_label(self): if not self.label: diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.js b/erpnext/accounts/doctype/bank_clearance/bank_clearance.js index 71f2dcca1b2..7af635bdd60 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.js +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.js @@ -41,7 +41,7 @@ frappe.ui.form.on("Bank Clearance", { frm.trigger("get_payment_entries") ); - frm.change_custom_button_type('Get Payment Entries', null, 'primary'); + frm.change_custom_button_type(__('Get Payment Entries'), null, 'primary'); }, update_clearance_date: function(frm) { @@ -53,8 +53,8 @@ frappe.ui.form.on("Bank Clearance", { frm.refresh_fields(); if (!frm.doc.payment_entries.length) { - frm.change_custom_button_type('Get Payment Entries', null, 'primary'); - frm.change_custom_button_type('Update Clearance Date', null, 'default'); + frm.change_custom_button_type(__('Get Payment Entries'), null, 'primary'); + frm.change_custom_button_type(__('Update Clearance Date'), null, 'default'); } } }); @@ -72,8 +72,8 @@ frappe.ui.form.on("Bank Clearance", { frm.trigger("update_clearance_date") ); - frm.change_custom_button_type('Get Payment Entries', null, 'default'); - frm.change_custom_button_type('Update Clearance Date', null, 'primary'); + frm.change_custom_button_type(__('Get Payment Entries'), null, 'default'); + frm.change_custom_button_type(__('Update Clearance Date'), null, 'primary'); } } }); diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index d9772614411..0647a5ccf38 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -81,7 +81,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frm.add_custom_button(__('Get Unreconciled Entries'), function() { frm.trigger("make_reconciliation_tool"); }); - frm.change_custom_button_type('Get Unreconciled Entries', null, 'primary'); + frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'primary'); }, diff --git a/erpnext/accounts/doctype/dunning/dunning.json b/erpnext/accounts/doctype/dunning/dunning.json index d55bfd1ac4c..2a32b99f428 100644 --- a/erpnext/accounts/doctype/dunning/dunning.json +++ b/erpnext/accounts/doctype/dunning/dunning.json @@ -245,6 +245,7 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -315,10 +316,11 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-08-03 18:55:43.683053", + "modified": "2023-06-03 16:24:01.677026", "modified_by": "Administrator", "module": "Accounts", "name": "Dunning", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { @@ -365,6 +367,7 @@ ], "sort_field": "modified", "sort_order": "ASC", + "states": [], "title_field": "customer_name", "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 34a753f267b..74fd5596123 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -952,6 +952,7 @@ class JournalEntry(AccountsController): blank_row.debit_in_account_currency = abs(diff) blank_row.debit = abs(diff) + self.set_total_debit_credit() self.validate_total_debit_and_credit() @frappe.whitelist() diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index 08d38dde474..22836776345 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -65,22 +65,22 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo this.frm.add_custom_button(__('Get Unreconciled Entries'), () => this.frm.trigger("get_unreconciled_entries") ); - this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'primary'); + this.frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'primary'); } if (this.frm.doc.invoices.length && this.frm.doc.payments.length) { this.frm.add_custom_button(__('Allocate'), () => this.frm.trigger("allocate") ); - this.frm.change_custom_button_type('Allocate', null, 'primary'); - this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default'); + this.frm.change_custom_button_type(__('Allocate'), null, 'primary'); + this.frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'default'); } if (this.frm.doc.allocation.length) { this.frm.add_custom_button(__('Reconcile'), () => this.frm.trigger("reconcile") ); - this.frm.change_custom_button_type('Reconcile', null, 'primary'); - this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default'); - this.frm.change_custom_button_type('Allocate', null, 'default'); + this.frm.change_custom_button_type(__('Reconcile'), null, 'primary'); + this.frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'default'); + this.frm.change_custom_button_type(__('Allocate'), null, 'default'); } // check for any running reconciliation jobs diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index cc2b9420cc2..081fe70354d 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -6,7 +6,6 @@ import frappe from frappe import _, msgprint, qb from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn -from frappe.query_builder.functions import IfNull from frappe.utils import flt, get_link_to_form, getdate, nowdate, today import erpnext @@ -127,12 +126,29 @@ class PaymentReconciliation(Document): return list(journal_entries) + def get_return_invoices(self): + voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice" + doc = qb.DocType(voucher_type) + self.return_invoices = ( + qb.from_(doc) + .select( + ConstantColumn(voucher_type).as_("voucher_type"), + doc.name.as_("voucher_no"), + doc.return_against, + ) + .where( + (doc.docstatus == 1) + & (doc[frappe.scrub(self.party_type)] == self.party) + & (doc.is_return == 1) + ) + .run(as_dict=True) + ) + def get_dr_or_cr_notes(self): self.build_qb_filter_conditions(get_return_invoices=True) ple = qb.DocType("Payment Ledger Entry") - voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice" if erpnext.get_party_account_type(self.party_type) == "Receivable": self.common_filter_conditions.append(ple.account_type == "Receivable") @@ -140,19 +156,10 @@ class PaymentReconciliation(Document): self.common_filter_conditions.append(ple.account_type == "Payable") self.common_filter_conditions.append(ple.account == self.receivable_payable_account) - # get return invoices - doc = qb.DocType(voucher_type) - return_invoices = ( - qb.from_(doc) - .select(ConstantColumn(voucher_type).as_("voucher_type"), doc.name.as_("voucher_no")) - .where( - (doc.docstatus == 1) - & (doc[frappe.scrub(self.party_type)] == self.party) - & (doc.is_return == 1) - & (IfNull(doc.return_against, "") == "") - ) - .run(as_dict=True) - ) + self.get_return_invoices() + return_invoices = [ + x for x in self.return_invoices if x.return_against == None or x.return_against == "" + ] outstanding_dr_or_cr = [] if return_invoices: @@ -204,6 +211,9 @@ class PaymentReconciliation(Document): accounting_dimensions=self.accounting_dimension_filter_conditions, ) + cr_dr_notes = [x.voucher_no for x in self.return_invoices] + non_reconciled_invoices = [x for x in non_reconciled_invoices if x.voucher_no not in cr_dr_notes] + if self.invoice_limit: non_reconciled_invoices = non_reconciled_invoices[: self.invoice_limit] diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 9d636adc57a..641f4528c53 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -44,6 +44,7 @@ class PeriodClosingVoucher(AccountsController): voucher_type="Period Closing Voucher", voucher_no=self.name, queue="long", + enqueue_after_commit=True, ) frappe.msgprint( _("The GL Entries will be cancelled in the background, it can take a few minutes."), alert=True diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json index eedaaaf338b..f6047079ff8 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json @@ -442,6 +442,7 @@ "fieldtype": "Data", "hidden": 1, "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -1554,11 +1555,10 @@ "icon": "fa fa-file-text", "is_submittable": 1, "links": [], - "modified": "2022-09-30 03:49:50.455199", + "modified": "2023-06-03 16:23:41.083409", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice", - "name_case": "Title Case", "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index b36f33be3bf..67dbe09d0db 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -158,7 +158,7 @@ def get_customers_based_on_territory_or_customer_group(customer_collection, coll return frappe.get_list( "Customer", fields=["name", "customer_name", "email_id"], - filters=[[fields_dict[customer_collection], "IN", selected]], + filters=[["disabled", "=", 0], [fields_dict[customer_collection], "IN", selected]], ) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 60f9d62bf21..0c18f5edb5b 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -443,12 +443,14 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { "fieldname": "contact_email", "fieldtype": "Small Text", "label": "Contact Email", + "options": "Email", "print_hide": 1, "read_only": 1 }, @@ -1364,12 +1366,12 @@ "depends_on": "eval:doc.update_stock && doc.is_internal_supplier", "fieldname": "set_from_warehouse", "fieldtype": "Link", + "ignore_user_permissions": 1, "label": "Set From Warehouse", "no_copy": 1, "options": "Warehouse", "print_hide": 1, "print_width": "50px", - "ignore_user_permissions": 1, "width": "50px" }, { @@ -1573,7 +1575,7 @@ "idx": 204, "is_submittable": 1, "links": [], - "modified": "2023-04-29 12:57:50.832598", + "modified": "2023-06-03 16:21:54.637245", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 6a65b30ceb0..7b68dd41d93 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -520,6 +520,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -2154,7 +2155,7 @@ "link_fieldname": "consolidated_invoice" } ], - "modified": "2023-04-28 14:15:59.901154", + "modified": "2023-06-03 16:22:16.219333", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 1f2d9803739..d8c037089d3 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -3,8 +3,10 @@ import frappe -from frappe import _ +from frappe import _, qb from frappe.model.document import Document +from frappe.query_builder import Criterion +from frappe.query_builder.functions import Abs, Sum from frappe.utils import cint, getdate @@ -346,26 +348,33 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): def get_advance_vouchers( parties, company=None, from_date=None, to_date=None, party_type="Supplier" ): - # for advance vouchers, debit and credit is reversed - dr_or_cr = "debit" if party_type == "Supplier" else "credit" + """ + Use Payment Ledger to fetch unallocated Advance Payments + """ - filters = { - dr_or_cr: [">", 0], - "is_opening": "No", - "is_cancelled": 0, - "party_type": party_type, - "party": ["in", parties], - } + ple = qb.DocType("Payment Ledger Entry") - if party_type == "Customer": - filters.update({"against_voucher": ["is", "not set"]}) + conditions = [] + + conditions.append(ple.amount.lt(0)) + conditions.append(ple.delinked == 0) + conditions.append(ple.party_type == party_type) + conditions.append(ple.party.isin(parties)) + conditions.append(ple.voucher_no == ple.against_voucher_no) if company: - filters["company"] = company - if from_date and to_date: - filters["posting_date"] = ["between", (from_date, to_date)] + conditions.append(ple.company == company) - return frappe.get_all("GL Entry", filters=filters, distinct=1, pluck="voucher_no") or [""] + if from_date and to_date: + conditions.append(ple.posting_date[from_date:to_date]) + + advances = ( + qb.from_(ple).select(ple.voucher_no).distinct().where(Criterion.all(conditions)).run(as_list=1) + ) + if advances: + advances = [x[0] for x in advances] + + return advances def get_taxes_deducted_on_advances_allocated(inv, tax_details): @@ -499,6 +508,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers): def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): tcs_amount = 0 + ple = qb.DocType("Payment Ledger Entry") # sum of debit entries made from sales invoices invoiced_amt = ( @@ -516,18 +526,20 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): ) # sum of credit entries made from PE / JV with unset 'against voucher' + + conditions = [] + conditions.append(ple.amount.lt(0)) + conditions.append(ple.delinked == 0) + conditions.append(ple.party.isin(parties)) + conditions.append(ple.voucher_no == ple.against_voucher_no) + conditions.append(ple.company == inv.company) + + advances = ( + qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run(as_list=1) + ) + advance_amt = ( - frappe.db.get_value( - "GL Entry", - { - "is_cancelled": 0, - "party": ["in", parties], - "company": inv.company, - "voucher_no": ["in", adv_vouchers], - }, - "sum(credit)", - ) - or 0.0 + qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run()[0][0] or 0.0 ) # sum of credit entries made from sales invoice diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index bc4f6709fca..4580b13613c 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -152,6 +152,60 @@ class TestTaxWithholdingCategory(unittest.TestCase): for d in reversed(invoices): d.cancel() + def test_tcs_on_unallocated_advance_payments(self): + frappe.db.set_value( + "Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS" + ) + + vouchers = [] + + # create advance payment + pe = create_payment_entry( + payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=20000 + ) + pe.paid_from = "Debtors - _TC" + pe.paid_to = "Cash - _TC" + pe.submit() + vouchers.append(pe) + + # create invoice + si1 = create_sales_invoice(customer="Test TCS Customer", rate=5000) + si1.submit() + vouchers.append(si1) + + # reconcile + pr = frappe.get_doc("Payment Reconciliation") + pr.company = "_Test Company" + pr.party_type = "Customer" + pr.party = "Test TCS Customer" + pr.receivable_payable_account = "Debtors - _TC" + pr.get_unreconciled_entries() + invoices = [x.as_dict() for x in pr.get("invoices")] + payments = [x.as_dict() for x in pr.get("payments")] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + + # make another invoice + # sum of unallocated amount from payment entry and this sales invoice will breach cumulative threashold + # TDS should be calculated + si2 = create_sales_invoice(customer="Test TCS Customer", rate=15000) + si2.submit() + vouchers.append(si2) + + si3 = create_sales_invoice(customer="Test TCS Customer", rate=10000) + si3.submit() + vouchers.append(si3) + + # assert tax collection on total invoice amount created until now + tcs_charged = sum([d.base_tax_amount for d in si2.taxes if d.account_head == "TCS - _TC"]) + tcs_charged += sum([d.base_tax_amount for d in si3.taxes if d.account_head == "TCS - _TC"]) + self.assertEqual(tcs_charged, 1500) + + # cancel invoice and payments to avoid clashing + for d in reversed(vouchers): + d.reload() + d.cancel() + def test_tds_calculation_on_net_total(self): frappe.db.set_value( "Supplier", "Test TDS Supplier4", "tax_withholding_category", "Cumulative Threshold TDS" diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index f86dd8f57ee..07b865e66cd 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -2,6 +2,8 @@ # License: GNU General Public License v3. See license.txt +from typing import Optional + import frappe from frappe import _, msgprint, scrub from frappe.contacts.doctype.address.address import ( @@ -647,12 +649,12 @@ def set_taxes( else: args.update(get_party_details(party, party_type)) - if party_type in ("Customer", "Lead"): + if party_type in ("Customer", "Lead", "Prospect"): args.update({"tax_type": "Sales"}) - if party_type == "Lead": + if party_type in ["Lead", "Prospect"]: args["customer"] = None - del args["lead"] + del args[frappe.scrub(party_type)] else: args.update({"tax_type": "Purchase"}) @@ -850,7 +852,7 @@ def get_dashboard_info(party_type, party, loyalty_program=None): return company_wise_info -def get_party_shipping_address(doctype, name): +def get_party_shipping_address(doctype: str, name: str) -> Optional[str]: """ Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true. and/or `is_shipping_address = 1`. @@ -861,22 +863,23 @@ def get_party_shipping_address(doctype, name): :param name: Party name :return: String """ - out = frappe.db.sql( - "SELECT dl.parent " - "from `tabDynamic Link` dl join `tabAddress` ta on dl.parent=ta.name " - "where " - "dl.link_doctype=%s " - "and dl.link_name=%s " - "and dl.parenttype='Address' " - "and ifnull(ta.disabled, 0) = 0 and" - "(ta.address_type='Shipping' or ta.is_shipping_address=1) " - "order by ta.is_shipping_address desc, ta.address_type desc limit 1", - (doctype, name), + shipping_addresses = frappe.get_all( + "Address", + filters=[ + ["Dynamic Link", "link_doctype", "=", doctype], + ["Dynamic Link", "link_name", "=", name], + ["disabled", "=", 0], + ], + or_filters=[ + ["is_shipping_address", "=", 1], + ["address_type", "=", "Shipping"], + ], + pluck="name", + limit=1, + order_by="is_shipping_address DESC", ) - if out: - return out[0][0] - else: - return "" + + return shipping_addresses[0] if shipping_addresses else None def get_partywise_advanced_payment_amount( @@ -910,31 +913,32 @@ def get_partywise_advanced_payment_amount( return frappe._dict(data) -def get_default_contact(doctype, name): +def get_default_contact(doctype: str, name: str) -> Optional[str]: """ - Returns default contact for the given doctype and name. - Can be ordered by `contact_type` to either is_primary_contact or is_billing_contact. + Returns contact name only if there is a primary contact for given doctype and name. + + Else returns None + + :param doctype: Party Doctype + :param name: Party name + :return: String """ - out = frappe.db.sql( - """ - SELECT dl.parent, c.is_primary_contact, c.is_billing_contact - FROM `tabDynamic Link` dl - INNER JOIN `tabContact` c ON c.name = dl.parent - WHERE - dl.link_doctype=%s AND - dl.link_name=%s AND - dl.parenttype = 'Contact' - ORDER BY is_primary_contact DESC, is_billing_contact DESC - """, - (doctype, name), + contacts = frappe.get_all( + "Contact", + filters=[ + ["Dynamic Link", "link_doctype", "=", doctype], + ["Dynamic Link", "link_name", "=", name], + ], + or_filters=[ + ["is_primary_contact", "=", 1], + ["is_billing_contact", "=", 1], + ], + pluck="name", + limit=1, + order_by="is_primary_contact DESC, is_billing_contact DESC", ) - if out: - try: - return out[0][0] - except Exception: - return None - else: - return None + + return contacts[0] if contacts else None def add_party_account(party_type, party, company, account): diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 11de9a098dc..30f7fb38c5f 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -181,6 +181,16 @@ class ReceivablePayableReport(object): return key = (ple.against_voucher_type, ple.against_voucher_no, ple.party) + + # If payment is made against credit note + # and credit note is made against a Sales Invoice + # then consider the payment against original sales invoice. + if ple.against_voucher_type in ("Sales Invoice", "Purchase Invoice"): + if ple.against_voucher_no in self.return_entries: + return_against = self.return_entries.get(ple.against_voucher_no) + if return_against: + key = (ple.against_voucher_type, return_against, ple.party) + row = self.voucher_balance.get(key) if not row: @@ -610,7 +620,7 @@ class ReceivablePayableReport(object): def get_return_entries(self): doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice" - filters = {"is_return": 1, "docstatus": 1} + filters = {"is_return": 1, "docstatus": 1, "company": self.filters.company} party_field = scrub(self.filters.party_type) if self.filters.get(party_field): filters.update({party_field: self.filters.get(party_field)}) diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py index afd02a006e6..6f1889b34e1 100644 --- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py @@ -210,6 +210,67 @@ class TestAccountsReceivable(FrappeTestCase): ], ) + def test_payment_against_credit_note(self): + """ + Payment against credit/debit note should be considered against the parent invoice + """ + company = "_Test Company 2" + customer = "_Test Customer 2" + + si1 = make_sales_invoice() + + pe = get_payment_entry("Sales Invoice", si1.name, bank_account="Cash - _TC2") + pe.paid_from = "Debtors - _TC2" + pe.insert() + pe.submit() + + cr_note = make_credit_note(si1.name) + + si2 = make_sales_invoice() + + # manually link cr_note with si2 using journal entry + je = frappe.new_doc("Journal Entry") + je.company = company + je.voucher_type = "Credit Note" + je.posting_date = today() + + debit_account = "Debtors - _TC2" + debit_entry = { + "account": debit_account, + "party_type": "Customer", + "party": customer, + "debit": 100, + "debit_in_account_currency": 100, + "reference_type": cr_note.doctype, + "reference_name": cr_note.name, + "cost_center": "Main - _TC2", + } + credit_entry = { + "account": debit_account, + "party_type": "Customer", + "party": customer, + "credit": 100, + "credit_in_account_currency": 100, + "reference_type": si2.doctype, + "reference_name": si2.name, + "cost_center": "Main - _TC2", + } + + je.append("accounts", debit_entry) + je.append("accounts", credit_entry) + je = je.save().submit() + + filters = { + "company": company, + "report_date": today(), + "range1": 30, + "range2": 60, + "range3": 90, + "range4": 120, + } + report = execute(filters) + self.assertEqual(report[1], []) + def make_sales_invoice(no_payment_schedule=False, do_not_submit=False): frappe.set_user("Administrator") @@ -256,7 +317,7 @@ def make_payment(docname): def make_credit_note(docname): - create_sales_invoice( + credit_note = create_sales_invoice( company="_Test Company 2", customer="_Test Customer 2", currency="EUR", @@ -269,3 +330,5 @@ def make_credit_note(docname): is_return=1, return_against=docname, ) + + return credit_note diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index dd9c0736128..0ebe13f4f32 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -399,8 +399,9 @@ def get_items(filters, additional_query_columns, additional_conditions=None): `tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to, `tabSales Invoice`.unrealized_profit_loss_account, `tabSales Invoice`.is_internal_customer, - `tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks, + `tabSales Invoice`.customer, `tabSales Invoice`.remarks, `tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total, + `tabSales Invoice Item`.project, `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description, `tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`, `tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note, diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index c64f29699d2..0dfcee4325a 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -812,14 +812,14 @@ class TestDepreciationMethods(AssetSetup): number_of_depreciations_booked=1, opening_accumulated_depreciation=50000, expected_value_after_useful_life=10000, - depreciation_start_date="2030-12-31", + depreciation_start_date="2031-12-31", total_number_of_depreciations=3, frequency_of_depreciation=12, ) self.assertEqual(asset.status, "Draft") - expected_schedules = [["2030-12-31", 33333.50, 83333.50], ["2031-12-31", 6666.50, 90000.0]] + expected_schedules = [["2031-12-31", 33333.50, 83333.50], ["2032-12-31", 6666.50, 90000.0]] schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 982d376ae4b..deae8c78913 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -10,6 +10,7 @@ from frappe.utils import ( cint, date_diff, flt, + get_first_day, get_last_day, getdate, is_last_day_of_the_month, @@ -271,8 +272,14 @@ class AssetDepreciationSchedule(Document): break # For first row - if n == 0 and has_pro_rata and not self.opening_accumulated_depreciation: - from_date = add_days(asset_doc.available_for_use_date, -1) + if ( + n == 0 + and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata) + and not self.opening_accumulated_depreciation + ): + from_date = add_days( + asset_doc.available_for_use_date, -1 + ) # needed to calc depr amount for available_for_use_date too depreciation_amount, days, months = _get_pro_rata_amt( row, depreciation_amount, @@ -281,10 +288,18 @@ class AssetDepreciationSchedule(Document): has_wdv_or_dd_non_yearly_pro_rata, ) elif n == 0 and has_wdv_or_dd_non_yearly_pro_rata and self.opening_accumulated_depreciation: - from_date = add_months( - getdate(asset_doc.available_for_use_date), - (self.number_of_depreciations_booked * row.frequency_of_depreciation), - ) + if not is_first_day_of_the_month(getdate(asset_doc.available_for_use_date)): + from_date = get_last_day( + add_months( + getdate(asset_doc.available_for_use_date), + ((self.number_of_depreciations_booked - 1) * row.frequency_of_depreciation), + ) + ) + else: + from_date = add_months( + getdate(add_days(asset_doc.available_for_use_date, -1)), + (self.number_of_depreciations_booked * row.frequency_of_depreciation), + ) depreciation_amount, days, months = _get_pro_rata_amt( row, depreciation_amount, @@ -702,3 +717,9 @@ def get_asset_depr_schedule_name(asset_name, status, finance_book=None): ["status", "=", status], ], ) + + +def is_first_day_of_the_month(date): + first_day_of_the_month = get_first_day(date) + + return getdate(first_day_of_the_month) == getdate(date) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 645abf25a8f..b242108a9a9 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -322,6 +322,7 @@ "fieldtype": "Small Text", "hidden": 1, "label": "Customer Mobile No", + "options": "Phone", "print_hide": 1 }, { @@ -368,6 +369,7 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Contact Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -1271,7 +1273,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2023-05-24 11:16:41.195340", + "modified": "2023-06-03 16:19:45.710444", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json index 11ff91af94d..7b635b36ba9 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json @@ -230,6 +230,7 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -844,7 +845,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-04-14 16:43:41.714832", + "modified": "2023-06-03 16:20:15.880114", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation", diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index d3195332d14..6f1a50dab1e 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -43,7 +43,6 @@ class SellingController(StockController): self.set_serial_and_batch_bundle(table_field) def set_missing_values(self, for_validate=False): - super(SellingController, self).set_missing_values(for_validate) # set contact and address details for customer, if they are not mentioned @@ -62,7 +61,7 @@ class SellingController(StockController): elif self.doctype == "Quotation" and self.party_name: if self.quotation_to == "Customer": customer = self.party_name - else: + elif self.quotation_to == "Lead": lead = self.party_name if customer: diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 2a588d8d13f..a98886c6481 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -3,7 +3,10 @@ import frappe from frappe import _ -from frappe.contacts.address_and_contact import load_address_and_contact +from frappe.contacts.address_and_contact import ( + delete_contact_and_address, + load_address_and_contact, +) from frappe.email.inbox import link_communication_to_document from frappe.model.mapper import get_mapped_doc from frappe.utils import comma_and, get_link_to_form, has_gravatar, validate_email_address @@ -40,9 +43,8 @@ class Lead(SellingController, CRMNote): self.update_prospect() def on_trash(self): - frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", self.name) - - self.unlink_dynamic_links() + frappe.db.set_value("Issue", {"lead": self.name}, "lead", None) + delete_contact_and_address(self.doctype, self.name) self.remove_link_from_prospect() def set_full_name(self): @@ -119,27 +121,6 @@ class Lead(SellingController, CRMNote): ) lead_row.db_update() - def unlink_dynamic_links(self): - links = frappe.get_all( - "Dynamic Link", - filters={"link_doctype": self.doctype, "link_name": self.name}, - fields=["parent", "parenttype"], - ) - - for link in links: - linked_doc = frappe.get_doc(link["parenttype"], link["parent"]) - - if len(linked_doc.get("links")) == 1: - linked_doc.delete(ignore_permissions=True) - else: - to_remove = None - for d in linked_doc.get("links"): - if d.link_doctype == self.doctype and d.link_name == self.name: - to_remove = d - if to_remove: - linked_doc.remove(to_remove) - linked_doc.save(ignore_permissions=True) - def remove_link_from_prospect(self): prospects = self.get_linked_prospects() diff --git a/erpnext/crm/doctype/prospect/prospect.py b/erpnext/crm/doctype/prospect/prospect.py index fbb115883f9..8b66a83f2ae 100644 --- a/erpnext/crm/doctype/prospect/prospect.py +++ b/erpnext/crm/doctype/prospect/prospect.py @@ -2,7 +2,10 @@ # For license information, please see license.txt import frappe -from frappe.contacts.address_and_contact import load_address_and_contact +from frappe.contacts.address_and_contact import ( + delete_contact_and_address, + load_address_and_contact, +) from frappe.model.mapper import get_mapped_doc from erpnext.crm.utils import CRMNote, copy_comments, link_communications, link_open_events @@ -16,7 +19,7 @@ class Prospect(CRMNote): self.link_with_lead_contact_and_address() def on_trash(self): - self.unlink_dynamic_links() + delete_contact_and_address(self.doctype, self.name) def after_insert(self): carry_forward_communication_and_comments = frappe.db.get_single_value( @@ -54,27 +57,6 @@ class Prospect(CRMNote): linked_doc.append("links", {"link_doctype": self.doctype, "link_name": self.name}) linked_doc.save(ignore_permissions=True) - def unlink_dynamic_links(self): - links = frappe.get_all( - "Dynamic Link", - filters={"link_doctype": self.doctype, "link_name": self.name}, - fields=["parent", "parenttype"], - ) - - for link in links: - linked_doc = frappe.get_doc(link["parenttype"], link["parent"]) - - if len(linked_doc.get("links")) == 1: - linked_doc.delete(ignore_permissions=True) - else: - to_remove = None - for d in linked_doc.get("links"): - if d.link_doctype == self.doctype and d.link_name == self.name: - to_remove = d - if to_remove: - linked_doc.remove(to_remove) - linked_doc.save(ignore_permissions=True) - @frappe.whitelist() def make_customer(source_name, target_doc=None): diff --git a/erpnext/e_commerce/product_ui/list.js b/erpnext/e_commerce/product_ui/list.js index 894a7cb3d87..c8fd7672c8e 100644 --- a/erpnext/e_commerce/product_ui/list.js +++ b/erpnext/e_commerce/product_ui/list.js @@ -78,9 +78,10 @@ erpnext.ProductList = class { let title_html = `
`; title_html += `
- + +
${ title } +
`; @@ -201,4 +202,4 @@ erpnext.ProductList = class { } } -}; \ No newline at end of file +}; diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py index 4daa2edb28a..9cc6ec9d4b4 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py @@ -160,4 +160,3 @@ class TestLoanDisbursement(unittest.TestCase): interest = per_day_interest * 15 self.assertEqual(amounts["pending_principal_amount"], 1500000) - self.assertEqual(amounts["interest_amount"], flt(interest + previous_interest, 2)) diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py index cac3f1f0f3f..ced63942ba8 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py @@ -22,7 +22,7 @@ class LoanInterestAccrual(AccountsController): frappe.throw(_("Interest Amount or Principal Amount is mandatory")) if not self.last_accrual_date: - self.last_accrual_date = get_last_accrual_date(self.loan) + self.last_accrual_date = get_last_accrual_date(self.loan, self.posting_date) def on_submit(self): self.make_gl_entries() @@ -274,14 +274,14 @@ def make_loan_interest_accrual_entry(args): def get_no_of_days_for_interest_accural(loan, posting_date): - last_interest_accrual_date = get_last_accrual_date(loan.name) + last_interest_accrual_date = get_last_accrual_date(loan.name, posting_date) no_of_days = date_diff(posting_date or nowdate(), last_interest_accrual_date) + 1 return no_of_days -def get_last_accrual_date(loan): +def get_last_accrual_date(loan, posting_date): last_posting_date = frappe.db.sql( """ SELECT MAX(posting_date) from `tabLoan Interest Accrual` WHERE loan = %s and docstatus = 1""", @@ -289,12 +289,30 @@ def get_last_accrual_date(loan): ) if last_posting_date[0][0]: + last_interest_accrual_date = last_posting_date[0][0] # interest for last interest accrual date is already booked, so add 1 day - return add_days(last_posting_date[0][0], 1) + last_disbursement_date = get_last_disbursement_date(loan, posting_date) + + if last_disbursement_date and getdate(last_disbursement_date) > getdate( + last_interest_accrual_date + ): + last_interest_accrual_date = last_disbursement_date + + return add_days(last_interest_accrual_date, 1) else: return frappe.db.get_value("Loan", loan, "disbursement_date") +def get_last_disbursement_date(loan, posting_date): + last_disbursement_date = frappe.db.get_value( + "Loan Disbursement", + {"docstatus": 1, "against_loan": loan, "posting_date": ("<", posting_date)}, + "MAX(posting_date)", + ) + + return last_disbursement_date + + def days_in_year(year): days = 365 diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py index 8a185f86833..82aab4a8820 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py @@ -101,7 +101,7 @@ class LoanRepayment(AccountsController): if flt(self.total_interest_paid, precision) > flt(self.interest_payable, precision): if not self.is_term_loan: # get last loan interest accrual date - last_accrual_date = get_last_accrual_date(self.against_loan) + last_accrual_date = get_last_accrual_date(self.against_loan, self.posting_date) # get posting date upto which interest has to be accrued per_day_interest = get_per_day_interest( @@ -725,7 +725,7 @@ def get_amounts(amounts, against_loan, posting_date): if due_date: pending_days = date_diff(posting_date, due_date) + 1 else: - last_accrual_date = get_last_accrual_date(against_loan_doc.name) + last_accrual_date = get_last_accrual_date(against_loan_doc.name, posting_date) pending_days = date_diff(posting_date, last_accrual_date) + 1 if pending_days > 0: diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json index 4f89a679c82..08026d031f2 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json @@ -152,6 +152,7 @@ "fieldtype": "Data", "hidden": 1, "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -160,6 +161,7 @@ "fieldtype": "Data", "hidden": 1, "label": "Contact Email", + "options": "Email", "print_hide": 1, "read_only": 1 }, @@ -236,10 +238,11 @@ "link_fieldname": "maintenance_schedule" } ], - "modified": "2021-05-27 16:05:10.746465", + "modified": "2023-06-03 16:15:43.958072", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { @@ -260,5 +263,6 @@ "search_fields": "status,customer,customer_name", "sort_field": "modified", "sort_order": "DESC", + "states": [], "timeline_field": "customer" } \ No newline at end of file diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json index 4a6aa0a34bf..b0d5cb89964 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json @@ -101,6 +101,7 @@ "fieldtype": "Data", "hidden": 1, "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -108,6 +109,7 @@ "fieldtype": "Data", "hidden": 1, "label": "Contact Email", + "options": "Email", "read_only": 1 }, { @@ -293,7 +295,7 @@ "idx": 1, "is_submittable": 1, "links": [], - "modified": "2021-12-17 03:10:27.608112", + "modified": "2023-06-03 16:19:07.902723", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Visit", @@ -319,6 +321,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "timeline_field": "customer", "title_field": "customer_name" } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py index 7477f9528ec..17b5aae9666 100644 --- a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py +++ b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py @@ -88,12 +88,14 @@ class BOMUpdateLog(Document): boms=boms, timeout=40000, now=frappe.flags.in_test, + enqueue_after_commit=True, ) else: frappe.enqueue( method="erpnext.manufacturing.doctype.bom_update_log.bom_update_log.process_boms_cost_level_wise", update_doc=self, now=frappe.flags.in_test, + enqueue_after_commit=True, ) diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index b9f4ec6ad1d..333d4d9b6ad 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -304,6 +304,7 @@ def set_tasks_as_overdue(): @frappe.whitelist() def make_timesheet(source_name, target_doc=None, ignore_permissions=False): def set_missing_values(source, target): + target.parent_project = source.project target.append( "time_logs", { diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js index 0cda93880fa..5e5742af8c1 100644 --- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js @@ -40,8 +40,8 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { name: __("Date"), editable: false, width: 100, + format: frappe.form.formatters.Date, }, - { name: __("Party Type"), editable: false, @@ -117,17 +117,13 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { return [ row["date"], row["party_type"], - row["party"], + frappe.form.formatters.Link(row["party"], {options: row["party_type"]}), row["description"], row["deposit"], row["withdrawal"], row["unallocated_amount"], row["reference_number"], - ` - ` ]; } diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index 1271e38049a..cbb64ca61b2 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -76,30 +76,17 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { callback: (result) => { const data = result.message; - if (data && data.length > 0) { const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; proposals_wrapper.show(); this.dialog.fields_dict.no_matching_vouchers.$wrapper.hide(); - this.data = []; - data.forEach((row) => { - const reference_date = row[5] ? row[5] : row[8]; - this.data.push([ - row[1], - row[2], - reference_date, - format_currency(row[3], row[9]), - row[4], - row[6], - ]); - }); + this.data = data.map((row) => this.format_row(row)); this.get_dt_columns(); this.get_datatable(proposals_wrapper); } else { const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper; proposals_wrapper.hide(); this.dialog.fields_dict.no_matching_vouchers.$wrapper.show(); - } this.dialog.show(); }, @@ -122,6 +109,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { name: __("Reference Date"), editable: false, width: 120, + format: frappe.form.formatters.Date, }, { name: __("Remaining"), @@ -141,6 +129,17 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { ]; } + format_row(row) { + return [ + row[1], // Document Type + frappe.form.formatters.Link(row[2], {options: row[1]}), // Document Name + row[5] || row[8], // Reference Date + format_currency(row[3], row[9]), // Remaining + row[4], // Reference Number + row[6], // Party + ]; + } + get_datatable(proposals_wrapper) { if (!this.datatable) { const datatable_options = { diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index fd961c4aaae..6f4e602abb6 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -805,11 +805,13 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { ); } - this.frm.doc.payments.find(pay => { - if (pay.default) { - pay.amount = total_amount_to_pay; - } - }); + if(!this.frm.doc.is_return){ + this.frm.doc.payments.find(payment => { + if (payment.default) { + payment.amount = total_amount_to_pay; + } + }); + } this.frm.refresh_fields(); } diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 644adff1e27..5c41aa06804 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -16,8 +16,8 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { || (frm.doc.party_name && in_list(['Quotation', 'Opportunity'], frm.doc.doctype))) { let party_type = "Customer"; - if (frm.doc.quotation_to && frm.doc.quotation_to === "Lead") { - party_type = "Lead"; + if (frm.doc.quotation_to && in_list(["Lead", "Prospect"], frm.doc.quotation_to)) { + party_type = frm.doc.quotation_to; } args = { diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index f15ac1257b2..6367e3cb6a5 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -454,12 +454,12 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False, customer_outstanding += flt(extra_amount) if credit_limit > 0 and flt(customer_outstanding) > credit_limit: - msgprint( - _("Credit limit has been crossed for customer {0} ({1}/{2})").format( - customer, customer_outstanding, credit_limit - ) + message = _("Credit limit has been crossed for customer {0} ({1}/{2})").format( + customer, customer_outstanding, credit_limit ) + message += "

" + # If not authorized person raise exception credit_controller_role = frappe.db.get_single_value("Accounts Settings", "credit_controller") if not credit_controller_role or credit_controller_role not in frappe.get_roles(): @@ -480,7 +480,7 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False, "
  • ".join(credit_controller_users_formatted) ) - message = _( + message += _( "Please contact any of the following users to extend the credit limits for {0}: {1}" ).format(customer, user_list) @@ -488,7 +488,7 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False, # prompt them to send out an email to the controller users frappe.msgprint( message, - title="Notify", + title=_("Credit Limit Crossed"), raise_exception=1, primary_action={ "label": "Send Email", @@ -519,7 +519,6 @@ def get_customer_outstanding( customer, company, ignore_outstanding_sales_order=False, cost_center=None ): # Outstanding based on GL Entries - cond = "" if cost_center: lft, rgt = frappe.get_cached_value("Cost Center", cost_center, ["lft", "rgt"]) diff --git a/erpnext/selling/doctype/installation_note/installation_note.json b/erpnext/selling/doctype/installation_note/installation_note.json index 765bc5c02cf..18c7d08e18f 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.json +++ b/erpnext/selling/doctype/installation_note/installation_note.json @@ -1,812 +1,267 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2013-04-30 13:13:06", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, + "actions": [], + "autoname": "naming_series:", + "creation": "2013-04-30 13:13:06", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "installation_note", + "column_break0", + "naming_series", + "customer", + "customer_address", + "contact_person", + "customer_name", + "address_display", + "contact_display", + "contact_mobile", + "contact_email", + "territory", + "customer_group", + "column_break1", + "inst_date", + "inst_time", + "status", + "company", + "amended_from", + "remarks", + "item_details", + "items" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "installation_note", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Installation Note", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "installation_note", + "fieldtype": "Section Break", + "label": "Installation Note", + "oldfieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break0", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "oldfieldtype": "Column Break", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "column_break0", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break", "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 1, - "oldfieldname": "naming_series", - "oldfieldtype": "Select", - "options": "MAT-INS-.YYYY.-", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "oldfieldname": "naming_series", + "oldfieldtype": "Select", + "options": "MAT-INS-.YYYY.-", + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Customer", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer", - "oldfieldtype": "Link", - "options": "Customer", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "customer", + "fieldtype": "Link", + "in_global_search": 1, + "in_standard_filter": 1, + "label": "Customer", + "oldfieldname": "customer", + "oldfieldtype": "Link", + "options": "Customer", + "print_hide": 1, + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "customer_address", - "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": "Customer Address", - "length": 0, - "no_copy": 0, - "options": "Address", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "customer_address", + "fieldtype": "Link", + "label": "Customer Address", + "options": "Address", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_person", - "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": "Contact Person", - "length": 0, - "no_copy": 0, - "options": "Contact", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "contact_person", + "fieldtype": "Link", + "label": "Contact Person", + "options": "Contact", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Name", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer_name", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "fieldname": "customer_name", + "fieldtype": "Data", + "label": "Name", + "oldfieldname": "customer_name", + "oldfieldtype": "Data", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address_display", - "fieldtype": "Small Text", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "address_display", + "fieldtype": "Small Text", + "hidden": 1, + "label": "Address", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_display", - "fieldtype": "Small Text", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_display", + "fieldtype": "Small Text", + "hidden": 1, + "in_global_search": 1, + "label": "Contact", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_mobile", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Mobile No", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "contact_mobile", + "fieldtype": "Small Text", + "in_global_search": 1, + "label": "Mobile No", + "options": "Phone", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_email", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact Email", - "length": 0, - "no_copy": 0, - "options": "Email", - "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 - }, + "depends_on": "customer", + "fieldname": "contact_email", + "fieldtype": "Data", + "label": "Contact Email", + "options": "Email", + "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, - "depends_on": "customer", - "description": "", - "fieldname": "territory", - "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": "Territory", - "length": 0, - "no_copy": 0, - "options": "Territory", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "territory", + "fieldtype": "Link", + "label": "Territory", + "options": "Territory", + "print_hide": 1, + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "description": "", - "fieldname": "customer_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Customer Group", - "length": 0, - "no_copy": 0, - "options": "Customer Group", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "customer_group", + "fieldtype": "Link", + "label": "Customer Group", + "options": "Customer Group", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "oldfieldtype": "Column Break", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "column_break1", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break", "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "inst_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Installation Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "inst_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "inst_date", + "fieldtype": "Date", + "label": "Installation Date", + "oldfieldname": "inst_date", + "oldfieldtype": "Date", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "inst_time", - "fieldtype": "Time", - "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": "Installation Time", - "length": 0, - "no_copy": 0, - "oldfieldname": "inst_time", - "oldfieldtype": "Time", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "inst_time", + "fieldtype": "Time", + "label": "Installation Time", + "oldfieldname": "inst_time", + "oldfieldtype": "Time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Draft", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Status", - "length": 0, - "no_copy": 1, - "oldfieldname": "status", - "oldfieldtype": "Select", - "options": "Draft\nSubmitted\nCancelled", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "in_standard_filter": 1, + "label": "Status", + "no_copy": 1, + "oldfieldname": "status", + "oldfieldtype": "Select", + "options": "Draft\nSubmitted\nCancelled", + "print_hide": 1, + "read_only": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Company", - "length": 0, - "no_copy": 0, - "oldfieldname": "company", - "oldfieldtype": "Select", - "options": "Company", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Select", + "options": "Company", + "print_hide": 1, + "remember_last_selected_value": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "oldfieldname": "amended_from", - "oldfieldtype": "Data", - "options": "Installation Note", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "amended_from", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "oldfieldname": "amended_from", + "oldfieldtype": "Data", + "options": "Installation Note", + "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": "remarks", - "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": "Remarks", - "length": 0, - "no_copy": 0, - "oldfieldname": "remarks", - "oldfieldtype": "Small Text", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "remarks", + "fieldtype": "Small Text", + "in_list_view": 1, + "label": "Remarks", + "oldfieldname": "remarks", + "oldfieldtype": "Small Text", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "Simple", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_details", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "Simple" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Items", - "length": 0, - "no_copy": 0, - "oldfieldname": "installed_item_details", - "oldfieldtype": "Table", - "options": "Installation Note Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "items", + "fieldtype": "Table", + "label": "Items", + "oldfieldname": "installed_item_details", + "oldfieldtype": "Table", + "options": "Installation Note Item", + "reqd": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-wrench", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-21 14:44:28.000728", - "modified_by": "Administrator", - "module": "Selling", - "name": "Installation Note", - "owner": "Administrator", + ], + "icon": "fa fa-wrench", + "idx": 1, + "is_submittable": 1, + "links": [], + "modified": "2023-06-03 16:31:08.386961", + "modified_by": "Administrator", + "module": "Selling", + "name": "Installation Note", + "naming_rule": "By \"Naming Series\" field", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales User", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 1, - "print": 0, - "read": 1, - "report": 1, - "role": "Sales User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "permlevel": 1, + "read": 1, + "report": 1, + "role": "Sales User" } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "timeline_field": "customer", - "title_field": "customer_name", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "timeline_field": "customer", + "title_field": "customer_name" } \ No newline at end of file diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index 83fa472d68b..2d5c3fa961d 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -13,7 +13,7 @@ frappe.ui.form.on('Quotation', { frm.set_query("quotation_to", function() { return{ "filters": { - "name": ["in", ["Customer", "Lead"]], + "name": ["in", ["Customer", "Lead", "Prospect"]], } } }); @@ -160,19 +160,16 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext. } set_dynamic_field_label(){ - if (this.frm.doc.quotation_to == "Customer") - { + if (this.frm.doc.quotation_to == "Customer") { this.frm.set_df_property("party_name", "label", "Customer"); this.frm.fields_dict.party_name.get_query = null; - } - - if (this.frm.doc.quotation_to == "Lead") - { + } else if (this.frm.doc.quotation_to == "Lead") { this.frm.set_df_property("party_name", "label", "Lead"); - this.frm.fields_dict.party_name.get_query = function() { return{ query: "erpnext.controllers.queries.lead_query" } } + } else if (this.frm.doc.quotation_to == "Prospect") { + this.frm.set_df_property("party_name", "label", "Prospect"); } } diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 2ffa6a5c120..8c816cf6e4e 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -291,6 +291,7 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -1072,7 +1073,7 @@ "idx": 82, "is_submittable": 1, "links": [], - "modified": "2023-04-14 16:50:44.550098", + "modified": "2023-06-03 16:21:04.980033", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index f7143d7594c..f65969e9938 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -398,6 +398,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -1475,6 +1476,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Phone", + "options": "Phone", "read_only": 1 }, { @@ -1643,7 +1645,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2023-04-22 09:55:37.008190", + "modified": "2023-06-03 16:16:23.411247", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index d3c23472167..58b9df8dab9 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -230,6 +230,7 @@ class SalesOrder(SellingController): frappe.throw(_("Quotation {0} is cancelled").format(quotation)) doc.set_status(update=True) + doc.update_opportunity("Converted" if flag == "submit" else "Quotation") def validate_drop_ship(self): for d in self.get("items"): diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index e58bc739495..6459deffaa2 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1772,7 +1772,14 @@ class TestSalesOrder(FrappeTestCase): self.assertEqual(pe.references[1].reference_name, so.name) self.assertEqual(pe.references[1].allocated_amount, 300) - @change_settings("Stock Settings", {"enable_stock_reservation": 1}) + @change_settings( + "Stock Settings", + { + "enable_stock_reservation": 1, + "auto_create_serial_and_batch_bundle_for_outward": 1, + "pick_serial_and_batch_based_on": "FIFO", + }, + ) def test_stock_reservation_against_sales_order(self) -> None: from random import randint, uniform diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index cf9600eb49e..1d5428a40e8 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -25,6 +25,7 @@ def after_install(): create_default_success_action() create_default_energy_point_rules() create_incoterms() + create_default_role_profiles() add_company_to_session_defaults() add_standard_navbar_items() add_app_name() @@ -202,3 +203,42 @@ def setup_log_settings(): def hide_workspaces(): for ws in ["Integration", "Settings"]: frappe.db.set_value("Workspace", ws, "public", 0) + + +def create_default_role_profiles(): + for role_profile_name, roles in DEFAULT_ROLE_PROFILES.items(): + role_profile = frappe.new_doc("Role Profile") + role_profile.role_profile = role_profile_name + for role in roles: + role_profile.append("roles", {"role": role}) + + role_profile.insert(ignore_permissions=True) + + +DEFAULT_ROLE_PROFILES = { + "Inventory": [ + "Stock User", + "Stock Manager", + "Item Manager", + ], + "Manufacturing": [ + "Stock User", + "Manufacturing User", + "Manufacturing Manager", + ], + "Accounts": [ + "Accounts User", + "Accounts Manager", + ], + "Sales": [ + "Sales User", + "Stock User", + "Sales Manager", + ], + "Purchase": [ + "Item Manager", + "Stock User", + "Purchase User", + "Purchase Manager", + ], +} diff --git a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py index a7963726ae3..295d979b835 100644 --- a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py +++ b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py @@ -51,7 +51,7 @@ class ClosingStockBalance(Document): for fieldname in ["warehouse", "item_code", "item_group", "warehouse_type"]: if self.get(fieldname): - query = query.where(table.get(fieldname) == self.get(fieldname)) + query = query.where(table[fieldname] == self.get(fieldname)) query = query.run(as_dict=True) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index 2adf9c310f9..6ee8f205e08 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -374,6 +374,7 @@ "fieldtype": "Small Text", "hidden": 1, "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -1398,7 +1399,7 @@ "idx": 146, "is_submittable": 1, "links": [], - "modified": "2023-04-21 11:15:23.931084", + "modified": "2023-06-03 16:13:25.011487", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", @@ -1468,4 +1469,4 @@ "title_field": "title", "track_changes": 1, "track_seen": 1 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 9a9ddf44044..6f1f981e2b9 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -772,12 +772,6 @@ $.extend(erpnext.item, { if (modal) { $(modal).removeClass("modal-dialog-scrollable"); } - }) - .on("awesomplete-close", () => { - let modal = field.$input.parents('.modal-dialog')[0]; - if (modal) { - $(modal).addClass("modal-dialog-scrollable"); - } }); }); }, diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 3cc59bed192..f91a9911737 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -714,6 +714,7 @@ class Item(Document): template=self, now=frappe.flags.in_test, timeout=600, + enqueue_after_commit=True, ) def validate_has_variants(self): diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index dc61ec4d243..b41e971c8ac 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -326,6 +326,7 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -1239,7 +1240,7 @@ "idx": 261, "is_submittable": 1, "links": [], - "modified": "2023-05-07 20:18:25.458185", + "modified": "2023-06-03 16:23:20.781368", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js index b02ad71b16d..d50bdba3c95 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js @@ -127,6 +127,14 @@ frappe.ui.form.on('Serial and Batch Bundle', { }, toggle_fields(frm) { + if (frm.doc.has_serial_no) { + frm.doc.entries.forEach(row => { + if (Math.abs(row.qty) !== 1) { + frappe.model.set_value(row.doctype, row.name, "qty", 1); + } + }) + } + frm.fields_dict.entries.grid.update_docfield_property( 'serial_no', 'read_only', !frm.doc.has_serial_no ); @@ -134,6 +142,10 @@ frappe.ui.form.on('Serial and Batch Bundle', { frm.fields_dict.entries.grid.update_docfield_property( 'batch_no', 'read_only', !frm.doc.has_batch_no ); + + frm.fields_dict.entries.grid.update_docfield_property( + 'qty', 'read_only', frm.doc.has_serial_no + ); }, set_queries(frm) { @@ -198,9 +210,9 @@ frappe.ui.form.on('Serial and Batch Bundle', { frappe.ui.form.on("Serial and Batch Entry", { - ledgers_add(frm, cdt, cdn) { + entries_add(frm, cdt, cdn) { if (frm.doc.warehouse) { - locals[cdt][cdn].warehouse = frm.doc.warehouse; + frappe.model.set_value(cdt, cdn, 'warehouse', frm.doc.warehouse); } }, }) \ No newline at end of file diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index 7e5cac986eb..cc55bd6ea84 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -133,7 +133,7 @@ class SerialandBatchBundle(Document): def calculate_total_qty(self, save=True): self.total_qty = 0.0 for d in self.entries: - d.qty = abs(d.qty) if d.qty else 0 + d.qty = 1 if self.has_serial_no and abs(d.qty) > 1 else abs(d.qty) if d.qty else 0 d.stock_value_difference = abs(d.stock_value_difference) if d.stock_value_difference else 0 if self.type_of_transaction == "Outward": d.qty *= -1 diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle_list.js b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle_list.js new file mode 100644 index 00000000000..355fcd0aaa1 --- /dev/null +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle_list.js @@ -0,0 +1,11 @@ +// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.listview_settings["Serial and Batch Bundle"] = { + add_fields: ["is_cancelled"], + get_indicator: function (doc) { + if (doc.is_cancelled) { + return [__("Cancelled"), "red", "is_cancelled,=,1"]; + } + }, +}; diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index e25c8439ca3..3b6db64a308 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -94,6 +94,7 @@ class StockSettings(Document): frappe.enqueue( "erpnext.stock.doctype.stock_settings.stock_settings.clean_all_descriptions", now=frappe.flags.in_test, + enqueue_after_commit=True, ) def validate_pending_reposts(self): diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index dc481e8281b..a668ab89dd0 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -944,7 +944,7 @@ class update_entries_after(object): for item in sr.items: # Skip for Serial and Batch Items - if item.serial_no or item.batch_no: + if item.name != sle.voucher_detail_no or item.serial_no or item.batch_no: continue previous_sle = get_previous_sle( diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json index f98f559d5ca..28c52c9272d 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json @@ -1,511 +1,512 @@ { - "actions": [], - "allow_auto_repeat": 1, - "allow_import": 1, - "autoname": "naming_series:", - "creation": "2022-04-01 22:39:17.662819", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "title", - "naming_series", - "purchase_order", - "supplier", - "supplier_name", - "supplier_warehouse", - "column_break_7", - "company", - "transaction_date", - "schedule_date", - "amended_from", - "accounting_dimensions_section", - "cost_center", - "dimension_col_break", - "project", - "address_and_contact_section", - "supplier_address", - "address_display", - "contact_person", - "contact_display", - "contact_mobile", - "contact_email", - "column_break_19", - "shipping_address", - "shipping_address_display", - "billing_address", - "billing_address_display", - "section_break_24", - "column_break_25", - "set_warehouse", - "items", - "section_break_32", - "total_qty", - "column_break_29", - "total", - "service_items_section", - "service_items", - "raw_materials_supplied_section", - "set_reserve_warehouse", - "supplied_items", - "additional_costs_section", - "distribute_additional_costs_based_on", - "additional_costs", - "total_additional_costs", - "order_status_section", - "status", - "column_break_39", - "per_received", - "printing_settings_section", - "select_print_heading", - "column_break_43", - "letter_head" - ], - "fields": [ - { - "allow_on_submit": 1, - "default": "{supplier_name}", - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1, - "print_hide": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "no_copy": 1, - "options": "SC-ORD-.YYYY.-", - "print_hide": 1, - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "purchase_order", - "fieldtype": "Link", - "label": "Subcontracting Purchase Order", - "options": "Purchase Order", - "reqd": 1 - }, - { - "bold": 1, - "fieldname": "supplier", - "fieldtype": "Link", - "in_global_search": 1, - "in_standard_filter": 1, - "label": "Supplier", - "options": "Supplier", - "print_hide": 1, - "reqd": 1, - "search_index": 1 - }, - { - "bold": 1, - "fetch_from": "supplier.supplier_name", - "fieldname": "supplier_name", - "fieldtype": "Data", - "in_global_search": 1, - "label": "Supplier Name", - "read_only": 1, - "reqd": 1 - }, - { - "depends_on": "supplier", - "fieldname": "supplier_warehouse", - "fieldtype": "Link", - "label": "Supplier Warehouse", - "options": "Warehouse", - "reqd": 1 - }, - { - "fieldname": "column_break_7", - "fieldtype": "Column Break", - "print_width": "50%", - "width": "50%" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "options": "Company", - "print_hide": 1, - "remember_last_selected_value": 1, - "reqd": 1 - }, - { - "default": "Today", - "fetch_from": "purchase_order.transaction_date", - "fetch_if_empty": 1, - "fieldname": "transaction_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Date", - "reqd": 1, - "search_index": 1 - }, - { - "allow_on_submit": 1, - "fetch_from": "purchase_order.schedule_date", - "fetch_if_empty": 1, - "fieldname": "schedule_date", - "fieldtype": "Date", - "label": "Required By", - "read_only": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Amended From", - "no_copy": 1, - "options": "Subcontracting Order", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "address_and_contact_section", - "fieldtype": "Section Break", - "label": "Address and Contact" - }, - { - "fetch_from": "supplier.supplier_primary_address", - "fetch_if_empty": 1, - "fieldname": "supplier_address", - "fieldtype": "Link", - "label": "Supplier Address", - "options": "Address", - "print_hide": 1 - }, - { - "fieldname": "address_display", - "fieldtype": "Small Text", - "label": "Supplier Address Details", - "read_only": 1 - }, - { - "fetch_from": "supplier.supplier_primary_contact", - "fetch_if_empty": 1, - "fieldname": "contact_person", - "fieldtype": "Link", - "label": "Supplier Contact", - "options": "Contact", - "print_hide": 1 - }, - { - "fieldname": "contact_display", - "fieldtype": "Small Text", - "in_global_search": 1, - "label": "Contact Name", - "read_only": 1 - }, - { - "fieldname": "contact_mobile", - "fieldtype": "Small Text", - "label": "Contact Mobile No", - "read_only": 1 - }, - { - "fieldname": "contact_email", - "fieldtype": "Small Text", - "label": "Contact Email", - "options": "Email", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_19", - "fieldtype": "Column Break" - }, - { - "fieldname": "shipping_address", - "fieldtype": "Link", - "label": "Company Shipping Address", - "options": "Address", - "print_hide": 1 - }, - { - "fieldname": "shipping_address_display", - "fieldtype": "Small Text", - "label": "Shipping Address Details", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "billing_address", - "fieldtype": "Link", - "label": "Company Billing Address", - "options": "Address" - }, - { - "fieldname": "billing_address_display", - "fieldtype": "Small Text", - "label": "Billing Address Details", - "read_only": 1 - }, - { - "fieldname": "section_break_24", - "fieldtype": "Section Break" - }, - { - "fieldname": "column_break_25", - "fieldtype": "Column Break" - }, - { - "depends_on": "purchase_order", - "description": "Sets 'Warehouse' in each row of the Items table.", - "fieldname": "set_warehouse", - "fieldtype": "Link", - "label": "Set Target Warehouse", - "options": "Warehouse", - "print_hide": 1 - }, - { - "allow_bulk_edit": 1, - "depends_on": "purchase_order", - "fieldname": "items", - "fieldtype": "Table", - "label": "Items", - "options": "Subcontracting Order Item", - "reqd": 1 - }, - { - "fieldname": "section_break_32", - "fieldtype": "Section Break" - }, - { - "depends_on": "purchase_order", - "fieldname": "total_qty", - "fieldtype": "Float", - "label": "Total Quantity", - "read_only": 1 - }, - { - "fieldname": "column_break_29", - "fieldtype": "Column Break" - }, - { - "depends_on": "purchase_order", - "fieldname": "total", - "fieldtype": "Currency", - "label": "Total", - "options": "currency", - "read_only": 1 - }, - { - "collapsible": 1, - "depends_on": "purchase_order", - "fieldname": "service_items_section", - "fieldtype": "Section Break", - "label": "Service Items" - }, - { - "fieldname": "service_items", - "fieldtype": "Table", - "label": "Service Items", - "options": "Subcontracting Order Service Item", - "read_only": 1, - "reqd": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "supplied_items", - "depends_on": "supplied_items", - "fieldname": "raw_materials_supplied_section", - "fieldtype": "Section Break", - "label": "Raw Materials Supplied" - }, - { - "depends_on": "supplied_items", - "description": "Sets 'Reserve Warehouse' in each row of the Supplied Items table.", - "fieldname": "set_reserve_warehouse", - "fieldtype": "Link", - "label": "Set Reserve Warehouse", - "options": "Warehouse" - }, - { - "fieldname": "supplied_items", - "fieldtype": "Table", - "label": "Supplied Items", - "no_copy": 1, - "options": "Subcontracting Order Supplied Item", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "total_additional_costs", - "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)", - "fieldname": "additional_costs_section", - "fieldtype": "Section Break", - "label": "Additional Costs" - }, - { - "fieldname": "additional_costs", - "fieldtype": "Table", - "label": "Additional Costs", - "options": "Landed Cost Taxes and Charges" - }, - { - "fieldname": "total_additional_costs", - "fieldtype": "Currency", - "label": "Total Additional Costs", - "print_hide_if_no_value": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "order_status_section", - "fieldtype": "Section Break", - "label": "Order Status" - }, - { - "default": "Draft", - "fieldname": "status", - "fieldtype": "Select", - "in_standard_filter": 1, - "label": "Status", - "no_copy": 1, - "options": "Draft\nOpen\nPartially Received\nCompleted\nMaterial Transferred\nPartial Material Transferred\nCancelled", - "print_hide": 1, - "read_only": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "column_break_39", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:!doc.__islocal", - "fieldname": "per_received", - "fieldtype": "Percent", - "in_list_view": 1, - "label": "% Received", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "printing_settings_section", - "fieldtype": "Section Break", - "label": "Printing Settings", - "print_hide": 1, - "print_width": "50%", - "width": "50%" - }, - { - "allow_on_submit": 1, - "fieldname": "select_print_heading", - "fieldtype": "Link", - "label": "Print Heading", - "no_copy": 1, - "options": "Print Heading", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "column_break_43", - "fieldtype": "Column Break" - }, - { - "allow_on_submit": 1, - "fieldname": "letter_head", - "fieldtype": "Link", - "label": "Letter Head", - "options": "Letter Head", - "print_hide": 1 - }, - { - "default": "Qty", - "fieldname": "distribute_additional_costs_based_on", - "fieldtype": "Select", - "label": "Distribute Additional Costs Based On ", - "options": "Qty\nAmount" - }, - { - "collapsible": 1, - "fieldname": "accounting_dimensions_section", - "fieldtype": "Section Break", - "label": "Accounting Dimensions" - }, - { - "fieldname": "cost_center", - "fieldtype": "Link", - "label": "Cost Center", - "options": "Cost Center" - }, - { - "fieldname": "dimension_col_break", - "fieldtype": "Column Break" - }, - { - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" - } - ], - "icon": "fa fa-file-text", - "is_submittable": 1, - "links": [], - "modified": "2022-08-15 14:08:49.204218", - "modified_by": "Administrator", - "module": "Subcontracting", - "name": "Subcontracting Order", - "naming_rule": "By \"Naming Series\" field", - "owner": "Administrator", - "permissions": [ - { - "read": 1, - "report": 1, - "role": "Stock User" - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase Manager", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase User", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "permlevel": 1, - "read": 1, - "role": "Purchase Manager", - "write": 1 - } - ], - "search_fields": "status, transaction_date, supplier", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "states": [], - "timeline_field": "supplier", - "title_field": "supplier_name", - "track_changes": 1 + "actions": [], + "allow_auto_repeat": 1, + "allow_import": 1, + "autoname": "naming_series:", + "creation": "2022-04-01 22:39:17.662819", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "title", + "naming_series", + "purchase_order", + "supplier", + "supplier_name", + "supplier_warehouse", + "column_break_7", + "company", + "transaction_date", + "schedule_date", + "amended_from", + "accounting_dimensions_section", + "cost_center", + "dimension_col_break", + "project", + "address_and_contact_section", + "supplier_address", + "address_display", + "contact_person", + "contact_display", + "contact_mobile", + "contact_email", + "column_break_19", + "shipping_address", + "shipping_address_display", + "billing_address", + "billing_address_display", + "section_break_24", + "column_break_25", + "set_warehouse", + "items", + "section_break_32", + "total_qty", + "column_break_29", + "total", + "service_items_section", + "service_items", + "raw_materials_supplied_section", + "set_reserve_warehouse", + "supplied_items", + "additional_costs_section", + "distribute_additional_costs_based_on", + "additional_costs", + "total_additional_costs", + "order_status_section", + "status", + "column_break_39", + "per_received", + "printing_settings_section", + "select_print_heading", + "column_break_43", + "letter_head" + ], + "fields": [ + { + "allow_on_submit": 1, + "default": "{supplier_name}", + "fieldname": "title", + "fieldtype": "Data", + "hidden": 1, + "label": "Title", + "no_copy": 1, + "print_hide": 1 + }, + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "SC-ORD-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, + { + "fieldname": "purchase_order", + "fieldtype": "Link", + "label": "Subcontracting Purchase Order", + "options": "Purchase Order", + "reqd": 1 + }, + { + "bold": 1, + "fieldname": "supplier", + "fieldtype": "Link", + "in_global_search": 1, + "in_standard_filter": 1, + "label": "Supplier", + "options": "Supplier", + "print_hide": 1, + "reqd": 1, + "search_index": 1 + }, + { + "bold": 1, + "fetch_from": "supplier.supplier_name", + "fieldname": "supplier_name", + "fieldtype": "Data", + "in_global_search": 1, + "label": "Supplier Name", + "read_only": 1, + "reqd": 1 + }, + { + "depends_on": "supplier", + "fieldname": "supplier_warehouse", + "fieldtype": "Link", + "label": "Supplier Warehouse", + "options": "Warehouse", + "reqd": 1 + }, + { + "fieldname": "column_break_7", + "fieldtype": "Column Break", + "print_width": "50%", + "width": "50%" + }, + { + "fieldname": "company", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Company", + "options": "Company", + "print_hide": 1, + "remember_last_selected_value": 1, + "reqd": 1 + }, + { + "default": "Today", + "fetch_from": "purchase_order.transaction_date", + "fetch_if_empty": 1, + "fieldname": "transaction_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Date", + "reqd": 1, + "search_index": 1 + }, + { + "allow_on_submit": 1, + "fetch_from": "purchase_order.schedule_date", + "fetch_if_empty": 1, + "fieldname": "schedule_date", + "fieldtype": "Date", + "label": "Required By", + "read_only": 1 + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "options": "Subcontracting Order", + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "address_and_contact_section", + "fieldtype": "Section Break", + "label": "Address and Contact" + }, + { + "fetch_from": "supplier.supplier_primary_address", + "fetch_if_empty": 1, + "fieldname": "supplier_address", + "fieldtype": "Link", + "label": "Supplier Address", + "options": "Address", + "print_hide": 1 + }, + { + "fieldname": "address_display", + "fieldtype": "Small Text", + "label": "Supplier Address Details", + "read_only": 1 + }, + { + "fetch_from": "supplier.supplier_primary_contact", + "fetch_if_empty": 1, + "fieldname": "contact_person", + "fieldtype": "Link", + "label": "Supplier Contact", + "options": "Contact", + "print_hide": 1 + }, + { + "fieldname": "contact_display", + "fieldtype": "Small Text", + "in_global_search": 1, + "label": "Contact Name", + "read_only": 1 + }, + { + "fieldname": "contact_mobile", + "fieldtype": "Small Text", + "label": "Contact Mobile No", + "options": "Phone", + "read_only": 1 + }, + { + "fieldname": "contact_email", + "fieldtype": "Small Text", + "label": "Contact Email", + "options": "Email", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_19", + "fieldtype": "Column Break" + }, + { + "fieldname": "shipping_address", + "fieldtype": "Link", + "label": "Company Shipping Address", + "options": "Address", + "print_hide": 1 + }, + { + "fieldname": "shipping_address_display", + "fieldtype": "Small Text", + "label": "Shipping Address Details", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "billing_address", + "fieldtype": "Link", + "label": "Company Billing Address", + "options": "Address" + }, + { + "fieldname": "billing_address_display", + "fieldtype": "Small Text", + "label": "Billing Address Details", + "read_only": 1 + }, + { + "fieldname": "section_break_24", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_25", + "fieldtype": "Column Break" + }, + { + "depends_on": "purchase_order", + "description": "Sets 'Warehouse' in each row of the Items table.", + "fieldname": "set_warehouse", + "fieldtype": "Link", + "label": "Set Target Warehouse", + "options": "Warehouse", + "print_hide": 1 + }, + { + "allow_bulk_edit": 1, + "depends_on": "purchase_order", + "fieldname": "items", + "fieldtype": "Table", + "label": "Items", + "options": "Subcontracting Order Item", + "reqd": 1 + }, + { + "fieldname": "section_break_32", + "fieldtype": "Section Break" + }, + { + "depends_on": "purchase_order", + "fieldname": "total_qty", + "fieldtype": "Float", + "label": "Total Quantity", + "read_only": 1 + }, + { + "fieldname": "column_break_29", + "fieldtype": "Column Break" + }, + { + "depends_on": "purchase_order", + "fieldname": "total", + "fieldtype": "Currency", + "label": "Total", + "options": "currency", + "read_only": 1 + }, + { + "collapsible": 1, + "depends_on": "purchase_order", + "fieldname": "service_items_section", + "fieldtype": "Section Break", + "label": "Service Items" + }, + { + "fieldname": "service_items", + "fieldtype": "Table", + "label": "Service Items", + "options": "Subcontracting Order Service Item", + "read_only": 1, + "reqd": 1 + }, + { + "collapsible": 1, + "collapsible_depends_on": "supplied_items", + "depends_on": "supplied_items", + "fieldname": "raw_materials_supplied_section", + "fieldtype": "Section Break", + "label": "Raw Materials Supplied" + }, + { + "depends_on": "supplied_items", + "description": "Sets 'Reserve Warehouse' in each row of the Supplied Items table.", + "fieldname": "set_reserve_warehouse", + "fieldtype": "Link", + "label": "Set Reserve Warehouse", + "options": "Warehouse" + }, + { + "fieldname": "supplied_items", + "fieldtype": "Table", + "label": "Supplied Items", + "no_copy": 1, + "options": "Subcontracting Order Supplied Item", + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "collapsible_depends_on": "total_additional_costs", + "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)", + "fieldname": "additional_costs_section", + "fieldtype": "Section Break", + "label": "Additional Costs" + }, + { + "fieldname": "additional_costs", + "fieldtype": "Table", + "label": "Additional Costs", + "options": "Landed Cost Taxes and Charges" + }, + { + "fieldname": "total_additional_costs", + "fieldtype": "Currency", + "label": "Total Additional Costs", + "print_hide_if_no_value": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "order_status_section", + "fieldtype": "Section Break", + "label": "Order Status" + }, + { + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "in_standard_filter": 1, + "label": "Status", + "no_copy": 1, + "options": "Draft\nOpen\nPartially Received\nCompleted\nMaterial Transferred\nPartial Material Transferred\nCancelled", + "print_hide": 1, + "read_only": 1, + "reqd": 1, + "search_index": 1 + }, + { + "fieldname": "column_break_39", + "fieldtype": "Column Break" + }, + { + "depends_on": "eval:!doc.__islocal", + "fieldname": "per_received", + "fieldtype": "Percent", + "in_list_view": 1, + "label": "% Received", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "printing_settings_section", + "fieldtype": "Section Break", + "label": "Printing Settings", + "print_hide": 1, + "print_width": "50%", + "width": "50%" + }, + { + "allow_on_submit": 1, + "fieldname": "select_print_heading", + "fieldtype": "Link", + "label": "Print Heading", + "no_copy": 1, + "options": "Print Heading", + "print_hide": 1, + "report_hide": 1 + }, + { + "fieldname": "column_break_43", + "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fieldname": "letter_head", + "fieldtype": "Link", + "label": "Letter Head", + "options": "Letter Head", + "print_hide": 1 + }, + { + "default": "Qty", + "fieldname": "distribute_additional_costs_based_on", + "fieldtype": "Select", + "label": "Distribute Additional Costs Based On ", + "options": "Qty\nAmount" + }, + { + "collapsible": 1, + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + } + ], + "icon": "fa fa-file-text", + "is_submittable": 1, + "links": [], + "modified": "2023-06-03 16:18:17.782538", + "modified_by": "Administrator", + "module": "Subcontracting", + "name": "Subcontracting Order", + "naming_rule": "By \"Naming Series\" field", + "owner": "Administrator", + "permissions": [ + { + "read": 1, + "report": 1, + "role": "Stock User" + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Manager", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase User", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "permlevel": 1, + "read": 1, + "role": "Purchase Manager", + "write": 1 + } + ], + "search_fields": "status, transaction_date, supplier", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "timeline_field": "supplier", + "title_field": "supplier_name", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index 3385eac0528..9dee3aae466 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -205,6 +205,7 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -629,7 +630,7 @@ "in_create": 1, "is_submittable": 1, "links": [], - "modified": "2022-11-16 14:18:57.001239", + "modified": "2023-06-03 16:18:39.088518", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt", diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.json b/erpnext/support/doctype/warranty_claim/warranty_claim.json index 45485ca2c2f..01d9b013906 100644 --- a/erpnext/support/doctype/warranty_claim/warranty_claim.json +++ b/erpnext/support/doctype/warranty_claim/warranty_claim.json @@ -1,9 +1,11 @@ { + "actions": [], "allow_import": 1, "autoname": "naming_series:", "creation": "2013-01-10 16:34:30", "doctype": "DocType", "document_type": "Setup", + "engine": "InnoDB", "field_order": [ "naming_series", "status", @@ -249,6 +251,7 @@ "fieldname": "contact_mobile", "fieldtype": "Data", "label": "Mobile No", + "options": "Phone", "read_only": 1 }, { @@ -362,10 +365,12 @@ ], "icon": "fa fa-bug", "idx": 1, - "modified": "2021-11-09 17:26:09.703215", + "links": [], + "modified": "2023-06-03 16:17:07.694449", "modified_by": "Administrator", "module": "Support", "name": "Warranty Claim", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { @@ -384,6 +389,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "timeline_field": "customer", "title_field": "customer_name" -} +} \ No newline at end of file