Skip to content

Commit

Permalink
Bump to v13.17.0 (#524) (#552)
Browse files Browse the repository at this point in the history
* feat: added QI link in Job Card Dashboard (backport frappe#28643)

* feat: Show Zero Values filter in consolidated financial statement

(cherry picked from commit 9610086)

* fix: ensure that reposting is finished before freezing stock/account

(cherry picked from commit d37541d)

* test: stock frozen validation

(cherry picked from commit 75bc404)

* fix: incorrect outgoing rates when material_consumption enabled

(cherry picked from commit 7f3e6d1)

* test: added tests for manufacture stock entry when material_consumption is enabled

(cherry picked from commit 35346de)

* fix: actual tax conversion in case of multicurrency invoices (backport frappe#28539)

* fix: Shipping Rule picking up old net_rate

(cherry picked from commit c78b8b7)

* fix: calling shipping rule method during net_total calculation in taxes_adn_totals.py

(cherry picked from commit 18ae03d)

* fix: check if shipping rule value exists

(cherry picked from commit af1fce0)

* fix: fixed tests, separated a  method for shipping charges

(cherry picked from commit a8e2c02)

* fix: sider issues

(cherry picked from commit e7b4204)

* fix: merge conflicts

* fix: Paid showing in AR/AP report

* fix: Better Error logging fordeferred revenue/expense booking

(cherry picked from commit 67a001d)

* fix: Commit joural entries

(cherry picked from commit 0ba4fce)

* fix: Log error before throwing exception

(cherry picked from commit 3c64e20)

* fix: mapping to maintenance visit gets erased (backport frappe#28917)

* fix: ignore mandatory fields while creating WO from SO (backport frappe#28772)

* refactor: map serial from schedule if only one (backport frappe#28745)

* fix: TDS Monthly payable report (backport frappe#28764)

* fix: Maintenance Visit purposes tables is not visible on submission (backport frappe#28792)

* fix: misleading "Set Default X" fields after saving (backport frappe#28798)

* fix: Fix depreciation_amount calculation

(cherry picked from commit 22cc8d2)

* fix: Create Depreciation Schedules properly for existing Assets

(cherry picked from commit 5c3d4ca)

* fix: Modify has_pro_rata() to include existing assets

(cherry picked from commit de00200)

* fix: Test if depreciation schedules are set up properly for existing assets

(cherry picked from commit 774ac85)

* fix: Remove unnecessary variable

(cherry picked from commit 828769c)

* fix: conflicts

* fix: conflicts

* feat: Add Serial No field

(cherry picked from commit 1aed8c4)

* fix: Rename item to item_code

(cherry picked from commit abb5355)

* feat: Add 'Add Serial No' button in the Stock Items table

(cherry picked from commit 4668bb4)

* fix: Add serial no to Stock Entry doc to decrease quantity for Stock Items consumed during repair

(cherry picked from commit 1393f97)

* fix: Replace 'item' with 'item_code' in tests

(cherry picked from commit c9e79ef)

* fix: Create stock item

(cherry picked from commit eea80b6)

* fix: Create setUpClass

(cherry picked from commit efac7b0)

* fix: Add test for consumption of serialized Assets

(cherry picked from commit 6b75d14)

* fix: Remove unused import

(cherry picked from commit b28f137)

* fix: Change order of import statements

(cherry picked from commit c94f1ed)

* Merge pull request frappe#29257 from marination/fix-reset-wh-defaults

fix: Avoid resetting Default wh fields for Manufacture Entry
(cherry picked from commit efcfb82)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
Co-authored-by: Subin Tom <subintom2@gmail.com>
Co-authored-by: GangaManoj <ganga.manoj98@gmail.com>
Co-authored-by: Saqib Ansari <nextchamp.saqib@gmail.com>
Co-authored-by: Marica <maricadsouza221197@gmail.com>
  • Loading branch information
8 people authored Apr 17, 2023
1 parent 4373214 commit b7eff24
Show file tree
Hide file tree
Showing 33 changed files with 453 additions and 57 deletions.
9 changes: 6 additions & 3 deletions erpnext/accounts/deferred_revenue.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,13 @@ def make_gl_entries(doc, credit_account, debit_account, against,
frappe.db.commit()
except Exception as e:
if frappe.flags.in_test:
traceback = frappe.get_traceback()
frappe.log_error(title=_('Error while processing deferred accounting for Invoice {0}').format(doc.name), message=traceback)
raise e
else:
frappe.db.rollback()
traceback = frappe.get_traceback()
frappe.log_error(message=traceback)

frappe.log_error(title=_('Error while processing deferred accounting for Invoice {0}').format(doc.name), message=traceback)
frappe.flags.deferred_accounting_error = True

def send_mail(deferred_process):
Expand Down Expand Up @@ -448,10 +449,12 @@ def book_revenue_via_journal_entry(doc, credit_account, debit_account, against,

if submit:
journal_entry.submit()

frappe.db.commit()
except Exception:
frappe.db.rollback()
traceback = frappe.get_traceback()
frappe.log_error(message=traceback)
frappe.log_error(title=_('Error while processing deferred accounting for Invoice {0}').format(doc.name), message=traceback)

frappe.flags.deferred_accounting_error = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from frappe.model.document import Document
from frappe.utils import cint

from erpnext.stock.utils import check_pending_reposting


class AccountsSettings(Document):
def on_update(self):
Expand All @@ -26,6 +28,7 @@ def validate(self):
self.validate_stale_days()
self.enable_payment_schedule_in_print()
self.toggle_discount_accounting_fields()
self.validate_pending_reposts()

def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
Expand Down Expand Up @@ -57,3 +60,8 @@ def toggle_discount_accounting_fields(self):
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)

make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)


def validate_pending_reposts(self):
if self.acc_frozen_upto:
check_pending_reposting(self.acc_frozen_upto)
3 changes: 3 additions & 0 deletions erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ def validate(self):
self.set_status()
self.validate_purchase_receipt_if_update_stock()
validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_invoice_reference)
self.reset_default_field_value("set_warehouse", "items", "warehouse")
self.reset_default_field_value("rejected_warehouse", "items", "rejected_warehouse")
self.reset_default_field_value("set_from_warehouse", "items", "from_warehouse")

def validate_release_date(self):
if self.release_date and getdate(nowdate()) >= getdate(self.release_date):
Expand Down
2 changes: 2 additions & 0 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ def validate(self):
if self.redeem_loyalty_points and self.loyalty_program and self.loyalty_points and not self.is_consolidated:
validate_loyalty_points(self, self.loyalty_points)

self.reset_default_field_value("set_warehouse", "items", "warehouse")

def validate_fixed_asset(self):
for d in self.get("items"):
if d.is_fixed_asset and d.meta.get_field("asset") and d.asset:
Expand Down
68 changes: 63 additions & 5 deletions erpnext/accounts/report/accounts_receivable/accounts_receivable.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ def init_voucher_balance(self):
invoiced = 0.0,
paid = 0.0,
credit_note = 0.0,
outstanding = 0.0
outstanding = 0.0,
invoiced_in_account_currency = 0.0,
paid_in_account_currency = 0.0,
credit_note_in_account_currency = 0.0,
outstanding_in_account_currency = 0.0
)
self.get_invoices(gle)

Expand Down Expand Up @@ -151,21 +155,28 @@ def update_voucher_balance(self, gle):
# gle_balance will be the total "debit - credit" for receivable type reports and
# and vice-versa for payable type reports
gle_balance = self.get_gle_balance(gle)
gle_balance_in_account_currency = self.get_gle_balance_in_account_currency(gle)

if gle_balance > 0:
if gle.voucher_type in ('Journal Entry', 'Payment Entry') and gle.against_voucher:
# debit against sales / purchase invoice
row.paid -= gle_balance
row.paid_in_account_currency -= gle_balance_in_account_currency
else:
# invoice
row.invoiced += gle_balance
row.invoiced_in_account_currency += gle_balance_in_account_currency
else:
# payment or credit note for receivables
if self.is_invoice(gle):
# stand alone debit / credit note
row.credit_note -= gle_balance
row.credit_note_in_account_currency -= gle_balance_in_account_currency
else:
# advance / unlinked payment or other adjustment
row.paid -= gle_balance
row.paid_in_account_currency -= gle_balance_in_account_currency

if gle.cost_center:
row.cost_center = str(gle.cost_center)

Expand Down Expand Up @@ -217,8 +228,46 @@ def build_data(self):
# as we can use this to filter out invoices without outstanding
for key, row in self.voucher_balance.items():
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
row.outstanding_in_account_currency = flt(row.invoiced_in_account_currency - row.paid_in_account_currency - \
row.credit_note_in_account_currency, self.currency_precision)
row.invoice_grand_total = row.invoiced
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:

if frappe.get_hooks('accounts_receivable_usd_column') and row.outstanding != 0.0:
if row['voucher_type'] == "Payment Entry":
currency_field = "paid_to_account_currency"
fields_to_get = ["paid_to_account_currency", "source_exchange_rate", "posting_date"]
elif row['voucher_type'] == "Journal Entry":
currency_field = "currency"
fields_to_get = ["posting_date"]
else:
currency_field = "currency"
fields_to_get = ["currency", "conversion_rate", "posting_date"]

vourcher_data = frappe.db.get_values(row['voucher_type'], row['voucher_no'], fields_to_get, as_dict=1)[0]

if row['voucher_type'] == "Journal Entry":
vourcher_data[currency_field] = "ARS"
elif row['voucher_type'] == "Payment Entry":
vourcher_data["conversion_rate"] = vourcher_data['source_exchange_rate']

if vourcher_data.get('conversion_rate') and vourcher_data.get('conversion_rate') != 1:
row.outstanding_original_currency = flt((row.outstanding / vourcher_data['conversion_rate']), self.currency_precision)
else:
if row['voucher_type'] == "Purchase Invoice":
exchange_type = "for_buying"
elif row['voucher_type'] == "Sales Invoice":
exchange_type = "for_selling"
elif row['voucher_type'] in ["Payment Entry", "Journal Entry"]:
if self.party_type == "Customer":
exchange_type = "for_selling"
else:
exchange_type = "for_buying"

conversion_rate = get_exchange_rate("USD", vourcher_data[currency_field], nowdate(), exchange_type)
row.outstanding_original_currency = flt((row.outstanding / conversion_rate), self.currency_precision)

if (abs(row.outstanding) > 1.0/10 ** self.currency_precision) and \
(abs(row.outstanding_in_account_currency) > 1.0/10 ** self.currency_precision):
# non-zero oustanding, we must consider this row

if self.is_invoice(row) and self.filters.based_on_payment_terms:
Expand Down Expand Up @@ -584,21 +633,23 @@ def get_gl_entries(self):
else:
select_fields = "debit, credit"

doc_currency_fields = "debit_in_account_currency, credit_in_account_currency"

remarks = ", remarks" if self.filters.get("show_remarks") else ""

self.gl_entries = frappe.db.sql("""
select
name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
against_voucher_type, against_voucher, account_currency, {0} {remarks}
against_voucher_type, against_voucher, account_currency, {0}, {1} {remarks}
from
`tabGL Entry`
where
docstatus < 2
and is_cancelled = 0
and party_type=%s
and (party is not null and party != '')
{1} {2} {3}"""
.format(select_fields, date_condition, conditions, order_by, remarks=remarks), values, as_dict=True)
{2} {3} {4}"""
.format(select_fields, doc_currency_fields, date_condition, conditions, order_by, remarks=remarks), values, as_dict=True)

def get_sales_invoices_or_customers_based_on_sales_person(self):
if self.filters.get("sales_person"):
Expand Down Expand Up @@ -719,6 +770,13 @@ def get_gle_balance(self, gle):
# get the balance of the GL (debit - credit) or reverse balance based on report type
return gle.get(self.dr_or_cr) - self.get_reverse_balance(gle)

def get_gle_balance_in_account_currency(self, gle):
# get the balance of the GL (debit - credit) or reverse balance based on report type
return gle.get(self.dr_or_cr + '_in_account_currency') - self.get_reverse_balance_in_account_currency(gle)

def get_reverse_balance_in_account_currency(self, gle):
return gle.get('debit_in_account_currency' if self.dr_or_cr=='credit' else 'credit_in_account_currency')

def get_reverse_balance(self, gle):
# get "credit" balance if report type is "debit" and vice versa
return gle.get('debit' if self.dr_or_cr=='credit' else 'credit')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"label": __("Include Default Book Entries"),
"fieldtype": "Check",
"default": 1
},
{
"fieldname": "show_zero_values",
"label": __("Show zero values"),
"fieldtype": "Check"
}
],
"formatter": function(value, row, column, data, default_formatter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
get_cash_flow_accounts,
)
from erpnext.accounts.report.cash_flow.cash_flow import get_report_summary as get_cash_flow_summary
from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts
from erpnext.accounts.report.financial_statements import (
filter_out_zero_value_rows,
get_fiscal_year_data,
sort_accounts,
)
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (
get_chart_data as get_pl_chart_data,
)
Expand Down Expand Up @@ -264,7 +268,7 @@ def get_columns(companies, filters):
return columns

def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, ignore_closing_entries=False):
accounts, accounts_by_name = get_account_heads(root_type,
accounts, accounts_by_name, parent_children_map = get_account_heads(root_type,
companies, filters)

if not accounts: return []
Expand Down Expand Up @@ -293,6 +297,8 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i

out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters)

out = filter_out_zero_value_rows(out, parent_children_map, show_zero_values=filters.get("show_zero_values"))

if out:
add_total_row(out, root_type, balance_must_be, companies, company_currency)

Expand Down Expand Up @@ -369,7 +375,7 @@ def get_account_heads(root_type, companies, filters):

accounts, accounts_by_name, parent_children_map = filter_accounts(accounts)

return accounts, accounts_by_name
return accounts, accounts_by_name, parent_children_map

def update_parent_account_names(accounts):
"""Update parent_account_name in accounts list.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map):
posting_date = entry.posting_date
voucher_type = entry.voucher_type

if not tax_withholding_category:
tax_withholding_category = supplier_map.get(supplier, {}).get('tax_withholding_category')
rate = tax_rate_map.get(tax_withholding_category)

if entry.account in tds_accounts:
tds_deducted += (entry.credit - entry.debit)

total_amount_credited += (entry.credit - entry.debit)

if rate and tds_deducted:
if tds_deducted:
row = {
'pan' if frappe.db.has_column('Supplier', 'pan') else 'tax_id': supplier_map.get(supplier).pan,
'supplier': supplier_map.get(supplier).name
Expand All @@ -68,7 +72,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map):

def get_supplier_pan_map():
supplier_map = frappe._dict()
suppliers = frappe.db.get_all('Supplier', fields=['name', 'pan', 'supplier_type', 'supplier_name'])
suppliers = frappe.db.get_all('Supplier', fields=['name', 'pan', 'supplier_type', 'supplier_name', 'tax_withholding_category'])

for d in suppliers:
supplier_map[d.name] = d
Expand Down
49 changes: 38 additions & 11 deletions erpnext/assets/doctype/asset/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,8 @@ def make_depreciation_schedule(self, date_of_sale):
start = self.clear_depreciation_schedule()

# value_after_depreciation - current Asset value
if d.value_after_depreciation:
value_after_depreciation = (flt(d.value_after_depreciation) -
flt(self.opening_accumulated_depreciation))
if self.docstatus == 1 and d.value_after_depreciation:
value_after_depreciation = flt(d.value_after_depreciation)
else:
value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
Expand Down Expand Up @@ -242,7 +241,7 @@ def make_depreciation_schedule(self, date_of_sale):
break

# For first row
if has_pro_rata and n==0:
if has_pro_rata and not self.opening_accumulated_depreciation and n==0:
depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
self.available_for_use_date, d.depreciation_start_date)

Expand All @@ -255,7 +254,7 @@ def make_depreciation_schedule(self, date_of_sale):
if not self.flags.increase_in_asset_life:
# In case of increase_in_asset_life, the self.to_date is already set on asset_repair submission
self.to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
(n + self.number_of_depreciations_booked) * cint(d.frequency_of_depreciation))

depreciation_amount, days, months = self.get_pro_rata_amt(d,
depreciation_amount, schedule_date, self.to_date)
Expand Down Expand Up @@ -351,7 +350,12 @@ def get_from_date(self, finance_book):
# if it returns True, depreciation_amount will not be equal for the first and last rows
def check_is_pro_rata(self, row):
has_pro_rata = False
days = date_diff(row.depreciation_start_date, self.available_for_use_date) + 1

# if not existing asset, from_date = available_for_use_date
# otherwise, if number_of_depreciations_booked = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
# from_date = 01/01/2022
from_date = self.get_modified_available_for_use_date(row)
days = date_diff(row.depreciation_start_date, from_date) + 1

# if frequency_of_depreciation is 12 months, total_days = 365
total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
Expand All @@ -361,6 +365,9 @@ def check_is_pro_rata(self, row):

return has_pro_rata

def get_modified_available_for_use_date(self, row):
return add_months(self.available_for_use_date, (self.number_of_depreciations_booked * row.frequency_of_depreciation))

def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
frappe.throw(_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount")
Expand Down Expand Up @@ -397,7 +404,29 @@ def validate_asset_finance_books(self, row):
frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date")
.format(row.idx))

def set_accumulated_depreciation(self, date_of_sale=None, ignore_booked_entry = False):
# to ensure that final accumulated depreciation amount is accurate
def get_adjusted_depreciation_amount(self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row, finance_book):
if not self.opening_accumulated_depreciation:
depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row(finance_book)

if depreciation_amount_for_first_row + depreciation_amount_for_last_row != depreciation_amount_without_pro_rata:
depreciation_amount_for_last_row = depreciation_amount_without_pro_rata - depreciation_amount_for_first_row

return depreciation_amount_for_last_row

def get_depreciation_amount_for_first_row(self, finance_book):
if self.has_only_one_finance_book():
return self.schedules[0].depreciation_amount
else:
for schedule in self.schedules:
if schedule.finance_book == finance_book:
return schedule.depreciation_amount

def has_only_one_finance_book(self):
if len(self.finance_books) == 1:
return True

def set_accumulated_depreciation(self, date_of_sale=None, date_of_return=None, ignore_booked_entry = False):
straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line']
finance_books = []

Expand Down Expand Up @@ -828,13 +857,11 @@ def get_total_days(date, frequency):

@erpnext.allow_regional
def get_depreciation_amount(asset, depreciable_value, row):
depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)

if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
if not asset.flags.increase_in_asset_life:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / depreciation_left
depreciation_amount = (flt(asset.gross_purchase_amount) -
flt(row.expected_value_after_useful_life)) / flt(row.total_number_of_depreciations)

# if the Depreciation Schedule is being modified after Asset Repair
else:
Expand Down
4 changes: 4 additions & 0 deletions erpnext/assets/doctype/asset_repair/asset_repair.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ frappe.ui.form.on('Asset Repair', {
if (frm.doc.repair_status == "Completed") {
frm.set_value('completion_date', frappe.datetime.now_datetime());
}
},

stock_items_on_form_rendered() {
erpnext.setup_serial_or_batch_no();
}
});

Expand Down
Loading

0 comments on commit b7eff24

Please sign in to comment.