mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-30 12:08:26 +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) }));
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
@@ -302,7 +302,7 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
|
||||
"docstatus": 1,
|
||||
}
|
||||
|
||||
if not tax_details.get("consider_party_ledger_amount") and doctype != "Sales Invoice":
|
||||
if doctype != "Sales Invoice":
|
||||
filters.update(
|
||||
{"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")}
|
||||
)
|
||||
|
||||
@@ -110,9 +110,9 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
||||
invoices.append(pi1)
|
||||
|
||||
# Cumulative threshold is 30000
|
||||
# Threshold calculation should be on both the invoices
|
||||
# TDS should be applied only on 1000
|
||||
self.assertEqual(pi1.taxes[0].tax_amount, 1000)
|
||||
# Threshold calculation should be only on the Second invoice
|
||||
# Second didn't breach, no TDS should be applied
|
||||
self.assertEqual(pi1.taxes, [])
|
||||
|
||||
for d in reversed(invoices):
|
||||
d.cancel()
|
||||
|
||||
@@ -425,7 +425,7 @@ class Asset(AccountsController):
|
||||
depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life
|
||||
skip_row = True
|
||||
|
||||
if depreciation_amount > 0:
|
||||
if flt(depreciation_amount, self.precision("gross_purchase_amount")) > 0:
|
||||
self._add_depreciation_row(
|
||||
schedule_date,
|
||||
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
|
||||
else:
|
||||
return (flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)) / flt(
|
||||
row.total_number_of_depreciations
|
||||
)
|
||||
return (
|
||||
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(
|
||||
|
||||
@@ -649,7 +649,7 @@ class TestDepreciationMethods(AssetSetup):
|
||||
)
|
||||
|
||||
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 = [
|
||||
[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
|
||||
for d in asset.get("schedules")
|
||||
|
||||
@@ -689,7 +689,6 @@ class SubcontractingController(StockController):
|
||||
"actual_qty": flt(item.rejected_qty) * flt(item.conversion_factor),
|
||||
"serial_no": cstr(item.rejected_serial_no).strip(),
|
||||
"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_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', {
|
||||
setup: (frm) => {
|
||||
frm.make_methods = {
|
||||
'Landed Cost Voucher': function () { frm.trigger('create_landedcost_voucher') },
|
||||
}
|
||||
},
|
||||
|
||||
mode_of_payment: function(frm) {
|
||||
get_payment_mode_account(frm, frm.doc.mode_of_payment, function(account){
|
||||
frm.set_value('cash_bank_account', account);
|
||||
@@ -99,6 +105,20 @@ frappe.ui.form.on('Purchase Invoice', {
|
||||
|
||||
payment_terms_template: function() {
|
||||
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
|
||||
for d in customer.get("sales_team"):
|
||||
for d in customer.get("sales_team") or []:
|
||||
target.append(
|
||||
"sales_team",
|
||||
{
|
||||
|
||||
@@ -25,15 +25,12 @@
|
||||
"documentation_url": "https://docs.erpnext.com/docs/v14/user/manual/en/setting-up/company-setup",
|
||||
"idx": 0,
|
||||
"is_complete": 0,
|
||||
"modified": "2023-05-16 13:13:24.043792",
|
||||
"modified": "2023-05-20 19:45:03.936741",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Home",
|
||||
"owner": "Administrator",
|
||||
"steps": [
|
||||
{
|
||||
"step": "Navigation Help"
|
||||
},
|
||||
{
|
||||
"step": "Create an Item"
|
||||
},
|
||||
@@ -47,7 +44,7 @@
|
||||
"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",
|
||||
"title": "Let's begin your journey with ERPNext"
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"is_complete": 0,
|
||||
"is_single": 0,
|
||||
"is_skipped": 0,
|
||||
"modified": "2023-05-16 12:54:54.112364",
|
||||
"modified": "2023-05-16 20:01:34.202622",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Create a Customer",
|
||||
"owner": "Administrator",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"is_complete": 0,
|
||||
"is_single": 0,
|
||||
"is_skipped": 0,
|
||||
"modified": "2023-05-16 12:55:08.610113",
|
||||
"modified": "2023-05-19 15:32:55.069257",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Create a Supplier",
|
||||
"owner": "Administrator",
|
||||
|
||||
@@ -29,6 +29,7 @@ class PickList(Document):
|
||||
self.validate_for_qty()
|
||||
|
||||
def before_save(self):
|
||||
self.update_status()
|
||||
self.set_item_locations()
|
||||
|
||||
# set percentage picked in SO
|
||||
@@ -89,20 +90,20 @@ class PickList(Document):
|
||||
self.update_reference_qty()
|
||||
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 self.docstatus == 0:
|
||||
status = "Draft"
|
||||
elif self.docstatus == 1:
|
||||
if self.status == "Draft":
|
||||
status = "Open"
|
||||
elif target_document_exists(self.name, self.purpose):
|
||||
if target_document_exists(self.name, self.purpose):
|
||||
status = "Completed"
|
||||
else:
|
||||
status = "Open"
|
||||
elif self.docstatus == 2:
|
||||
status = "Cancelled"
|
||||
|
||||
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):
|
||||
packed_items = []
|
||||
|
||||
@@ -33,5 +33,40 @@ frappe.query_reports["Stock and Account Value Comparison"] = {
|
||||
"fieldtype": "Date",
|
||||
"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
|
||||
from frappe import _
|
||||
from frappe.utils import get_link_to_form, parse_json
|
||||
|
||||
import erpnext
|
||||
from erpnext.accounts.utils import get_currency_precision, get_stock_accounts
|
||||
@@ -134,3 +135,35 @@ def get_columns(filters):
|
||||
"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) {
|
||||
batch_no_field.get_route_options_for_new_doc = function(row) {
|
||||
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) => {
|
||||
@@ -157,6 +145,8 @@ frappe.ui.form.on('Subcontracting Receipt', {
|
||||
}
|
||||
});
|
||||
}, __('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):
|
||||
if cint(self.is_return):
|
||||
self.status_updater.extend(
|
||||
|
||||
Reference in New Issue
Block a user