Compare commits

..

12 Commits

Author SHA1 Message Date
Frappe PR Bot
7c1288f726 chore(release): Bumped to Version 13.53.0
# [13.53.0](https://github.com/frappe/erpnext/compare/v13.52.15...v13.53.0) (2023-09-19)

### Bug Fixes

* fetch logic for repay_from_salary in loan_repayment [v13] ([#37136](https://github.com/frappe/erpnext/issues/37136)) ([d4f8b05](d4f8b057e1))

### Features

* provision to create RIV from `Stock Ledger Invariant Check` report (backport [#37115](https://github.com/frappe/erpnext/issues/37115)) ([#37149](https://github.com/frappe/erpnext/issues/37149)) ([86b152f](86b152fe5c))
2023-09-19 13:22:41 +00:00
Deepesh Garg
c89715d6da Merge pull request #37154 from frappe/version-13-hotfix
chore: release v13
2023-09-19 18:50:07 +05:30
Anand Baburajan
d4f8b057e1 fix: fetch logic for repay_from_salary in loan_repayment [v13] (#37136)
fix: fetch logic for repay_from_salary in loan_repayment
2023-09-19 15:18:17 +05:30
mergify[bot]
86b152fe5c feat: provision to create RIV from Stock Ledger Invariant Check report (backport #37115) (#37149)
* feat: provision to create RIV from `Stock Ledger Invariant Check` report (#37115)

* feat: provision to create RIV from `Stock Ledger Invariant Check` report

* fix: `linter`

(cherry picked from commit 9c9d0ecb73)

# Conflicts:
#	erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py

* chore: `conflicts`

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-09-19 09:19:46 +00:00
Frappe PR Bot
11b16569e5 chore(release): Bumped to Version 13.52.15
## [13.52.15](https://github.com/frappe/erpnext/compare/v13.52.14...v13.52.15) (2023-09-12)

### Bug Fixes

* prorate factor for subscription plan ([#36953](https://github.com/frappe/erpnext/issues/36953)) ([9a15ed8](9a15ed8083))
2023-09-12 12:21:41 +00:00
Deepesh Garg
cd99630457 Merge pull request #37044 from frappe/version-13-hotfix
chore: release v13
2023-09-12 17:50:08 +05:30
Frappe PR Bot
efab1e7361 chore(release): Bumped to Version 13.52.14
## [13.52.14](https://github.com/frappe/erpnext/compare/v13.52.13...v13.52.14) (2023-09-10)

### Bug Fixes

* prorate factor for subscription plan ([#36953](https://github.com/frappe/erpnext/issues/36953)) ([d7f09f8](d7f09f8795))
2023-09-10 18:30:02 +00:00
Deepesh Garg
63a6e7e35c Merge pull request #37018 from frappe/mergify/bp/version-13/pr-37009
fix: prorate factor for subscription plan (#36953)
2023-09-10 23:58:35 +05:30
Gursheen Kaur Anand
d7f09f8795 fix: prorate factor for subscription plan (#36953)
(cherry picked from commit fc79af5926)
(cherry picked from commit 9a15ed8083)
2023-09-10 17:58:33 +00:00
Deepesh Garg
437a294621 Merge pull request #37009 from frappe/mergify/bp/version-13-hotfix/pr-36953
fix: prorate factor for subscription plan (#36953)
2023-09-10 12:21:09 +05:30
Gursheen Kaur Anand
9a15ed8083 fix: prorate factor for subscription plan (#36953)
(cherry picked from commit fc79af5926)
2023-09-10 06:06:12 +00:00
mergify[bot]
3a49d4f9b3 chore: asset finance books validation (backport #36979) (#36982)
* chore: asset finance books validation (#36979)

(cherry picked from commit 0077659e93)

# Conflicts:
#	erpnext/assets/doctype/asset/asset.py

* chore: fix conflicts

* chore: fix tests

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-09-06 15:39:44 +05:30
10 changed files with 180 additions and 42 deletions

View File

@@ -4,7 +4,7 @@ import frappe
from erpnext.hooks import regional_overrides
__version__ = "13.52.13"
__version__ = "13.53.0"
def get_default_company(user=None):

View File

@@ -694,3 +694,23 @@ class TestSubscription(unittest.TestCase):
# Check the currency of the created invoice
currency = frappe.db.get_value("Sales Invoice", subscription.invoices[0].invoice, "currency")
self.assertEqual(currency, "USD")
def test_plan_rate_for_midmonth_start_date(self):
subscription = frappe.new_doc("Subscription")
subscription.party_type = "Supplier"
subscription.party = "_Test Supplier"
subscription.generate_invoice_at_period_start = 1
subscription.follow_calendar_months = 1
subscription.generate_new_invoices_past_due_date = 1
subscription.start_date = "2023-04-08"
subscription.end_date = "2024-02-27"
subscription.append("plans", {"plan": "_Test Plan Name 4", "qty": 1})
subscription.save()
subscription.process()
self.assertEqual(len(subscription.invoices), 1)
pi = frappe.get_doc("Purchase Invoice", subscription.invoices[0].invoice)
self.assertEqual(pi.total, 55333.33)
subscription.delete()

View File

@@ -56,18 +56,17 @@ def get_plan_rate(
prorate = frappe.db.get_single_value("Subscription Settings", "prorate")
if prorate:
prorate_factor = flt(
date_diff(start_date, get_first_day(start_date))
/ date_diff(get_last_day(start_date), get_first_day(start_date)),
1,
)
prorate_factor += flt(
date_diff(get_last_day(end_date), end_date)
/ date_diff(get_last_day(end_date), get_first_day(end_date)),
1,
)
cost -= plan.cost * prorate_factor
cost -= plan.cost * get_prorate_factor(start_date, end_date)
return cost
def get_prorate_factor(start_date, end_date):
total_days_to_skip = date_diff(start_date, get_first_day(start_date))
total_days_in_month = int(get_last_day(start_date).strftime("%d"))
prorate_factor = flt(total_days_to_skip / total_days_in_month)
total_days_to_skip = date_diff(get_last_day(end_date), end_date)
total_days_in_month = int(get_last_day(end_date).strftime("%d"))
prorate_factor += flt(total_days_to_skip / total_days_in_month)
return prorate_factor

View File

@@ -41,6 +41,7 @@ class Asset(AccountsController):
self.validate_item()
self.validate_cost_center()
self.set_missing_values()
self.validate_finance_books()
self.prepare_depreciation_data()
self.validate_gross_and_purchase_amount()
if self.get("schedules"):
@@ -197,6 +198,27 @@ class Asset(AccountsController):
finance_books = get_item_details(self.item_code, self.asset_category)
self.set("finance_books", finance_books)
def validate_finance_books(self):
if not self.calculate_depreciation or len(self.finance_books) == 1:
return
finance_books = set()
for d in self.finance_books:
if d.finance_book in finance_books:
frappe.throw(
_("Row #{}: Please use a different Finance Book.").format(d.idx),
title=_("Duplicate Finance Book"),
)
else:
finance_books.add(d.finance_book)
if not d.finance_book:
frappe.throw(
_("Row #{}: Finance Book should not be empty since you're using multiple.").format(d.idx),
title=_("Missing Finance Book"),
)
def validate_asset_values(self):
if not self.asset_category:
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")

View File

@@ -1287,6 +1287,7 @@ class TestDepreciationBasics(AssetSetup):
asset.append(
"finance_books",
{
"finance_book": "Test Finance Book 1",
"depreciation_method": "Straight Line",
"frequency_of_depreciation": 1,
"total_number_of_depreciations": 3,
@@ -1297,6 +1298,7 @@ class TestDepreciationBasics(AssetSetup):
asset.append(
"finance_books",
{
"finance_book": "Test Finance Book 2",
"depreciation_method": "Straight Line",
"frequency_of_depreciation": 1,
"total_number_of_depreciations": 6,
@@ -1307,6 +1309,7 @@ class TestDepreciationBasics(AssetSetup):
asset.append(
"finance_books",
{
"finance_book": "Test Finance Book 3",
"depreciation_method": "Straight Line",
"frequency_of_depreciation": 12,
"total_number_of_depreciations": 3,
@@ -1336,6 +1339,7 @@ class TestDepreciationBasics(AssetSetup):
asset.append(
"finance_books",
{
"finance_book": "Test Finance Book 1",
"depreciation_method": "Straight Line",
"frequency_of_depreciation": 12,
"total_number_of_depreciations": 3,
@@ -1346,6 +1350,7 @@ class TestDepreciationBasics(AssetSetup):
asset.append(
"finance_books",
{
"finance_book": "Test Finance Book 2",
"depreciation_method": "Straight Line",
"frequency_of_depreciation": 12,
"total_number_of_depreciations": 6,
@@ -1581,6 +1586,15 @@ def create_asset_data():
if not frappe.db.exists("Location", "Test Location"):
frappe.get_doc({"doctype": "Location", "location_name": "Test Location"}).insert()
if not frappe.db.exists("Finance Book", "Test Finance Book 1"):
frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 1"}).insert()
if not frappe.db.exists("Finance Book", "Test Finance Book 2"):
frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 2"}).insert()
if not frappe.db.exists("Finance Book", "Test Finance Book 3"):
frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 3"}).insert()
def create_asset(**args):
args = frappe._dict(args)

View File

@@ -6,7 +6,12 @@
frappe.ui.form.on('Loan Repayment', {
// refresh: function(frm) {
// }
// },
setup: function(frm) {
frm.add_fetch("against_loan", "repay_from_salary", "repay_from_salary");
},
onload: function(frm) {
frm.set_query('against_loan', function() {
return {

View File

@@ -262,8 +262,6 @@
},
{
"default": "0",
"fetch_from": "against_loan.repay_from_salary",
"fetch_if_empty": 1,
"fieldname": "repay_from_salary",
"fieldtype": "Check",
"label": "Repay From Salary"
@@ -313,11 +311,10 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-08-04 17:13:51.964203",
"modified": "2023-09-18 16:50:32.897005",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Repayment",
"naming_rule": "Expression (old style)",
"owner": "Administrator",
"permissions": [
{
@@ -353,6 +350,5 @@
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -81,6 +81,11 @@ class LoanRepayment(AccountsController):
if amounts.get("due_date"):
self.due_date = amounts.get("due_date")
if self.repay_from_salary and not self.payroll_payable_account:
frappe.throw(_("Please set Payroll Payable Account in Loan Repayment"))
elif not self.repay_from_salary and self.payroll_payable_account:
self.repay_from_salary = 1
def check_future_entries(self):
future_repayment_date = frappe.db.get_value(
"Loan Repayment",

View File

@@ -3,23 +3,23 @@
/* eslint-disable */
const DIFFERNCE_FIELD_NAMES = [
"difference_in_qty",
"fifo_qty_diff",
"fifo_value_diff",
"fifo_valuation_diff",
"valuation_diff",
"fifo_difference_diff",
"diff_value_diff"
'difference_in_qty',
'fifo_qty_diff',
'fifo_value_diff',
'fifo_valuation_diff',
'valuation_diff',
'fifo_difference_diff',
'diff_value_diff'
];
frappe.query_reports["Stock Ledger Invariant Check"] = {
"filters": [
frappe.query_reports['Stock Ledger Invariant Check'] = {
'filters': [
{
"fieldname": "item_code",
"fieldtype": "Link",
"label": "Item",
"mandatory": 1,
"options": "Item",
'fieldname': 'item_code',
'fieldtype': 'Link',
'label': 'Item',
'mandatory': 1,
'options': 'Item',
get_query: function() {
return {
filters: {is_stock_item: 1, has_serial_no: 0}
@@ -27,18 +27,61 @@ frappe.query_reports["Stock Ledger Invariant Check"] = {
}
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
"mandatory": 1,
"options": "Warehouse",
'fieldname': 'warehouse',
'fieldtype': 'Link',
'label': 'Warehouse',
'mandatory': 1,
'options': 'Warehouse',
}
],
formatter (value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (DIFFERNCE_FIELD_NAMES.includes(column.fieldname) && Math.abs(data[column.fieldname]) > 0.001) {
value = "<span style='color:red'>" + value + "</span>";
value = '<span style="color:red">' + value + '</span>';
}
return value;
},
get_datatable_options(options) {
return Object.assign(options, {
checkboxColumn: true,
});
},
onload(report) {
report.page.add_inner_button(__('Create Reposting Entry'), () => {
let message = `
<div>
<p>
Reposting Entry will change the value of
accounts Stock In Hand, and Stock Expenses
in the Trial Balance report and will also change
the Balance Value in the Stock Balance report.
</p>
<p>Are you sure you want to create a Reposting Entry?</p>
</div>`;
let indexes = frappe.query_report.datatable.rowmanager.getCheckedRows();
let selected_rows = indexes.map(i => frappe.query_report.data[i]);
if (!selected_rows.length) {
frappe.throw(__('Please select a row to create a Reposting Entry'));
}
else if (selected_rows.length > 1) {
frappe.throw(__('Please select only one row to create a Reposting Entry'));
}
else {
frappe.confirm(__(message), () => {
frappe.call({
method: 'erpnext.stock.report.stock_ledger_invariant_check.stock_ledger_invariant_check.create_reposting_entries',
args: {
rows: selected_rows,
item_code: frappe.query_report.get_filter_values().item_code,
warehouse: frappe.query_report.get_filter_values().warehouse,
}
});
});
}
});
},
};

View File

@@ -4,6 +4,8 @@
import json
import frappe
from frappe import _
from frappe.utils import get_link_to_form, parse_json
SLE_FIELDS = (
"name",
@@ -247,3 +249,35 @@ def get_columns():
"label": "H - J",
},
]
@frappe.whitelist()
def create_reposting_entries(rows, item_code=None, warehouse=None):
if isinstance(rows, str):
rows = parse_json(rows)
entries = []
for row in rows:
row = frappe._dict(row)
try:
doc = frappe.get_doc(
{
"doctype": "Repost Item Valuation",
"based_on": "Item and Warehouse",
"status": "Queued",
"item_code": item_code or row.item_code,
"warehouse": warehouse or row.warehouse,
"posting_date": row.posting_date,
"posting_time": row.posting_time,
"allow_nagative_stock": 1,
}
).submit()
entries.append(get_link_to_form("Repost Item Valuation", doc.name))
except frappe.DuplicateEntryError:
continue
if entries:
entries = ", ".join(entries)
frappe.msgprint(_("Reposting entries created: {0}").format(entries))