Merge branch 'develop' into github-issue-33344

This commit is contained in:
Sagar Sharma 2023-02-18 22:24:06 +05:30 committed by GitHub
commit 07c6ad6fa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 191 additions and 58 deletions

View File

@ -16,6 +16,7 @@ erpnext/maintenance/ @rohitwaghchaure @s-aga-r
erpnext/manufacturing/ @rohitwaghchaure @s-aga-r
erpnext/quality_management/ @rohitwaghchaure @s-aga-r
erpnext/stock/ @rohitwaghchaure @s-aga-r
erpnext/subcontracting @rohitwaghchaure @s-aga-r
erpnext/crm/ @NagariaHussain
erpnext/education/ @rutwikhdev

View File

@ -238,21 +238,16 @@ class JournalEntry(AccountsController):
):
processed_assets.append(d.reference_name)
asset = frappe.db.get_value(
"Asset", d.reference_name, ["calculate_depreciation", "value_after_depreciation"], as_dict=1
)
asset = frappe.get_doc("Asset", d.reference_name)
if asset.calculate_depreciation:
continue
depr_value = d.debit or d.credit
frappe.db.set_value(
"Asset",
d.reference_name,
"value_after_depreciation",
asset.value_after_depreciation - depr_value,
)
asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value)
asset.set_status()
def update_inter_company_jv(self):
if (
@ -348,12 +343,9 @@ class JournalEntry(AccountsController):
else:
depr_value = d.debit or d.credit
frappe.db.set_value(
"Asset",
d.reference_name,
"value_after_depreciation",
asset.value_after_depreciation + depr_value,
)
asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value)
asset.set_status()
def unlink_inter_company_jv(self):
if (

View File

@ -239,7 +239,7 @@
"depends_on": "paid_from",
"fieldname": "paid_from_account_currency",
"fieldtype": "Link",
"label": "Account Currency",
"label": "Account Currency (From)",
"options": "Currency",
"print_hide": 1,
"read_only": 1,
@ -249,7 +249,7 @@
"depends_on": "paid_from",
"fieldname": "paid_from_account_balance",
"fieldtype": "Currency",
"label": "Account Balance",
"label": "Account Balance (From)",
"options": "paid_from_account_currency",
"print_hide": 1,
"read_only": 1
@ -272,7 +272,7 @@
"depends_on": "paid_to",
"fieldname": "paid_to_account_currency",
"fieldtype": "Link",
"label": "Account Currency",
"label": "Account Currency (To)",
"options": "Currency",
"print_hide": 1,
"read_only": 1,
@ -282,7 +282,7 @@
"depends_on": "paid_to",
"fieldname": "paid_to_account_balance",
"fieldtype": "Currency",
"label": "Account Balance",
"label": "Account Balance (To)",
"options": "paid_to_account_currency",
"print_hide": 1,
"read_only": 1
@ -304,7 +304,7 @@
{
"fieldname": "source_exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate",
"label": "Source Exchange Rate",
"precision": "9",
"print_hide": 1,
"reqd": 1
@ -334,7 +334,7 @@
{
"fieldname": "target_exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate",
"label": "Target Exchange Rate",
"precision": "9",
"print_hide": 1,
"reqd": 1
@ -633,14 +633,14 @@
"depends_on": "eval:doc.party_type == 'Supplier'",
"fieldname": "purchase_taxes_and_charges_template",
"fieldtype": "Link",
"label": "Taxes and Charges Template",
"label": "Purchase Taxes and Charges Template",
"options": "Purchase Taxes and Charges Template"
},
{
"depends_on": "eval: doc.party_type == 'Customer'",
"fieldname": "sales_taxes_and_charges_template",
"fieldtype": "Link",
"label": "Taxes and Charges Template",
"label": "Sales Taxes and Charges Template",
"options": "Sales Taxes and Charges Template"
},
{
@ -733,7 +733,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-12-08 16:25:43.824051",
"modified": "2023-02-14 04:52:30.478523",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@ -472,7 +472,7 @@
"description": "If rate is zero them item will be treated as \"Free Item\"",
"fieldname": "free_item_rate",
"fieldtype": "Currency",
"label": "Rate"
"label": "Free Item Rate"
},
{
"collapsible": 1,
@ -608,7 +608,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2022-10-13 19:05:35.056304",
"modified": "2023-02-14 04:53:34.887358",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@ -258,7 +258,7 @@ frappe.ui.form.on('Asset', {
$.each(depr_entries || [], function(i, v) {
x_intervals.push(frappe.format(v.posting_date, { fieldtype: 'Date' }));
let last_asset_value = asset_values[asset_values.length - 1]
asset_values.push(last_asset_value - v.value);
asset_values.push(flt(last_asset_value - v.value, precision('gross_purchase_amount')));
});
}

View File

@ -413,11 +413,14 @@ class Asset(AccountsController):
if self.journal_entry_for_scrap:
status = "Scrapped"
elif self.finance_books:
idx = self.get_default_finance_book_idx() or 0
else:
expected_value_after_useful_life = 0
value_after_depreciation = self.value_after_depreciation
expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
value_after_depreciation = self.finance_books[idx].value_after_depreciation
if self.calculate_depreciation:
idx = self.get_default_finance_book_idx() or 0
expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
value_after_depreciation = self.finance_books[idx].value_after_depreciation
if flt(value_after_depreciation) <= expected_value_after_useful_life:
status = "Fully Depreciated"
@ -463,6 +466,7 @@ class Asset(AccountsController):
.where(gle.debit != 0)
.where(gle.is_cancelled == 0)
.orderby(gle.posting_date)
.orderby(gle.creation)
).run(as_dict=True)
return records

View File

@ -168,7 +168,7 @@ def make_depreciation_entry(asset_depr_schedule_name, date=None):
row.value_after_depreciation -= d.depreciation_amount
row.db_update()
frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Successful")
asset.db_set("depr_entry_posting_status", "Successful")
asset.set_status()

View File

@ -91,6 +91,9 @@ class AssetRepair(AccountsController):
make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
self.asset_doc.save()
def after_delete(self):
frappe.get_doc("Asset", self.asset).set_status()
def check_repair_status(self):
if self.repair_status == "Pending":
frappe.throw(_("Please update Repair Status."))

View File

@ -21,6 +21,7 @@
"allow_multiple_items",
"bill_for_rejected_quantity_in_purchase_invoice",
"disable_last_purchase_rate",
"show_pay_button",
"subcontract",
"backflush_raw_materials_of_subcontract_based_on",
"column_break_11",
@ -140,6 +141,12 @@
"fieldname": "disable_last_purchase_rate",
"fieldtype": "Check",
"label": "Disable Last Purchase Rate"
},
{
"default": "1",
"fieldname": "show_pay_button",
"fieldtype": "Check",
"label": "Show Pay Button in Purchase Order Portal"
}
],
"icon": "fa fa-cog",
@ -147,7 +154,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-01-09 17:08:28.828173",
"modified": "2023-02-15 14:42:10.200679",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",

View File

@ -409,7 +409,14 @@ class SubcontractingController(StockController):
if self.available_materials.get(key) and self.available_materials[key]["batch_no"]:
new_rm_obj = None
for batch_no, batch_qty in self.available_materials[key]["batch_no"].items():
if batch_qty >= qty:
if batch_qty >= qty or (
rm_obj.consumed_qty == 0
and self.backflush_based_on == "BOM"
and len(self.available_materials[key]["batch_no"]) == 1
):
if rm_obj.consumed_qty == 0:
self.__set_consumed_qty(rm_obj, qty)
self.__set_batch_no_as_per_qty(item_row, rm_obj, batch_no, qty)
self.available_materials[key]["batch_no"][batch_no] -= qty
return

View File

@ -306,7 +306,6 @@ erpnext.patches.v13_0.set_per_billed_in_return_delivery_note
execute:frappe.delete_doc("DocType", "Naming Series")
erpnext.patches.v13_0.job_card_status_on_hold
erpnext.patches.v14_0.copy_is_subcontracted_value_to_is_old_subcontracting_flow
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
erpnext.patches.v14_0.crm_ux_cleanup
erpnext.patches.v14_0.migrate_existing_lead_notes_as_per_the_new_format
erpnext.patches.v14_0.remove_india_localisation # 14-07-2022
@ -315,7 +314,6 @@ erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
erpnext.patches.v14_0.fix_crm_no_of_employees
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
erpnext.patches.v13_0.update_schedule_type_in_loans
erpnext.patches.v13_0.drop_unused_sle_index_parts
erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization
@ -327,3 +325,6 @@ erpnext.patches.v14_0.update_entry_type_for_journal_entry
erpnext.patches.v14_0.change_autoname_for_tax_withheld_vouchers
erpnext.patches.v14_0.set_pick_list_status
erpnext.patches.v15_0.update_asset_value_for_manual_depr_entries
# below 2 migration patches should always run last
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger

View File

@ -408,7 +408,7 @@
"depends_on": "eval:(doc.frequency == \"Daily\" && doc.collect_progress == true)",
"fieldname": "daily_time_to_send",
"fieldtype": "Time",
"label": "Time to send"
"label": "Daily Time to send"
},
{
"depends_on": "eval:(doc.frequency == \"Weekly\" && doc.collect_progress == true)",
@ -421,7 +421,7 @@
"depends_on": "eval:(doc.frequency == \"Weekly\" && doc.collect_progress == true)",
"fieldname": "weekly_time_to_send",
"fieldtype": "Time",
"label": "Time to send"
"label": "Weekly Time to send"
},
{
"fieldname": "column_break_45",
@ -451,7 +451,7 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 4,
"modified": "2022-06-23 16:45:06.108499",
"modified": "2023-02-14 04:54:25.819620",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project",
@ -497,4 +497,4 @@
"timeline_field": "customer",
"title_field": "project_name",
"track_seen": 1
}
}

View File

@ -282,21 +282,21 @@
{
"fieldname": "base_total_costing_amount",
"fieldtype": "Currency",
"label": "Total Costing Amount",
"label": "Base Total Costing Amount",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "base_total_billable_amount",
"fieldtype": "Currency",
"label": "Total Billable Amount",
"label": "Base Total Billable Amount",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "base_total_billed_amount",
"fieldtype": "Currency",
"label": "Total Billed Amount",
"label": "Base Total Billed Amount",
"print_hide": 1,
"read_only": 1
},
@ -311,10 +311,11 @@
"idx": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-06-15 22:08:53.930200",
"modified": "2023-02-14 04:55:41.735991",
"modified_by": "Administrator",
"module": "Projects",
"name": "Timesheet",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
@ -388,5 +389,6 @@
],
"sort_field": "modified",
"sort_order": "ASC",
"states": [],
"title_field": "title"
}

View File

@ -521,6 +521,7 @@
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
"label": "Delivery Note Item",
"oldfieldname": "delivery_note_details",
"oldfieldtype": "Table",
"options": "Delivery Note Item",
@ -666,6 +667,7 @@
{
"fieldname": "taxes",
"fieldtype": "Table",
"label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
"options": "Sales Taxes and Charges"
@ -1401,7 +1403,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
"modified": "2022-12-12 18:38:53.067799",
"modified": "2023-02-14 04:45:44.179670",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",

View File

@ -706,7 +706,7 @@
"depends_on": "enable_deferred_expense",
"fieldname": "no_of_months_exp",
"fieldtype": "Int",
"label": "No of Months"
"label": "No of Months (Expense)"
},
{
"collapsible": 1,
@ -911,7 +911,7 @@
"index_web_pages_for_search": 1,
"links": [],
"make_attachments_public": 1,
"modified": "2023-01-07 22:45:00.341745",
"modified": "2023-02-14 04:48:26.343620",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@ -2,7 +2,22 @@
// For license information, please see license.txt
frappe.ui.form.on('Stock Reposting Settings', {
// refresh: function(frm) {
refresh: function(frm) {
frm.trigger('convert_to_item_based_reposting');
},
// }
convert_to_item_based_reposting: function(frm) {
frm.add_custom_button(__('Convert to Item Based Reposting'), function() {
frm.call({
method: 'convert_to_item_wh_reposting',
frezz: true,
doc: frm.doc,
callback: function(r) {
if (!r.exc) {
frm.reload_doc();
}
}
})
})
}
});

View File

@ -1,6 +1,8 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import add_to_date, get_datetime, get_time_str, time_diff_in_hours
@ -24,3 +26,62 @@ class StockRepostingSettings(Document):
if diff < 10:
self.end_time = get_time_str(add_to_date(self.start_time, hours=10, as_datetime=True))
@frappe.whitelist()
def convert_to_item_wh_reposting(self):
"""Convert Transaction reposting to Item Warehouse based reposting if Item Based Reposting has enabled."""
reposting_data = get_reposting_entries()
vouchers = [d.voucher_no for d in reposting_data]
item_warehouses = {}
for ledger in get_stock_ledgers(vouchers):
key = (ledger.item_code, ledger.warehouse)
if key not in item_warehouses:
item_warehouses[key] = ledger.posting_date
elif frappe.utils.getdate(item_warehouses.get(key)) > frappe.utils.getdate(ledger.posting_date):
item_warehouses[key] = ledger.posting_date
for key, posting_date in item_warehouses.items():
item_code, warehouse = key
create_repost_item_valuation(item_code, warehouse, posting_date)
for row in reposting_data:
frappe.db.set_value("Repost Item Valuation", row.name, "status", "Skipped")
self.db_set("item_based_reposting", 1)
frappe.msgprint(_("Item Warehouse based reposting has been enabled."))
def get_reposting_entries():
return frappe.get_all(
"Repost Item Valuation",
fields=["voucher_no", "name"],
filters={"status": ("in", ["Queued", "In Progress"]), "docstatus": 1, "based_on": "Transaction"},
)
def get_stock_ledgers(vouchers):
return frappe.get_all(
"Stock Ledger Entry",
fields=["item_code", "warehouse", "posting_date"],
filters={"voucher_no": ("in", vouchers)},
)
def create_repost_item_valuation(item_code, warehouse, posting_date):
frappe.get_doc(
{
"doctype": "Repost Item Valuation",
"company": frappe.get_cached_value("Warehouse", warehouse, "company"),
"posting_date": posting_date,
"based_on": "Item and Warehouse",
"posting_time": "00:00:01",
"item_code": item_code,
"warehouse": warehouse,
"allow_negative_stock": True,
"status": "Queued",
}
).submit()

View File

@ -2,6 +2,7 @@
# See license.txt
import copy
from collections import defaultdict
import frappe
from frappe.tests.utils import FrappeTestCase
@ -186,6 +187,40 @@ class TestSubcontractingOrder(FrappeTestCase):
)
self.assertEqual(len(ste.items), len(rm_items))
def test_make_rm_stock_entry_for_batch_items_with_less_transfer(self):
set_backflush_based_on("BOM")
service_items = [
{
"warehouse": "_Test Warehouse - _TC",
"item_code": "Subcontracted Service Item 4",
"qty": 5,
"rate": 100,
"fg_item": "Subcontracted Item SA4",
"fg_item_qty": 5,
}
]
sco = get_subcontracting_order(service_items=service_items)
rm_items = get_rm_items(sco.supplied_items)
itemwise_details = make_stock_in_entry(rm_items=rm_items)
itemwise_transfer_qty = defaultdict(int)
for item in rm_items:
item["qty"] -= 1
itemwise_transfer_qty[item["item_code"]] += item["qty"]
ste = make_stock_transfer_entry(
sco_no=sco.name,
rm_items=rm_items,
itemwise_details=copy.deepcopy(itemwise_details),
)
scr = make_subcontracting_receipt(sco.name)
for row in scr.supplied_items:
self.assertEqual(row.consumed_qty, itemwise_transfer_qty.get(row.rm_item_code) + 1)
def test_update_reserved_qty_for_subcontracting(self):
# Create RM Material Receipt
make_stock_entry(target="_Test Warehouse - _TC", item_code="_Test Item", qty=10, basic_rate=100)

View File

@ -34,16 +34,18 @@
</a>
</ul>
</div>
<div class="form-column col-sm-6">
<div class="page-header-actions-block" data-html-block="header-actions">
<p>
<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
class="btn btn-primary btn-sm" id="pay-for-order">
{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
</a>
</p>
{% if show_pay_button %}
<div class="form-column col-sm-6">
<div class="page-header-actions-block" data-html-block="header-actions">
<p>
<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
class="btn btn-primary btn-sm" id="pay-for-order">
{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
</a>
</p>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -55,6 +55,7 @@ def get_context(context):
)
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
context.show_pay_button = frappe.db.get_single_value("Buying Settings", "show_pay_button")
context.show_make_pi_button = False
if context.doc.get("supplier"):
# show Make Purchase Invoice button based on permission