mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-31 10:49:09 +00:00
Merge branch 'version-14-hotfix' into gross-and-net-profit-fix
This commit is contained in:
@@ -905,7 +905,7 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
function(d) { return flt(d.amount) }));
|
function(d) { return flt(d.amount) }));
|
||||||
|
|
||||||
frm.set_value("difference_amount", difference_amount - total_deductions +
|
frm.set_value("difference_amount", difference_amount - total_deductions +
|
||||||
frm.doc.base_total_taxes_and_charges);
|
flt(frm.doc.base_total_taxes_and_charges));
|
||||||
|
|
||||||
frm.events.hide_unhide_fields(frm);
|
frm.events.hide_unhide_fields(frm);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
|
|||||||
"docstatus": 1,
|
"docstatus": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if not tax_details.get("consider_party_ledger_amount") and doctype != "Sales Invoice":
|
if doctype != "Sales Invoice":
|
||||||
filters.update(
|
filters.update(
|
||||||
{"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")}
|
{"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
|||||||
invoices.append(pi1)
|
invoices.append(pi1)
|
||||||
|
|
||||||
# Cumulative threshold is 30000
|
# Cumulative threshold is 30000
|
||||||
# Threshold calculation should be on both the invoices
|
# Threshold calculation should be only on the Second invoice
|
||||||
# TDS should be applied only on 1000
|
# Second didn't breach, no TDS should be applied
|
||||||
self.assertEqual(pi1.taxes[0].tax_amount, 1000)
|
self.assertEqual(pi1.taxes, [])
|
||||||
|
|
||||||
for d in reversed(invoices):
|
for d in reversed(invoices):
|
||||||
d.cancel()
|
d.cancel()
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ class Asset(AccountsController):
|
|||||||
depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life
|
depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life
|
||||||
skip_row = True
|
skip_row = True
|
||||||
|
|
||||||
if depreciation_amount > 0:
|
if flt(depreciation_amount, self.precision("gross_purchase_amount")) > 0:
|
||||||
self._add_depreciation_row(
|
self._add_depreciation_row(
|
||||||
schedule_date,
|
schedule_date,
|
||||||
depreciation_amount,
|
depreciation_amount,
|
||||||
@@ -1287,9 +1287,11 @@ def get_straight_line_or_manual_depr_amount(asset, row):
|
|||||||
)
|
)
|
||||||
# if the Depreciation Schedule is being prepared for the first time
|
# if the Depreciation Schedule is being prepared for the first time
|
||||||
else:
|
else:
|
||||||
return (flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)) / flt(
|
return (
|
||||||
row.total_number_of_depreciations
|
flt(asset.gross_purchase_amount)
|
||||||
)
|
- flt(asset.opening_accumulated_depreciation)
|
||||||
|
- flt(row.expected_value_after_useful_life)
|
||||||
|
) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
|
||||||
|
|
||||||
|
|
||||||
def get_wdv_or_dd_depr_amount(
|
def get_wdv_or_dd_depr_amount(
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ class TestDepreciationMethods(AssetSetup):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(asset.status, "Draft")
|
self.assertEqual(asset.status, "Draft")
|
||||||
expected_schedules = [["2032-12-31", 30000.0, 77095.89], ["2033-06-06", 12904.11, 90000.0]]
|
expected_schedules = [["2032-12-31", 42904.11, 90000.0]]
|
||||||
schedules = [
|
schedules = [
|
||||||
[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
|
[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
|
||||||
for d in asset.get("schedules")
|
for d in asset.get("schedules")
|
||||||
|
|||||||
@@ -689,7 +689,6 @@ class SubcontractingController(StockController):
|
|||||||
"actual_qty": flt(item.rejected_qty) * flt(item.conversion_factor),
|
"actual_qty": flt(item.rejected_qty) * flt(item.conversion_factor),
|
||||||
"serial_no": cstr(item.rejected_serial_no).strip(),
|
"serial_no": cstr(item.rejected_serial_no).strip(),
|
||||||
"incoming_rate": 0.0,
|
"incoming_rate": 0.0,
|
||||||
"recalculate_rate": 1,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ def execute():
|
|||||||
frappe.reload_doc("manufacturing", "doctype", "work_order")
|
frappe.reload_doc("manufacturing", "doctype", "work_order")
|
||||||
frappe.reload_doc("manufacturing", "doctype", "work_order_item")
|
frappe.reload_doc("manufacturing", "doctype", "work_order_item")
|
||||||
|
|
||||||
frappe.db.sql("""UPDATE `tabWork Order Item` SET amount = rate * required_qty""")
|
frappe.db.sql(
|
||||||
|
"""UPDATE `tabWork Order Item` SET amount = ifnull(rate, 0.0) * ifnull(required_qty, 0.0)"""
|
||||||
|
)
|
||||||
|
|||||||
@@ -91,6 +91,12 @@ frappe.ui.form.on("Sales Invoice", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
frappe.ui.form.on('Purchase Invoice', {
|
frappe.ui.form.on('Purchase Invoice', {
|
||||||
|
setup: (frm) => {
|
||||||
|
frm.make_methods = {
|
||||||
|
'Landed Cost Voucher': function () { frm.trigger('create_landedcost_voucher') },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mode_of_payment: function(frm) {
|
mode_of_payment: function(frm) {
|
||||||
get_payment_mode_account(frm, frm.doc.mode_of_payment, function(account){
|
get_payment_mode_account(frm, frm.doc.mode_of_payment, function(account){
|
||||||
frm.set_value('cash_bank_account', account);
|
frm.set_value('cash_bank_account', account);
|
||||||
@@ -99,6 +105,20 @@ frappe.ui.form.on('Purchase Invoice', {
|
|||||||
|
|
||||||
payment_terms_template: function() {
|
payment_terms_template: function() {
|
||||||
cur_frm.trigger("disable_due_date");
|
cur_frm.trigger("disable_due_date");
|
||||||
|
},
|
||||||
|
|
||||||
|
create_landedcost_voucher: function (frm) {
|
||||||
|
let lcv = frappe.model.get_new_doc('Landed Cost Voucher');
|
||||||
|
lcv.company = frm.doc.company;
|
||||||
|
|
||||||
|
let lcv_receipt = frappe.model.get_new_doc('Landed Cost Purchase Invoice');
|
||||||
|
lcv_receipt.receipt_document_type = 'Purchase Invoice';
|
||||||
|
lcv_receipt.receipt_document = frm.doc.name;
|
||||||
|
lcv_receipt.supplier = frm.doc.supplier;
|
||||||
|
lcv_receipt.grand_total = frm.doc.grand_total;
|
||||||
|
lcv.purchase_receipts = [lcv_receipt];
|
||||||
|
|
||||||
|
frappe.set_route("Form", lcv.doctype, lcv.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# sales team
|
# sales team
|
||||||
for d in customer.get("sales_team"):
|
for d in customer.get("sales_team") or []:
|
||||||
target.append(
|
target.append(
|
||||||
"sales_team",
|
"sales_team",
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,15 +25,12 @@
|
|||||||
"documentation_url": "https://docs.erpnext.com/docs/v14/user/manual/en/setting-up/company-setup",
|
"documentation_url": "https://docs.erpnext.com/docs/v14/user/manual/en/setting-up/company-setup",
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_complete": 0,
|
"is_complete": 0,
|
||||||
"modified": "2023-05-16 13:13:24.043792",
|
"modified": "2023-05-20 19:45:03.936741",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Home",
|
"name": "Home",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
|
||||||
"step": "Navigation Help"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"step": "Create an Item"
|
"step": "Create an Item"
|
||||||
},
|
},
|
||||||
@@ -47,7 +44,7 @@
|
|||||||
"step": "Create a Quotation"
|
"step": "Create a Quotation"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subtitle": "Item, Customer, Supplier, Navigation Help and Quotation",
|
"subtitle": "Item, Customer, Supplier and Quotation",
|
||||||
"success_message": "You're ready to start your journey with ERPNext",
|
"success_message": "You're ready to start your journey with ERPNext",
|
||||||
"title": "Let's begin your journey with ERPNext"
|
"title": "Let's begin your journey with ERPNext"
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"is_complete": 0,
|
"is_complete": 0,
|
||||||
"is_single": 0,
|
"is_single": 0,
|
||||||
"is_skipped": 0,
|
"is_skipped": 0,
|
||||||
"modified": "2023-05-16 12:54:54.112364",
|
"modified": "2023-05-16 20:01:34.202622",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Create a Customer",
|
"name": "Create a Customer",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"is_complete": 0,
|
"is_complete": 0,
|
||||||
"is_single": 0,
|
"is_single": 0,
|
||||||
"is_skipped": 0,
|
"is_skipped": 0,
|
||||||
"modified": "2023-05-16 12:55:08.610113",
|
"modified": "2023-05-19 15:32:55.069257",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Create a Supplier",
|
"name": "Create a Supplier",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class PickList(Document):
|
|||||||
self.validate_for_qty()
|
self.validate_for_qty()
|
||||||
|
|
||||||
def before_save(self):
|
def before_save(self):
|
||||||
|
self.update_status()
|
||||||
self.set_item_locations()
|
self.set_item_locations()
|
||||||
|
|
||||||
# set percentage picked in SO
|
# set percentage picked in SO
|
||||||
@@ -89,20 +90,20 @@ class PickList(Document):
|
|||||||
self.update_reference_qty()
|
self.update_reference_qty()
|
||||||
self.update_sales_order_picking_status()
|
self.update_sales_order_picking_status()
|
||||||
|
|
||||||
def update_status(self, status=None, update_modified=True):
|
def update_status(self, status=None):
|
||||||
if not status:
|
if not status:
|
||||||
if self.docstatus == 0:
|
if self.docstatus == 0:
|
||||||
status = "Draft"
|
status = "Draft"
|
||||||
elif self.docstatus == 1:
|
elif self.docstatus == 1:
|
||||||
if self.status == "Draft":
|
if target_document_exists(self.name, self.purpose):
|
||||||
status = "Open"
|
|
||||||
elif target_document_exists(self.name, self.purpose):
|
|
||||||
status = "Completed"
|
status = "Completed"
|
||||||
|
else:
|
||||||
|
status = "Open"
|
||||||
elif self.docstatus == 2:
|
elif self.docstatus == 2:
|
||||||
status = "Cancelled"
|
status = "Cancelled"
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
frappe.db.set_value("Pick List", self.name, "status", status, update_modified=update_modified)
|
self.db_set("status", status)
|
||||||
|
|
||||||
def update_reference_qty(self):
|
def update_reference_qty(self):
|
||||||
packed_items = []
|
packed_items = []
|
||||||
|
|||||||
@@ -33,5 +33,40 @@ frappe.query_reports["Stock and Account Value Comparison"] = {
|
|||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"default": frappe.datetime.get_today(),
|
"default": frappe.datetime.get_today(),
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
|
|
||||||
|
get_datatable_options(options) {
|
||||||
|
return Object.assign(options, {
|
||||||
|
checkboxColumn: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onload(report) {
|
||||||
|
report.page.add_inner_button(__("Create Reposting Entries"), function() {
|
||||||
|
let message = `<div>
|
||||||
|
<p>
|
||||||
|
Reposting Entries 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 Reposting Entries?</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
frappe.confirm(__(message), () => {
|
||||||
|
let indexes = frappe.query_report.datatable.rowmanager.getCheckedRows();
|
||||||
|
let selected_rows = indexes.map(i => frappe.query_report.data[i]);
|
||||||
|
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison.create_reposting_entries",
|
||||||
|
args: {
|
||||||
|
rows: selected_rows,
|
||||||
|
company: frappe.query_report.get_filter_values().company
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.utils import get_link_to_form, parse_json
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.accounts.utils import get_currency_precision, get_stock_accounts
|
from erpnext.accounts.utils import get_currency_precision, get_stock_accounts
|
||||||
@@ -134,3 +135,35 @@ def get_columns(filters):
|
|||||||
"width": "120",
|
"width": "120",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_reposting_entries(rows, company):
|
||||||
|
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": "Transaction",
|
||||||
|
"status": "Queued",
|
||||||
|
"voucher_type": row.voucher_type,
|
||||||
|
"voucher_no": row.voucher_no,
|
||||||
|
"posting_date": row.posting_date,
|
||||||
|
"company": company,
|
||||||
|
"allow_nagative_stock": 1,
|
||||||
|
}
|
||||||
|
).submit()
|
||||||
|
|
||||||
|
entries.append(get_link_to_form("Repost Item Valuation", doc.name))
|
||||||
|
except frappe.DuplicateEntryError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if entries:
|
||||||
|
entries = ", ".join(entries)
|
||||||
|
frappe.msgprint(_(f"Reposting entries created: {entries}"))
|
||||||
|
|||||||
@@ -76,26 +76,14 @@ frappe.ui.form.on('Subcontracting Receipt', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let batch_no_field = frm.get_docfield("items", "batch_no");
|
let batch_no_field = frm.get_docfield('items', 'batch_no');
|
||||||
if (batch_no_field) {
|
if (batch_no_field) {
|
||||||
batch_no_field.get_route_options_for_new_doc = function(row) {
|
batch_no_field.get_route_options_for_new_doc = function(row) {
|
||||||
return {
|
return {
|
||||||
"item": row.doc.item_code
|
'item': row.doc.item_code
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.db.get_single_value('Buying Settings', 'backflush_raw_materials_of_subcontract_based_on').then(val => {
|
|
||||||
if (val == 'Material Transferred for Subcontract') {
|
|
||||||
frm.fields_dict['supplied_items'].grid.grid_rows.forEach((grid_row) => {
|
|
||||||
grid_row.docfields.forEach((df) => {
|
|
||||||
if (df.fieldname == 'consumed_qty') {
|
|
||||||
df.read_only = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: (frm) => {
|
refresh: (frm) => {
|
||||||
@@ -157,6 +145,8 @@ frappe.ui.form.on('Subcontracting Receipt', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, __('Get Items From'));
|
}, __('Get Items From'));
|
||||||
|
|
||||||
|
frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', 'read_only', frm.doc.__onload && frm.doc.__onload.backflush_based_on === 'BOM');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def onload(self):
|
||||||
|
self.set_onload(
|
||||||
|
"backflush_based_on",
|
||||||
|
frappe.db.get_single_value(
|
||||||
|
"Buying Settings", "backflush_raw_materials_of_subcontract_based_on"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def update_status_updater_args(self):
|
def update_status_updater_args(self):
|
||||||
if cint(self.is_return):
|
if cint(self.is_return):
|
||||||
self.status_updater.extend(
|
self.status_updater.extend(
|
||||||
|
|||||||
Reference in New Issue
Block a user