mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 20:29:09 +00:00
Merge pull request #41031 from frappe/version-15-hotfix
chore: release v15
This commit is contained in:
@@ -139,6 +139,10 @@ class Dunning(AccountsController):
|
|||||||
)
|
)
|
||||||
row.dunning_level = len(past_dunnings) + 1
|
row.dunning_level = len(past_dunnings) + 1
|
||||||
|
|
||||||
|
def on_cancel(self):
|
||||||
|
super().on_cancel()
|
||||||
|
self.ignore_linked_doctypes = ["GL Entry"]
|
||||||
|
|
||||||
|
|
||||||
def resolve_dunning(doc, state):
|
def resolve_dunning(doc, state):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class PaymentRequest(Document):
|
|||||||
self.status = "Draft"
|
self.status = "Draft"
|
||||||
self.validate_reference_document()
|
self.validate_reference_document()
|
||||||
self.validate_payment_request_amount()
|
self.validate_payment_request_amount()
|
||||||
self.validate_currency()
|
# self.validate_currency()
|
||||||
self.validate_subscription_details()
|
self.validate_subscription_details()
|
||||||
|
|
||||||
def validate_reference_document(self):
|
def validate_reference_document(self):
|
||||||
@@ -330,21 +330,17 @@ class PaymentRequest(Document):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if party_account_currency == ref_doc.company_currency and party_account_currency != self.currency:
|
||||||
|
amount = payment_entry.base_paid_amount
|
||||||
|
else:
|
||||||
|
amount = self.grand_total
|
||||||
|
|
||||||
|
payment_entry.received_amount = amount
|
||||||
|
payment_entry.get("references")[0].allocated_amount = amount
|
||||||
|
|
||||||
for dimension in get_accounting_dimensions():
|
for dimension in get_accounting_dimensions():
|
||||||
payment_entry.update({dimension: self.get(dimension)})
|
payment_entry.update({dimension: self.get(dimension)})
|
||||||
|
|
||||||
if payment_entry.difference_amount:
|
|
||||||
company_details = get_company_defaults(ref_doc.company)
|
|
||||||
|
|
||||||
payment_entry.append(
|
|
||||||
"deductions",
|
|
||||||
{
|
|
||||||
"account": company_details.exchange_gain_loss_account,
|
|
||||||
"cost_center": company_details.cost_center,
|
|
||||||
"amount": payment_entry.difference_amount,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if submit:
|
if submit:
|
||||||
payment_entry.insert(ignore_permissions=True)
|
payment_entry.insert(ignore_permissions=True)
|
||||||
payment_entry.submit()
|
payment_entry.submit()
|
||||||
@@ -463,6 +459,12 @@ def make_payment_request(**args):
|
|||||||
pr = frappe.get_doc("Payment Request", draft_payment_request)
|
pr = frappe.get_doc("Payment Request", draft_payment_request)
|
||||||
else:
|
else:
|
||||||
pr = frappe.new_doc("Payment Request")
|
pr = frappe.new_doc("Payment Request")
|
||||||
|
|
||||||
|
if not args.get("payment_request_type"):
|
||||||
|
args["payment_request_type"] = (
|
||||||
|
"Outward" if args.get("dt") in ["Purchase Order", "Purchase Invoice"] else "Inward"
|
||||||
|
)
|
||||||
|
|
||||||
pr.update(
|
pr.update(
|
||||||
{
|
{
|
||||||
"payment_gateway_account": gateway_account.get("name"),
|
"payment_gateway_account": gateway_account.get("name"),
|
||||||
@@ -521,9 +523,9 @@ def get_amount(ref_doc, payment_account=None):
|
|||||||
elif dt in ["Sales Invoice", "Purchase Invoice"]:
|
elif dt in ["Sales Invoice", "Purchase Invoice"]:
|
||||||
if not ref_doc.get("is_pos"):
|
if not ref_doc.get("is_pos"):
|
||||||
if ref_doc.party_account_currency == ref_doc.currency:
|
if ref_doc.party_account_currency == ref_doc.currency:
|
||||||
grand_total = flt(ref_doc.outstanding_amount)
|
grand_total = flt(ref_doc.grand_total)
|
||||||
else:
|
else:
|
||||||
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
|
grand_total = flt(ref_doc.base_grand_total) / ref_doc.conversion_rate
|
||||||
elif dt == "Sales Invoice":
|
elif dt == "Sales Invoice":
|
||||||
for pay in ref_doc.payments:
|
for pay in ref_doc.payments:
|
||||||
if pay.type == "Phone" and pay.account == payment_account:
|
if pay.type == "Phone" and pay.account == payment_account:
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
pr = make_payment_request(
|
pr = make_payment_request(
|
||||||
dt="Purchase Invoice",
|
dt="Purchase Invoice",
|
||||||
dn=si_usd.name,
|
dn=si_usd.name,
|
||||||
|
party_type="Supplier",
|
||||||
|
party="_Test Supplier USD",
|
||||||
recipient_id="user@example.com",
|
recipient_id="user@example.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD",
|
||||||
@@ -98,6 +100,51 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(pr.status, "Paid")
|
self.assertEqual(pr.status, "Paid")
|
||||||
|
|
||||||
|
def test_multiple_payment_entry_against_purchase_invoice(self):
|
||||||
|
purchase_invoice = make_purchase_invoice(
|
||||||
|
customer="_Test Supplier USD",
|
||||||
|
debit_to="_Test Payable USD - _TC",
|
||||||
|
currency="USD",
|
||||||
|
conversion_rate=50,
|
||||||
|
)
|
||||||
|
|
||||||
|
pr = make_payment_request(
|
||||||
|
dt="Purchase Invoice",
|
||||||
|
party_type="Supplier",
|
||||||
|
party="_Test Supplier USD",
|
||||||
|
dn=purchase_invoice.name,
|
||||||
|
recipient_id="user@example.com",
|
||||||
|
mute_email=1,
|
||||||
|
payment_gateway_account="_Test Gateway - USD",
|
||||||
|
return_doc=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
pr.grand_total = pr.grand_total / 2
|
||||||
|
|
||||||
|
pr.submit()
|
||||||
|
pr.create_payment_entry()
|
||||||
|
|
||||||
|
purchase_invoice.load_from_db()
|
||||||
|
self.assertEqual(purchase_invoice.status, "Partly Paid")
|
||||||
|
|
||||||
|
pr = make_payment_request(
|
||||||
|
dt="Purchase Invoice",
|
||||||
|
party_type="Supplier",
|
||||||
|
party="_Test Supplier USD",
|
||||||
|
dn=purchase_invoice.name,
|
||||||
|
recipient_id="user@example.com",
|
||||||
|
mute_email=1,
|
||||||
|
payment_gateway_account="_Test Gateway - USD",
|
||||||
|
return_doc=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
pr.save()
|
||||||
|
pr.submit()
|
||||||
|
pr.create_payment_entry()
|
||||||
|
|
||||||
|
purchase_invoice.load_from_db()
|
||||||
|
self.assertEqual(purchase_invoice.status, "Paid")
|
||||||
|
|
||||||
def test_payment_entry(self):
|
def test_payment_entry(self):
|
||||||
frappe.db.set_value(
|
frappe.db.set_value(
|
||||||
"Company", "_Test Company", "exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"
|
"Company", "_Test Company", "exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
|
|||||||
|
|
||||||
for gle in gl_entries:
|
for gle in gl_entries:
|
||||||
group_by_value = gle.get(group_by)
|
group_by_value = gle.get(group_by)
|
||||||
gle.voucher_type = _(gle.voucher_type)
|
gle.voucher_type = gle.voucher_type
|
||||||
|
|
||||||
if gle.posting_date < from_date or (cstr(gle.is_opening) == "Yes" and not show_opening_entries):
|
if gle.posting_date < from_date or (cstr(gle.is_opening) == "Yes" and not show_opening_entries):
|
||||||
if not group_by_voucher_consolidated:
|
if not group_by_voucher_consolidated:
|
||||||
|
|||||||
@@ -655,13 +655,13 @@ class GrossProfitGenerator:
|
|||||||
elif self.delivery_notes.get((row.parent, row.item_code), None):
|
elif self.delivery_notes.get((row.parent, row.item_code), None):
|
||||||
# check if Invoice has delivery notes
|
# check if Invoice has delivery notes
|
||||||
dn = self.delivery_notes.get((row.parent, row.item_code))
|
dn = self.delivery_notes.get((row.parent, row.item_code))
|
||||||
parenttype, parent, item_row, _warehouse = (
|
parenttype, parent, item_row, dn_warehouse = (
|
||||||
"Delivery Note",
|
"Delivery Note",
|
||||||
dn["delivery_note"],
|
dn["delivery_note"],
|
||||||
dn["item_row"],
|
dn["item_row"],
|
||||||
dn["warehouse"],
|
dn["warehouse"],
|
||||||
)
|
)
|
||||||
my_sle = self.get_stock_ledger_entries(item_code, row.warehouse)
|
my_sle = self.get_stock_ledger_entries(item_code, dn_warehouse)
|
||||||
return self.calculate_buying_amount_from_sle(
|
return self.calculate_buying_amount_from_sle(
|
||||||
row, my_sle, parenttype, parent, item_row, item_code
|
row, my_sle, parenttype, parent, item_row, item_code
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1437,7 +1437,8 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
dr_or_cr = "debit" if d.exchange_gain_loss > 0 else "credit"
|
dr_or_cr = "debit" if d.exchange_gain_loss > 0 else "credit"
|
||||||
|
|
||||||
if d.reference_doctype == "Purchase Invoice":
|
# Inverse debit/credit for payable accounts
|
||||||
|
if self.is_payable_account(d.reference_doctype, party_account):
|
||||||
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
|
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
|
||||||
|
|
||||||
reverse_dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
|
reverse_dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
|
||||||
@@ -1471,6 +1472,14 @@ class AccountsController(TransactionBase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_payable_account(self, reference_doctype, account):
|
||||||
|
if reference_doctype == "Purchase Invoice" or (
|
||||||
|
reference_doctype == "Journal Entry"
|
||||||
|
and frappe.get_cached_value("Account", account, "account_type") == "Payable"
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def update_against_document_in_jv(self):
|
def update_against_document_in_jv(self):
|
||||||
"""
|
"""
|
||||||
Links invoice and advance voucher:
|
Links invoice and advance voucher:
|
||||||
|
|||||||
@@ -135,6 +135,27 @@ class TestAccountsController(FrappeTestCase):
|
|||||||
acc = frappe.get_doc("Account", name)
|
acc = frappe.get_doc("Account", name)
|
||||||
self.debtors_usd = acc.name
|
self.debtors_usd = acc.name
|
||||||
|
|
||||||
|
account_name = "Creditors USD"
|
||||||
|
if not frappe.db.get_value(
|
||||||
|
"Account", filters={"account_name": account_name, "company": self.company}
|
||||||
|
):
|
||||||
|
acc = frappe.new_doc("Account")
|
||||||
|
acc.account_name = account_name
|
||||||
|
acc.parent_account = "Accounts Payable - " + self.company_abbr
|
||||||
|
acc.company = self.company
|
||||||
|
acc.account_currency = "USD"
|
||||||
|
acc.account_type = "Payable"
|
||||||
|
acc.insert()
|
||||||
|
else:
|
||||||
|
name = frappe.db.get_value(
|
||||||
|
"Account",
|
||||||
|
filters={"account_name": account_name, "company": self.company},
|
||||||
|
fieldname="name",
|
||||||
|
pluck=True,
|
||||||
|
)
|
||||||
|
acc = frappe.get_doc("Account", name)
|
||||||
|
self.creditors_usd = acc.name
|
||||||
|
|
||||||
def create_sales_invoice(
|
def create_sales_invoice(
|
||||||
self,
|
self,
|
||||||
qty=1,
|
qty=1,
|
||||||
@@ -174,7 +195,9 @@ class TestAccountsController(FrappeTestCase):
|
|||||||
)
|
)
|
||||||
return sinv
|
return sinv
|
||||||
|
|
||||||
def create_payment_entry(self, amount=1, source_exc_rate=75, posting_date=None, customer=None):
|
def create_payment_entry(
|
||||||
|
self, amount=1, source_exc_rate=75, posting_date=None, customer=None, submit=True
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Helper function to populate default values in payment entry
|
Helper function to populate default values in payment entry
|
||||||
"""
|
"""
|
||||||
@@ -1606,3 +1629,72 @@ class TestAccountsController(FrappeTestCase):
|
|||||||
exc_je_for_je2 = self.get_journals_for(je2.doctype, je2.name)
|
exc_je_for_je2 = self.get_journals_for(je2.doctype, je2.name)
|
||||||
self.assertEqual(exc_je_for_je1, [])
|
self.assertEqual(exc_je_for_je1, [])
|
||||||
self.assertEqual(exc_je_for_je2, [])
|
self.assertEqual(exc_je_for_je2, [])
|
||||||
|
|
||||||
|
def test_61_payment_entry_against_journal_for_payable_accounts(self):
|
||||||
|
# Invoices
|
||||||
|
exc_rate1 = 75
|
||||||
|
exc_rate2 = 77
|
||||||
|
amount = 1
|
||||||
|
je1 = self.create_journal_entry(
|
||||||
|
acc1=self.creditors_usd,
|
||||||
|
acc1_exc_rate=exc_rate1,
|
||||||
|
acc2=self.cash,
|
||||||
|
acc1_amount=-amount,
|
||||||
|
acc2_amount=(-amount * 75),
|
||||||
|
acc2_exc_rate=1,
|
||||||
|
)
|
||||||
|
je1.accounts[0].party_type = "Supplier"
|
||||||
|
je1.accounts[0].party = self.supplier
|
||||||
|
je1 = je1.save().submit()
|
||||||
|
|
||||||
|
# Payment
|
||||||
|
pe = create_payment_entry(
|
||||||
|
company=self.company,
|
||||||
|
payment_type="Pay",
|
||||||
|
party_type="Supplier",
|
||||||
|
party=self.supplier,
|
||||||
|
paid_from=self.cash,
|
||||||
|
paid_to=self.creditors_usd,
|
||||||
|
paid_amount=amount,
|
||||||
|
)
|
||||||
|
pe.target_exchange_rate = exc_rate2
|
||||||
|
pe.received_amount = amount
|
||||||
|
pe.paid_amount = amount * exc_rate2
|
||||||
|
pe.save().submit()
|
||||||
|
|
||||||
|
pr = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Payment Reconciliation",
|
||||||
|
"company": self.company,
|
||||||
|
"party_type": "Supplier",
|
||||||
|
"party": self.supplier,
|
||||||
|
"receivable_payable_account": get_party_account("Supplier", self.supplier, self.company),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate()
|
||||||
|
pr.get_unreconciled_entries()
|
||||||
|
self.assertEqual(len(pr.invoices), 1)
|
||||||
|
self.assertEqual(len(pr.payments), 1)
|
||||||
|
invoices = [x.as_dict() for x in pr.invoices]
|
||||||
|
payments = [x.as_dict() for x in pr.payments]
|
||||||
|
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
|
||||||
|
pr.reconcile()
|
||||||
|
self.assertEqual(len(pr.invoices), 0)
|
||||||
|
self.assertEqual(len(pr.payments), 0)
|
||||||
|
|
||||||
|
# There should be no outstanding in both currencies
|
||||||
|
self.assert_ledger_outstanding(je1.doctype, je1.name, 0.0, 0.0)
|
||||||
|
|
||||||
|
# Exchange Gain/Loss Journal should've been created
|
||||||
|
exc_je_for_je1 = self.get_journals_for(je1.doctype, je1.name)
|
||||||
|
self.assertEqual(len(exc_je_for_je1), 1)
|
||||||
|
|
||||||
|
# Cancel Payment
|
||||||
|
pe.reload()
|
||||||
|
pe.cancel()
|
||||||
|
|
||||||
|
self.assert_ledger_outstanding(je1.doctype, je1.name, (amount * exc_rate1), amount)
|
||||||
|
|
||||||
|
# Exchange Gain/Loss Journal should've been cancelled
|
||||||
|
exc_je_for_je1 = self.get_journals_for(je1.doctype, je1.name)
|
||||||
|
self.assertEqual(exc_je_for_je1, [])
|
||||||
|
|||||||
@@ -540,6 +540,7 @@ accounting_dimension_doctypes = [
|
|||||||
"Supplier Quotation Item",
|
"Supplier Quotation Item",
|
||||||
"Payment Reconciliation",
|
"Payment Reconciliation",
|
||||||
"Payment Reconciliation Allocation",
|
"Payment Reconciliation Allocation",
|
||||||
|
"Payment Request",
|
||||||
]
|
]
|
||||||
|
|
||||||
get_matching_queries = (
|
get_matching_queries = (
|
||||||
|
|||||||
@@ -355,6 +355,7 @@ erpnext.patches.v14_0.update_total_asset_cost_field
|
|||||||
erpnext.patches.v14_0.create_accounting_dimensions_in_reconciliation_tool
|
erpnext.patches.v14_0.create_accounting_dimensions_in_reconciliation_tool
|
||||||
erpnext.patches.v15_0.allow_on_submit_dimensions_for_repostable_doctypes
|
erpnext.patches.v15_0.allow_on_submit_dimensions_for_repostable_doctypes
|
||||||
erpnext.patches.v14_0.update_flag_for_return_invoices #2024-03-22
|
erpnext.patches.v14_0.update_flag_for_return_invoices #2024-03-22
|
||||||
|
erpnext.patches.v15_0.create_accounting_dimensions_in_payment_request
|
||||||
# below migration patch should always run last
|
# below migration patch should always run last
|
||||||
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
||||||
erpnext.stock.doctype.delivery_note.patches.drop_unused_return_against_index # 2023-12-20
|
erpnext.stock.doctype.delivery_note.patches.drop_unused_return_against_index # 2023-12-20
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||||
|
create_accounting_dimensions_for_doctype,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
create_accounting_dimensions_for_doctype(doctype="Payment Request")
|
||||||
@@ -384,7 +384,6 @@ def _make_sales_order(source_name, target_doc=None, customer_group=None, ignore_
|
|||||||
)
|
)
|
||||||
|
|
||||||
target.flags.ignore_permissions = ignore_permissions
|
target.flags.ignore_permissions = ignore_permissions
|
||||||
target.delivery_date = nowdate()
|
|
||||||
target.run_method("set_missing_values")
|
target.run_method("set_missing_values")
|
||||||
target.run_method("calculate_taxes_and_totals")
|
target.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ class TestQuotation(FrappeTestCase):
|
|||||||
|
|
||||||
sales_order.naming_series = "_T-Quotation-"
|
sales_order.naming_series = "_T-Quotation-"
|
||||||
sales_order.transaction_date = nowdate()
|
sales_order.transaction_date = nowdate()
|
||||||
|
sales_order.delivery_date = nowdate()
|
||||||
sales_order.insert()
|
sales_order.insert()
|
||||||
|
|
||||||
def test_make_sales_order_with_terms(self):
|
def test_make_sales_order_with_terms(self):
|
||||||
@@ -152,6 +153,7 @@ class TestQuotation(FrappeTestCase):
|
|||||||
|
|
||||||
sales_order.naming_series = "_T-Quotation-"
|
sales_order.naming_series = "_T-Quotation-"
|
||||||
sales_order.transaction_date = nowdate()
|
sales_order.transaction_date = nowdate()
|
||||||
|
sales_order.delivery_date = nowdate()
|
||||||
sales_order.insert()
|
sales_order.insert()
|
||||||
|
|
||||||
# Remove any unknown taxes if applied
|
# Remove any unknown taxes if applied
|
||||||
|
|||||||
@@ -169,6 +169,27 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// When multiple companies are set up. in case company name is changed set default company address
|
||||||
|
company: function (frm) {
|
||||||
|
if (frm.doc.company) {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.setup.doctype.company.company.get_default_company_address",
|
||||||
|
args: {
|
||||||
|
name: frm.doc.company,
|
||||||
|
existing_address: frm.doc.company_address || "",
|
||||||
|
},
|
||||||
|
debounce: 2000,
|
||||||
|
callback: function (r) {
|
||||||
|
if (r.message) {
|
||||||
|
frm.set_value("company_address", r.message);
|
||||||
|
} else {
|
||||||
|
frm.set_value("company_address", "");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onload: function (frm) {
|
onload: function (frm) {
|
||||||
if (!frm.doc.transaction_date) {
|
if (!frm.doc.transaction_date) {
|
||||||
frm.set_value("transaction_date", frappe.datetime.get_today());
|
frm.set_value("transaction_date", frappe.datetime.get_today());
|
||||||
@@ -288,6 +309,7 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
label: __("Items to Reserve"),
|
label: __("Items to Reserve"),
|
||||||
allow_bulk_edit: false,
|
allow_bulk_edit: false,
|
||||||
cannot_add_rows: true,
|
cannot_add_rows: true,
|
||||||
|
cannot_delete_rows: true,
|
||||||
data: [],
|
data: [],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@@ -356,7 +378,7 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
],
|
],
|
||||||
primary_action_label: __("Reserve Stock"),
|
primary_action_label: __("Reserve Stock"),
|
||||||
primary_action: () => {
|
primary_action: () => {
|
||||||
var data = { items: dialog.fields_dict.items.grid.data };
|
var data = { items: dialog.fields_dict.items.grid.get_selected_children() };
|
||||||
|
|
||||||
if (data.items && data.items.length > 0) {
|
if (data.items && data.items.length > 0) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
@@ -373,9 +395,11 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
frm.reload_doc();
|
frm.reload_doc();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
|
} else {
|
||||||
|
frappe.msgprint(__("Please select items to reserve."));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -390,6 +414,7 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
|
|
||||||
if (unreserved_qty > 0) {
|
if (unreserved_qty > 0) {
|
||||||
dialog.fields_dict.items.df.data.push({
|
dialog.fields_dict.items.df.data.push({
|
||||||
|
__checked: 1,
|
||||||
sales_order_item: item.name,
|
sales_order_item: item.name,
|
||||||
item_code: item.item_code,
|
item_code: item.item_code,
|
||||||
warehouse: item.warehouse,
|
warehouse: item.warehouse,
|
||||||
@@ -414,6 +439,7 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
label: __("Reserved Stock"),
|
label: __("Reserved Stock"),
|
||||||
allow_bulk_edit: false,
|
allow_bulk_edit: false,
|
||||||
cannot_add_rows: true,
|
cannot_add_rows: true,
|
||||||
|
cannot_delete_rows: true,
|
||||||
in_place_edit: true,
|
in_place_edit: true,
|
||||||
data: [],
|
data: [],
|
||||||
fields: [
|
fields: [
|
||||||
@@ -457,7 +483,7 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
],
|
],
|
||||||
primary_action_label: __("Unreserve Stock"),
|
primary_action_label: __("Unreserve Stock"),
|
||||||
primary_action: () => {
|
primary_action: () => {
|
||||||
var data = { sr_entries: dialog.fields_dict.sr_entries.grid.data };
|
var data = { sr_entries: dialog.fields_dict.sr_entries.grid.get_selected_children() };
|
||||||
|
|
||||||
if (data.sr_entries && data.sr_entries.length > 0) {
|
if (data.sr_entries && data.sr_entries.length > 0) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
@@ -473,9 +499,11 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
frm.reload_doc();
|
frm.reload_doc();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
|
} else {
|
||||||
|
frappe.msgprint(__("Please select items to unreserve."));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1641,11 +1641,7 @@ class StockEntry(StockController):
|
|||||||
ret.update(get_uom_details(args.get("item_code"), args.get("uom"), args.get("qty")))
|
ret.update(get_uom_details(args.get("item_code"), args.get("uom"), args.get("qty")))
|
||||||
|
|
||||||
if self.purpose == "Material Issue":
|
if self.purpose == "Material Issue":
|
||||||
ret["expense_account"] = (
|
ret["expense_account"] = item.get("expense_account") or item_group_defaults.get("expense_account")
|
||||||
item.get("expense_account")
|
|
||||||
or item_group_defaults.get("expense_account")
|
|
||||||
or frappe.get_cached_value("Company", self.company, "default_expense_account")
|
|
||||||
)
|
|
||||||
|
|
||||||
for company_field, field in {
|
for company_field, field in {
|
||||||
"stock_adjustment_account": "expense_account",
|
"stock_adjustment_account": "expense_account",
|
||||||
|
|||||||
@@ -86,7 +86,11 @@ class DelayedItemReport:
|
|||||||
filters = {"parent": ("in", sales_orders), "name": ("in", sales_order_items)}
|
filters = {"parent": ("in", sales_orders), "name": ("in", sales_order_items)}
|
||||||
|
|
||||||
so_data = {}
|
so_data = {}
|
||||||
for d in frappe.get_all(doctype, filters=filters, fields=["delivery_date", "parent", "name"]):
|
fields = ["delivery_date", "name"]
|
||||||
|
if frappe.db.has_column(doctype, "parent"):
|
||||||
|
fields.append("parent")
|
||||||
|
|
||||||
|
for d in frappe.get_all(doctype, filters=filters, fields=fields):
|
||||||
key = d.name if consolidated else (d.parent, d.name)
|
key = d.name if consolidated else (d.parent, d.name)
|
||||||
if key not in so_data:
|
if key not in so_data:
|
||||||
so_data.setdefault(key, d.delivery_date)
|
so_data.setdefault(key, d.delivery_date)
|
||||||
|
|||||||
@@ -722,6 +722,7 @@ def make_purchase_receipt(source_name, target_doc=None, save=False, submit=False
|
|||||||
"purchase_order": item.purchase_order,
|
"purchase_order": item.purchase_order,
|
||||||
"purchase_order_item": item.purchase_order_item,
|
"purchase_order_item": item.purchase_order_item,
|
||||||
"subcontracting_receipt_item": item.name,
|
"subcontracting_receipt_item": item.name,
|
||||||
|
"project": po_item.project,
|
||||||
}
|
}
|
||||||
target_doc.append("items", item_row)
|
target_doc.append("items", item_row)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user