diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py index 9d2deea523b..449ebdcd924 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py @@ -22,8 +22,7 @@ def get_columns(): { "label": _("Payment Document Type"), "fieldname": "payment_document_type", - "fieldtype": "Link", - "options": "Doctype", + "fieldtype": "Data", "width": 130, }, { @@ -33,15 +32,15 @@ def get_columns(): "options": "payment_document_type", "width": 140, }, - {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 100}, + {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 120}, {"label": _("Cheque/Reference No"), "fieldname": "cheque_no", "width": 120}, - {"label": _("Clearance Date"), "fieldname": "clearance_date", "fieldtype": "Date", "width": 100}, + {"label": _("Clearance Date"), "fieldname": "clearance_date", "fieldtype": "Date", "width": 120}, { "label": _("Against Account"), "fieldname": "against", "fieldtype": "Link", "options": "Account", - "width": 170, + "width": 200, }, {"label": _("Amount"), "fieldname": "amount", "fieldtype": "Currency", "width": 120}, ] diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 3beaa2bfe74..f5b46bde586 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -27,6 +27,7 @@ class PartyLedgerSummaryReport(object): ) self.get_gl_entries() + self.get_additional_columns() self.get_return_invoices() self.get_party_adjustment_amounts() @@ -34,6 +35,42 @@ class PartyLedgerSummaryReport(object): data = self.get_data() return columns, data + def get_additional_columns(self): + """ + Additional Columns for 'User Permission' based access control + """ + from frappe import qb + + if self.filters.party_type == "Customer": + self.territories = frappe._dict({}) + self.customer_group = frappe._dict({}) + + customer = qb.DocType("Customer") + result = ( + frappe.qb.from_(customer) + .select( + customer.name, customer.territory, customer.customer_group, customer.default_sales_partner + ) + .where((customer.disabled == 0)) + .run(as_dict=True) + ) + + for x in result: + self.territories[x.name] = x.territory + self.customer_group[x.name] = x.customer_group + else: + self.supplier_group = frappe._dict({}) + supplier = qb.DocType("Supplier") + result = ( + frappe.qb.from_(supplier) + .select(supplier.name, supplier.supplier_group) + .where((supplier.disabled == 0)) + .run(as_dict=True) + ) + + for x in result: + self.supplier_group[x.name] = x.supplier_group + def get_columns(self): columns = [ { @@ -117,6 +154,35 @@ class PartyLedgerSummaryReport(object): }, ] + # Hidden columns for handling 'User Permissions' + if self.filters.party_type == "Customer": + columns += [ + { + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Link", + "options": "Territory", + "hidden": 1, + }, + { + "label": _("Customer Group"), + "fieldname": "customer_group", + "fieldtype": "Link", + "options": "Customer Group", + "hidden": 1, + }, + ] + else: + columns += [ + { + "label": _("Supplier Group"), + "fieldname": "supplier_group", + "fieldtype": "Link", + "options": "Supplier Group", + "hidden": 1, + } + ] + return columns def get_data(self): @@ -144,6 +210,12 @@ class PartyLedgerSummaryReport(object): ), ) + if self.filters.party_type == "Customer": + self.party_data[gle.party].update({"territory": self.territories.get(gle.party)}) + self.party_data[gle.party].update({"customer_group": self.customer_group.get(gle.party)}) + else: + self.party_data[gle.party].update({"supplier_group": self.supplier_group.get(gle.party)}) + amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) self.party_data[gle.party].closing_balance += amount diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index b71b31a5ec2..6bd3ee5aa6b 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -551,6 +551,7 @@ class GrossProfitGenerator(object): return abs(previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty)) else: return flt(row.qty) * self.get_average_buying_rate(row, item_code) + return 0.0 def get_buying_amount(self, row, item_code): # IMP NOTE diff --git a/erpnext/accounts/report/gross_profit/test_gross_profit.py b/erpnext/accounts/report/gross_profit/test_gross_profit.py index 1279dec25af..d9febb74fd4 100644 --- a/erpnext/accounts/report/gross_profit/test_gross_profit.py +++ b/erpnext/accounts/report/gross_profit/test_gross_profit.py @@ -6,6 +6,8 @@ from frappe.utils import add_days, flt, nowdate from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_delivery_note from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.report.gross_profit.gross_profit import execute +from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice +from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -14,6 +16,7 @@ class TestGrossProfit(FrappeTestCase): def setUp(self): self.create_company() self.create_item() + self.create_bundle() self.create_customer() self.create_sales_invoice() self.clear_old_entries() @@ -42,6 +45,7 @@ class TestGrossProfit(FrappeTestCase): self.company = company.name self.cost_center = company.cost_center self.warehouse = "Stores - " + abbr + self.finished_warehouse = "Finished Goods - " + abbr self.income_account = "Sales - " + abbr self.expense_account = "Cost of Goods Sold - " + abbr self.debit_to = "Debtors - " + abbr @@ -53,6 +57,23 @@ class TestGrossProfit(FrappeTestCase): ) self.item = item if isinstance(item, str) else item.item_code + def create_bundle(self): + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + + item2 = create_item( + item_code="_Test GP Item 2", is_stock_item=1, company=self.company, warehouse=self.warehouse + ) + self.item2 = item2 if isinstance(item2, str) else item2.item_code + + # This will be parent item + bundle = create_item( + item_code="_Test GP bundle", is_stock_item=0, company=self.company, warehouse=self.warehouse + ) + self.bundle = bundle if isinstance(bundle, str) else bundle.item_code + + # Create Product Bundle + self.product_bundle = make_product_bundle(parent=self.bundle, items=[self.item, self.item2]) + def create_customer(self): name = "_Test GP Customer" if frappe.db.exists("Customer", name): @@ -93,6 +114,28 @@ class TestGrossProfit(FrappeTestCase): ) return sinv + def create_delivery_note( + self, item=None, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False + ): + """ + Helper function to populate default values in Delivery Note + """ + dnote = create_delivery_note( + company=self.company, + customer=self.customer, + currency="INR", + item=item or self.item, + qty=qty, + rate=rate, + cost_center=self.cost_center, + warehouse=self.warehouse, + return_against=None, + expense_account=self.expense_account, + do_not_save=do_not_save, + do_not_submit=do_not_submit, + ) + return dnote + def clear_old_entries(self): doctype_list = [ "Sales Invoice", @@ -206,3 +249,55 @@ class TestGrossProfit(FrappeTestCase): } gp_entry = [x for x in data if x.parent_invoice == sinv.name] self.assertDictContainsSubset(expected_entry_with_dn, gp_entry[0]) + + def test_bundled_delivery_note_with_different_warehouses(self): + """ + Test Delivery Note with bundled item. Packed Item from the bundle having different warehouses + """ + se = make_stock_entry( + company=self.company, + item_code=self.item, + target=self.warehouse, + qty=1, + basic_rate=100, + do_not_submit=True, + ) + item = se.items[0] + se.append( + "items", + { + "item_code": self.item2, + "s_warehouse": "", + "t_warehouse": self.finished_warehouse, + "qty": 1, + "basic_rate": 100, + "conversion_factor": item.conversion_factor or 1.0, + "transfer_qty": flt(item.qty) * (flt(item.conversion_factor) or 1.0), + "serial_no": item.serial_no, + "batch_no": item.batch_no, + "cost_center": item.cost_center, + "expense_account": item.expense_account, + }, + ) + se = se.save().submit() + + # Make a Delivery note with Product bundle + # Packed Items will have different warehouses + dnote = self.create_delivery_note(item=self.bundle, qty=1, rate=200, do_not_submit=True) + dnote.packed_items[1].warehouse = self.finished_warehouse + dnote = dnote.submit() + + # make Sales Invoice for above delivery note + sinv = make_sales_invoice(dnote.name) + sinv = sinv.save().submit() + + filters = frappe._dict( + company=self.company, + from_date=nowdate(), + to_date=nowdate(), + group_by="Invoice", + sales_invoice=sinv.name, + ) + + columns, data = execute(filters=filters) + self.assertGreater(len(data), 0) diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js index f81297760ed..5dc4c3d1c15 100644 --- a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js @@ -63,24 +63,6 @@ frappe.query_reports["Supplier Ledger Summary"] = { "fieldtype": "Link", "options": "Payment Terms Template" }, - { - "fieldname":"territory", - "label": __("Territory"), - "fieldtype": "Link", - "options": "Territory" - }, - { - "fieldname":"sales_partner", - "label": __("Sales Partner"), - "fieldtype": "Link", - "options": "Sales Partner" - }, - { - "fieldname":"sales_person", - "label": __("Sales Person"), - "fieldtype": "Link", - "options": "Sales Person" - }, { "fieldname":"tax_id", "label": __("Tax Id"), diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 2144ae00366..6358896e7dc 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -370,7 +370,7 @@ { "fieldname": "shipping_address", "fieldtype": "Link", - "label": "Company Shipping Address", + "label": "Shipping Address", "options": "Address", "print_hide": 1 }, @@ -1170,7 +1170,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2022-11-17 12:34:36.033363", + "modified": "2022-12-25 18:08:59.074182", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/patches/v11_0/create_salary_structure_assignments.py b/erpnext/patches/v11_0/create_salary_structure_assignments.py index b81e867b9dd..51b2a2cc0b1 100644 --- a/erpnext/patches/v11_0/create_salary_structure_assignments.py +++ b/erpnext/patches/v11_0/create_salary_structure_assignments.py @@ -13,8 +13,10 @@ from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assign def execute(): + frappe.reload_doc("Payroll", "doctype", "Payroll Settings") frappe.reload_doc("Payroll", "doctype", "Salary Structure") frappe.reload_doc("Payroll", "doctype", "Salary Structure Assignment") + frappe.db.sql( """ delete from `tabSalary Structure Assignment` diff --git a/erpnext/payroll/doctype/payroll_settings/payroll_settings.json b/erpnext/payroll/doctype/payroll_settings/payroll_settings.json index 54377e94b30..f4db6f099a6 100644 --- a/erpnext/payroll/doctype/payroll_settings/payroll_settings.json +++ b/erpnext/payroll/doctype/payroll_settings/payroll_settings.json @@ -11,6 +11,7 @@ "max_working_hours_against_timesheet", "include_holidays_in_total_working_days", "disable_rounded_total", + "define_opening_balance_for_earning_and_deductions", "column_break_11", "daily_wages_fraction_for_half_day", "email_salary_slip_to_employee", @@ -91,13 +92,20 @@ "fieldname": "show_leave_balances_in_salary_slip", "fieldtype": "Check", "label": "Show Leave Balances in Salary Slip" + }, + { + "default": "0", + "description": "If checked, then the system will enable the provision to set the opening balance for earnings and deductions till date while creating a Salary Structure Assignment (if any)", + "fieldname": "define_opening_balance_for_earning_and_deductions", + "fieldtype": "Check", + "label": "Define Opening Balance for Earning and Deductions" } ], "icon": "fa fa-cog", "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-03-03 17:49:59.579723", + "modified": "2022-12-21 17:30:08.704247", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll Settings", diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index b2243838202..0563541eaa5 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -1063,7 +1063,25 @@ class SalarySlip(TransactionBase): ) exempted_amount = flt(exempted_amount[0][0]) if exempted_amount else 0 - return taxable_earnings - exempted_amount + opening_taxable_earning = self.get_opening_balance_for( + "taxable_earnings_till_date", start_date, end_date + ) + + return (taxable_earnings + opening_taxable_earning) - exempted_amount + + def get_opening_balance_for(self, field_to_select, start_date, end_date): + opening_balance = frappe.db.get_all( + "Salary Structure Assignment", + { + "employee": self.employee, + "salary_structure": self.salary_structure, + "from_date": ["between", (start_date, end_date)], + "docstatus": 1, + }, + field_to_select, + ) + + return opening_balance[0].get(field_to_select) if opening_balance else 0.0 def get_tax_paid_in_period(self, start_date, end_date, tax_component): # find total_tax_paid, tax paid for benefit, additional_salary @@ -1092,7 +1110,11 @@ class SalarySlip(TransactionBase): )[0][0] ) - return total_tax_paid + tax_deducted_till_date = self.get_opening_balance_for( + "tax_deducted_till_date", start_date, end_date + ) + + return total_tax_paid + tax_deducted_till_date def get_taxable_earnings( self, allow_tax_exemption=False, based_on_payment_days=0, payroll_period=None diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 6e3b57239d4..32d0c7ed08f 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -1030,6 +1030,104 @@ class TestSalarySlip(FrappeTestCase): activity_type.wage_rate = 25 activity_type.save() + def test_salary_slip_generation_against_opening_entries_in_ssa(self): + import math + + from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor + from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + + payroll_period = frappe.db.get_value( + "Payroll Period", + { + "company": "_Test Company", + "start_date": ["<=", "2023-03-31"], + "end_date": [">=", "2022-04-01"], + }, + "name", + ) + + if not payroll_period: + payroll_period = create_payroll_period( + name="_Test Payroll Period for Tax", + company="_Test Company", + start_date="2022-04-01", + end_date="2023-03-31", + ) + else: + payroll_period = frappe.get_cached_doc("Payroll Period", payroll_period) + + emp = make_employee( + "test_employee_ss_with_opening_balance@salary.com", + company="_Test Company", + **{"date_of_joining": "2021-12-01"}, + ) + employee_doc = frappe.get_doc("Employee", emp) + + create_tax_slab(payroll_period, allow_tax_exemption=True) + + salary_structure_name = "Test Salary Structure for Opening Balance" + if not frappe.db.exists("Salary Structure", salary_structure_name): + salary_structure_doc = make_salary_structure( + salary_structure_name, + "Monthly", + company="_Test Company", + employee=emp, + from_date="2022-04-01", + payroll_period=payroll_period, + test_tax=True, + ) + + # validate no salary slip exists for the employee + self.assertTrue( + frappe.db.count( + "Salary Slip", + { + "employee": emp, + "salary_structure": salary_structure_doc.name, + "docstatus": 1, + "start_date": [">=", "2022-04-01"], + }, + ) + == 0 + ) + + remaining_sub_periods = get_period_factor( + emp, + get_first_day("2022-10-01"), + get_last_day("2022-10-01"), + "Monthly", + payroll_period, + depends_on_payment_days=0, + )[1] + + prev_period = math.ceil(remaining_sub_periods) + + annual_tax = 93036 # 89220 #data[0].get('applicable_tax') + monthly_tax_amount = 7732.40 # 7435 #annual_tax/12 + annual_earnings = 933600 # data[0].get('ctc') + monthly_earnings = 77800 # annual_earnings/12 + + # Get Salary Structure Assignment + ssa = frappe.get_value( + "Salary Structure Assignment", + {"employee": emp, "salary_structure": salary_structure_doc.name}, + "name", + ) + ssa_doc = frappe.get_doc("Salary Structure Assignment", ssa) + + # Set opening balance for earning and tax deduction in Salary Structure Assignment + ssa_doc.taxable_earnings_till_date = monthly_earnings * prev_period + ssa_doc.tax_deducted_till_date = monthly_tax_amount * prev_period + ssa_doc.save() + + # Create Salary Slip + salary_slip = make_salary_slip( + salary_structure_doc.name, employee=employee_doc.name, posting_date=getdate("2022-10-01") + ) + for deduction in salary_slip.deductions: + if deduction.salary_component == "TDS": + self.assertEqual(deduction.amount, rounded(monthly_tax_amount)) + def get_no_of_days(): no_of_days_in_month = calendar.monthrange(getdate(nowdate()).year, getdate(nowdate()).month) diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js index 6cd897e95d1..7cb573d6307 100644 --- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js +++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js @@ -42,6 +42,13 @@ frappe.ui.form.on('Salary Structure Assignment', { }); }, + refresh: function(frm) { + if(frm.doc.__onload){ + frm.unhide_earnings_and_taxation_section = frm.doc.__onload.earning_and_deduction_entries_does_not_exists; + frm.trigger("set_earnings_and_taxation_section_visibility"); + } + }, + employee: function(frm) { if(frm.doc.employee){ frappe.call({ @@ -59,6 +66,8 @@ frappe.ui.form.on('Salary Structure Assignment', { } } }); + + frm.trigger("valiadte_joining_date_and_salary_slips"); } else{ frm.set_value("company", null); @@ -71,5 +80,33 @@ frappe.ui.form.on('Salary Structure Assignment', { frm.set_value("payroll_payable_account", r.default_payroll_payable_account); }); } - } + }, + + valiadte_joining_date_and_salary_slips: function(frm) { + frappe.call({ + method: "earning_and_deduction_entries_does_not_exists", + doc: frm.doc, + callback: function(data) { + let earning_and_deduction_entries_does_not_exists = data.message; + frm.unhide_earnings_and_taxation_section = earning_and_deduction_entries_does_not_exists; + frm.trigger("set_earnings_and_taxation_section_visibility"); + } + }); + }, + + set_earnings_and_taxation_section_visibility: function(frm) { + if(frm.unhide_earnings_and_taxation_section){ + frm.set_df_property('earnings_and_taxation_section', 'hidden', 0); + } + else{ + frm.set_df_property('earnings_and_taxation_section', 'hidden', 1); + } + }, + + from_date: function(frm) { + if (frm.doc.from_date) { + frm.trigger("valiadte_joining_date_and_salary_slips" ); + } + }, + }); diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json index c8b98e5aafc..4db023c6d51 100644 --- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json +++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.json @@ -22,6 +22,10 @@ "base", "column_break_9", "variable", + "earnings_and_taxation_section", + "taxable_earnings_till_date", + "column_break_18", + "tax_deducted_till_date", "amended_from" ], "fields": [ @@ -141,11 +145,31 @@ "fieldtype": "Link", "label": "Payroll Payable Account", "options": "Account" + }, + { + "fieldname": "earnings_and_taxation_section", + "fieldtype": "Section Break" + }, + { + "allow_on_submit": 1, + "fieldname": "tax_deducted_till_date", + "fieldtype": "Currency", + "label": "Tax Deducted Till Date" + }, + { + "fieldname": "column_break_18", + "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fieldname": "taxable_earnings_till_date", + "fieldtype": "Currency", + "label": "Taxable Earnings Till Date" } ], "is_submittable": 1, "links": [], - "modified": "2021-03-31 22:44:46.267974", + "modified": "2022-12-26 12:47:42.521891", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Structure Assignment", diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py index e34e48e6c05..21196c3e52d 100644 --- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py +++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py @@ -13,10 +13,32 @@ class DuplicateAssignment(frappe.ValidationError): class SalaryStructureAssignment(Document): + def onload(self): + if self.employee: + self.set_onload( + "earning_and_deduction_entries_exists", self.earning_and_deduction_entries_does_not_exists() + ) + def validate(self): self.validate_dates() self.validate_income_tax_slab() self.set_payroll_payable_account() + self.valiadte_missing_taxable_earnings_and_deductions_till_date() + + def valiadte_missing_taxable_earnings_and_deductions_till_date(self): + if self.earning_and_deduction_entries_does_not_exists(): + if not self.taxable_earnings_till_date and not self.tax_deducted_till_date: + frappe.msgprint( + _( + """Not found any salary slip record(s) for the employee {0}.

Please specify {1} and {2} (if any), for the correct tax calculation in future salary slips.""" + ).format( + self.employee, + "" + _("Taxable Earnings Till Date") + "", + "" + _("Tax Deducted Till Date") + "", + ), + indicator="orange", + title=_("Warning"), + ) def validate_dates(self): joining_date, relieving_date = frappe.db.get_value( @@ -76,6 +98,56 @@ class SalaryStructureAssignment(Document): ) self.payroll_payable_account = payroll_payable_account + @frappe.whitelist() + def earning_and_deduction_entries_does_not_exists(self): + if self.enabled_settings_to_specify_earnings_and_deductions_till_date(): + if not self.joined_in_the_same_month() and not self.have_salary_slips(): + return True + else: + if self.docstatus in [1, 2] and ( + self.taxable_earnings_till_date or self.tax_deducted_till_date + ): + return True + return False + else: + return False + + def enabled_settings_to_specify_earnings_and_deductions_till_date(self): + """returns True if settings are enabled to specify earnings and deductions till date else False""" + + if frappe.db.get_single_value( + "Payroll Settings", "define_opening_balance_for_earning_and_deductions" + ): + return True + return False + + def have_salary_slips(self): + """returns True if salary structure assignment has salary slips else False""" + + salary_slip = frappe.db.get_value( + "Salary Slip", filters={"employee": self.employee, "docstatus": 1} + ) + + if salary_slip: + return True + + return False + + def joined_in_the_same_month(self): + """returns True if employee joined in same month as salary structure assignment from date else False""" + + date_of_joining = frappe.db.get_value("Employee", self.employee, "date_of_joining") + from_date = getdate(self.from_date) + + if not self.from_date or not date_of_joining: + return False + + elif date_of_joining.month == from_date.month: + return True + + else: + return False + def get_assigned_salary_structure(employee, on_date): if not employee or not on_date: diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 303e4fff4af..8b28e02797d 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1090,6 +1090,15 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): ] items_to_map = list(set(items_to_map)) + def is_drop_ship_order(target): + drop_ship = True + for item in target.items: + if not item.delivered_by_supplier: + drop_ship = False + break + + return drop_ship + def set_missing_values(source, target): target.supplier = "" target.apply_discount_on = "" @@ -1097,8 +1106,14 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.discount_amount = 0.0 target.inter_company_order_reference = "" target.shipping_rule = "" - target.customer = "" - target.customer_name = "" + + if is_drop_ship_order(target): + target.customer = source.customer + target.customer_name = source.customer_name + target.shipping_address = source.shipping_address_name + else: + target.customer = target.customer_name = target.shipping_address = None + target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json index 0e2ed9efcf8..d6a431ea616 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.json +++ b/erpnext/setup/doctype/customer_group/customer_group.json @@ -139,10 +139,11 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2021-02-08 17:01:52.162202", + "modified": "2022-12-24 11:15:17.142746", "modified_by": "Administrator", "module": "Setup", "name": "Customer Group", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_customer_group", "owner": "Administrator", "permissions": [ @@ -198,10 +199,19 @@ "role": "Customer", "select": 1, "share": 1 + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } ], "search_fields": "parent_customer_group", "show_name_in_global_search": 1, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.json b/erpnext/setup/doctype/supplier_group/supplier_group.json index 9119bb947cb..b3ed608cd03 100644 --- a/erpnext/setup/doctype/supplier_group/supplier_group.json +++ b/erpnext/setup/doctype/supplier_group/supplier_group.json @@ -6,6 +6,7 @@ "creation": "2013-01-10 16:34:24", "doctype": "DocType", "document_type": "Setup", + "engine": "InnoDB", "field_order": [ "supplier_group_name", "parent_supplier_group", @@ -106,10 +107,11 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2020-03-18 18:10:49.228407", + "modified": "2022-12-24 11:16:12.486719", "modified_by": "Administrator", "module": "Setup", "name": "Supplier Group", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_supplier_group", "owner": "Administrator", "permissions": [ @@ -156,8 +158,18 @@ "permlevel": 1, "read": 1, "role": "Purchase User" + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } ], "show_name_in_global_search": 1, - "sort_order": "ASC" + "sort_field": "modified", + "sort_order": "ASC", + "states": [] } \ No newline at end of file diff --git a/erpnext/setup/doctype/territory/territory.json b/erpnext/setup/doctype/territory/territory.json index a25bda054b9..c3a49933746 100644 --- a/erpnext/setup/doctype/territory/territory.json +++ b/erpnext/setup/doctype/territory/territory.json @@ -123,11 +123,12 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2021-02-08 17:10:03.767426", + "modified": "2022-12-24 11:16:39.964956", "modified_by": "Administrator", "module": "Setup", "name": "Territory", "name_case": "Title Case", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_territory", "owner": "Administrator", "permissions": [ @@ -175,10 +176,19 @@ "role": "Customer", "select": 1, "share": 1 + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } ], "search_fields": "parent_territory,territory_manager", "show_name_in_global_search": 1, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index d53f4cdbac9..b27abae513e 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -10,7 +10,6 @@ import frappe from frappe import _ from frappe.model.mapper import get_mapped_doc from frappe.query_builder.functions import Sum -from six import iteritems, itervalues, string_types from frappe.utils import ( add_days, cint, @@ -23,6 +22,7 @@ from frappe.utils import ( nowdate, today, ) +from six import iteritems, itervalues, string_types import erpnext from erpnext.accounts.general_ledger import process_gl_map @@ -2625,4 +2625,3 @@ def get_incorrect_stock_entries() -> Dict: stock_entries.setdefault(row.name, row) return stock_entries -