mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-30 22:38:35 +00:00
Compare commits
63 Commits
revert-362
...
ankush-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f784b17564 | ||
|
|
f83a100a8d | ||
|
|
e8eeeb16e2 | ||
|
|
652398fad2 | ||
|
|
ce36d1f668 | ||
|
|
05b07e098a | ||
|
|
1ddfaa7605 | ||
|
|
c6d8f15b10 | ||
|
|
c6b024c34b | ||
|
|
b38d300a92 | ||
|
|
eeddeeeeb3 | ||
|
|
c0642cf528 | ||
|
|
b71dafd1f1 | ||
|
|
caad4537c5 | ||
|
|
f999b75ed6 | ||
|
|
ecca9cb023 | ||
|
|
3173546d5c | ||
|
|
3b58055410 | ||
|
|
bc470591ac | ||
|
|
ee7da639e7 | ||
|
|
bc6cbb9e25 | ||
|
|
1c687a4afd | ||
|
|
d9ac7f9b87 | ||
|
|
4e58503075 | ||
|
|
c82cb379a5 | ||
|
|
148d466ae5 | ||
|
|
58d867503b | ||
|
|
1c2148b637 | ||
|
|
49981fecc7 | ||
|
|
e36c8ce5be | ||
|
|
f9fa34ff40 | ||
|
|
50d294fd1e | ||
|
|
dac9fd64a8 | ||
|
|
829387c2bc | ||
|
|
fff83bc847 | ||
|
|
ebdf1959fd | ||
|
|
a25f34c3d5 | ||
|
|
2341061852 | ||
|
|
4496a6760e | ||
|
|
dacf013170 | ||
|
|
523d2c38eb | ||
|
|
4f9242d699 | ||
|
|
ccf1920a78 | ||
|
|
1c2da92233 | ||
|
|
3558c3d24e | ||
|
|
fd2c272bed | ||
|
|
4bb6db86f8 | ||
|
|
4b4d828260 | ||
|
|
3f5afb9cac | ||
|
|
23e56d3ec1 | ||
|
|
e19a6f5dcb | ||
|
|
b3f6d991b5 | ||
|
|
77deac4fb9 | ||
|
|
3a3ffa2307 | ||
|
|
1e1e4b93c1 | ||
|
|
ecaf0aba3c | ||
|
|
ed3bef1840 | ||
|
|
4004427892 | ||
|
|
22ba12172f | ||
|
|
4e09de4db2 | ||
|
|
d3759b3971 | ||
|
|
72f577aad2 | ||
|
|
2268f7db43 |
@@ -79,8 +79,8 @@ frappe.ui.form.on('Account', {
|
||||
frm.add_custom_button(__('General Ledger'), function () {
|
||||
frappe.route_options = {
|
||||
"account": frm.doc.name,
|
||||
"from_date": frappe.sys_defaults.year_start_date,
|
||||
"to_date": frappe.sys_defaults.year_end_date,
|
||||
"from_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"to_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
"company": frm.doc.company
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
|
||||
@@ -194,8 +194,8 @@ frappe.treeview_settings["Account"] = {
|
||||
click: function(node, btn) {
|
||||
frappe.route_options = {
|
||||
"account": node.label,
|
||||
"from_date": frappe.sys_defaults.year_start_date,
|
||||
"to_date": frappe.sys_defaults.year_end_date,
|
||||
"from_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"to_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
"company": frappe.treeview_settings['Account'].treeview.page.fields_dict.company.get_value()
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
|
||||
@@ -15,6 +15,17 @@ frappe.ui.form.on('Accounting Dimension', {
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("offsetting_account", "dimension_defaults", function(doc, cdt, cdn) {
|
||||
let d = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
company: d.company,
|
||||
root_type: ["in", ["Asset", "Liability"]],
|
||||
is_group: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
|
||||
frappe.set_route("List", frm.doc.document_type);
|
||||
|
||||
@@ -39,6 +39,8 @@ class AccountingDimension(Document):
|
||||
if not self.is_new():
|
||||
self.validate_document_type_change()
|
||||
|
||||
self.validate_dimension_defaults()
|
||||
|
||||
def validate_document_type_change(self):
|
||||
doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
|
||||
if doctype_before_save != self.document_type:
|
||||
@@ -46,6 +48,14 @@ class AccountingDimension(Document):
|
||||
message += _("Please create a new Accounting Dimension if required.")
|
||||
frappe.throw(message)
|
||||
|
||||
def validate_dimension_defaults(self):
|
||||
companies = []
|
||||
for default in self.get("dimension_defaults"):
|
||||
if default.company not in companies:
|
||||
companies.append(default.company)
|
||||
else:
|
||||
frappe.throw(_("Company {0} is added more than once").format(frappe.bold(default.company)))
|
||||
|
||||
def after_insert(self):
|
||||
if frappe.flags.in_test:
|
||||
make_dimension_in_accounting_doctypes(doc=self)
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
"reference_document",
|
||||
"default_dimension",
|
||||
"mandatory_for_bs",
|
||||
"mandatory_for_pl"
|
||||
"mandatory_for_pl",
|
||||
"column_break_lqns",
|
||||
"automatically_post_balancing_accounting_entry",
|
||||
"offsetting_account"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -50,6 +53,23 @@
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory For Profit and Loss Account"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "automatically_post_balancing_accounting_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Automatically post balancing accounting entry"
|
||||
},
|
||||
{
|
||||
"fieldname": "offsetting_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Offsetting Account",
|
||||
"mandatory_depends_on": "eval: doc.automatically_post_balancing_accounting_entry",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_lqns",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"closing_settings_tab",
|
||||
"period_closing_settings_section",
|
||||
"acc_frozen_upto",
|
||||
"ignore_account_closing_balance",
|
||||
"column_break_25",
|
||||
"frozen_accounts_modifier",
|
||||
"tab_break_dpet",
|
||||
@@ -406,6 +407,13 @@
|
||||
"fieldname": "enable_fuzzy_matching",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Fuzzy Matching"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Financial reports will be generated using GL Entry doctypes (should be enabled if Period Closing Voucher is not posted for all years sequentially or missing) ",
|
||||
"fieldname": "ignore_account_closing_balance",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Account Closing Balance"
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
@@ -413,7 +421,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2023-06-15 16:35:45.123456",
|
||||
"modified": "2023-07-27 15:05:34.000264",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -14,21 +14,32 @@ from erpnext.stock.utils import check_pending_reposting
|
||||
|
||||
|
||||
class AccountsSettings(Document):
|
||||
def on_update(self):
|
||||
frappe.clear_cache()
|
||||
|
||||
def validate(self):
|
||||
frappe.db.set_default(
|
||||
"add_taxes_from_item_tax_template", self.get("add_taxes_from_item_tax_template", 0)
|
||||
)
|
||||
old_doc = self.get_doc_before_save()
|
||||
clear_cache = False
|
||||
|
||||
frappe.db.set_default(
|
||||
"enable_common_party_accounting", self.get("enable_common_party_accounting", 0)
|
||||
)
|
||||
if old_doc.add_taxes_from_item_tax_template != self.add_taxes_from_item_tax_template:
|
||||
frappe.db.set_default(
|
||||
"add_taxes_from_item_tax_template", self.get("add_taxes_from_item_tax_template", 0)
|
||||
)
|
||||
clear_cache = True
|
||||
|
||||
if old_doc.enable_common_party_accounting != self.enable_common_party_accounting:
|
||||
frappe.db.set_default(
|
||||
"enable_common_party_accounting", self.get("enable_common_party_accounting", 0)
|
||||
)
|
||||
clear_cache = True
|
||||
|
||||
self.validate_stale_days()
|
||||
self.enable_payment_schedule_in_print()
|
||||
self.validate_pending_reposts()
|
||||
|
||||
if old_doc.show_payment_schedule_in_print != self.show_payment_schedule_in_print:
|
||||
self.enable_payment_schedule_in_print()
|
||||
|
||||
if old_doc.acc_frozen_upto != self.acc_frozen_upto:
|
||||
self.validate_pending_reposts()
|
||||
|
||||
if clear_cache:
|
||||
frappe.clear_cache()
|
||||
|
||||
def validate_stale_days(self):
|
||||
if not self.allow_stale and cint(self.stale_days) <= 0:
|
||||
|
||||
@@ -903,12 +903,12 @@ frappe.ui.form.on('Payment Entry', {
|
||||
if(frm.doc.payment_type == "Receive"
|
||||
&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
|
||||
&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
|
||||
unallocated_amount = (frm.doc.base_received_amount + total_deductions + frm.doc.base_total_taxes_and_charges
|
||||
unallocated_amount = (frm.doc.base_received_amount + total_deductions + flt(frm.doc.base_total_taxes_and_charges)
|
||||
- frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
|
||||
} else if (frm.doc.payment_type == "Pay"
|
||||
&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions
|
||||
&& frm.doc.total_allocated_amount < frm.doc.received_amount + (total_deductions / frm.doc.target_exchange_rate)) {
|
||||
unallocated_amount = (frm.doc.base_paid_amount + frm.doc.base_total_taxes_and_charges - (total_deductions
|
||||
unallocated_amount = (frm.doc.base_paid_amount + flt(frm.doc.base_total_taxes_and_charges) - (total_deductions
|
||||
+ frm.doc.base_total_allocated_amount)) / frm.doc.target_exchange_rate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +101,6 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
|
||||
cur_frm.add_custom_button(__('Return / Debit Note'),
|
||||
this.make_debit_note, __('Create'));
|
||||
}
|
||||
|
||||
if(!doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
}
|
||||
|
||||
if (doc.outstanding_amount > 0 && !cint(doc.is_return) && !doc.on_hold) {
|
||||
|
||||
@@ -1736,6 +1736,61 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin):
|
||||
rate = flt(sle.stock_value_difference) / flt(sle.actual_qty)
|
||||
self.assertAlmostEqual(returned_inv.items[0].rate, rate)
|
||||
|
||||
def test_offsetting_entries_for_accounting_dimensions(self):
|
||||
from erpnext.accounts.doctype.account.test_account import create_account
|
||||
from erpnext.accounts.report.trial_balance.test_trial_balance import (
|
||||
clear_dimension_defaults,
|
||||
create_accounting_dimension,
|
||||
disable_dimension,
|
||||
)
|
||||
|
||||
create_account(
|
||||
account_name="Offsetting",
|
||||
company="_Test Company",
|
||||
parent_account="Temporary Accounts - _TC",
|
||||
)
|
||||
|
||||
create_accounting_dimension(company="_Test Company", offsetting_account="Offsetting - _TC")
|
||||
|
||||
branch1 = frappe.new_doc("Branch")
|
||||
branch1.branch = "Location 1"
|
||||
branch1.insert(ignore_if_duplicate=True)
|
||||
branch2 = frappe.new_doc("Branch")
|
||||
branch2.branch = "Location 2"
|
||||
branch2.insert(ignore_if_duplicate=True)
|
||||
|
||||
pi = make_purchase_invoice(
|
||||
company="_Test Company",
|
||||
customer="_Test Supplier",
|
||||
do_not_save=True,
|
||||
do_not_submit=True,
|
||||
rate=1000,
|
||||
price_list_rate=1000,
|
||||
qty=1,
|
||||
)
|
||||
pi.branch = branch1.branch
|
||||
pi.items[0].branch = branch2.branch
|
||||
pi.save()
|
||||
pi.submit()
|
||||
|
||||
expected_gle = [
|
||||
["_Test Account Cost for Goods Sold - _TC", 1000, 0.0, nowdate(), branch2.branch],
|
||||
["Creditors - _TC", 0.0, 1000, nowdate(), branch1.branch],
|
||||
["Offsetting - _TC", 1000, 0.0, nowdate(), branch1.branch],
|
||||
["Offsetting - _TC", 0.0, 1000, nowdate(), branch2.branch],
|
||||
]
|
||||
|
||||
check_gl_entries(
|
||||
self,
|
||||
pi.name,
|
||||
expected_gle,
|
||||
nowdate(),
|
||||
voucher_type="Purchase Invoice",
|
||||
additional_columns=["branch"],
|
||||
)
|
||||
clear_dimension_defaults("Branch")
|
||||
disable_dimension()
|
||||
|
||||
|
||||
def set_advance_flag(company, flag, default_account):
|
||||
frappe.db.set_value(
|
||||
@@ -1748,9 +1803,16 @@ def set_advance_flag(company, flag, default_account):
|
||||
)
|
||||
|
||||
|
||||
def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type="Purchase Invoice"):
|
||||
def check_gl_entries(
|
||||
doc,
|
||||
voucher_no,
|
||||
expected_gle,
|
||||
posting_date,
|
||||
voucher_type="Purchase Invoice",
|
||||
additional_columns=None,
|
||||
):
|
||||
gl = frappe.qb.DocType("GL Entry")
|
||||
q = (
|
||||
query = (
|
||||
frappe.qb.from_(gl)
|
||||
.select(gl.account, gl.debit, gl.credit, gl.posting_date)
|
||||
.where(
|
||||
@@ -1761,7 +1823,12 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type="
|
||||
)
|
||||
.orderby(gl.posting_date, gl.account, gl.creation)
|
||||
)
|
||||
gl_entries = q.run(as_dict=True)
|
||||
|
||||
if additional_columns:
|
||||
for col in additional_columns:
|
||||
query = query.select(gl[col])
|
||||
|
||||
gl_entries = query.run(as_dict=True)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
doc.assertEqual(expected_gle[i][0], gle.account)
|
||||
@@ -1769,6 +1836,12 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type="
|
||||
doc.assertEqual(expected_gle[i][2], gle.credit)
|
||||
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||
|
||||
if additional_columns:
|
||||
j = 4
|
||||
for col in additional_columns:
|
||||
doc.assertEqual(expected_gle[i][j], gle[col])
|
||||
j += 1
|
||||
|
||||
|
||||
def create_tax_witholding_category(category_name, company, account):
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
@@ -443,7 +443,8 @@
|
||||
"hidden": 1,
|
||||
"label": "Batch No",
|
||||
"options": "Batch",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "col_br_wh",
|
||||
@@ -890,7 +891,8 @@
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.update_stock == 1",
|
||||
@@ -905,7 +907,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-07-04 17:22:21.501152",
|
||||
"modified": "2023-07-26 12:54:53.178156",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -163,12 +163,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
|
||||
cur_frm.cscript.make_maintenance_schedule();
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
if(!doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
}
|
||||
|
||||
// Show buttons only when pos view is active
|
||||
|
||||
@@ -1833,7 +1833,7 @@ def validate_inter_company_party(doctype, party, company, inter_company_referenc
|
||||
doc = frappe.get_doc(ref_doc, inter_company_reference)
|
||||
ref_party = doc.supplier if doctype in ["Sales Invoice", "Sales Order"] else doc.customer
|
||||
if not frappe.db.get_value(partytype, {"represents_company": doc.company}, "name") == party:
|
||||
frappe.throw(_("Invalid {0} for Inter Company Transaction.").format(partytype))
|
||||
frappe.throw(_("Invalid {0} for Inter Company Transaction.").format(_(partytype)))
|
||||
if not frappe.get_cached_value(ref_partytype, ref_party, "represents_company") == company:
|
||||
frappe.throw(_("Invalid Company for Inter Company Transaction."))
|
||||
|
||||
@@ -1847,7 +1847,7 @@ def validate_inter_company_party(doctype, party, company, inter_company_referenc
|
||||
if not company in companies:
|
||||
frappe.throw(
|
||||
_("{0} not allowed to transact with {1}. Please change the Company.").format(
|
||||
partytype, company
|
||||
_(partytype), company
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -604,7 +604,8 @@
|
||||
"hidden": 1,
|
||||
"label": "Batch No",
|
||||
"options": "Batch",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "col_break5",
|
||||
@@ -894,13 +895,14 @@
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-03-12 13:42:24.303113",
|
||||
"modified": "2023-07-26 12:53:22.404057",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -28,6 +28,7 @@ def make_gl_entries(
|
||||
):
|
||||
if gl_map:
|
||||
if not cancel:
|
||||
make_acc_dimensions_offsetting_entry(gl_map)
|
||||
validate_accounting_period(gl_map)
|
||||
validate_disabled_accounts(gl_map)
|
||||
gl_map = process_gl_map(gl_map, merge_entries)
|
||||
@@ -51,6 +52,63 @@ def make_gl_entries(
|
||||
make_reverse_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
||||
|
||||
|
||||
def make_acc_dimensions_offsetting_entry(gl_map):
|
||||
accounting_dimensions_to_offset = get_accounting_dimensions_for_offsetting_entry(
|
||||
gl_map, gl_map[0].company
|
||||
)
|
||||
no_of_dimensions = len(accounting_dimensions_to_offset)
|
||||
if no_of_dimensions == 0:
|
||||
return
|
||||
|
||||
offsetting_entries = []
|
||||
|
||||
for gle in gl_map:
|
||||
for dimension in accounting_dimensions_to_offset:
|
||||
offsetting_entry = gle.copy()
|
||||
debit = flt(gle.credit) / no_of_dimensions if gle.credit != 0 else 0
|
||||
credit = flt(gle.debit) / no_of_dimensions if gle.debit != 0 else 0
|
||||
offsetting_entry.update(
|
||||
{
|
||||
"account": dimension.offsetting_account,
|
||||
"debit": debit,
|
||||
"credit": credit,
|
||||
"debit_in_account_currency": debit,
|
||||
"credit_in_account_currency": credit,
|
||||
"remarks": _("Offsetting for Accounting Dimension") + " - {0}".format(dimension.name),
|
||||
"against_voucher": None,
|
||||
}
|
||||
)
|
||||
offsetting_entry["against_voucher_type"] = None
|
||||
offsetting_entries.append(offsetting_entry)
|
||||
|
||||
gl_map += offsetting_entries
|
||||
|
||||
|
||||
def get_accounting_dimensions_for_offsetting_entry(gl_map, company):
|
||||
acc_dimension = frappe.qb.DocType("Accounting Dimension")
|
||||
dimension_detail = frappe.qb.DocType("Accounting Dimension Detail")
|
||||
|
||||
acc_dimensions = (
|
||||
frappe.qb.from_(acc_dimension)
|
||||
.inner_join(dimension_detail)
|
||||
.on(acc_dimension.name == dimension_detail.parent)
|
||||
.select(acc_dimension.fieldname, acc_dimension.name, dimension_detail.offsetting_account)
|
||||
.where(
|
||||
(acc_dimension.disabled == 0)
|
||||
& (dimension_detail.company == company)
|
||||
& (dimension_detail.automatically_post_balancing_accounting_entry == 1)
|
||||
)
|
||||
).run(as_dict=True)
|
||||
|
||||
accounting_dimensions_to_offset = []
|
||||
for acc_dimension in acc_dimensions:
|
||||
values = set([entry.get(acc_dimension.fieldname) for entry in gl_map])
|
||||
if len(values) > 1:
|
||||
accounting_dimensions_to_offset.append(acc_dimension)
|
||||
|
||||
return accounting_dimensions_to_offset
|
||||
|
||||
|
||||
def validate_disabled_accounts(gl_map):
|
||||
accounts = [d.account for d in gl_map if d.account]
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ frappe.query_reports["Asset Depreciations and Balances"] = {
|
||||
"fieldname":"from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ frappe.query_reports["Bank Clearance Summary"] = {
|
||||
"fieldname":"from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"width": "80"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ frappe.query_reports["Budget Variance Report"] = {
|
||||
label: __("From Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year,
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Budget Variance Report"] = {
|
||||
label: __("To Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year,
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ import unittest
|
||||
|
||||
import frappe
|
||||
from frappe import qb
|
||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||
from frappe.utils import nowdate
|
||||
|
||||
from erpnext.accounts.doctype.account.test_account import create_account
|
||||
@@ -10,16 +11,15 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
|
||||
from erpnext.accounts.report.deferred_revenue_and_expense.deferred_revenue_and_expense import (
|
||||
Deferred_Revenue_and_Expense_Report,
|
||||
)
|
||||
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
|
||||
|
||||
class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
clear_accounts_and_items()
|
||||
create_company()
|
||||
self.maxDiff = None
|
||||
|
||||
def clear_old_entries(self):
|
||||
@@ -51,55 +51,58 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
if deferred_invoices:
|
||||
qb.from_(pinv).delete().where(pinv.name.isin(deferred_invoices)).run()
|
||||
|
||||
def test_deferred_revenue(self):
|
||||
self.clear_old_entries()
|
||||
def setup_deferred_accounts_and_items(self):
|
||||
# created deferred expense accounts, if not found
|
||||
self.deferred_revenue_account = create_account(
|
||||
account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - " + self.company_abbr,
|
||||
company=self.company,
|
||||
)
|
||||
|
||||
# created deferred expense accounts, if not found
|
||||
deferred_revenue_account = create_account(
|
||||
account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - _CD",
|
||||
company="_Test Company DR",
|
||||
self.deferred_expense_account = create_account(
|
||||
account_name="Deferred Expense",
|
||||
parent_account="Current Assets - " + self.company_abbr,
|
||||
company=self.company,
|
||||
)
|
||||
|
||||
acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
|
||||
acc_settings.book_deferred_entries_based_on = "Months"
|
||||
acc_settings.save()
|
||||
def setUp(self):
|
||||
self.create_company()
|
||||
self.create_customer("_Test Customer")
|
||||
self.create_supplier("_Test Furniture Supplier")
|
||||
self.setup_deferred_accounts_and_items()
|
||||
self.clear_old_entries()
|
||||
|
||||
customer = frappe.new_doc("Customer")
|
||||
customer.customer_name = "_Test Customer DR"
|
||||
customer.type = "Individual"
|
||||
customer.insert()
|
||||
def tearDown(self):
|
||||
frappe.db.rollback()
|
||||
|
||||
item = create_item(
|
||||
"_Test Internet Subscription",
|
||||
is_stock_item=0,
|
||||
warehouse="All Warehouses - _CD",
|
||||
company="_Test Company DR",
|
||||
)
|
||||
@change_settings("Accounts Settings", {"book_deferred_entries_based_on": "Months"})
|
||||
def test_deferred_revenue(self):
|
||||
self.create_item("_Test Internet Subscription", 0, self.warehouse, self.company)
|
||||
item = frappe.get_doc("Item", self.item)
|
||||
item.enable_deferred_revenue = 1
|
||||
item.deferred_revenue_account = deferred_revenue_account
|
||||
item.deferred_revenue_account = self.deferred_revenue_account
|
||||
item.no_of_months = 3
|
||||
item.save()
|
||||
|
||||
si = create_sales_invoice(
|
||||
item=item.name,
|
||||
company="_Test Company DR",
|
||||
customer="_Test Customer DR",
|
||||
debit_to="Debtors - _CD",
|
||||
item=self.item,
|
||||
company=self.company,
|
||||
customer=self.customer,
|
||||
debit_to=self.debit_to,
|
||||
posting_date="2021-05-01",
|
||||
parent_cost_center="Main - _CD",
|
||||
cost_center="Main - _CD",
|
||||
parent_cost_center=self.cost_center,
|
||||
cost_center=self.cost_center,
|
||||
do_not_save=True,
|
||||
rate=300,
|
||||
price_list_rate=300,
|
||||
)
|
||||
|
||||
si.items[0].income_account = "Sales - _CD"
|
||||
si.items[0].income_account = self.income_account
|
||||
si.items[0].enable_deferred_revenue = 1
|
||||
si.items[0].service_start_date = "2021-05-01"
|
||||
si.items[0].service_end_date = "2021-08-01"
|
||||
si.items[0].deferred_revenue_account = deferred_revenue_account
|
||||
si.items[0].income_account = "Sales - _CD"
|
||||
si.items[0].deferred_revenue_account = self.deferred_revenue_account
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
@@ -110,7 +113,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
start_date="2021-05-01",
|
||||
end_date="2021-08-01",
|
||||
type="Income",
|
||||
company="_Test Company DR",
|
||||
company=self.company,
|
||||
)
|
||||
)
|
||||
pda.insert()
|
||||
@@ -120,7 +123,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2021-05-01"))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
"company": self.company,
|
||||
"filter_based_on": "Date Range",
|
||||
"period_start_date": "2021-05-01",
|
||||
"period_end_date": "2021-08-01",
|
||||
@@ -142,57 +145,36 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
]
|
||||
self.assertEqual(report.period_total, expected)
|
||||
|
||||
@change_settings("Accounts Settings", {"book_deferred_entries_based_on": "Months"})
|
||||
def test_deferred_expense(self):
|
||||
self.clear_old_entries()
|
||||
|
||||
# created deferred expense accounts, if not found
|
||||
deferred_expense_account = create_account(
|
||||
account_name="Deferred Expense",
|
||||
parent_account="Current Assets - _CD",
|
||||
company="_Test Company DR",
|
||||
)
|
||||
|
||||
acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
|
||||
acc_settings.book_deferred_entries_based_on = "Months"
|
||||
acc_settings.save()
|
||||
|
||||
supplier = create_supplier(
|
||||
supplier_name="_Test Furniture Supplier", supplier_group="Local", supplier_type="Company"
|
||||
)
|
||||
supplier.save()
|
||||
|
||||
item = create_item(
|
||||
"_Test Office Desk",
|
||||
is_stock_item=0,
|
||||
warehouse="All Warehouses - _CD",
|
||||
company="_Test Company DR",
|
||||
)
|
||||
self.create_item("_Test Office Desk", 0, self.warehouse, self.company)
|
||||
item = frappe.get_doc("Item", self.item)
|
||||
item.enable_deferred_expense = 1
|
||||
item.deferred_expense_account = deferred_expense_account
|
||||
item.deferred_expense_account = self.deferred_expense_account
|
||||
item.no_of_months_exp = 3
|
||||
item.save()
|
||||
|
||||
pi = make_purchase_invoice(
|
||||
item=item.name,
|
||||
company="_Test Company DR",
|
||||
supplier="_Test Furniture Supplier",
|
||||
item=self.item,
|
||||
company=self.company,
|
||||
supplier=self.supplier,
|
||||
is_return=False,
|
||||
update_stock=False,
|
||||
posting_date=frappe.utils.datetime.date(2021, 5, 1),
|
||||
parent_cost_center="Main - _CD",
|
||||
cost_center="Main - _CD",
|
||||
parent_cost_center=self.cost_center,
|
||||
cost_center=self.cost_center,
|
||||
do_not_save=True,
|
||||
rate=300,
|
||||
price_list_rate=300,
|
||||
warehouse="All Warehouses - _CD",
|
||||
warehouse=self.warehouse,
|
||||
qty=1,
|
||||
)
|
||||
pi.set_posting_time = True
|
||||
pi.items[0].enable_deferred_expense = 1
|
||||
pi.items[0].service_start_date = "2021-05-01"
|
||||
pi.items[0].service_end_date = "2021-08-01"
|
||||
pi.items[0].deferred_expense_account = deferred_expense_account
|
||||
pi.items[0].expense_account = "Office Maintenance Expenses - _CD"
|
||||
pi.items[0].deferred_expense_account = self.deferred_expense_account
|
||||
pi.items[0].expense_account = self.expense_account
|
||||
pi.save()
|
||||
pi.submit()
|
||||
|
||||
@@ -203,7 +185,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
start_date="2021-05-01",
|
||||
end_date="2021-08-01",
|
||||
type="Expense",
|
||||
company="_Test Company DR",
|
||||
company=self.company,
|
||||
)
|
||||
)
|
||||
pda.insert()
|
||||
@@ -213,7 +195,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2021-05-01"))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
"company": self.company,
|
||||
"filter_based_on": "Date Range",
|
||||
"period_start_date": "2021-05-01",
|
||||
"period_end_date": "2021-08-01",
|
||||
@@ -235,52 +217,31 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
]
|
||||
self.assertEqual(report.period_total, expected)
|
||||
|
||||
@change_settings("Accounts Settings", {"book_deferred_entries_based_on": "Months"})
|
||||
def test_zero_months(self):
|
||||
self.clear_old_entries()
|
||||
# created deferred expense accounts, if not found
|
||||
deferred_revenue_account = create_account(
|
||||
account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - _CD",
|
||||
company="_Test Company DR",
|
||||
)
|
||||
|
||||
acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
|
||||
acc_settings.book_deferred_entries_based_on = "Months"
|
||||
acc_settings.save()
|
||||
|
||||
customer = frappe.new_doc("Customer")
|
||||
customer.customer_name = "_Test Customer DR"
|
||||
customer.type = "Individual"
|
||||
customer.insert()
|
||||
|
||||
item = create_item(
|
||||
"_Test Internet Subscription",
|
||||
is_stock_item=0,
|
||||
warehouse="All Warehouses - _CD",
|
||||
company="_Test Company DR",
|
||||
)
|
||||
self.create_item("_Test Internet Subscription", 0, self.warehouse, self.company)
|
||||
item = frappe.get_doc("Item", self.item)
|
||||
item.enable_deferred_revenue = 1
|
||||
item.deferred_revenue_account = deferred_revenue_account
|
||||
item.deferred_revenue_account = self.deferred_revenue_account
|
||||
item.no_of_months = 0
|
||||
item.save()
|
||||
|
||||
si = create_sales_invoice(
|
||||
item=item.name,
|
||||
company="_Test Company DR",
|
||||
customer="_Test Customer DR",
|
||||
debit_to="Debtors - _CD",
|
||||
company=self.company,
|
||||
customer=self.customer,
|
||||
debit_to=self.debit_to,
|
||||
posting_date="2021-05-01",
|
||||
parent_cost_center="Main - _CD",
|
||||
cost_center="Main - _CD",
|
||||
parent_cost_center=self.cost_center,
|
||||
cost_center=self.cost_center,
|
||||
do_not_save=True,
|
||||
rate=300,
|
||||
price_list_rate=300,
|
||||
)
|
||||
|
||||
si.items[0].enable_deferred_revenue = 1
|
||||
si.items[0].income_account = "Sales - _CD"
|
||||
si.items[0].deferred_revenue_account = deferred_revenue_account
|
||||
si.items[0].income_account = "Sales - _CD"
|
||||
si.items[0].income_account = self.income_account
|
||||
si.items[0].deferred_revenue_account = self.deferred_revenue_account
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
@@ -291,7 +252,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
start_date="2021-05-01",
|
||||
end_date="2021-08-01",
|
||||
type="Income",
|
||||
company="_Test Company DR",
|
||||
company=self.company,
|
||||
)
|
||||
)
|
||||
pda.insert()
|
||||
@@ -301,7 +262,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2021-05-01"))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
"company": self.company,
|
||||
"filter_based_on": "Date Range",
|
||||
"period_start_date": "2021-05-01",
|
||||
"period_end_date": "2021-08-01",
|
||||
@@ -322,30 +283,3 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
{"key": "aug_2021", "total": 0, "actual": 0},
|
||||
]
|
||||
self.assertEqual(report.period_total, expected)
|
||||
|
||||
|
||||
def create_company():
|
||||
company = frappe.db.exists("Company", "_Test Company DR")
|
||||
if not company:
|
||||
company = frappe.new_doc("Company")
|
||||
company.company_name = "_Test Company DR"
|
||||
company.default_currency = "INR"
|
||||
company.chart_of_accounts = "Standard"
|
||||
company.insert()
|
||||
|
||||
|
||||
def clear_accounts_and_items():
|
||||
item = qb.DocType("Item")
|
||||
account = qb.DocType("Account")
|
||||
customer = qb.DocType("Customer")
|
||||
supplier = qb.DocType("Supplier")
|
||||
|
||||
qb.from_(account).delete().where(
|
||||
(account.account_name == "Deferred Revenue")
|
||||
| (account.account_name == "Deferred Expense") & (account.company == "_Test Company DR")
|
||||
).run()
|
||||
qb.from_(item).delete().where(
|
||||
(item.item_code == "_Test Internet Subscription") | (item.item_code == "_Test Office Rent")
|
||||
).run()
|
||||
qb.from_(customer).delete().where(customer.customer_name == "_Test Customer DR").run()
|
||||
qb.from_(supplier).delete().where(supplier.supplier_name == "_Test Furniture Supplier").run()
|
||||
|
||||
@@ -38,14 +38,14 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -429,11 +429,17 @@ def set_gl_entries_by_account(
|
||||
|
||||
if accounts_list:
|
||||
# For balance sheet
|
||||
if not from_date:
|
||||
from_date = filters["period_start_date"]
|
||||
ignore_closing_balances = frappe.db.get_single_value(
|
||||
"Accounts Settings", "ignore_account_closing_balance"
|
||||
)
|
||||
if not from_date and not ignore_closing_balances:
|
||||
last_period_closing_voucher = frappe.db.get_all(
|
||||
"Period Closing Voucher",
|
||||
filters={"docstatus": 1, "company": filters.company, "posting_date": ("<", from_date)},
|
||||
filters={
|
||||
"docstatus": 1,
|
||||
"company": filters.company,
|
||||
"posting_date": ("<", filters["period_start_date"]),
|
||||
},
|
||||
fields=["posting_date", "name"],
|
||||
order_by="posting_date desc",
|
||||
limit=1,
|
||||
|
||||
@@ -15,14 +15,14 @@ frappe.query_reports["Gross Profit"] = {
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
|
||||
@@ -50,20 +50,20 @@ def get_pos_entries(filters, group_by_field):
|
||||
order_by = "p.posting_date"
|
||||
select_mop_field, from_sales_invoice_payment, group_by_mop_condition = "", "", ""
|
||||
if group_by_field == "mode_of_payment":
|
||||
select_mop_field = ", sip.mode_of_payment"
|
||||
select_mop_field = ", sip.mode_of_payment, sip.base_amount - IF(sip.type='Cash', p.change_amount, 0) as paid_amount"
|
||||
from_sales_invoice_payment = ", `tabSales Invoice Payment` sip"
|
||||
group_by_mop_condition = "sip.parent = p.name AND ifnull(sip.base_amount, 0) != 0 AND"
|
||||
group_by_mop_condition = "sip.parent = p.name AND ifnull(sip.base_amount - IF(sip.type='Cash', p.change_amount, 0), 0) != 0 AND"
|
||||
order_by += ", sip.mode_of_payment"
|
||||
|
||||
elif group_by_field:
|
||||
order_by += ", p.{}".format(group_by_field)
|
||||
select_mop_field = ", p.base_paid_amount - p.change_amount as paid_amount "
|
||||
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
p.posting_date, p.name as pos_invoice, p.pos_profile,
|
||||
p.owner, p.base_grand_total as grand_total, p.base_paid_amount - p.change_amount as paid_amount,
|
||||
p.customer, p.is_return {select_mop_field}
|
||||
p.owner, p.customer, p.is_return, p.base_grand_total as grand_total {select_mop_field}
|
||||
FROM
|
||||
`tabPOS Invoice` p {from_sales_invoice_payment}
|
||||
WHERE
|
||||
|
||||
@@ -66,13 +66,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
},
|
||||
{
|
||||
"fieldname": "show_zero_values",
|
||||
|
||||
118
erpnext/accounts/report/trial_balance/test_trial_balance.py
Normal file
118
erpnext/accounts/report/trial_balance/test_trial_balance.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.utils import today
|
||||
|
||||
from erpnext.accounts.report.trial_balance.trial_balance import execute
|
||||
|
||||
|
||||
class TestTrialBalance(FrappeTestCase):
|
||||
def setUp(self):
|
||||
from erpnext.accounts.doctype.account.test_account import create_account
|
||||
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
self.company = create_company()
|
||||
create_cost_center(
|
||||
cost_center_name="Test Cost Center",
|
||||
company="Trial Balance Company",
|
||||
parent_cost_center="Trial Balance Company - TBC",
|
||||
)
|
||||
create_account(
|
||||
account_name="Offsetting",
|
||||
company="Trial Balance Company",
|
||||
parent_account="Temporary Accounts - TBC",
|
||||
)
|
||||
self.fiscal_year = get_fiscal_year(today(), company="Trial Balance Company")[0]
|
||||
create_accounting_dimension()
|
||||
|
||||
def test_offsetting_entries_for_accounting_dimensions(self):
|
||||
"""
|
||||
Checks if Trial Balance Report is balanced when filtered using a particular Accounting Dimension
|
||||
"""
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
|
||||
frappe.db.sql("delete from `tabSales Invoice` where company='Trial Balance Company'")
|
||||
frappe.db.sql("delete from `tabGL Entry` where company='Trial Balance Company'")
|
||||
|
||||
branch1 = frappe.new_doc("Branch")
|
||||
branch1.branch = "Location 1"
|
||||
branch1.insert(ignore_if_duplicate=True)
|
||||
branch2 = frappe.new_doc("Branch")
|
||||
branch2.branch = "Location 2"
|
||||
branch2.insert(ignore_if_duplicate=True)
|
||||
|
||||
si = create_sales_invoice(
|
||||
company=self.company,
|
||||
debit_to="Debtors - TBC",
|
||||
cost_center="Test Cost Center - TBC",
|
||||
income_account="Sales - TBC",
|
||||
do_not_submit=1,
|
||||
)
|
||||
si.branch = "Location 1"
|
||||
si.items[0].branch = "Location 2"
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
filters = frappe._dict(
|
||||
{"company": self.company, "fiscal_year": self.fiscal_year, "branch": ["Location 1"]}
|
||||
)
|
||||
total_row = execute(filters)[1][-1]
|
||||
self.assertEqual(total_row["debit"], total_row["credit"])
|
||||
|
||||
def tearDown(self):
|
||||
clear_dimension_defaults("Branch")
|
||||
disable_dimension()
|
||||
|
||||
|
||||
def create_company(**args):
|
||||
args = frappe._dict(args)
|
||||
company = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Company",
|
||||
"company_name": args.company_name or "Trial Balance Company",
|
||||
"country": args.country or "India",
|
||||
"default_currency": args.currency or "INR",
|
||||
}
|
||||
)
|
||||
company.insert(ignore_if_duplicate=True)
|
||||
return company.name
|
||||
|
||||
|
||||
def create_accounting_dimension(**args):
|
||||
args = frappe._dict(args)
|
||||
document_type = args.document_type or "Branch"
|
||||
if frappe.db.exists("Accounting Dimension", document_type):
|
||||
accounting_dimension = frappe.get_doc("Accounting Dimension", document_type)
|
||||
accounting_dimension.disabled = 0
|
||||
else:
|
||||
accounting_dimension = frappe.new_doc("Accounting Dimension")
|
||||
accounting_dimension.document_type = document_type
|
||||
accounting_dimension.insert()
|
||||
|
||||
accounting_dimension.set("dimension_defaults", [])
|
||||
accounting_dimension.append(
|
||||
"dimension_defaults",
|
||||
{
|
||||
"company": args.company or "Trial Balance Company",
|
||||
"automatically_post_balancing_accounting_entry": 1,
|
||||
"offsetting_account": args.offsetting_account or "Offsetting - TBC",
|
||||
},
|
||||
)
|
||||
accounting_dimension.save()
|
||||
|
||||
|
||||
def disable_dimension(**args):
|
||||
args = frappe._dict(args)
|
||||
document_type = args.document_type or "Branch"
|
||||
dimension = frappe.get_doc("Accounting Dimension", document_type)
|
||||
dimension.disabled = 1
|
||||
dimension.save()
|
||||
|
||||
|
||||
def clear_dimension_defaults(dimension_name):
|
||||
accounting_dimension = frappe.get_doc("Accounting Dimension", dimension_name)
|
||||
accounting_dimension.dimension_defaults = []
|
||||
accounting_dimension.save()
|
||||
@@ -37,13 +37,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
|
||||
@@ -142,14 +142,20 @@ def get_opening_balances(filters):
|
||||
def get_rootwise_opening_balances(filters, report_type):
|
||||
gle = []
|
||||
|
||||
last_period_closing_voucher = frappe.db.get_all(
|
||||
"Period Closing Voucher",
|
||||
filters={"docstatus": 1, "company": filters.company, "posting_date": ("<", filters.from_date)},
|
||||
fields=["posting_date", "name"],
|
||||
order_by="posting_date desc",
|
||||
limit=1,
|
||||
last_period_closing_voucher = ""
|
||||
ignore_closing_balances = frappe.db.get_single_value(
|
||||
"Accounts Settings", "ignore_account_closing_balance"
|
||||
)
|
||||
|
||||
if not ignore_closing_balances:
|
||||
last_period_closing_voucher = frappe.db.get_all(
|
||||
"Period Closing Voucher",
|
||||
filters={"docstatus": 1, "company": filters.company, "posting_date": ("<", filters.from_date)},
|
||||
fields=["posting_date", "name"],
|
||||
order_by="posting_date desc",
|
||||
limit=1,
|
||||
)
|
||||
|
||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||
|
||||
if last_period_closing_voucher:
|
||||
@@ -253,7 +259,7 @@ def get_opening_balance(
|
||||
lft, rgt = frappe.db.get_value("Cost Center", filters.cost_center, ["lft", "rgt"])
|
||||
cost_center = frappe.qb.DocType("Cost Center")
|
||||
opening_balance = opening_balance.where(
|
||||
closing_balance.cost_center.in_(
|
||||
closing_balance.cost_center.isin(
|
||||
frappe.qb.from_(cost_center)
|
||||
.select("name")
|
||||
.where((cost_center.lft >= lft) & (cost_center.rgt <= rgt))
|
||||
|
||||
@@ -36,13 +36,13 @@ frappe.query_reports["Trial Balance for Party"] = {
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
},
|
||||
{
|
||||
"fieldname":"party_type",
|
||||
|
||||
@@ -46,6 +46,7 @@ def get_data(filters):
|
||||
.select(
|
||||
gle.voucher_type, gle.voucher_no, Sum(gle.debit).as_("debit"), Sum(gle.credit).as_("credit")
|
||||
)
|
||||
.where(gle.is_cancelled == 0)
|
||||
.groupby(gle.voucher_no)
|
||||
)
|
||||
query = apply_filters(query, filters, gle)
|
||||
|
||||
80
erpnext/accounts/test/accounts_mixin.py
Normal file
80
erpnext/accounts/test/accounts_mixin.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import frappe
|
||||
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
|
||||
|
||||
class AccountsTestMixin:
|
||||
def create_customer(self, customer_name, currency=None):
|
||||
if not frappe.db.exists("Customer", customer_name):
|
||||
customer = frappe.new_doc("Customer")
|
||||
customer.customer_name = customer_name
|
||||
customer.type = "Individual"
|
||||
|
||||
if currency:
|
||||
customer.default_currency = currency
|
||||
customer.save()
|
||||
self.customer = customer.name
|
||||
else:
|
||||
self.customer = customer_name
|
||||
|
||||
def create_supplier(self, supplier_name, currency=None):
|
||||
if not frappe.db.exists("Supplier", supplier_name):
|
||||
supplier = frappe.new_doc("Supplier")
|
||||
supplier.supplier_name = supplier_name
|
||||
supplier.supplier_type = "Individual"
|
||||
supplier.supplier_group = "Local"
|
||||
|
||||
if currency:
|
||||
supplier.default_currency = currency
|
||||
supplier.save()
|
||||
self.supplier = supplier.name
|
||||
else:
|
||||
self.supplier = supplier_name
|
||||
|
||||
def create_item(self, item_name, is_stock=0, warehouse=None, company=None):
|
||||
item = create_item(item_name, is_stock_item=is_stock, warehouse=warehouse, company=company)
|
||||
self.item = item.name
|
||||
|
||||
def create_company(self, company_name="_Test Company", abbr="_TC"):
|
||||
self.company_abbr = abbr
|
||||
if frappe.db.exists("Company", company_name):
|
||||
company = frappe.get_doc("Company", company_name)
|
||||
else:
|
||||
company = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Company",
|
||||
"company_name": company_name,
|
||||
"country": "India",
|
||||
"default_currency": "INR",
|
||||
"create_chart_of_accounts_based_on": "Standard Template",
|
||||
"chart_of_accounts": "Standard",
|
||||
}
|
||||
)
|
||||
company = company.save()
|
||||
|
||||
self.company = company.name
|
||||
self.cost_center = company.cost_center
|
||||
self.warehouse = "Stores - " + abbr
|
||||
self.finished_warehouse = "Finished Goods - " + abbr
|
||||
self.income_account = "Sales - " + abbr
|
||||
self.expense_account = "Cost of Goods Sold - " + abbr
|
||||
self.debit_to = "Debtors - " + abbr
|
||||
self.debit_usd = "Debtors USD - " + abbr
|
||||
self.cash = "Cash - " + abbr
|
||||
self.creditors = "Creditors - " + abbr
|
||||
|
||||
# create bank account
|
||||
bank_account = "HDFC - " + abbr
|
||||
if frappe.db.exists("Account", bank_account):
|
||||
self.bank = bank_account
|
||||
else:
|
||||
bank_acc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Account",
|
||||
"account_name": "HDFC",
|
||||
"parent_account": "Bank Accounts - " + abbr,
|
||||
"company": self.company,
|
||||
}
|
||||
)
|
||||
bank_acc.save()
|
||||
self.bank = bank_acc.name
|
||||
@@ -576,7 +576,11 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
|
||||
# new row with references
|
||||
new_row = journal_entry.append("accounts")
|
||||
|
||||
new_row.update((frappe.copy_doc(jv_detail)).as_dict())
|
||||
# Copy field values into new row
|
||||
[
|
||||
new_row.set(field, jv_detail.get(field))
|
||||
for field in frappe.get_meta("Journal Entry Account").get_fieldnames_with_value()
|
||||
]
|
||||
|
||||
new_row.set(d["dr_or_cr"], d["allocated_amount"])
|
||||
new_row.set(
|
||||
|
||||
@@ -65,7 +65,7 @@ frappe.ui.form.on("Purchase Order", {
|
||||
get_materials_from_supplier: function(frm) {
|
||||
let po_details = [];
|
||||
|
||||
if (frm.doc.supplied_items && (frm.doc.per_received == 100 || frm.doc.status === 'Closed')) {
|
||||
if (frm.doc.supplied_items && (flt(frm.doc.per_received, 2) == 100 || frm.doc.status === 'Closed')) {
|
||||
frm.doc.supplied_items.forEach(d => {
|
||||
if (d.total_supplied_qty && d.total_supplied_qty != d.consumed_qty) {
|
||||
po_details.push(d.name)
|
||||
@@ -184,7 +184,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
||||
}
|
||||
|
||||
if(!in_list(["Closed", "Delivered"], doc.status)) {
|
||||
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) {
|
||||
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received, 2) < 100 && flt(this.frm.doc.per_billed, 2) < 100) {
|
||||
// Don't add Update Items button if the PO is following the new subcontracting flow.
|
||||
if (!(this.frm.doc.is_subcontracted && !this.frm.doc.is_old_subcontracting_flow)) {
|
||||
this.frm.add_custom_button(__('Update Items'), () => {
|
||||
@@ -198,7 +198,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
||||
}
|
||||
}
|
||||
if (this.frm.has_perm("submit")) {
|
||||
if(flt(doc.per_billed, 6) < 100 || flt(doc.per_received, 6) < 100) {
|
||||
if(flt(doc.per_billed, 2) < 100 || flt(doc.per_received, 2) < 100) {
|
||||
if (doc.status != "On Hold") {
|
||||
this.frm.add_custom_button(__('Hold'), () => this.hold_purchase_order(), __("Status"));
|
||||
} else{
|
||||
@@ -221,7 +221,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
||||
}
|
||||
if(doc.status != "Closed") {
|
||||
if (doc.status != "On Hold") {
|
||||
if(flt(doc.per_received) < 100 && allow_receipt) {
|
||||
if(flt(doc.per_received, 2) < 100 && allow_receipt) {
|
||||
cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
|
||||
if (doc.is_subcontracted) {
|
||||
if (doc.is_old_subcontracting_flow) {
|
||||
@@ -234,11 +234,11 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
||||
}
|
||||
}
|
||||
}
|
||||
if(flt(doc.per_billed) < 100)
|
||||
if(flt(doc.per_billed, 2) < 100)
|
||||
cur_frm.add_custom_button(__('Purchase Invoice'),
|
||||
this.make_purchase_invoice, __('Create'));
|
||||
|
||||
if(flt(doc.per_billed) < 100 && doc.status != "Delivered") {
|
||||
if(flt(doc.per_billed, 2) < 100 && doc.status != "Delivered") {
|
||||
this.frm.add_custom_button(
|
||||
__('Payment'),
|
||||
() => this.make_payment_entry(),
|
||||
@@ -246,17 +246,11 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
||||
);
|
||||
}
|
||||
|
||||
if(flt(doc.per_billed) < 100) {
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
this.frm.add_custom_button(__('Payment Request'),
|
||||
function() { me.make_payment_request() }, __('Create'));
|
||||
}
|
||||
|
||||
if(!doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
|
||||
if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
|
||||
let me = this;
|
||||
let internal = me.frm.doc.is_internal_supplier;
|
||||
|
||||
@@ -27,13 +27,13 @@ frappe.query_reports["Procurement Tracker"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ frappe.query_reports["Purchase Analytics"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -206,9 +206,11 @@ def post_process(doctype, data):
|
||||
)
|
||||
|
||||
if doc.get("per_delivered"):
|
||||
doc.status_percent += flt(doc.per_delivered)
|
||||
doc.status_percent += flt(doc.per_delivered, 2)
|
||||
doc.status_display.append(
|
||||
_("Delivered") if doc.per_delivered == 100 else _("{0}% Delivered").format(doc.per_delivered)
|
||||
_("Delivered")
|
||||
if flt(doc.per_delivered, 2) == 100
|
||||
else _("{0}% Delivered").format(doc.per_delivered)
|
||||
)
|
||||
|
||||
if hasattr(doc, "set_indicator"):
|
||||
|
||||
@@ -6,13 +6,13 @@ frappe.query_reports["Campaign Efficiency"] = {
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
}
|
||||
]};
|
||||
|
||||
@@ -410,11 +410,11 @@ scheduler_events = {
|
||||
],
|
||||
},
|
||||
"all": [
|
||||
"erpnext.projects.doctype.project.project.project_status_update_reminder",
|
||||
"erpnext.crm.doctype.social_media_post.social_media_post.process_scheduled_social_media_posts",
|
||||
],
|
||||
"hourly": [
|
||||
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization",
|
||||
"erpnext.projects.doctype.project.project.project_status_update_reminder",
|
||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||
"erpnext.projects.doctype.project.project.collect_project_status",
|
||||
],
|
||||
|
||||
@@ -93,6 +93,7 @@ class BOMUpdateLog(Document):
|
||||
else:
|
||||
frappe.enqueue(
|
||||
method="erpnext.manufacturing.doctype.bom_update_log.bom_update_log.process_boms_cost_level_wise",
|
||||
queue="long",
|
||||
update_doc=self,
|
||||
now=frappe.flags.in_test,
|
||||
enqueue_after_commit=True,
|
||||
|
||||
@@ -157,12 +157,19 @@ def get_next_higher_level_boms(
|
||||
def get_leaf_boms() -> List[str]:
|
||||
"Get BOMs that have no dependencies."
|
||||
|
||||
return frappe.db.sql_list(
|
||||
"""select name from `tabBOM` bom
|
||||
where docstatus=1 and is_active=1
|
||||
and not exists(select bom_no from `tabBOM Item`
|
||||
where parent=bom.name and bom_no !='')"""
|
||||
)
|
||||
bom = frappe.qb.DocType("BOM")
|
||||
bom_item = frappe.qb.DocType("BOM Item")
|
||||
|
||||
boms = (
|
||||
frappe.qb.from_(bom)
|
||||
.left_join(bom_item)
|
||||
.on((bom.name == bom_item.parent) & (bom_item.bom_no != ""))
|
||||
.select(bom.name)
|
||||
.where((bom.docstatus == 1) & (bom.is_active == 1) & (bom_item.bom_no.isnull()))
|
||||
.distinct()
|
||||
).run(pluck=True)
|
||||
|
||||
return boms
|
||||
|
||||
|
||||
def _generate_dependence_map() -> defaultdict:
|
||||
|
||||
@@ -544,12 +544,12 @@ class JobCard(Document):
|
||||
if self.for_quantity and flt(total_completed_qty, precision) != flt(
|
||||
self.for_quantity, precision
|
||||
):
|
||||
total_completed_qty = bold(_("Total Completed Qty"))
|
||||
total_completed_qty_label = bold(_("Total Completed Qty"))
|
||||
qty_to_manufacture = bold(_("Qty to Manufacture"))
|
||||
|
||||
frappe.throw(
|
||||
_("The {0} ({1}) must be equal to {2} ({3})").format(
|
||||
total_completed_qty,
|
||||
total_completed_qty_label,
|
||||
bold(flt(total_completed_qty, precision)),
|
||||
qty_to_manufacture,
|
||||
bold(self.for_quantity),
|
||||
|
||||
@@ -9,19 +9,25 @@ frappe.ui.form.on('Production Plan', {
|
||||
item.temporary_name = item.name;
|
||||
});
|
||||
},
|
||||
|
||||
setup(frm) {
|
||||
frm.trigger("setup_queries");
|
||||
|
||||
frm.custom_make_buttons = {
|
||||
'Work Order': 'Work Order / Subcontract PO',
|
||||
'Material Request': 'Material Request',
|
||||
};
|
||||
},
|
||||
|
||||
frm.fields_dict['po_items'].grid.get_field('warehouse').get_query = function(doc) {
|
||||
setup_queries(frm) {
|
||||
frm.set_query("sales_order", "sales_orders", () => {
|
||||
return {
|
||||
query: "erpnext.manufacturing.doctype.production_plan.production_plan.sales_order_query",
|
||||
filters: {
|
||||
company: doc.company
|
||||
company: frm.doc.company,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query('for_warehouse', function(doc) {
|
||||
return {
|
||||
@@ -42,32 +48,40 @@ frappe.ui.form.on('Production Plan', {
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict['po_items'].grid.get_field('item_code').get_query = function(doc) {
|
||||
frm.set_query("item_code", "po_items", (doc, cdt, cdn) => {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{
|
||||
'is_stock_item': 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.fields_dict['po_items'].grid.get_field('bom_no').get_query = function(doc, cdt, cdn) {
|
||||
frm.set_query("bom_no", "po_items", (doc, cdt, cdn) => {
|
||||
var d = locals[cdt][cdn];
|
||||
if (d.item_code) {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.bom",
|
||||
filters:{'item': cstr(d.item_code), 'docstatus': 1}
|
||||
filters:{'item': d.item_code, 'docstatus': 1}
|
||||
}
|
||||
} else frappe.msgprint(__("Please enter Item first"));
|
||||
}
|
||||
});
|
||||
|
||||
frm.fields_dict['mr_items'].grid.get_field('warehouse').get_query = function(doc) {
|
||||
frm.set_query("warehouse", "mr_items", (doc) => {
|
||||
return {
|
||||
filters: {
|
||||
company: doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query("warehouse", "po_items", (doc) => {
|
||||
return {
|
||||
filters: {
|
||||
company: doc.company
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refresh(frm) {
|
||||
@@ -436,7 +450,7 @@ frappe.ui.form.on("Production Plan Item", {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Material Request Plan Item", {
|
||||
@@ -467,31 +481,36 @@ frappe.ui.form.on("Material Request Plan Item", {
|
||||
|
||||
frappe.ui.form.on("Production Plan Sales Order", {
|
||||
sales_order(frm, cdt, cdn) {
|
||||
const { sales_order } = locals[cdt][cdn];
|
||||
let row = locals[cdt][cdn];
|
||||
const sales_order = row.sales_order;
|
||||
if (!sales_order) {
|
||||
return;
|
||||
}
|
||||
frappe.call({
|
||||
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_so_details",
|
||||
args: { sales_order },
|
||||
callback(r) {
|
||||
const {transaction_date, customer, grand_total} = r.message;
|
||||
frappe.model.set_value(cdt, cdn, 'sales_order_date', transaction_date);
|
||||
frappe.model.set_value(cdt, cdn, 'customer', customer);
|
||||
frappe.model.set_value(cdt, cdn, 'grand_total', grand_total);
|
||||
}
|
||||
});
|
||||
|
||||
if (row.sales_order) {
|
||||
frm.call({
|
||||
method: "validate_sales_orders",
|
||||
doc: frm.doc,
|
||||
args: {
|
||||
sales_order: row.sales_order,
|
||||
},
|
||||
callback(r) {
|
||||
frappe.call({
|
||||
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_so_details",
|
||||
args: { sales_order },
|
||||
callback(r) {
|
||||
const {transaction_date, customer, grand_total} = r.message;
|
||||
frappe.model.set_value(cdt, cdn, 'sales_order_date', transaction_date);
|
||||
frappe.model.set_value(cdt, cdn, 'customer', customer);
|
||||
frappe.model.set_value(cdt, cdn, 'grand_total', grand_total);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cur_frm.fields_dict['sales_orders'].grid.get_field("sales_order").get_query = function() {
|
||||
return{
|
||||
filters: [
|
||||
['Sales Order','docstatus', '=' ,1]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
frappe.tour['Production Plan'] = [
|
||||
{
|
||||
fieldname: "get_items_from",
|
||||
|
||||
@@ -228,10 +228,10 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "To know more about projected quantity, <a href=\"https://erpnext.com/docs/user/manual/en/stock/projected-quantity\" style=\"text-decoration: underline;\" target=\"_blank\">click here</a>.",
|
||||
"description": "If enabled, the system won't create material requests for the available items.",
|
||||
"fieldname": "ignore_existing_ordered_qty",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Existing Projected Quantity"
|
||||
"label": "Ignore Available Stock"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_25",
|
||||
@@ -339,7 +339,7 @@
|
||||
"depends_on": "eval:doc.get_items_from == 'Sales Order'",
|
||||
"fieldname": "combine_items",
|
||||
"fieldtype": "Check",
|
||||
"label": "Consolidate Items"
|
||||
"label": "Consolidate Sales Order Items"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_25",
|
||||
@@ -399,7 +399,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "System consider the projected quantity to check available or will be available sub-assembly items ",
|
||||
"description": "If this checkbox is enabled, then the system won\u2019t run the MRP for the available sub-assembly items.",
|
||||
"fieldname": "skip_available_sub_assembly_item",
|
||||
"fieldtype": "Check",
|
||||
"label": "Skip Available Sub Assembly Items"
|
||||
@@ -422,7 +422,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-05-22 23:36:31.770517",
|
||||
"modified": "2023-07-28 13:37:43.926686",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan",
|
||||
|
||||
@@ -39,6 +39,36 @@ class ProductionPlan(Document):
|
||||
self.set_status()
|
||||
self._rename_temporary_references()
|
||||
validate_uom_is_integer(self, "stock_uom", "planned_qty")
|
||||
self.validate_sales_orders()
|
||||
|
||||
@frappe.whitelist()
|
||||
def validate_sales_orders(self, sales_order=None):
|
||||
sales_orders = []
|
||||
|
||||
if sales_order:
|
||||
sales_orders.append(sales_order)
|
||||
else:
|
||||
sales_orders = [row.sales_order for row in self.sales_orders if row.sales_order]
|
||||
|
||||
data = sales_order_query(filters={"company": self.company, "sales_orders": sales_orders})
|
||||
|
||||
title = _("Production Plan Already Submitted")
|
||||
if not data:
|
||||
msg = _("No items are available in the sales order {0} for production").format(sales_orders[0])
|
||||
if len(sales_orders) > 1:
|
||||
sales_orders = ", ".join(sales_orders)
|
||||
msg = _("No items are available in sales orders {0} for production").format(sales_orders)
|
||||
|
||||
frappe.throw(msg, title=title)
|
||||
|
||||
data = [d[0] for d in data]
|
||||
|
||||
for sales_order in sales_orders:
|
||||
if sales_order not in data:
|
||||
frappe.throw(
|
||||
_("No items are available in the sales order {0} for production").format(sales_order),
|
||||
title=title,
|
||||
)
|
||||
|
||||
def set_pending_qty_in_row_without_reference(self):
|
||||
"Set Pending Qty in independent rows (not from SO or MR)."
|
||||
@@ -205,6 +235,7 @@ class ProductionPlan(Document):
|
||||
).as_("pending_qty"),
|
||||
so_item.description,
|
||||
so_item.name,
|
||||
so_item.bom_no,
|
||||
)
|
||||
.distinct()
|
||||
.where(
|
||||
@@ -342,7 +373,7 @@ class ProductionPlan(Document):
|
||||
"item_code": data.item_code,
|
||||
"description": data.description or item_details.description,
|
||||
"stock_uom": item_details and item_details.stock_uom or "",
|
||||
"bom_no": item_details and item_details.bom_no or "",
|
||||
"bom_no": data.bom_no or item_details and item_details.bom_no or "",
|
||||
"planned_qty": data.pending_qty,
|
||||
"pending_qty": data.pending_qty,
|
||||
"planned_start_date": now_datetime(),
|
||||
@@ -401,11 +432,50 @@ class ProductionPlan(Document):
|
||||
|
||||
def on_submit(self):
|
||||
self.update_bin_qty()
|
||||
self.update_sales_order()
|
||||
|
||||
def on_cancel(self):
|
||||
self.db_set("status", "Cancelled")
|
||||
self.delete_draft_work_order()
|
||||
self.update_bin_qty()
|
||||
self.update_sales_order()
|
||||
|
||||
def update_sales_order(self):
|
||||
sales_orders = [row.sales_order for row in self.po_items if row.sales_order]
|
||||
if sales_orders:
|
||||
so_wise_planned_qty = self.get_so_wise_planned_qty(sales_orders)
|
||||
|
||||
for row in self.po_items:
|
||||
if not row.sales_order and not row.sales_order_item:
|
||||
continue
|
||||
|
||||
key = (row.sales_order, row.sales_order_item)
|
||||
frappe.db.set_value(
|
||||
"Sales Order Item",
|
||||
row.sales_order_item,
|
||||
"production_plan_qty",
|
||||
flt(so_wise_planned_qty.get(key)),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_so_wise_planned_qty(sales_orders):
|
||||
so_wise_planned_qty = frappe._dict()
|
||||
data = frappe.get_all(
|
||||
"Production Plan Item",
|
||||
fields=["sales_order", "sales_order_item", "SUM(planned_qty) as qty"],
|
||||
filters={
|
||||
"sales_order": ("in", sales_orders),
|
||||
"docstatus": 1,
|
||||
"sales_order_item": ("is", "set"),
|
||||
},
|
||||
group_by="sales_order, sales_order_item",
|
||||
)
|
||||
|
||||
for row in data:
|
||||
key = (row.sales_order, row.sales_order_item)
|
||||
so_wise_planned_qty[key] = row.qty
|
||||
|
||||
return so_wise_planned_qty
|
||||
|
||||
def update_bin_qty(self):
|
||||
for d in self.mr_items:
|
||||
@@ -719,6 +789,9 @@ class ProductionPlan(Document):
|
||||
sub_assembly_items_store = [] # temporary store to process all subassembly items
|
||||
|
||||
for row in self.po_items:
|
||||
if self.skip_available_sub_assembly_item and not row.warehouse:
|
||||
frappe.throw(_("Row #{0}: Please select the FG Warehouse in Assembly Items").format(row.idx))
|
||||
|
||||
if not row.item_code:
|
||||
frappe.throw(_("Row #{0}: Please select Item Code in Assembly Items").format(row.idx))
|
||||
|
||||
@@ -1142,7 +1215,7 @@ def get_sales_orders(self):
|
||||
& (so.docstatus == 1)
|
||||
& (so.status.notin(["Stopped", "Closed"]))
|
||||
& (so.company == self.company)
|
||||
& (so_item.qty > so_item.work_order_qty)
|
||||
& (so_item.qty > so_item.production_plan_qty)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1566,7 +1639,6 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
|
||||
def get_raw_materials_of_sub_assembly_items(
|
||||
item_details, company, bom_no, include_non_stock_items, sub_assembly_items, planned_qty=1
|
||||
):
|
||||
|
||||
bei = frappe.qb.DocType("BOM Item")
|
||||
bom = frappe.qb.DocType("BOM")
|
||||
item = frappe.qb.DocType("Item")
|
||||
@@ -1609,7 +1681,10 @@ def get_raw_materials_of_sub_assembly_items(
|
||||
|
||||
for item in items:
|
||||
key = (item.item_code, item.bom_no)
|
||||
if item.bom_no and key in sub_assembly_items:
|
||||
if item.bom_no and key not in sub_assembly_items:
|
||||
continue
|
||||
|
||||
if item.bom_no:
|
||||
planned_qty = flt(sub_assembly_items[key])
|
||||
get_raw_materials_of_sub_assembly_items(
|
||||
item_details,
|
||||
@@ -1626,3 +1701,42 @@ def get_raw_materials_of_sub_assembly_items(
|
||||
item_details.setdefault(item.get("item_code"), item)
|
||||
|
||||
return item_details
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def sales_order_query(
|
||||
doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None
|
||||
):
|
||||
frappe.has_permission("Production Plan", throw=True)
|
||||
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
so_table = frappe.qb.DocType("Sales Order")
|
||||
table = frappe.qb.DocType("Sales Order Item")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(so_table)
|
||||
.join(table)
|
||||
.on(table.parent == so_table.name)
|
||||
.select(table.parent)
|
||||
.distinct()
|
||||
.where((table.qty > table.production_plan_qty) & (table.docstatus == 1))
|
||||
)
|
||||
|
||||
if filters.get("company"):
|
||||
query = query.where(so_table.company == filters.get("company"))
|
||||
|
||||
if filters.get("sales_orders"):
|
||||
query = query.where(so_table.name.isin(filters.get("sales_orders")))
|
||||
|
||||
if txt:
|
||||
query = query.where(table.item_code.like(f"{txt}%"))
|
||||
|
||||
if page_len:
|
||||
query = query.limit(page_len)
|
||||
|
||||
if start:
|
||||
query = query.offset(start)
|
||||
|
||||
return query.run()
|
||||
|
||||
@@ -225,6 +225,102 @@ class TestProductionPlan(FrappeTestCase):
|
||||
|
||||
self.assertEqual(sales_orders, [])
|
||||
|
||||
def test_donot_allow_to_make_multiple_pp_against_same_so(self):
|
||||
item = "Test SO Production Item 1"
|
||||
create_item(item)
|
||||
|
||||
raw_material = "Test SO RM Production Item 1"
|
||||
create_item(raw_material)
|
||||
|
||||
if not frappe.db.get_value("BOM", {"item": item}):
|
||||
make_bom(item=item, raw_materials=[raw_material])
|
||||
|
||||
so = make_sales_order(item_code=item, qty=4)
|
||||
pln = frappe.new_doc("Production Plan")
|
||||
pln.company = so.company
|
||||
pln.get_items_from = "Sales Order"
|
||||
|
||||
pln.append(
|
||||
"sales_orders",
|
||||
{
|
||||
"sales_order": so.name,
|
||||
"sales_order_date": so.transaction_date,
|
||||
"customer": so.customer,
|
||||
"grand_total": so.grand_total,
|
||||
},
|
||||
)
|
||||
|
||||
pln.get_so_items()
|
||||
pln.submit()
|
||||
|
||||
pln = frappe.new_doc("Production Plan")
|
||||
pln.company = so.company
|
||||
pln.get_items_from = "Sales Order"
|
||||
|
||||
pln.append(
|
||||
"sales_orders",
|
||||
{
|
||||
"sales_order": so.name,
|
||||
"sales_order_date": so.transaction_date,
|
||||
"customer": so.customer,
|
||||
"grand_total": so.grand_total,
|
||||
},
|
||||
)
|
||||
|
||||
pln.get_so_items()
|
||||
self.assertRaises(frappe.ValidationError, pln.save)
|
||||
|
||||
def test_so_based_bill_of_material(self):
|
||||
item = "Test SO Production Item 1"
|
||||
create_item(item)
|
||||
|
||||
raw_material = "Test SO RM Production Item 1"
|
||||
create_item(raw_material)
|
||||
|
||||
bom1 = make_bom(item=item, raw_materials=[raw_material])
|
||||
|
||||
so = make_sales_order(item_code=item, qty=4)
|
||||
|
||||
# Create new BOM and assign to new sales order
|
||||
bom2 = make_bom(item=item, raw_materials=[raw_material])
|
||||
so2 = make_sales_order(item_code=item, qty=4)
|
||||
|
||||
pln1 = frappe.new_doc("Production Plan")
|
||||
pln1.company = so.company
|
||||
pln1.get_items_from = "Sales Order"
|
||||
|
||||
pln1.append(
|
||||
"sales_orders",
|
||||
{
|
||||
"sales_order": so.name,
|
||||
"sales_order_date": so.transaction_date,
|
||||
"customer": so.customer,
|
||||
"grand_total": so.grand_total,
|
||||
},
|
||||
)
|
||||
|
||||
pln1.get_so_items()
|
||||
|
||||
self.assertEqual(pln1.po_items[0].bom_no, bom1.name)
|
||||
|
||||
pln2 = frappe.new_doc("Production Plan")
|
||||
pln2.company = so2.company
|
||||
pln2.get_items_from = "Sales Order"
|
||||
|
||||
pln2.append(
|
||||
"sales_orders",
|
||||
{
|
||||
"sales_order": so2.name,
|
||||
"sales_order_date": so2.transaction_date,
|
||||
"customer": so2.customer,
|
||||
"grand_total": so2.grand_total,
|
||||
},
|
||||
)
|
||||
|
||||
pln2.get_so_items()
|
||||
|
||||
self.assertEqual(pln2.po_items[0].bom_no, bom2.name)
|
||||
|
||||
def test_production_plan_combine_items(self):
|
||||
"Test combining FG items in Production Plan."
|
||||
item = "Test Production Item 1"
|
||||
|
||||
@@ -114,7 +114,7 @@ class Workstation(Document):
|
||||
|
||||
if schedule_date in tuple(get_holidays(self.holiday_list)):
|
||||
schedule_date = add_days(schedule_date, 1)
|
||||
self.validate_workstation_holiday(schedule_date, skip_holiday_list_check=True)
|
||||
return self.validate_workstation_holiday(schedule_date, skip_holiday_list_check=True)
|
||||
|
||||
return schedule_date
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ frappe.query_reports["Job Card Summary"] = {
|
||||
label: __("From Posting Date"),
|
||||
fieldname:"from_date",
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: __("To Posting Date"),
|
||||
fieldname:"to_date",
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -16,14 +16,14 @@ frappe.query_reports["Production Analytics"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,7 +6,9 @@ def execute():
|
||||
frappe.reload_doc("selling", "doctype", "sales_order_item")
|
||||
|
||||
for doctype in ["Sales Order", "Material Request"]:
|
||||
condition = " and child_doc.stock_qty > child_doc.produced_qty and doc.per_delivered < 100"
|
||||
condition = (
|
||||
" and child_doc.stock_qty > child_doc.produced_qty and ROUND(doc.per_delivered, 2) < 100"
|
||||
)
|
||||
if doctype == "Material Request":
|
||||
condition = " and doc.per_ordered < 100 and doc.material_request_type = 'Manufacture'"
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ erpnext.get_purchase_trends_filters = function() {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options":'Fiscal Year',
|
||||
"default": frappe.sys_defaults.fiscal_year
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today())
|
||||
},
|
||||
{
|
||||
"fieldname":"period_based_on",
|
||||
|
||||
@@ -48,7 +48,7 @@ erpnext.get_sales_trends_filters = function() {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options":'Fiscal Year',
|
||||
"default": frappe.sys_defaults.fiscal_year
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
},
|
||||
{
|
||||
"fieldname":"company",
|
||||
|
||||
@@ -400,7 +400,7 @@ $.extend(erpnext.utils, {
|
||||
});
|
||||
},
|
||||
|
||||
get_fiscal_year: function(date) {
|
||||
get_fiscal_year: function(date, with_dates=false) {
|
||||
if(!date) {
|
||||
date = frappe.datetime.get_today();
|
||||
}
|
||||
@@ -414,7 +414,10 @@ $.extend(erpnext.utils, {
|
||||
async: false,
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
fiscal_year = r.message[0];
|
||||
if (with_dates)
|
||||
fiscal_year = r.message;
|
||||
else
|
||||
fiscal_year = r.message[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -62,10 +62,10 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "process_owner.full_name",
|
||||
"fetch_from": "procedure.process_owner_full_name",
|
||||
"fieldname": "full_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"read_only": 1,
|
||||
"label": "Full Name"
|
||||
},
|
||||
{
|
||||
@@ -81,7 +81,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-02-26 15:27:47.247814",
|
||||
"modified": "2023-07-31 08:10:47.247814",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Non Conformance",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:{####}",
|
||||
"creation": "2019-05-26 15:03:43.996455",
|
||||
"doctype": "DocType",
|
||||
@@ -12,7 +13,6 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fetch_from": "goal.objective",
|
||||
"fieldname": "objective",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
@@ -38,14 +38,17 @@
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-05-26 16:12:54.832058",
|
||||
"links": [],
|
||||
"modified": "2023-07-28 18:10:23.351246",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Goal Objective",
|
||||
"naming_rule": "Expression",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -56,6 +56,7 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Open",
|
||||
"columns": 2,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
@@ -67,7 +68,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-27 16:28:20.908637",
|
||||
"modified": "2023-07-31 09:20:20.908637",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Review Objective",
|
||||
@@ -76,4 +77,4 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,12 +126,6 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext.
|
||||
});
|
||||
}
|
||||
|
||||
if(!doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
|
||||
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ frappe.ui.form.on("Sales Order", {
|
||||
|
||||
refresh: function(frm) {
|
||||
if(frm.doc.docstatus === 1) {
|
||||
if (frm.doc.status !== 'Closed' && flt(frm.doc.per_delivered, 6) < 100 && flt(frm.doc.per_billed, 6) < 100) {
|
||||
if (frm.doc.status !== 'Closed' && flt(frm.doc.per_delivered, 2) < 100 && flt(frm.doc.per_billed, 2) < 100) {
|
||||
frm.add_custom_button(__('Update Items'), () => {
|
||||
erpnext.utils.update_child_items({
|
||||
frm: frm,
|
||||
@@ -309,7 +309,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
|
||||
me.frm.cscript.update_status('Resume', 'Draft')
|
||||
}, __("Status"));
|
||||
|
||||
if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) {
|
||||
if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) {
|
||||
// close
|
||||
this.frm.add_custom_button(__('Close'), () => this.close_sales_order(), __("Status"))
|
||||
}
|
||||
@@ -327,7 +327,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
|
||||
&& !this.frm.doc.skip_delivery_note
|
||||
|
||||
if (this.frm.has_perm("submit")) {
|
||||
if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) {
|
||||
if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) {
|
||||
// hold
|
||||
this.frm.add_custom_button(__('Hold'), () => this.hold_sales_order(), __("Status"))
|
||||
// close
|
||||
@@ -335,7 +335,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
|
||||
}
|
||||
}
|
||||
|
||||
if (flt(doc.per_picked, 6) < 100 && flt(doc.per_delivered, 6) < 100) {
|
||||
if (flt(doc.per_picked, 2) < 100 && flt(doc.per_delivered, 2) < 100) {
|
||||
this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create'));
|
||||
}
|
||||
|
||||
@@ -345,18 +345,18 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
|
||||
const order_is_a_custom_sale = ["Sales", "Shopping Cart", "Maintenance"].indexOf(doc.order_type) === -1;
|
||||
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 6) < 100 && (order_is_a_sale || order_is_a_custom_sale) && allow_delivery) {
|
||||
if(flt(doc.per_delivered, 2) < 100 && (order_is_a_sale || order_is_a_custom_sale) && allow_delivery) {
|
||||
this.frm.add_custom_button(__('Delivery Note'), () => this.make_delivery_note_based_on_delivery_date(), __('Create'));
|
||||
this.frm.add_custom_button(__('Work Order'), () => this.make_work_order(), __('Create'));
|
||||
}
|
||||
|
||||
// sales invoice
|
||||
if(flt(doc.per_billed, 6) < 100) {
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
this.frm.add_custom_button(__('Sales Invoice'), () => me.make_sales_invoice(), __('Create'));
|
||||
}
|
||||
|
||||
// material request
|
||||
if(!doc.order_type || (order_is_a_sale || order_is_a_custom_sale) && flt(doc.per_delivered, 6) < 100) {
|
||||
if(!doc.order_type || (order_is_a_sale || order_is_a_custom_sale) && flt(doc.per_delivered, 2) < 100) {
|
||||
this.frm.add_custom_button(__('Material Request'), () => this.make_material_request(), __('Create'));
|
||||
this.frm.add_custom_button(__('Request for Raw Materials'), () => this.make_raw_material_request(), __('Create'));
|
||||
}
|
||||
@@ -377,12 +377,6 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
|
||||
this.frm.add_custom_button(__('Project'), () => this.make_project(), __('Create'));
|
||||
}
|
||||
|
||||
if(!doc.auto_repeat) {
|
||||
this.frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
|
||||
if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
|
||||
let me = this;
|
||||
let internal = me.frm.doc.is_internal_customer;
|
||||
|
||||
@@ -733,7 +733,7 @@ def make_material_request(source_name, target_doc=None):
|
||||
# qty is for packed items, because packed items don't have stock_qty field
|
||||
qty = source.get("qty")
|
||||
target.project = source_parent.project
|
||||
target.qty = qty - requested_item_qty.get(source.name, 0) - source.delivered_qty
|
||||
target.qty = qty - requested_item_qty.get(source.name, 0) - flt(source.get("delivered_qty"))
|
||||
target.stock_qty = flt(target.qty) * flt(target.conversion_factor)
|
||||
|
||||
args = target.as_dict().copy()
|
||||
@@ -767,7 +767,7 @@ def make_material_request(source_name, target_doc=None):
|
||||
"doctype": "Material Request Item",
|
||||
"field_map": {"name": "sales_order_item", "parent": "sales_order"},
|
||||
"condition": lambda doc: not frappe.db.exists("Product Bundle", doc.item_code)
|
||||
and (doc.stock_qty - doc.delivered_qty) > requested_item_qty.get(doc.name, 0),
|
||||
and (doc.stock_qty - flt(doc.get("delivered_qty"))) > requested_item_qty.get(doc.name, 0),
|
||||
"postprocess": update_item,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ frappe.listview_settings['Sales Order'] = {
|
||||
return [__("On Hold"), "orange", "status,=,On Hold"];
|
||||
} else if (doc.status === "Completed") {
|
||||
return [__("Completed"), "green", "status,=,Completed"];
|
||||
} else if (!doc.skip_delivery_note && flt(doc.per_delivered, 6) < 100) {
|
||||
} else if (!doc.skip_delivery_note && flt(doc.per_delivered, 2) < 100) {
|
||||
if (frappe.datetime.get_diff(doc.delivery_date) < 0) {
|
||||
// not delivered & overdue
|
||||
return [__("Overdue"), "red",
|
||||
@@ -19,7 +19,7 @@ frappe.listview_settings['Sales Order'] = {
|
||||
// not delivered (zeroount order)
|
||||
return [__("To Deliver"), "orange",
|
||||
"per_delivered,<,100|grand_total,=,0|status,!=,Closed"];
|
||||
} else if (flt(doc.per_billed, 6) < 100) {
|
||||
} else if (flt(doc.per_billed, 2) < 100) {
|
||||
// not delivered & not billed
|
||||
return [__("To Deliver and Bill"), "orange",
|
||||
"per_delivered,<,100|per_billed,<,100|status,!=,Closed"];
|
||||
@@ -28,12 +28,12 @@ frappe.listview_settings['Sales Order'] = {
|
||||
return [__("To Deliver"), "orange",
|
||||
"per_delivered,<,100|per_billed,=,100|status,!=,Closed"];
|
||||
}
|
||||
} else if ((flt(doc.per_delivered, 6) === 100) && flt(doc.grand_total) !== 0
|
||||
&& flt(doc.per_billed, 6) < 100) {
|
||||
} else if ((flt(doc.per_delivered, 2) === 100) && flt(doc.grand_total) !== 0
|
||||
&& flt(doc.per_billed, 2) < 100) {
|
||||
// to bill
|
||||
return [__("To Bill"), "orange",
|
||||
"per_delivered,=,100|per_billed,<,100|status,!=,Closed"];
|
||||
} else if (doc.skip_delivery_note && flt(doc.per_billed, 6) < 100){
|
||||
} else if (doc.skip_delivery_note && flt(doc.per_billed, 2) < 100){
|
||||
return [__("To Bill"), "orange", "per_billed,<,100|status,!=,Closed"];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -549,6 +549,26 @@ class TestSalesOrder(FrappeTestCase):
|
||||
workflow.is_active = 0
|
||||
workflow.save()
|
||||
|
||||
def test_material_request_for_product_bundle(self):
|
||||
# Create the Material Request from the sales order for the Packing Items
|
||||
# Check whether the material request has the correct packing item or not.
|
||||
if not frappe.db.exists("Item", "_Test Product Bundle Item New 1"):
|
||||
bundle_item = make_item("_Test Product Bundle Item New 1", {"is_stock_item": 0})
|
||||
bundle_item.append(
|
||||
"item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
|
||||
)
|
||||
bundle_item.save(ignore_permissions=True)
|
||||
|
||||
make_item("_Packed Item New 2", {"is_stock_item": 1})
|
||||
make_product_bundle("_Test Product Bundle Item New 1", ["_Packed Item New 2"], 2)
|
||||
|
||||
so = make_sales_order(
|
||||
item_code="_Test Product Bundle Item New 1",
|
||||
)
|
||||
|
||||
mr = make_material_request(so.name)
|
||||
self.assertEqual(mr.items[0].item_code, "_Packed Item New 2")
|
||||
|
||||
def test_bin_details_of_packed_item(self):
|
||||
# test Update Items with product bundle
|
||||
if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
"actual_qty",
|
||||
"ordered_qty",
|
||||
"planned_qty",
|
||||
"production_plan_qty",
|
||||
"column_break_69",
|
||||
"work_order_qty",
|
||||
"delivered_qty",
|
||||
@@ -882,12 +883,19 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "production_plan_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Production Plan Qty",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-04-04 10:44:05.707488",
|
||||
"modified": "2023-07-28 14:56:42.031636",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Item",
|
||||
|
||||
@@ -605,7 +605,6 @@ erpnext.PointOfSale.Controller = class {
|
||||
i => i.item_code === item_code
|
||||
&& (!has_batch_no || (has_batch_no && i.batch_no === batch_no))
|
||||
&& (i.uom === uom)
|
||||
&& (i.rate == rate)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,14 @@ frappe.query_reports["Customer Acquisition and Loyalty"] = {
|
||||
"fieldname":"from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
|
||||
@@ -35,14 +35,14 @@ frappe.query_reports["Sales Analytics"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Sales Partner Target Variance based on Item Group"] = {
|
||||
label: __("Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today())
|
||||
},
|
||||
{
|
||||
fieldname: "doctype",
|
||||
|
||||
@@ -22,7 +22,7 @@ frappe.query_reports["Sales Person Commission Summary"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Sales Person Target Variance Based On Item Group"] = {
|
||||
label: __("Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
},
|
||||
{
|
||||
fieldname: "doctype",
|
||||
|
||||
@@ -20,7 +20,7 @@ frappe.query_reports["Sales Person-wise Transaction Summary"] = {
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Territory Target Variance Based On Item Group"] = {
|
||||
label: __("Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today())
|
||||
},
|
||||
{
|
||||
fieldname: "doctype",
|
||||
|
||||
@@ -73,7 +73,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
||||
return self.route
|
||||
|
||||
def on_trash(self):
|
||||
NestedSet.on_trash(self)
|
||||
NestedSet.on_trash(self, allow_root_deletion=True)
|
||||
WebsiteGenerator.on_trash(self)
|
||||
self.delete_child_item_groups_key()
|
||||
|
||||
|
||||
@@ -235,12 +235,6 @@ erpnext.stock.DeliveryNoteController = class DeliveryNoteController extends erpn
|
||||
__("Status"))
|
||||
}
|
||||
erpnext.stock.delivery_note.set_print_hide(doc, dt, dn);
|
||||
|
||||
if(doc.docstatus==1 && !doc.is_return && !doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
}
|
||||
|
||||
make_shipment() {
|
||||
|
||||
@@ -854,7 +854,8 @@
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "pick_serial_and_batch",
|
||||
@@ -884,14 +885,15 @@
|
||||
"hidden": 1,
|
||||
"label": "Batch No",
|
||||
"options": "Batch",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-05-02 21:05:14.175640",
|
||||
"modified": "2023-07-26 12:53:49.357171",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note Item",
|
||||
|
||||
@@ -395,16 +395,16 @@ class Item(Document):
|
||||
|
||||
def validate_warehouse_for_reorder(self):
|
||||
"""Validate Reorder level table for duplicate and conditional mandatory"""
|
||||
warehouse = []
|
||||
warehouse_material_request_type: list[tuple[str, str]] = []
|
||||
for d in self.get("reorder_levels"):
|
||||
if not d.warehouse_group:
|
||||
d.warehouse_group = d.warehouse
|
||||
if d.get("warehouse") and d.get("warehouse") not in warehouse:
|
||||
warehouse += [d.get("warehouse")]
|
||||
if (d.get("warehouse"), d.get("material_request_type")) not in warehouse_material_request_type:
|
||||
warehouse_material_request_type += [(d.get("warehouse"), d.get("material_request_type"))]
|
||||
else:
|
||||
frappe.throw(
|
||||
_("Row {0}: An Reorder entry already exists for this warehouse {1}").format(
|
||||
d.idx, d.warehouse
|
||||
_("Row #{0}: A reorder entry already exists for warehouse {1} with reorder type {2}.").format(
|
||||
d.idx, d.warehouse, d.material_request_type
|
||||
),
|
||||
DuplicateReorderRows,
|
||||
)
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch No",
|
||||
"options": "Batch",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
@@ -199,7 +200,8 @@
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "pick_serial_and_batch",
|
||||
@@ -209,7 +211,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-06-16 14:05:51.719959",
|
||||
"modified": "2023-07-26 12:54:15.785962",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Pick List Item",
|
||||
|
||||
@@ -189,12 +189,6 @@ erpnext.stock.PurchaseReceiptController = class PurchaseReceiptController extend
|
||||
}
|
||||
cur_frm.add_custom_button(__('Retention Stock Entry'), this.make_retention_stock_entry, __('Create'));
|
||||
|
||||
if(!this.frm.doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(me.frm.doc.doctype, me.frm.doc.name)
|
||||
}, __('Create'))
|
||||
}
|
||||
|
||||
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +502,6 @@
|
||||
{
|
||||
"fieldname": "rejected_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Rejected Warehouse",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "rejected_warehouse",
|
||||
@@ -1003,7 +1002,8 @@
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.is_old_subcontracting_flow",
|
||||
@@ -1028,7 +1028,8 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch No",
|
||||
"options": "Batch",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rejected_serial_and_batch_bundle",
|
||||
@@ -1059,7 +1060,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-07-04 17:22:02.830029",
|
||||
"modified": "2023-07-26 12:55:15.234477",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt Item",
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_group",
|
||||
@@ -78,7 +79,8 @@
|
||||
"in_standard_filter": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_name",
|
||||
@@ -180,14 +182,16 @@
|
||||
"in_standard_filter": 1,
|
||||
"label": "Warehouse",
|
||||
"mandatory_depends_on": "eval:doc.type_of_transaction != \"Maintenance\"",
|
||||
"options": "Warehouse"
|
||||
"options": "Warehouse",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "type_of_transaction",
|
||||
"fieldtype": "Select",
|
||||
"label": "Type of Transaction",
|
||||
"options": "\nInward\nOutward\nMaintenance\nAsset Repair",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
@@ -244,7 +248,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-07-16 10:53:04.045605",
|
||||
"modified": "2023-07-26 12:56:03.072224",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Bundle",
|
||||
|
||||
@@ -173,7 +173,8 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch No",
|
||||
"options": "Batch",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -197,7 +198,8 @@
|
||||
"label": "Serial / Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "current_serial_and_batch_bundle",
|
||||
@@ -214,7 +216,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-06-15 11:45:55.808942",
|
||||
"modified": "2023-07-26 12:54:34.011915",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Reconciliation Item",
|
||||
|
||||
@@ -8,7 +8,7 @@ frappe.query_reports["Batch Item Expiry Status"] = {
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"width": "80",
|
||||
"default": frappe.sys_defaults.year_start_date,
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"reqd": 1,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Batch-Wise Balance History"] = {
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"width": "80",
|
||||
"default": frappe.sys_defaults.year_start_date,
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ def execute(filters=None):
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
sle_count = frappe.db.count("Stock Ledger Entry", {"is_cancelled": 0})
|
||||
sle_count = frappe.db.count("Stock Ledger Entry")
|
||||
|
||||
if sle_count > SLE_COUNT_LIMIT and not filters.get("item_code") and not filters.get("warehouse"):
|
||||
frappe.throw(_("Please select either the Item or Warehouse filter to generate the report."))
|
||||
|
||||
@@ -22,14 +22,14 @@ frappe.query_reports["Incorrect Serial No Valuation"] = {
|
||||
fieldtype: 'Date',
|
||||
fieldname: 'from_date',
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("year_start_date")
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
label: __('To Date'),
|
||||
fieldtype: 'Date',
|
||||
fieldname: 'to_date',
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("year_end_date")
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = {
|
||||
"fieldname":"from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.sys_defaults.year_start_date
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
|
||||
},
|
||||
{
|
||||
"fieldname":"to_date",
|
||||
|
||||
@@ -446,10 +446,9 @@ class StockBalanceReport(object):
|
||||
{
|
||||
"label": _("Valuation Rate"),
|
||||
"fieldname": "val_rate",
|
||||
"fieldtype": "Currency",
|
||||
"fieldtype": "Float",
|
||||
"width": 90,
|
||||
"convertible": "rate",
|
||||
"options": "currency",
|
||||
},
|
||||
{
|
||||
"label": _("Reserved Stock"),
|
||||
|
||||
@@ -196,7 +196,7 @@ def get_columns(filters):
|
||||
{
|
||||
"label": _("Avg Rate (Balance Stock)"),
|
||||
"fieldname": "valuation_rate",
|
||||
"fieldtype": "Currency",
|
||||
"fieldtype": "Float",
|
||||
"width": 180,
|
||||
"options": "Company:company:default_currency",
|
||||
"convertible": "rate",
|
||||
@@ -204,7 +204,7 @@ def get_columns(filters):
|
||||
{
|
||||
"label": _("Valuation Rate"),
|
||||
"fieldname": "in_out_rate",
|
||||
"fieldtype": "Currency",
|
||||
"fieldtype": "Float",
|
||||
"width": 140,
|
||||
"options": "Company:company:default_currency",
|
||||
"convertible": "rate",
|
||||
|
||||
@@ -358,6 +358,8 @@ def update_args_in_repost_item_valuation(
|
||||
"current_index": index,
|
||||
"total_reposting_count": len(args),
|
||||
},
|
||||
doctype=doc.doctype,
|
||||
docname=doc.name,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
title = "Warehouse",
|
||||
actual_qty = (frm.doc.doctype==="Sales Order"
|
||||
? doc.projected_qty : doc.actual_qty);
|
||||
if(flt(frm.doc.per_delivered) < 100
|
||||
if(flt(frm.doc.per_delivered, 2) < 100
|
||||
&& in_list(["Sales Order Item", "Delivery Note Item"], doc.doctype)) {
|
||||
if(actual_qty != undefined) {
|
||||
if(actual_qty >= doc.qty) {
|
||||
|
||||
@@ -1063,6 +1063,7 @@ Get Items from Prescriptions,Holen Sie sich Artikel aus Verordnungen,
|
||||
Get Items from Product Bundle,Artikel aus dem Produkt-Bundle übernehmen,
|
||||
Get Suppliers,Holen Sie sich Lieferanten,
|
||||
Get Suppliers By,Holen Sie sich Lieferanten durch,
|
||||
Get Supplier Group Details,Werte aus Lieferantengruppe übernehmen,
|
||||
Get Updates,Newsletter abonnieren,
|
||||
Get customers from,Holen Sie Kunden von,
|
||||
Get from Patient Encounter,Von der Patientenbegegnung erhalten,
|
||||
@@ -4726,6 +4727,7 @@ Credit To,Gutschreiben auf,
|
||||
Party Account Currency,Währung des Kontos der Partei,
|
||||
Against Expense Account,Zu Aufwandskonto,
|
||||
Inter Company Invoice Reference,Unternehmensübergreifende Rechnungsreferenz,
|
||||
Internal Supplier,Interner Lieferant,
|
||||
Is Internal Supplier,Ist interner Lieferant,
|
||||
Start date of current invoice's period,Startdatum der laufenden Rechnungsperiode,
|
||||
End date of current invoice's period,Schlußdatum der laufenden Eingangsrechnungsperiode,
|
||||
@@ -5172,6 +5174,8 @@ Tracking,Verfolgung,
|
||||
Ref SQ,Ref-SQ,
|
||||
Inter Company Order Reference,Inter Company Bestellreferenz,
|
||||
Supplier Part Number,Lieferanten-Artikelnummer,
|
||||
Supplier Primary Contact,Hauptkontakt des Lieferanten,
|
||||
Supplier Primary Address,Hauptadresse des Lieferanten,
|
||||
Billed Amt,Rechnungsbetrag,
|
||||
Warehouse and Reference,Lager und Referenz,
|
||||
To be delivered to customer,Zur Auslieferung an den Kunden,
|
||||
@@ -6773,7 +6777,7 @@ Accounts Manager,Buchhalter,
|
||||
Allow Sales Invoice Creation Without Sales Order,Ermöglichen Sie die Erstellung von Kundenrechnungen ohne Auftrag,
|
||||
Allow Sales Invoice Creation Without Delivery Note,Ermöglichen Sie die Erstellung einer Ausgangsrechnung ohne Lieferschein,
|
||||
Default Price List,Standardpreisliste,
|
||||
Primary Address and Contact Detail,Primäre Adresse und Kontaktdetails,
|
||||
Primary Address and Contact,Hauptadresse und -kontakt,
|
||||
"Select, to make the customer searchable with these fields","Wählen Sie, um den Kunden mit diesen Feldern durchsuchbar zu machen",
|
||||
Customer Primary Contact,Hauptkontakt des Kunden,
|
||||
"Reselect, if the chosen contact is edited after save","Wählen Sie erneut, wenn der ausgewählte Kontakt nach dem Speichern bearbeitet wird",
|
||||
|
||||
|
Can't render this file because it is too large.
|
Reference in New Issue
Block a user