Compare commits

..

1 Commits

Author SHA1 Message Date
rohitwaghchaure
2b3e1a1747 fix: list view and form status not same for purchase order (#43690)
(cherry picked from commit a671fe13d4)

# Conflicts:
#	erpnext/buying/doctype/purchase_order/purchase_order.js
#	erpnext/buying/doctype/purchase_order/purchase_order_list.js
2024-10-16 08:15:05 +00:00
44 changed files with 158 additions and 295 deletions

View File

@@ -3,7 +3,7 @@ import inspect
import frappe
__version__ = "14.75.2"
__version__ = "14.67.1"
def get_default_company(user=None):

View File

@@ -58,7 +58,7 @@ def build_conditions(process_type, account, company):
)
if account:
conditions += f"AND {deferred_account}={frappe.db.escape(account)}"
conditions += f"AND {deferred_account}='{account}'"
elif company:
conditions += f"AND p.company = {frappe.db.escape(company)}"

View File

@@ -224,6 +224,11 @@
"link_doctype": "Bank Guarantee",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Payroll Entry",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Bank Transaction",
@@ -250,7 +255,7 @@
"link_fieldname": "default_bank_account"
}
],
"modified": "2024-10-30 09:41:14.113414",
"modified": "2024-09-24 06:57:41.292970",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",

View File

@@ -55,7 +55,7 @@ class BankClearance(Document):
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit,
if(paid_from=%(account)s, 0, received_amount + total_taxes_and_charges) as debit,
if(paid_from=%(account)s, 0, received_amount) as debit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`

View File

@@ -153,7 +153,7 @@ class JournalEntry(AccountsController):
frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation"))
def validate_stock_accounts(self):
stock_accounts = get_stock_accounts(self.company, accounts=self.accounts)
stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
for account in stock_accounts:
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(
account, self.posting_date, self.company

View File

@@ -146,12 +146,12 @@ class TestJournalEntry(unittest.TestCase):
"credit_in_account_currency": 0 if diff > 0 else abs(diff),
},
)
jv.insert()
if account_bal == stock_bal:
self.assertRaises(StockAccountInvalidTransaction, jv.insert)
self.assertRaises(StockAccountInvalidTransaction, jv.submit)
frappe.db.rollback()
else:
jv.insert()
jv.submit()
jv.cancel()

View File

@@ -2270,9 +2270,7 @@ def get_party_details(company, party_type, party, date, cost_center=None):
account_balance = get_balance_on(party_account, date, cost_center=cost_center)
_party_name = "title" if party_type == "Shareholder" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
party_balance = get_balance_on(
party_type=party_type, party=party, company=company, cost_center=cost_center
)
party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center)
if party_type in ["Customer", "Supplier"]:
bank_account = get_party_bank_account(party_type, party)

View File

@@ -256,7 +256,6 @@ class PaymentReconciliation(Document):
"posting_date": inv.posting_date,
"currency": inv.currency,
"cost_center": inv.cost_center,
"remarks": inv.remarks,
}
)
)

View File

@@ -14,7 +14,7 @@
"amount",
"difference_amount",
"sec_break1",
"remarks",
"remark",
"currency",
"exchange_rate",
"cost_center"
@@ -74,6 +74,12 @@
"fieldname": "sec_break1",
"fieldtype": "Section Break"
},
{
"fieldname": "remark",
"fieldtype": "Small Text",
"label": "Remark",
"read_only": 1
},
{
"fieldname": "currency",
"fieldtype": "Link",
@@ -99,18 +105,12 @@
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
},
{
"fieldname": "remarks",
"fieldtype": "Small Text",
"label": "Remarks",
"read_only": 1
}
],
"is_virtual": 1,
"istable": 1,
"links": [],
"modified": "2024-10-29 16:24:43.021230",
"modified": "2023-11-17 17:33:34.818530",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Payment",

View File

@@ -238,12 +238,12 @@ class PaymentRequest(Document):
return controller.get_payment_url(
**{
"amount": flt(self.grand_total, self.precision("grand_total")),
"title": data.company,
"description": self.subject,
"title": data.company.encode("utf-8"),
"description": self.subject.encode("utf-8"),
"reference_doctype": "Payment Request",
"reference_docname": self.name,
"payer_email": self.email_to or frappe.session.user,
"payer_name": data.customer_name,
"payer_name": frappe.safe_encode(data.customer_name),
"order_id": self.name,
"currency": self.currency,
}

View File

@@ -80,10 +80,8 @@ frappe.ui.form.on("POS Closing Entry", {
) {
reset_values(frm);
frappe.run_serially([
() => frappe.dom.freeze(__("Loading Invoices! Please Wait...")),
() => frm.trigger("set_opening_amounts"),
() => frm.trigger("get_pos_invoices"),
() => frappe.dom.unfreeze(),
]);
}
},

View File

@@ -389,9 +389,7 @@ def split_invoices(invoices):
if not item.serial_no:
continue
return_against_is_added = any(
d for d in _invoices if d and d[0].pos_invoice == pos_invoice.return_against
)
return_against_is_added = any(d for d in _invoices if d.pos_invoice == pos_invoice.return_against)
if return_against_is_added:
break

View File

@@ -715,11 +715,14 @@ def get_pricing_rule_items(pr_doc, other_items=False) -> list:
def validate_coupon_code(coupon_name):
coupon = frappe.get_doc("Coupon Code", coupon_name)
if coupon.valid_from and coupon.valid_from > getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has not started"))
elif coupon.valid_upto and coupon.valid_upto < getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has expired"))
elif coupon.maximum_use and coupon.used >= coupon.maximum_use:
if coupon.valid_from:
if coupon.valid_from > getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has not started"))
elif coupon.valid_upto:
if coupon.valid_upto < getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has expired"))
elif coupon.used >= coupon.maximum_use:
frappe.throw(_("Sorry, this coupon code is no longer valid"))

View File

@@ -25,7 +25,6 @@
"payment_terms_template",
"sales_partner",
"sales_person",
"show_remarks",
"based_on_payment_terms",
"section_break_3",
"customer_collection",
@@ -389,16 +388,10 @@
"fieldname": "ignore_cr_dr_notes",
"fieldtype": "Check",
"label": "Ignore System Generated Credit / Debit Notes"
},
{
"default": "0",
"fieldname": "show_remarks",
"fieldtype": "Check",
"label": "Show Remarks"
}
],
"links": [],
"modified": "2024-10-18 17:51:39.108481",
"modified": "2024-08-13 10:41:18.381165",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

View File

@@ -132,7 +132,6 @@ def get_common_filters(doc):
"finance_book": doc.finance_book if doc.finance_book else None,
"account": [doc.account] if doc.account else None,
"cost_center": [cc.cost_center_name for cc in doc.cost_center],
"show_remarks": doc.show_remarks,
}
)

View File

@@ -25,13 +25,6 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
}
};
});
this.frm.set_query("expense_account", "items", function () {
return {
query: "erpnext.controllers.queries.get_expense_account",
filters: { company: doc.company },
};
});
}
onload() {
@@ -310,11 +303,8 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
party_type: "Supplier",
account: this.frm.doc.credit_to,
price_list: this.frm.doc.buying_price_list,
fetch_payment_terms_template: cint(
(this.frm.doc.is_return == 0) & !this.frm.doc.ignore_default_payment_terms_template
),
},
function () {
fetch_payment_terms_template: cint(!this.frm.doc.ignore_default_payment_terms_template)
}, function() {
me.apply_pricing_rule();
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
me.frm.doc.tax_withholding_category = me.frm.supplier_tds;
@@ -479,6 +469,13 @@ cur_frm.fields_dict['select_print_heading'].get_query = function(doc, cdt, cdn)
}
}
cur_frm.set_query("expense_account", "items", function(doc) {
return {
query: "erpnext.controllers.queries.get_expense_account",
filters: {'company': doc.company }
}
});
cur_frm.set_query("wip_composite_asset", "items", function() {
return {
filters: {'is_composite_asset': 1, 'docstatus': 0 }

View File

@@ -1128,14 +1128,12 @@
"label": "Payment Terms"
},
{
"depends_on": "eval:(!doc.is_paid && !doc.is_return)",
"fieldname": "payment_terms_template",
"fieldtype": "Link",
"label": "Payment Terms Template",
"options": "Payment Terms Template"
},
{
"depends_on": "eval:(!doc.is_paid && !doc.is_return)",
"fieldname": "payment_schedule",
"fieldtype": "Table",
"label": "Payment Schedule",
@@ -1613,7 +1611,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2024-10-25 18:13:01.944477",
"modified": "2024-09-11 12:59:19.130593",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -280,12 +280,8 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
party_type: "Customer",
account: this.frm.doc.debit_to,
price_list: this.frm.doc.selling_price_list,
pos_profile: pos_profile,
fetch_payment_terms_template: cint(
(this.frm.doc.is_return == 0) & !this.frm.doc.ignore_default_payment_terms_template
),
},
function () {
pos_profile: pos_profile
}, function() {
me.apply_pricing_rule();
});

View File

@@ -482,7 +482,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
payment_entry_filters.pop("apply_tax_withholding_amount", None)
payment_entry_filters.pop("tax_withholding_category", None)
supp_inv_credit_amt = frappe.db.get_value("Purchase Invoice", invoice_filters, field) or 0.0
supp_credit_amt = frappe.db.get_value("Purchase Invoice", invoice_filters, field) or 0.0
supp_jv_credit_amt = (
frappe.db.get_value(
@@ -506,7 +506,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
group_by="payment_type",
)
supp_credit_amt = supp_jv_credit_amt
supp_credit_amt += supp_jv_credit_amt
supp_credit_amt += inv.tax_withholding_net_total
for type in payment_entry_amounts:
@@ -524,18 +524,18 @@ def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
tax_withholding_net_total = inv.tax_withholding_net_total
if (threshold and tax_withholding_net_total >= threshold) or (
cumulative_threshold and (supp_credit_amt + supp_inv_credit_amt) >= cumulative_threshold
cumulative_threshold and supp_credit_amt >= cumulative_threshold
):
# Get net total again as TDS is calculated on net total
# Grand is used to just check for threshold breach
net_total = (
frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(tax_withholding_net_total)") or 0.0
)
supp_credit_amt += net_total
if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint(
tax_details.tax_on_excess_amount
):
# Get net total again as TDS is calculated on net total
# Grand is used to just check for threshold breach
net_total = (
frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(tax_withholding_net_total)")
or 0.0
)
net_total += inv.tax_withholding_net_total
supp_credit_amt = net_total - cumulative_threshold
if ldc and is_valid_certificate(ldc, inv.get("posting_date") or inv.get("transaction_date"), 0):

View File

@@ -121,46 +121,6 @@ class TestTaxWithholdingCategory(FrappeTestCase):
for d in reversed(invoices):
d.cancel()
def test_cumulative_threshold_with_party_ledger_amount_on_net_total(self):
invoices = []
frappe.db.set_value(
"Supplier", "Test TDS Supplier3", "tax_withholding_category", "Advance TDS Category"
)
# Invoice with tax and without exceeding single and cumulative thresholds
for _ in range(2):
pi = create_purchase_invoice(supplier="Test TDS Supplier3", rate=1000, do_not_save=True)
pi.apply_tds = 1
pi.append(
"taxes",
{
"category": "Total",
"charge_type": "Actual",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
"tax_amount": 500,
"description": "Test",
"add_deduct_tax": "Add",
},
)
pi.save()
pi.submit()
invoices.append(pi)
# Third Invoice exceeds single threshold and not exceeding cumulative threshold
pi1 = create_purchase_invoice(supplier="Test TDS Supplier3", rate=6000)
pi1.apply_tds = 1
pi1.save()
pi1.submit()
invoices.append(pi1)
# Cumulative threshold is 10,000
# Threshold calculation should be only on the third invoice
self.assertEqual(pi1.taxes[0].tax_amount, 800)
for d in reversed(invoices):
d.cancel()
def test_cumulative_threshold_tcs(self):
frappe.db.set_value(
"Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS"

View File

@@ -500,8 +500,7 @@ class ReceivablePayableReport:
from `tab{row.voucher_type}` si, `tabPayment Schedule` ps
where
si.name = ps.parent and
si.name = %s and
si.is_return = 0
si.name = %s
order by ps.paid_amount desc, due_date
""",
row.voucher_no,

View File

@@ -122,24 +122,21 @@ class Deferred_Item:
"""
simulate future posting by creating dummy gl entries. starts from the last posting date.
"""
if (
self.service_start_date != self.service_end_date
and add_days(self.last_entry_date, 1) < self.service_end_date
):
self.estimate_for_period_list = get_period_list(
self.filters.from_fiscal_year,
self.filters.to_fiscal_year,
add_days(self.last_entry_date, 1),
self.service_end_date,
"Date Range",
"Monthly",
company=self.filters.company,
)
for period in self.estimate_for_period_list:
amount = self.calculate_amount(period.from_date, period.to_date)
gle = self.make_dummy_gle(period.key, period.to_date, amount)
self.gle_entries.append(gle)
if self.service_start_date != self.service_end_date:
if add_days(self.last_entry_date, 1) < self.period_list[-1].to_date:
self.estimate_for_period_list = get_period_list(
self.filters.from_fiscal_year,
self.filters.to_fiscal_year,
add_days(self.last_entry_date, 1),
self.period_list[-1].to_date,
"Date Range",
"Monthly",
company=self.filters.company,
)
for period in self.estimate_for_period_list:
amount = self.calculate_amount(period.from_date, period.to_date)
gle = self.make_dummy_gle(period.key, period.to_date, amount)
self.gle_entries.append(gle)
def calculate_item_revenue_expense_for_period(self):
"""

View File

@@ -337,17 +337,9 @@ def get_accounts_with_children(accounts):
return list(set(all_accounts)) if all_accounts else None
def set_bill_no(gl_entries):
inv_details = get_supplier_invoice_details()
for gl in gl_entries:
gl["bill_no"] = inv_details.get(gl.get("against_voucher"), "")
def get_data_with_opening_closing(filters, account_details, accounting_dimensions, gl_entries):
data = []
set_bill_no(gl_entries)
gle_map = initialize_gle_map(gl_entries, filters)
totals, entries = get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map)
@@ -521,6 +513,7 @@ def get_account_type_map(company):
def get_result_as_list(data, filters):
balance, _balance_in_account_currency = 0, 0
inv_details = get_supplier_invoice_details()
for d in data:
if not d.get("posting_date"):
@@ -530,6 +523,7 @@ def get_result_as_list(data, filters):
d["balance"] = balance
d["account_currency"] = filters.account_currency
d["bill_no"] = inv_details.get(d.get("against_voucher"), "")
return data

View File

@@ -522,8 +522,7 @@ def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts, inclu
tax_details = frappe.db.sql(
"""select parent, account_head,
sum(base_tax_amount_after_discount_amount) as tax_amount
from `tabSales Taxes and Charges` where parent in (%s) and parenttype = 'Sales Invoice'
group by parent, account_head"""
from `tabSales Taxes and Charges` where parent in (%s) group by parent, account_head"""
% ", ".join(["%s"] * len(invoice_list)),
tuple(inv.name for inv in invoice_list),
as_dict=1,

View File

@@ -1524,16 +1524,12 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
return matched
def get_stock_accounts(company, voucher_type=None, voucher_no=None, accounts=None):
def get_stock_accounts(company, voucher_type=None, voucher_no=None):
stock_accounts = [
d.name
for d in frappe.db.get_all("Account", {"account_type": "Stock", "company": company, "is_group": 0})
]
if accounts:
stock_accounts = [row.account for row in accounts if row.account in stock_accounts]
elif voucher_type and voucher_no:
if voucher_type and voucher_no:
if voucher_type == "Journal Entry":
stock_accounts = [
d.account
@@ -1930,7 +1926,6 @@ class QueryPaymentLedger:
ple.cost_center.as_("cost_center"),
Sum(ple.amount).as_("amount"),
Sum(ple.amount_in_account_currency).as_("amount_in_account_currency"),
ple.remarks,
)
.where(ple.delinked == 0)
.where(Criterion.all(filter_on_voucher_no))
@@ -1993,7 +1988,6 @@ class QueryPaymentLedger:
Table("vouchers").due_date,
Table("vouchers").currency,
Table("vouchers").cost_center.as_("cost_center"),
Table("vouchers").remarks,
)
.where(Criterion.all(filter_on_outstanding_amount))
)

View File

@@ -218,8 +218,19 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
}
if(doc.status != "Closed") {
if (doc.status != "On Hold") {
<<<<<<< HEAD
if(flt(doc.per_received) < 100 && allow_receipt) {
cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
=======
if (flt(doc.per_received) < 100 && allow_receipt) {
this.frm.add_custom_button(
__("Purchase Receipt"),
() => {
me.make_purchase_receipt();
},
__("Create")
);
>>>>>>> a671fe13d4 (fix: list view and form status not same for purchase order (#43690))
if (doc.is_subcontracted) {
if (doc.is_old_subcontracting_flow) {
if (me.has_unsupplied_items()) {
@@ -231,9 +242,21 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
}
}
}
<<<<<<< HEAD
if(flt(doc.per_billed) < 100)
cur_frm.add_custom_button(__('Purchase Invoice'),
this.make_purchase_invoice, __('Create'));
=======
// Please do not add precision in the below flt function
if (flt(doc.per_billed) < 100)
this.frm.add_custom_button(
__("Purchase Invoice"),
() => {
me.make_purchase_invoice();
},
__("Create")
);
>>>>>>> a671fe13d4 (fix: list view and form status not same for purchase order (#43690))
if(flt(doc.per_billed) < 100 && doc.status != "Delivered") {
this.frm.add_custom_button(

View File

@@ -14,26 +14,15 @@ def get_data():
"Material Request": ["items", "material_request"],
"Supplier Quotation": ["items", "supplier_quotation"],
"Project": ["items", "project"],
"Sales Order": ["items", "sales_order"],
"BOM": ["items", "bom"],
"Production Plan": ["items", "production_plan"],
"Blanket Order": ["items", "blanket_order"],
},
"transactions": [
{"label": _("Related"), "items": ["Purchase Receipt", "Purchase Invoice", "Sales Order"]},
{"label": _("Related"), "items": ["Purchase Receipt", "Purchase Invoice"]},
{"label": _("Payment"), "items": ["Payment Entry", "Journal Entry", "Payment Request"]},
{
"label": _("Reference"),
"items": ["Supplier Quotation", "Project", "Auto Repeat"],
},
{
"label": _("Manufacturing"),
"items": ["Material Request", "BOM", "Production Plan", "Blanket Order"],
},
{
"label": _("Sub-contracting"),
"items": ["Subcontracting Order", "Stock Entry"],
"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
},
{"label": _("Sub-contracting"), "items": ["Subcontracting Order", "Stock Entry"]},
{"label": _("Internal"), "items": ["Sales Order"]},
],
}

View File

@@ -10,14 +10,22 @@ frappe.listview_settings["Purchase Order"] = {
"status",
],
get_indicator: function (doc) {
// Please do not add precision in the flt function
if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
} else if (doc.status === "On Hold") {
return [__("On Hold"), "orange", "status,=,On Hold"];
} else if (doc.status === "Delivered") {
return [__("Delivered"), "green", "status,=,Closed"];
<<<<<<< HEAD
} else if (flt(doc.per_received, 2) < 100 && doc.status !== "Closed") {
if (flt(doc.per_billed, 2) < 100) {
=======
} else if (doc.advance_payment_status == "Initiated") {
return [__("To Pay"), "gray", "advance_payment_status,=,Initiated"];
} else if (flt(doc.per_received) < 100 && doc.status !== "Closed") {
if (flt(doc.per_billed) < 100) {
>>>>>>> a671fe13d4 (fix: list view and form status not same for purchase order (#43690))
return [
__("To Receive and Bill"),
"orange",
@@ -26,17 +34,9 @@ frappe.listview_settings["Purchase Order"] = {
} else {
return [__("To Receive"), "orange", "per_received,<,100|per_billed,=,100|status,!=,Closed"];
}
} else if (
flt(doc.per_received, 2) >= 100 &&
flt(doc.per_billed, 2) < 100 &&
doc.status !== "Closed"
) {
} else if (flt(doc.per_received) >= 100 && flt(doc.per_billed) < 100 && doc.status !== "Closed") {
return [__("To Bill"), "orange", "per_received,=,100|per_billed,<,100|status,!=,Closed"];
} else if (
flt(doc.per_received, 2) >= 100 &&
flt(doc.per_billed, 2) == 100 &&
doc.status !== "Closed"
) {
} else if (flt(doc.per_received) >= 100 && flt(doc.per_billed) == 100 && doc.status !== "Closed") {
return [__("Completed"), "green", "per_received,=,100|per_billed,=,100|status,!=,Closed"];
}
},

View File

@@ -137,8 +137,8 @@ frappe.ui.form.on("Request for Quotation",{
return;
}
},
__("Download PDF for Supplier"),
__("Download")
"Download PDF for Supplier",
"Download"
);
},
__("Tools")
@@ -257,10 +257,8 @@ frappe.ui.form.on("Request for Quotation",{
});
};
const msg = __(
"This is a preview of the email to be sent. A PDF of the document will automatically be attached with the email."
);
dialog.fields_dict.note.$wrapper.append(`<p class="small text-muted">${msg}</p>`);
dialog.fields_dict.note.$wrapper.append(`<p class="small text-muted">This is a preview of the email to be sent. A PDF of the document will
automatically be attached with the email.</p>`);
dialog.show();
}

View File

@@ -357,15 +357,12 @@ class AccountsController(TransactionBase):
def validate_return_against_account(self):
if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against:
cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to"
original_account = frappe.get_value(self.doctype, self.return_against, cr_dr_account_field)
if original_account != self.get(cr_dr_account_field):
cr_dr_account_label = "Debit To" if self.doctype == "Sales Invoice" else "Credit To"
cr_dr_account = self.get(cr_dr_account_field)
if frappe.get_value(self.doctype, self.return_against, cr_dr_account_field) != cr_dr_account:
frappe.throw(
_(
"Please set {0} to {1}, the same account that was used in the original invoice {2}."
).format(
frappe.bold(_(self.meta.get_label(cr_dr_account_field), context=self.doctype)),
frappe.bold(original_account),
frappe.bold(self.return_against),
_("'{0}' account: '{1}' should match the Return Against Invoice").format(
frappe.bold(cr_dr_account_label), frappe.bold(cr_dr_account)
)
)
@@ -415,11 +412,6 @@ class AccountsController(TransactionBase):
)
def validate_invoice_documents_schedule(self):
if self.is_return:
self.payment_terms_template = ""
self.payment_schedule = []
return
self.validate_payment_schedule_dates()
self.set_due_date()
self.set_payment_schedule()
@@ -434,7 +426,7 @@ class AccountsController(TransactionBase):
self.validate_payment_schedule_amount()
def validate_all_documents_schedule(self):
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return:
self.validate_invoice_documents_schedule()
elif self.doctype in ("Quotation", "Purchase Order", "Sales Order"):
self.validate_non_invoice_documents_schedule()
@@ -3313,9 +3305,6 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
parent.update_billing_percentage()
parent.set_status()
parent.validate_uom_is_integer("uom", "qty")
parent.validate_uom_is_integer("stock_uom", "stock_qty")
def check_if_child_table_updated(child_table_before_update, child_table_after_update, fields_to_check):
accounting_dimensions = [*get_accounting_dimensions(), "cost_center", "project"]

View File

@@ -78,9 +78,6 @@ def validate_returned_items(doc):
if doc.doctype in ["Purchase Invoice", "Purchase Receipt", "Subcontracting Receipt"]:
select_fields += ",rejected_qty, received_qty"
if doc.doctype in ["Purchase Receipt", "Purchase Invoice"]:
select_fields += ",name"
for d in frappe.db.sql(
f"""select {select_fields} from `tab{doc.doctype} Item` where parent = %s""",
doc.return_against,
@@ -106,24 +103,15 @@ def validate_returned_items(doc):
items_returned = False
for d in doc.get("items"):
key = d.item_code
raise_exception = False
if doc.doctype in ["Purchase Receipt", "Purchase Invoice"]:
field = frappe.scrub(doc.doctype) + "_item"
if d.get(field):
key = (d.item_code, d.get(field))
raise_exception = True
if d.item_code and (flt(d.qty) < 0 or flt(d.get("received_qty")) < 0):
if key not in valid_items:
frappe.msgprint(
if d.item_code not in valid_items:
frappe.throw(
_("Row # {0}: Returned Item {1} does not exist in {2} {3}").format(
d.idx, d.item_code, doc.doctype, doc.return_against
),
raise_exception=raise_exception,
)
)
else:
ref = valid_items.get(key, frappe._dict())
ref = valid_items.get(d.item_code, frappe._dict())
validate_quantity(doc, d, ref, valid_items, already_returned_items)
if (
@@ -218,12 +206,8 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
def get_ref_item_dict(valid_items, ref_item_row):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
key = ref_item_row.item_code
if ref_item_row.get("name"):
key = (ref_item_row.item_code, ref_item_row.name)
valid_items.setdefault(
key,
ref_item_row.item_code,
frappe._dict(
{
"qty": 0,
@@ -237,7 +221,7 @@ def get_ref_item_dict(valid_items, ref_item_row):
}
),
)
item_dict = valid_items[key]
item_dict = valid_items[ref_item_row.item_code]
item_dict["qty"] += ref_item_row.qty
item_dict["stock_qty"] += ref_item_row.get("stock_qty", 0)
if ref_item_row.get("rate", 0) > item_dict["rate"]:

View File

@@ -767,19 +767,26 @@ class JobCard(Document):
qty = 0
if self.work_order:
doc = frappe.get_doc("Work Order", self.work_order)
if doc.transfer_material_against == "Job Card" and not doc.skip_transfer:
min_qty = []
completed = True
for d in doc.operations:
if d.completed_qty:
min_qty.append(d.completed_qty)
else:
min_qty = []
if d.status != "Completed":
completed = False
break
if min_qty:
qty = min(min_qty)
if completed:
job_cards = frappe.get_all(
"Job Card",
filters={"work_order": self.work_order, "docstatus": ("!=", 2)},
fields="sum(transferred_qty) as qty",
group_by="operation_id",
)
doc.db_set("material_transferred_for_manufacturing", qty)
if job_cards:
qty = min(d.qty for d in job_cards)
doc.db_set("material_transferred_for_manufacturing", qty)
self.set_status(update_status)

View File

@@ -47,7 +47,6 @@ frappe.ui.form.on("Project", {
frm.set_query("sales_order", function () {
var filters = {
project: ["in", frm.doc.__islocal ? [""] : [frm.doc.name, ""]],
company: frm.doc.company,
};
if (frm.doc.customer) {

View File

@@ -15,7 +15,6 @@ def execute(filters=None):
filters=filters,
fields=[
"name",
"project_name",
"status",
"percent_complete",
"expected_start_date",
@@ -49,11 +48,6 @@ def get_columns():
"options": "Project",
"width": 200,
},
{
"fieldname": "project_name",
"label": _("Project Name"),
"width": 200,
},
{
"fieldname": "project_type",
"label": _("Type"),
@@ -88,7 +82,7 @@ def get_chart_data(data):
overdue = []
for project in data:
labels.append(project.project_name)
labels.append(project.name)
total.append(project.total_tasks)
completed.append(project.completed_tasks)
overdue.append(project.overdue_tasks)

View File

@@ -2213,7 +2213,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
payment_terms_template() {
var me = this;
const doc = this.frm.doc;
if(doc.payment_terms_template && doc.doctype !== 'Delivery Note' && doc.is_return == 0) {
if(doc.payment_terms_template && doc.doctype !== 'Delivery Note') {
var posting_date = doc.posting_date || doc.transaction_date;
frappe.call({
method: "erpnext.controllers.accounts_controller.get_payment_terms",

View File

@@ -4,8 +4,7 @@ erpnext.accounts.unreconcile_payment = {
add_unreconcile_btn(frm) {
if (frm.doc.docstatus == 1) {
if (
(frm.doc.doctype == "Journal Entry" &&
!["Journal Entry", "Bank Entry", "Cash Entry"].includes(frm.doc.voucher_type)) ||
(frm.doc.doctype == "Journal Entry" && frm.doc.voucher_type != "Journal Entry") ||
!["Purchase Invoice", "Sales Invoice", "Journal Entry", "Payment Entry"].includes(
frm.doc.doctype
)

View File

@@ -14,8 +14,6 @@ def get_data():
},
"internal_links": {
"Quotation": ["items", "prevdoc_docname"],
"BOM": ["items", "bom_no"],
"Blanket Order": ["items", "blanket_order"],
},
"transactions": [
{
@@ -24,8 +22,8 @@ def get_data():
},
{"label": _("Purchasing"), "items": ["Material Request", "Purchase Order"]},
{"label": _("Projects"), "items": ["Project"]},
{"label": _("Manufacturing"), "items": ["Work Order"]},
{"label": _("Reference"), "items": ["Quotation", "Auto Repeat"]},
{"label": _("Manufacturing"), "items": ["Work Order", "BOM", "Blanket Order"]},
{"label": _("Payment"), "items": ["Payment Entry", "Payment Request", "Journal Entry"]},
],
}

View File

@@ -18,21 +18,3 @@ cur_frm.cscript.onload = function () {
frappe.ui.form.on("Serial No", "refresh", function (frm) {
frm.toggle_enable("item_code", frm.doc.__islocal);
});
frappe.ui.form.on("Serial No", {
refresh(frm) {
frm.trigger("view_ledgers");
},
view_ledgers(frm) {
frm.add_custom_button(__("View Ledgers"), () => {
frappe.route_options = {
item_code: frm.doc.item_code,
serial_no: frm.doc.name,
posting_date: frappe.datetime.now_date(),
posting_time: frappe.datetime.now_time(),
};
frappe.set_route("query-report", "Serial No Ledger");
});
},
});

View File

@@ -335,16 +335,11 @@ def validate_serial_no(sle, item_det):
if sr.work_order and work_order and sr.work_order == work_order:
allow_existing_serial_no = True
if (
not allow_existing_serial_no
and sle.voucher_type
in [
"Stock Entry",
"Purchase Receipt",
"Purchase Invoice",
]
and cint(sle.actual_qty) > 0
):
if not allow_existing_serial_no and sle.voucher_type in [
"Stock Entry",
"Purchase Receipt",
"Purchase Invoice",
]:
msg = ""
if sle.voucher_type == "Stock Entry":

View File

@@ -714,17 +714,7 @@ frappe.ui.form.on('Stock Entry', {
}
});
frappe.ui.form.on('Stock Entry Detail', {
set_basic_rate_manually(frm, cdt, cdn) {
let row = locals[cdt][cdn];
frm.fields_dict.items.grid.update_docfield_property(
"basic_rate",
"read_only",
row?.set_basic_rate_manually ? 0 : 1
);
},
qty: function(frm, cdt, cdn) {
frm.events.set_serial_no(frm, cdt, cdn, () => {
frm.events.set_basic_rate(frm, cdt, cdn);

View File

@@ -45,16 +45,8 @@ frappe.query_reports["Serial No Ledger"] = {
{
label: __("As On Date"),
fieldtype: "Date",
reqd: 1,
fieldname: "posting_date",
default: frappe.datetime.get_today(),
},
{
label: __("Posting Time"),
fieldtype: "Time",
reqd: 1,
fieldname: "posting_time",
default: frappe.datetime.now_time(),
},
],
};

View File

@@ -742,7 +742,7 @@ class update_entries_after:
rate = 0
# Material Transfer, Repack, Manufacturing
if sle.voucher_type == "Stock Entry":
self.recalculate_amounts_in_stock_entry(sle.voucher_no, sle.voucher_detail_no)
self.recalculate_amounts_in_stock_entry(sle.voucher_no)
rate = frappe.db.get_value("Stock Entry Detail", sle.voucher_detail_no, "valuation_rate")
# Sales and Purchase Return
elif sle.voucher_type in (
@@ -853,15 +853,14 @@ class update_entries_after:
# Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
if not sle.dependant_sle_voucher_detail_no:
self.recalculate_amounts_in_stock_entry(sle.voucher_no, sle.voucher_detail_no)
self.recalculate_amounts_in_stock_entry(sle.voucher_no)
def recalculate_amounts_in_stock_entry(self, voucher_no, voucher_detail_no):
def recalculate_amounts_in_stock_entry(self, voucher_no):
stock_entry = frappe.get_doc("Stock Entry", voucher_no, for_update=True)
stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)
stock_entry.db_update()
for d in stock_entry.items:
if d.name == voucher_detail_no or (not d.s_warehouse and d.t_warehouse):
d.db_update()
d.db_update()
def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate):
# Update item's incoming rate on transaction

View File

@@ -51,7 +51,7 @@ def get_tasks(project, start=0, search=None, item_status=None):
"parent_task",
],
limit_start=start,
limit_page_length=100,
limit_page_length=10,
)
task_nest = []
for task in tasks:

View File

@@ -5268,7 +5268,6 @@ Request for Quotation Supplier,Angebotsanfrage Lieferant,
Send Email,E-Mail absenden,
Quote Status,Zitat Status,
Download PDF,PDF Herunterladen,
Download PDF for Supplier,PDF für Lieferanten herunterladen,
Supplier of Goods or Services.,Lieferant von Waren oder Dienstleistungen.,
Name and Type,Name und Typ,
SUP-.YYYY.-,SUP-.YYYY.-,
@@ -6625,7 +6624,6 @@ This is a location where operations are executed.,"Dies ist ein Ort, an dem Oper
This is a location where final product stored.,"Dies ist ein Ort, an dem das Endprodukt gelagert wird.",
Scrap Warehouse,Ausschusslager,
This is a location where scraped materials are stored.,"Dies ist ein Ort, an dem abgekratzte Materialien gelagert werden.",
This is a preview of the email to be sent. A PDF of the document will automatically be attached with the email.,Dies ist eine Vorschau der zu sendenden E-Mail. Ein PDF des Dokuments wird automatisch an die E-Mail angehängt.,
Required Items,Erforderliche Elemente,
Actual Start Date,Tatsächliches Startdatum,
Planned End Date,Geplantes Enddatum,
Can't render this file because it is too large.