mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-07 07:20:26 +00:00
Merge branch 'develop' into version-15-beta
This commit is contained in:
@@ -15,6 +15,8 @@ pull_request_rules:
|
||||
- or:
|
||||
- base=version-13
|
||||
- base=version-12
|
||||
- base=version-14
|
||||
- base=version-15
|
||||
actions:
|
||||
close:
|
||||
comment:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"entry_type_and_date",
|
||||
"is_system_generated",
|
||||
"title",
|
||||
"voucher_type",
|
||||
"naming_series",
|
||||
@@ -88,7 +89,7 @@
|
||||
"label": "Entry Type",
|
||||
"oldfieldname": "voucher_type",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense",
|
||||
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense\nReversal Of ITC",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
@@ -533,57 +534,28 @@
|
||||
"label": "Process Deferred Accounting",
|
||||
"options": "Process Deferred Accounting",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.is_system_generated == 1;",
|
||||
"fieldname": "is_system_generated",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is System Generated",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 176,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-03-01 14:58:59.286591",
|
||||
"modified": "2023-08-10 14:32:22.366895",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry",
|
||||
"naming_rule": "By \"Naming Series\" field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"import": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor"
|
||||
}
|
||||
],
|
||||
"permissions": [],
|
||||
"search_fields": "voucher_type,posting_date, due_date, cheque_no",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
|
||||
@@ -797,6 +797,9 @@ class JournalEntry(AccountsController):
|
||||
def create_remarks(self):
|
||||
r = []
|
||||
|
||||
if self.flags.skip_remarks_creation:
|
||||
return
|
||||
|
||||
if self.user_remark:
|
||||
r.append(_("Note: {0}").format(self.user_remark))
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import frappe
|
||||
from frappe import _, msgprint, qb
|
||||
from frappe.model.document import Document
|
||||
from frappe.query_builder.custom import ConstantColumn
|
||||
from frappe.utils import flt, get_link_to_form, getdate, nowdate, today
|
||||
from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
|
||||
|
||||
import erpnext
|
||||
from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation import (
|
||||
@@ -657,6 +657,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
|
||||
"reference_name": inv.against_voucher,
|
||||
"cost_center": erpnext.get_default_cost_center(company),
|
||||
"exchange_rate": inv.exchange_rate,
|
||||
"user_remark": f"{fmt_money(flt(inv.allocated_amount), currency=company_currency)} against {inv.against_voucher}",
|
||||
},
|
||||
{
|
||||
"account": inv.account,
|
||||
@@ -671,6 +672,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
|
||||
"reference_name": inv.voucher_no,
|
||||
"cost_center": erpnext.get_default_cost_center(company),
|
||||
"exchange_rate": inv.exchange_rate,
|
||||
"user_remark": f"{fmt_money(flt(inv.allocated_amount), currency=company_currency)} from {inv.voucher_no}",
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -678,6 +680,9 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
|
||||
|
||||
jv.flags.ignore_mandatory = True
|
||||
jv.flags.ignore_exchange_rate = True
|
||||
jv.remark = None
|
||||
jv.flags.skip_remarks_creation = True
|
||||
jv.is_system_generated = True
|
||||
jv.submit()
|
||||
|
||||
if inv.difference_amount != 0:
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-04-21 17:19:30.912953",
|
||||
"modified": "2023-08-11 10:56:51.699137",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Process Payment Reconciliation",
|
||||
@@ -154,15 +154,25 @@
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"read": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1654,15 +1654,13 @@ class SalesInvoice(SellingController):
|
||||
frappe.db.set_value("Customer", self.customer, "loyalty_program_tier", lp_details.tier_name)
|
||||
|
||||
def get_returned_amount(self):
|
||||
from frappe.query_builder.functions import Coalesce, Sum
|
||||
from frappe.query_builder.functions import Sum
|
||||
|
||||
doc = frappe.qb.DocType(self.doctype)
|
||||
returned_amount = (
|
||||
frappe.qb.from_(doc)
|
||||
.select(Sum(doc.grand_total))
|
||||
.where(
|
||||
(doc.docstatus == 1) & (doc.is_return == 1) & (Coalesce(doc.return_against, "") == self.name)
|
||||
)
|
||||
.where((doc.docstatus == 1) & (doc.is_return == 1) & (doc.return_against == self.name))
|
||||
).run()
|
||||
|
||||
return abs(returned_amount[0][0]) if returned_amount[0][0] else 0
|
||||
|
||||
@@ -707,6 +707,7 @@ def get_payment_terms_template(party_name, party_type, company=None):
|
||||
if party_type not in ("Customer", "Supplier"):
|
||||
return
|
||||
template = None
|
||||
|
||||
if party_type == "Customer":
|
||||
customer = frappe.get_cached_value(
|
||||
"Customer", party_name, fieldname=["payment_terms", "customer_group"], as_dict=1
|
||||
|
||||
@@ -335,12 +335,10 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
||||
for period in period_list:
|
||||
total_row.setdefault(period.key, 0.0)
|
||||
total_row[period.key] += row.get(period.key, 0.0)
|
||||
row[period.key] = row.get(period.key, 0.0)
|
||||
|
||||
total_row.setdefault("total", 0.0)
|
||||
total_row["total"] += flt(row["total"])
|
||||
total_row["opening_balance"] += row["opening_balance"]
|
||||
row["total"] = ""
|
||||
|
||||
if "total" in total_row:
|
||||
out.append(total_row)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"label": "Profit and Loss"
|
||||
}
|
||||
],
|
||||
"content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
|
||||
"content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Payment\",\"col\":3}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
|
||||
"creation": "2020-03-02 15:41:59.515192",
|
||||
"custom_blocks": [],
|
||||
"docstatus": 0,
|
||||
@@ -1061,11 +1061,28 @@
|
||||
"type": "Link"
|
||||
}
|
||||
],
|
||||
"modified": "2023-07-04 14:32:15.842044",
|
||||
"modified": "2023-08-10 17:41:14.059005",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting",
|
||||
"number_cards": [],
|
||||
"number_cards": [
|
||||
{
|
||||
"label": "Total Outgoing Bills",
|
||||
"number_card_name": "Total Outgoing Bills"
|
||||
},
|
||||
{
|
||||
"label": "Total Incoming Bills",
|
||||
"number_card_name": "Total Incoming Bills"
|
||||
},
|
||||
{
|
||||
"label": "Total Incoming Payment",
|
||||
"number_card_name": "Total Incoming Payment"
|
||||
},
|
||||
{
|
||||
"label": "Total Outgoing Payment",
|
||||
"number_card_name": "Total Outgoing Payment"
|
||||
}
|
||||
],
|
||||
"owner": "Administrator",
|
||||
"parent_page": "",
|
||||
"public": 1,
|
||||
|
||||
@@ -478,7 +478,9 @@ class Asset(AccountsController):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_manual_depreciation_entries(self):
|
||||
(_, _, depreciation_expense_account) = get_depreciation_accounts(self)
|
||||
(_, _, depreciation_expense_account) = get_depreciation_accounts(
|
||||
self.asset_category, self.company
|
||||
)
|
||||
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
|
||||
@@ -821,10 +823,10 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non
|
||||
def make_journal_entry(asset_name):
|
||||
asset = frappe.get_doc("Asset", asset_name)
|
||||
(
|
||||
fixed_asset_account,
|
||||
_,
|
||||
accumulated_depreciation_account,
|
||||
depreciation_expense_account,
|
||||
) = get_depreciation_accounts(asset)
|
||||
) = get_depreciation_accounts(asset.asset_category, asset.company)
|
||||
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
|
||||
"Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.query_builder import Order
|
||||
from frappe.query_builder.functions import Max, Min
|
||||
from frappe.utils import (
|
||||
add_months,
|
||||
cint,
|
||||
@@ -43,11 +45,48 @@ def post_depreciation_entries(date=None):
|
||||
failed_asset_names = []
|
||||
error_log_names = []
|
||||
|
||||
for asset_name in get_depreciable_assets(date):
|
||||
asset_doc = frappe.get_doc("Asset", asset_name)
|
||||
depreciable_asset_depr_schedules_data = get_depreciable_asset_depr_schedules_data(date)
|
||||
|
||||
credit_and_debit_accounts_for_asset_category_and_company = {}
|
||||
depreciation_cost_center_and_depreciation_series_for_company = (
|
||||
get_depreciation_cost_center_and_depreciation_series_for_company()
|
||||
)
|
||||
|
||||
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
|
||||
|
||||
for asset_depr_schedule_data in depreciable_asset_depr_schedules_data:
|
||||
(
|
||||
asset_depr_schedule_name,
|
||||
asset_name,
|
||||
asset_category,
|
||||
asset_company,
|
||||
sch_start_idx,
|
||||
sch_end_idx,
|
||||
) = asset_depr_schedule_data
|
||||
|
||||
if (
|
||||
asset_category,
|
||||
asset_company,
|
||||
) not in credit_and_debit_accounts_for_asset_category_and_company:
|
||||
credit_and_debit_accounts_for_asset_category_and_company.update(
|
||||
{
|
||||
(asset_category, asset_company): get_credit_and_debit_accounts_for_asset_category_and_company(
|
||||
asset_category, asset_company
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
try:
|
||||
make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date)
|
||||
make_depreciation_entry(
|
||||
asset_depr_schedule_name,
|
||||
date,
|
||||
sch_start_idx,
|
||||
sch_end_idx,
|
||||
credit_and_debit_accounts_for_asset_category_and_company[(asset_category, asset_company)],
|
||||
depreciation_cost_center_and_depreciation_series_for_company[asset_company],
|
||||
accounting_dimensions,
|
||||
)
|
||||
|
||||
frappe.db.commit()
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
@@ -62,18 +101,36 @@ def post_depreciation_entries(date=None):
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
def get_depreciable_assets(date):
|
||||
return frappe.db.sql_list(
|
||||
"""select distinct a.name
|
||||
from tabAsset a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds
|
||||
where a.name = ads.asset and ads.name = ds.parent and a.docstatus=1 and ads.docstatus=1
|
||||
and a.status in ('Submitted', 'Partially Depreciated')
|
||||
and a.calculate_depreciation = 1
|
||||
and ds.schedule_date<=%s
|
||||
and ifnull(ds.journal_entry, '')=''""",
|
||||
date,
|
||||
def get_depreciable_asset_depr_schedules_data(date):
|
||||
a = frappe.qb.DocType("Asset")
|
||||
ads = frappe.qb.DocType("Asset Depreciation Schedule")
|
||||
ds = frappe.qb.DocType("Depreciation Schedule")
|
||||
|
||||
res = (
|
||||
frappe.qb.from_(ads)
|
||||
.join(a)
|
||||
.on(ads.asset == a.name)
|
||||
.join(ds)
|
||||
.on(ads.name == ds.parent)
|
||||
.select(ads.name, a.name, a.asset_category, a.company, Min(ds.idx) - 1, Max(ds.idx))
|
||||
.where(a.calculate_depreciation == 1)
|
||||
.where(a.docstatus == 1)
|
||||
.where(ads.docstatus == 1)
|
||||
.where(a.status.isin(["Submitted", "Partially Depreciated"]))
|
||||
.where(ds.journal_entry.isnull())
|
||||
.where(ds.schedule_date <= date)
|
||||
.groupby(ads.name)
|
||||
.orderby(a.creation, order=Order.desc)
|
||||
)
|
||||
|
||||
acc_frozen_upto = get_acc_frozen_upto()
|
||||
if acc_frozen_upto:
|
||||
res = res.where(ds.schedule_date > acc_frozen_upto)
|
||||
|
||||
res = res.run()
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None):
|
||||
for row in asset_doc.get("finance_books"):
|
||||
@@ -83,8 +140,60 @@ def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None):
|
||||
make_depreciation_entry(asset_depr_schedule_name, date)
|
||||
|
||||
|
||||
def get_acc_frozen_upto():
|
||||
acc_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto")
|
||||
|
||||
if not acc_frozen_upto:
|
||||
return
|
||||
|
||||
frozen_accounts_modifier = frappe.db.get_single_value(
|
||||
"Accounts Settings", "frozen_accounts_modifier"
|
||||
)
|
||||
|
||||
if frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator":
|
||||
return getdate(acc_frozen_upto)
|
||||
|
||||
return
|
||||
|
||||
|
||||
def get_credit_and_debit_accounts_for_asset_category_and_company(asset_category, company):
|
||||
(
|
||||
_,
|
||||
accumulated_depreciation_account,
|
||||
depreciation_expense_account,
|
||||
) = get_depreciation_accounts(asset_category, company)
|
||||
|
||||
credit_account, debit_account = get_credit_and_debit_accounts(
|
||||
accumulated_depreciation_account, depreciation_expense_account
|
||||
)
|
||||
|
||||
return (credit_account, debit_account)
|
||||
|
||||
|
||||
def get_depreciation_cost_center_and_depreciation_series_for_company():
|
||||
company_names = frappe.db.get_all("Company", pluck="name")
|
||||
|
||||
res = {}
|
||||
|
||||
for company_name in company_names:
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
|
||||
"Company", company_name, ["depreciation_cost_center", "series_for_depreciation_entry"]
|
||||
)
|
||||
res.update({company_name: (depreciation_cost_center, depreciation_series)})
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_depreciation_entry(asset_depr_schedule_name, date=None):
|
||||
def make_depreciation_entry(
|
||||
asset_depr_schedule_name,
|
||||
date=None,
|
||||
sch_start_idx=None,
|
||||
sch_end_idx=None,
|
||||
credit_and_debit_accounts=None,
|
||||
depreciation_cost_center_and_depreciation_series=None,
|
||||
accounting_dimensions=None,
|
||||
):
|
||||
frappe.has_permission("Journal Entry", throw=True)
|
||||
|
||||
if not date:
|
||||
@@ -92,100 +201,144 @@ def make_depreciation_entry(asset_depr_schedule_name, date=None):
|
||||
|
||||
asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name)
|
||||
|
||||
asset_name = asset_depr_schedule_doc.asset
|
||||
asset = frappe.get_doc("Asset", asset_depr_schedule_doc.asset)
|
||||
|
||||
asset = frappe.get_doc("Asset", asset_name)
|
||||
(
|
||||
fixed_asset_account,
|
||||
accumulated_depreciation_account,
|
||||
depreciation_expense_account,
|
||||
) = get_depreciation_accounts(asset)
|
||||
if credit_and_debit_accounts:
|
||||
credit_account, debit_account = credit_and_debit_accounts
|
||||
else:
|
||||
credit_account, debit_account = get_credit_and_debit_accounts_for_asset_category_and_company(
|
||||
asset.asset_category, asset.company
|
||||
)
|
||||
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
|
||||
"Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]
|
||||
)
|
||||
if depreciation_cost_center_and_depreciation_series:
|
||||
depreciation_cost_center, depreciation_series = depreciation_cost_center_and_depreciation_series
|
||||
else:
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
|
||||
"Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]
|
||||
)
|
||||
|
||||
depreciation_cost_center = asset.cost_center or depreciation_cost_center
|
||||
|
||||
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
|
||||
if not accounting_dimensions:
|
||||
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
|
||||
|
||||
for d in asset_depr_schedule_doc.get("depreciation_schedule"):
|
||||
if not d.journal_entry and getdate(d.schedule_date) <= getdate(date):
|
||||
je = frappe.new_doc("Journal Entry")
|
||||
je.voucher_type = "Depreciation Entry"
|
||||
je.naming_series = depreciation_series
|
||||
je.posting_date = d.schedule_date
|
||||
je.company = asset.company
|
||||
je.finance_book = asset_depr_schedule_doc.finance_book
|
||||
je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
|
||||
depreciation_posting_error = None
|
||||
|
||||
credit_account, debit_account = get_credit_and_debit_accounts(
|
||||
accumulated_depreciation_account, depreciation_expense_account
|
||||
for d in asset_depr_schedule_doc.get("depreciation_schedule")[
|
||||
sch_start_idx or 0 : sch_end_idx or len(asset_depr_schedule_doc.get("depreciation_schedule"))
|
||||
]:
|
||||
try:
|
||||
_make_journal_entry_for_depreciation(
|
||||
asset_depr_schedule_doc,
|
||||
asset,
|
||||
date,
|
||||
d,
|
||||
sch_start_idx,
|
||||
sch_end_idx,
|
||||
depreciation_cost_center,
|
||||
depreciation_series,
|
||||
credit_account,
|
||||
debit_account,
|
||||
accounting_dimensions,
|
||||
)
|
||||
|
||||
credit_entry = {
|
||||
"account": credit_account,
|
||||
"credit_in_account_currency": d.depreciation_amount,
|
||||
"reference_type": "Asset",
|
||||
"reference_name": asset.name,
|
||||
"cost_center": depreciation_cost_center,
|
||||
}
|
||||
|
||||
debit_entry = {
|
||||
"account": debit_account,
|
||||
"debit_in_account_currency": d.depreciation_amount,
|
||||
"reference_type": "Asset",
|
||||
"reference_name": asset.name,
|
||||
"cost_center": depreciation_cost_center,
|
||||
}
|
||||
|
||||
for dimension in accounting_dimensions:
|
||||
if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_bs"):
|
||||
credit_entry.update(
|
||||
{
|
||||
dimension["fieldname"]: asset.get(dimension["fieldname"])
|
||||
or dimension.get("default_dimension")
|
||||
}
|
||||
)
|
||||
|
||||
if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_pl"):
|
||||
debit_entry.update(
|
||||
{
|
||||
dimension["fieldname"]: asset.get(dimension["fieldname"])
|
||||
or dimension.get("default_dimension")
|
||||
}
|
||||
)
|
||||
|
||||
je.append("accounts", credit_entry)
|
||||
|
||||
je.append("accounts", debit_entry)
|
||||
|
||||
je.flags.ignore_permissions = True
|
||||
je.flags.planned_depr_entry = True
|
||||
je.save()
|
||||
|
||||
d.db_set("journal_entry", je.name)
|
||||
|
||||
if not je.meta.get_workflow():
|
||||
je.submit()
|
||||
idx = cint(asset_depr_schedule_doc.finance_book_id)
|
||||
row = asset.get("finance_books")[idx - 1]
|
||||
row.value_after_depreciation -= d.depreciation_amount
|
||||
row.db_update()
|
||||
|
||||
asset.db_set("depr_entry_posting_status", "Successful")
|
||||
frappe.db.commit()
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
depreciation_posting_error = e
|
||||
|
||||
asset.set_status()
|
||||
|
||||
return asset_depr_schedule_doc
|
||||
if not depreciation_posting_error:
|
||||
asset.db_set("depr_entry_posting_status", "Successful")
|
||||
return asset_depr_schedule_doc
|
||||
|
||||
raise depreciation_posting_error
|
||||
|
||||
|
||||
def get_depreciation_accounts(asset):
|
||||
def _make_journal_entry_for_depreciation(
|
||||
asset_depr_schedule_doc,
|
||||
asset,
|
||||
date,
|
||||
depr_schedule,
|
||||
sch_start_idx,
|
||||
sch_end_idx,
|
||||
depreciation_cost_center,
|
||||
depreciation_series,
|
||||
credit_account,
|
||||
debit_account,
|
||||
accounting_dimensions,
|
||||
):
|
||||
if not (sch_start_idx and sch_end_idx) and not (
|
||||
not depr_schedule.journal_entry and getdate(depr_schedule.schedule_date) <= getdate(date)
|
||||
):
|
||||
return
|
||||
|
||||
je = frappe.new_doc("Journal Entry")
|
||||
je.voucher_type = "Depreciation Entry"
|
||||
je.naming_series = depreciation_series
|
||||
je.posting_date = depr_schedule.schedule_date
|
||||
je.company = asset.company
|
||||
je.finance_book = asset_depr_schedule_doc.finance_book
|
||||
je.remark = "Depreciation Entry against {0} worth {1}".format(
|
||||
asset.name, depr_schedule.depreciation_amount
|
||||
)
|
||||
|
||||
credit_entry = {
|
||||
"account": credit_account,
|
||||
"credit_in_account_currency": depr_schedule.depreciation_amount,
|
||||
"reference_type": "Asset",
|
||||
"reference_name": asset.name,
|
||||
"cost_center": depreciation_cost_center,
|
||||
}
|
||||
|
||||
debit_entry = {
|
||||
"account": debit_account,
|
||||
"debit_in_account_currency": depr_schedule.depreciation_amount,
|
||||
"reference_type": "Asset",
|
||||
"reference_name": asset.name,
|
||||
"cost_center": depreciation_cost_center,
|
||||
}
|
||||
|
||||
for dimension in accounting_dimensions:
|
||||
if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_bs"):
|
||||
credit_entry.update(
|
||||
{
|
||||
dimension["fieldname"]: asset.get(dimension["fieldname"])
|
||||
or dimension.get("default_dimension")
|
||||
}
|
||||
)
|
||||
|
||||
if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_pl"):
|
||||
debit_entry.update(
|
||||
{
|
||||
dimension["fieldname"]: asset.get(dimension["fieldname"])
|
||||
or dimension.get("default_dimension")
|
||||
}
|
||||
)
|
||||
|
||||
je.append("accounts", credit_entry)
|
||||
je.append("accounts", debit_entry)
|
||||
|
||||
je.flags.ignore_permissions = True
|
||||
je.flags.planned_depr_entry = True
|
||||
je.save()
|
||||
|
||||
depr_schedule.db_set("journal_entry", je.name)
|
||||
|
||||
if not je.meta.get_workflow():
|
||||
je.submit()
|
||||
idx = cint(asset_depr_schedule_doc.finance_book_id)
|
||||
row = asset.get("finance_books")[idx - 1]
|
||||
row.value_after_depreciation -= depr_schedule.depreciation_amount
|
||||
row.db_update()
|
||||
|
||||
|
||||
def get_depreciation_accounts(asset_category, company):
|
||||
fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None
|
||||
|
||||
accounts = frappe.db.get_value(
|
||||
"Asset Category Account",
|
||||
filters={"parent": asset.asset_category, "company_name": asset.company},
|
||||
filters={"parent": asset_category, "company_name": company},
|
||||
fieldname=[
|
||||
"fixed_asset_account",
|
||||
"accumulated_depreciation_account",
|
||||
@@ -201,7 +354,7 @@ def get_depreciation_accounts(asset):
|
||||
|
||||
if not accumulated_depreciation_account or not depreciation_expense_account:
|
||||
accounts = frappe.get_cached_value(
|
||||
"Company", asset.company, ["accumulated_depreciation_account", "depreciation_expense_account"]
|
||||
"Company", company, ["accumulated_depreciation_account", "depreciation_expense_account"]
|
||||
)
|
||||
|
||||
if not accumulated_depreciation_account:
|
||||
@@ -216,7 +369,7 @@ def get_depreciation_accounts(asset):
|
||||
):
|
||||
frappe.throw(
|
||||
_("Please set Depreciation related Accounts in Asset Category {0} or Company {1}").format(
|
||||
asset.asset_category, asset.company
|
||||
asset_category, company
|
||||
)
|
||||
)
|
||||
|
||||
@@ -565,8 +718,8 @@ def get_gl_entries_on_asset_disposal(
|
||||
|
||||
|
||||
def get_asset_details(asset, finance_book=None):
|
||||
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(
|
||||
asset
|
||||
fixed_asset_account, accumulated_depr_account, _ = get_depreciation_accounts(
|
||||
asset.asset_category, asset.company
|
||||
)
|
||||
disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company)
|
||||
depreciation_cost_center = asset.cost_center or depreciation_cost_center
|
||||
|
||||
@@ -754,6 +754,40 @@ class TestDepreciationMethods(AssetSetup):
|
||||
|
||||
self.assertEqual(schedules, expected_schedules)
|
||||
|
||||
def test_schedule_for_straight_line_method_with_daily_depreciation(self):
|
||||
asset = create_asset(
|
||||
calculate_depreciation=1,
|
||||
available_for_use_date="2023-01-01",
|
||||
purchase_date="2023-01-01",
|
||||
gross_purchase_amount=12000,
|
||||
depreciation_start_date="2023-01-31",
|
||||
total_number_of_depreciations=12,
|
||||
frequency_of_depreciation=1,
|
||||
daily_depreciation=1,
|
||||
)
|
||||
|
||||
expected_schedules = [
|
||||
["2023-01-31", 1019.18, 1019.18],
|
||||
["2023-02-28", 920.55, 1939.73],
|
||||
["2023-03-31", 1019.18, 2958.91],
|
||||
["2023-04-30", 986.3, 3945.21],
|
||||
["2023-05-31", 1019.18, 4964.39],
|
||||
["2023-06-30", 986.3, 5950.69],
|
||||
["2023-07-31", 1019.18, 6969.87],
|
||||
["2023-08-31", 1019.18, 7989.05],
|
||||
["2023-09-30", 986.3, 8975.35],
|
||||
["2023-10-31", 1019.18, 9994.53],
|
||||
["2023-11-30", 986.3, 10980.83],
|
||||
["2023-12-31", 1019.17, 12000.0],
|
||||
]
|
||||
|
||||
schedules = [
|
||||
[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
||||
for d in get_depr_schedule(asset.name, "Draft")
|
||||
]
|
||||
|
||||
self.assertEqual(schedules, expected_schedules)
|
||||
|
||||
def test_schedule_for_straight_line_method_for_existing_asset(self):
|
||||
asset = create_asset(
|
||||
calculate_depreciation=1,
|
||||
@@ -1724,6 +1758,7 @@ def create_asset(**args):
|
||||
"total_number_of_depreciations": args.total_number_of_depreciations or 5,
|
||||
"expected_value_after_useful_life": args.expected_value_after_useful_life or 0,
|
||||
"depreciation_start_date": args.depreciation_start_date,
|
||||
"daily_depreciation": args.daily_depreciation or 0,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"depreciation_method",
|
||||
"total_number_of_depreciations",
|
||||
"rate_of_depreciation",
|
||||
"daily_depreciation",
|
||||
"column_break_8",
|
||||
"frequency_of_depreciation",
|
||||
"expected_value_after_useful_life",
|
||||
@@ -174,12 +175,21 @@
|
||||
"label": "Number of Depreciations Booked",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
|
||||
"fieldname": "daily_depreciation",
|
||||
"fieldtype": "Check",
|
||||
"label": "Daily Depreciation",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-02-26 16:37:23.734806",
|
||||
"modified": "2023-08-10 22:22:09.722968",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Depreciation Schedule",
|
||||
|
||||
@@ -153,6 +153,7 @@ class AssetDepreciationSchedule(Document):
|
||||
self.frequency_of_depreciation = row.frequency_of_depreciation
|
||||
self.rate_of_depreciation = row.rate_of_depreciation
|
||||
self.expected_value_after_useful_life = row.expected_value_after_useful_life
|
||||
self.daily_depreciation = row.daily_depreciation
|
||||
self.status = "Draft"
|
||||
|
||||
def make_depr_schedule(
|
||||
@@ -499,29 +500,36 @@ def get_total_days(date, frequency):
|
||||
return date_diff(date, period_start_date)
|
||||
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_depreciation_amount(
|
||||
asset,
|
||||
depreciable_value,
|
||||
row,
|
||||
fb_row,
|
||||
schedule_idx=0,
|
||||
prev_depreciation_amount=0,
|
||||
has_wdv_or_dd_non_yearly_pro_rata=False,
|
||||
):
|
||||
if row.depreciation_method in ("Straight Line", "Manual"):
|
||||
return get_straight_line_or_manual_depr_amount(asset, row)
|
||||
if fb_row.depreciation_method in ("Straight Line", "Manual"):
|
||||
return get_straight_line_or_manual_depr_amount(asset, fb_row, schedule_idx)
|
||||
else:
|
||||
rate_of_depreciation = get_updated_rate_of_depreciation_for_wdv_and_dd(
|
||||
asset, depreciable_value, fb_row
|
||||
)
|
||||
return get_wdv_or_dd_depr_amount(
|
||||
depreciable_value,
|
||||
row.rate_of_depreciation,
|
||||
row.frequency_of_depreciation,
|
||||
rate_of_depreciation,
|
||||
fb_row.frequency_of_depreciation,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
)
|
||||
|
||||
|
||||
def get_straight_line_or_manual_depr_amount(asset, row):
|
||||
@erpnext.allow_regional
|
||||
def get_updated_rate_of_depreciation_for_wdv_and_dd(asset, depreciable_value, fb_row):
|
||||
return fb_row.rate_of_depreciation
|
||||
|
||||
|
||||
def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx):
|
||||
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
|
||||
if asset.flags.increase_in_asset_life:
|
||||
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
|
||||
@@ -534,11 +542,30 @@ def get_straight_line_or_manual_depr_amount(asset, row):
|
||||
)
|
||||
# if the Depreciation Schedule is being prepared for the first time
|
||||
else:
|
||||
return (
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
|
||||
if row.daily_depreciation:
|
||||
daily_depr_amount = (
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
) / date_diff(
|
||||
add_months(
|
||||
row.depreciation_start_date,
|
||||
flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
|
||||
* row.frequency_of_depreciation,
|
||||
),
|
||||
row.depreciation_start_date,
|
||||
)
|
||||
to_date = add_months(row.depreciation_start_date, schedule_idx * row.frequency_of_depreciation)
|
||||
from_date = add_months(
|
||||
row.depreciation_start_date, (schedule_idx - 1) * row.frequency_of_depreciation
|
||||
)
|
||||
return daily_depr_amount * date_diff(to_date, from_date)
|
||||
else:
|
||||
return (
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
|
||||
|
||||
|
||||
def get_wdv_or_dd_depr_amount(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"finance_book",
|
||||
"depreciation_method",
|
||||
"total_number_of_depreciations",
|
||||
"daily_depreciation",
|
||||
"column_break_5",
|
||||
"frequency_of_depreciation",
|
||||
"depreciation_start_date",
|
||||
@@ -17,6 +18,7 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "finance_book",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
@@ -32,6 +34,7 @@
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "total_number_of_depreciations",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
@@ -43,6 +46,7 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "frequency_of_depreciation",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
@@ -57,6 +61,7 @@
|
||||
"mandatory_depends_on": "eval:parent.doctype == 'Asset'"
|
||||
},
|
||||
{
|
||||
"columns": 1,
|
||||
"default": "0",
|
||||
"depends_on": "eval:parent.doctype == 'Asset'",
|
||||
"fieldname": "expected_value_after_useful_life",
|
||||
@@ -79,12 +84,19 @@
|
||||
"fieldname": "rate_of_depreciation",
|
||||
"fieldtype": "Percent",
|
||||
"label": "Rate of Depreciation"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
|
||||
"fieldname": "daily_depreciation",
|
||||
"fieldtype": "Check",
|
||||
"label": "Daily Depreciation"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-06-17 12:59:05.743683",
|
||||
"modified": "2023-08-10 22:10:36.576199",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Finance Book",
|
||||
@@ -93,5 +105,6 @@
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -64,10 +64,10 @@ class AssetValueAdjustment(Document):
|
||||
def make_depreciation_entry(self):
|
||||
asset = frappe.get_doc("Asset", self.asset)
|
||||
(
|
||||
fixed_asset_account,
|
||||
_,
|
||||
accumulated_depreciation_account,
|
||||
depreciation_expense_account,
|
||||
) = get_depreciation_accounts(asset)
|
||||
) = get_depreciation_accounts(asset.asset_category, asset.company)
|
||||
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
|
||||
"Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]
|
||||
@@ -78,9 +78,7 @@ class AssetValueAdjustment(Document):
|
||||
je.naming_series = depreciation_series
|
||||
je.posting_date = self.date
|
||||
je.company = self.company
|
||||
je.remark = _("Depreciation Entry against {0} worth {1}").format(
|
||||
self.asset, self.difference_amount
|
||||
)
|
||||
je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
|
||||
je.finance_book = self.finance_book
|
||||
|
||||
credit_entry = {
|
||||
|
||||
@@ -7,13 +7,14 @@ from itertools import chain
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.query_builder.functions import IfNull, Sum
|
||||
from frappe.utils import cstr, flt, formatdate, getdate
|
||||
from frappe.utils import add_months, cstr, flt, formatdate, getdate, nowdate, today
|
||||
|
||||
from erpnext.accounts.report.financial_statements import (
|
||||
get_fiscal_year_data,
|
||||
get_period_list,
|
||||
validate_fiscal_year,
|
||||
)
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.assets.doctype.asset.asset import get_asset_value_after_depreciation
|
||||
|
||||
|
||||
@@ -37,15 +38,26 @@ def get_conditions(filters):
|
||||
|
||||
if filters.get("company"):
|
||||
conditions["company"] = filters.company
|
||||
|
||||
if filters.filter_based_on == "Date Range":
|
||||
if not filters.from_date and not filters.to_date:
|
||||
filters.from_date = add_months(nowdate(), -12)
|
||||
filters.to_date = nowdate()
|
||||
|
||||
conditions[date_field] = ["between", [filters.from_date, filters.to_date]]
|
||||
if filters.filter_based_on == "Fiscal Year":
|
||||
elif filters.filter_based_on == "Fiscal Year":
|
||||
if not filters.from_fiscal_year and not filters.to_fiscal_year:
|
||||
default_fiscal_year = get_fiscal_year(today())[0]
|
||||
filters.from_fiscal_year = default_fiscal_year
|
||||
filters.to_fiscal_year = default_fiscal_year
|
||||
|
||||
fiscal_year = get_fiscal_year_data(filters.from_fiscal_year, filters.to_fiscal_year)
|
||||
validate_fiscal_year(fiscal_year, filters.from_fiscal_year, filters.to_fiscal_year)
|
||||
filters.year_start_date = getdate(fiscal_year.year_start_date)
|
||||
filters.year_end_date = getdate(fiscal_year.year_end_date)
|
||||
|
||||
conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]]
|
||||
|
||||
if filters.get("only_existing_assets"):
|
||||
conditions["is_existing_asset"] = filters.get("only_existing_assets")
|
||||
if filters.get("asset_category"):
|
||||
|
||||
@@ -273,7 +273,9 @@
|
||||
"fieldname": "html_llwp",
|
||||
"fieldtype": "HTML",
|
||||
"options": "<p>In your <b>Email Template</b>, you can use the following special variables:\n</p>\n<ul>\n <li>\n <code>{{ update_password_link }}</code>: A link where your supplier can set a new password to log into your portal.\n </li>\n <li>\n <code>{{ portal_link }}</code>: A link to this RFQ in your supplier portal.\n </li>\n <li>\n <code>{{ supplier_name }}</code>: The company name of your supplier.\n </li>\n <li>\n <code>{{ contact.salutation }} {{ contact.last_name }}</code>: The contact person of your supplier.\n </li><li>\n <code>{{ user_fullname }}</code>: Your full name.\n </li>\n </ul>\n<p></p>\n<p>Apart from these, you can access all values in this RFQ, like <code>{{ message_for_supplier }}</code> or <code>{{ terms }}</code>.</p>",
|
||||
"read_only": 1
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
@@ -287,7 +289,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-07-27 16:41:48.468873",
|
||||
"modified": "2023-08-08 16:30:10.870429",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Request for Quotation",
|
||||
|
||||
@@ -14,9 +14,6 @@ def set_print_templates_for_item_table(doc, settings):
|
||||
}
|
||||
}
|
||||
|
||||
if doc.meta.get_field("items"):
|
||||
doc.meta.get_field("items").hide_in_print_layout = ["uom", "stock_uom"]
|
||||
|
||||
doc.flags.compact_item_fields = ["description", "qty", "rate", "amount"]
|
||||
|
||||
if settings.compact_item_print:
|
||||
|
||||
@@ -233,7 +233,7 @@ class StatusUpdater(Document):
|
||||
if hasattr(d, "qty") and d.qty > 0 and self.get("is_return"):
|
||||
frappe.throw(_("For an item {0}, quantity must be negative number").format(d.item_code))
|
||||
|
||||
if hasattr(d, "item_code") and hasattr(d, "rate") and d.rate < 0:
|
||||
if hasattr(d, "item_code") and hasattr(d, "rate") and flt(d.rate) < 0:
|
||||
frappe.throw(_("For an item {0}, rate must be a positive number").format(d.item_code))
|
||||
|
||||
if d.doctype == args["source_dt"] and d.get(args["join_field"]):
|
||||
|
||||
@@ -70,6 +70,19 @@ treeviews = [
|
||||
"Department",
|
||||
]
|
||||
|
||||
demo_master_doctypes = [
|
||||
"item_group",
|
||||
"item",
|
||||
"customer_group",
|
||||
"supplier_group",
|
||||
"customer",
|
||||
"supplier",
|
||||
]
|
||||
demo_transaction_doctypes = [
|
||||
"purchase_order",
|
||||
"sales_order",
|
||||
]
|
||||
|
||||
jinja = {
|
||||
"methods": [
|
||||
"erpnext.stock.serial_batch_bundle.get_serial_or_batch_nos",
|
||||
@@ -429,7 +442,6 @@ scheduler_events = {
|
||||
"erpnext.controllers.accounts_controller.update_invoice_status",
|
||||
"erpnext.accounts.doctype.fiscal_year.fiscal_year.auto_create_fiscal_year",
|
||||
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
|
||||
"erpnext.assets.doctype.asset.depreciation.post_depreciation_entries",
|
||||
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
|
||||
"erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
|
||||
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history",
|
||||
@@ -454,6 +466,7 @@ scheduler_events = {
|
||||
"erpnext.setup.doctype.email_digest.email_digest.send",
|
||||
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.auto_update_latest_price_in_all_boms",
|
||||
"erpnext.crm.utils.open_leads_opportunities_based_on_todays_event",
|
||||
"erpnext.assets.doctype.asset.depreciation.post_depreciation_entries",
|
||||
],
|
||||
"monthly_long": [
|
||||
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
|
||||
|
||||
@@ -262,7 +262,6 @@ erpnext.patches.v14_0.update_reference_due_date_in_journal_entry
|
||||
erpnext.patches.v15_0.saudi_depreciation_warning
|
||||
erpnext.patches.v15_0.delete_saudi_doctypes
|
||||
erpnext.patches.v14_0.show_loan_management_deprecation_warning
|
||||
erpnext.patches.v14_0.update_subscription_details
|
||||
execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True)
|
||||
|
||||
[post_model_sync]
|
||||
@@ -322,6 +321,7 @@ erpnext.patches.v14_0.create_accounting_dimensions_for_closing_balance
|
||||
erpnext.patches.v14_0.update_closing_balances #14-07-2023
|
||||
execute:frappe.db.set_single_value("Accounts Settings", "merge_similar_account_heads", 0)
|
||||
erpnext.patches.v14_0.update_reference_type_in_journal_entry_accounts
|
||||
erpnext.patches.v14_0.update_subscription_details
|
||||
# below migration patches should always run last
|
||||
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
||||
execute:frappe.delete_doc_if_exists("Report", "Tax Detail")
|
||||
|
||||
@@ -10,7 +10,7 @@ def execute():
|
||||
frappe.db.set_value(
|
||||
subscription_invoice.document_type,
|
||||
subscription_invoice.invoice,
|
||||
"Subscription",
|
||||
"subscription",
|
||||
subscription_invoice.parent,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"css/erpnext.css": [
|
||||
"public/less/erpnext.less",
|
||||
"public/scss/call_popup.scss",
|
||||
"public/scss/point-of-sale.scss"
|
||||
],
|
||||
"js/erpnext-web.min.js": [
|
||||
"public/js/website_utils.js",
|
||||
"public/js/shopping_cart.js",
|
||||
"public/js/wishlist.js"
|
||||
],
|
||||
"css/erpnext-web.css": [
|
||||
"public/scss/website.scss",
|
||||
"public/scss/shopping_cart.scss"
|
||||
],
|
||||
"js/erpnext.min.js": [
|
||||
"public/js/conf.js",
|
||||
"public/js/utils.js",
|
||||
"public/js/queries.js",
|
||||
"public/js/sms_manager.js",
|
||||
"public/js/utils/party.js",
|
||||
"public/js/controllers/stock_controller.js",
|
||||
"public/js/payment/payments.js",
|
||||
"public/js/controllers/taxes_and_totals.js",
|
||||
"public/js/controllers/transaction.js",
|
||||
"public/js/templates/item_selector.html",
|
||||
"public/js/utils/item_selector.js",
|
||||
"public/js/help_links.js",
|
||||
"public/js/templates/item_quick_entry.html",
|
||||
"public/js/utils/customer_quick_entry.js",
|
||||
"public/js/utils/supplier_quick_entry.js",
|
||||
"public/js/education/student_button.html",
|
||||
"public/js/education/assessment_result_tool.html",
|
||||
"public/js/call_popup/call_popup.js",
|
||||
"public/js/utils/dimension_tree_filter.js",
|
||||
"public/js/telephony.js",
|
||||
"public/js/templates/call_link.html",
|
||||
"public/js/bulk_transaction_processing.js"
|
||||
],
|
||||
"js/item-dashboard.min.js": [
|
||||
"stock/dashboard/item_dashboard.html",
|
||||
"stock/dashboard/item_dashboard_list.html",
|
||||
"stock/dashboard/item_dashboard.js",
|
||||
"stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html",
|
||||
"stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html"
|
||||
],
|
||||
"js/point-of-sale.min.js": [
|
||||
"selling/page/point_of_sale/pos_item_selector.js",
|
||||
"selling/page/point_of_sale/pos_item_cart.js",
|
||||
"selling/page/point_of_sale/pos_item_details.js",
|
||||
"selling/page/point_of_sale/pos_number_pad.js",
|
||||
"selling/page/point_of_sale/pos_payment.js",
|
||||
"selling/page/point_of_sale/pos_past_order_list.js",
|
||||
"selling/page/point_of_sale/pos_past_order_summary.js",
|
||||
"selling/page/point_of_sale/pos_controller.js"
|
||||
],
|
||||
"js/bank-reconciliation-tool.min.js": [
|
||||
"public/js/bank_reconciliation_tool/data_table_manager.js",
|
||||
"public/js/bank_reconciliation_tool/number_card.js",
|
||||
"public/js/bank_reconciliation_tool/dialog_manager.js"
|
||||
],
|
||||
"js/e-commerce.min.js": [
|
||||
"e_commerce/product_ui/views.js",
|
||||
"e_commerce/product_ui/grid.js",
|
||||
"e_commerce/product_ui/list.js",
|
||||
"e_commerce/product_ui/search.js"
|
||||
]
|
||||
}
|
||||
@@ -28,5 +28,6 @@ import "./controllers/accounts.js"
|
||||
import "./utils/landed_taxes_and_charges_common.js";
|
||||
import "./utils/sales_common.js";
|
||||
import "./controllers/buying.js";
|
||||
import "./utils/demo.js";
|
||||
|
||||
// import { sum } from 'frappe/public/utils/util.js'
|
||||
|
||||
@@ -40,6 +40,12 @@ erpnext.setup.slides_settings = [
|
||||
{ fieldname: 'fy_start_date', label: __('Financial Year Begins On'), fieldtype: 'Date', reqd: 1 },
|
||||
// end date should be hidden (auto calculated)
|
||||
{ fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1, hidden: 1 },
|
||||
{ fieldtype: "Section Break" },
|
||||
{
|
||||
fieldname: 'setup_demo',
|
||||
label: __('Generate Demo Data for Exploration'),
|
||||
fieldtype: 'Check',
|
||||
description: 'If checked, we will create demo data for you to explore the system. This demo data can be erased later.'},
|
||||
],
|
||||
|
||||
onload: function (slide) {
|
||||
|
||||
91
erpnext/public/js/utils/demo.js
Normal file
91
erpnext/public/js/utils/demo.js
Normal file
@@ -0,0 +1,91 @@
|
||||
$(document).on("toolbar_setup", function () {
|
||||
if (frappe.boot.sysdefaults.demo_company) {
|
||||
render_clear_demo_button();
|
||||
}
|
||||
|
||||
// for first load after setup.
|
||||
frappe.realtime.on("demo_data_complete", () => {
|
||||
render_clear_demo_button();
|
||||
});
|
||||
});
|
||||
|
||||
function render_clear_demo_button() {
|
||||
let wait_for_onboaring_tours = setInterval(() => {
|
||||
if ($("#driver-page-overlay").length) {
|
||||
return;
|
||||
}
|
||||
setup_clear_demo_button();
|
||||
clearInterval(wait_for_onboaring_tours);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function setup_clear_demo_button() {
|
||||
let message_string = __(
|
||||
"Demo data is present on the system, erase data before starting real usage."
|
||||
);
|
||||
let $floatingBar = $(`
|
||||
<div class="flex justify-content-center" style="width: 100%;">
|
||||
<div class="flex justify-content-center flex-col shadow rounded p-2"
|
||||
style="
|
||||
background-color: #e0f2fe;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
z-index: 1;">
|
||||
<p style="margin: auto 0; padding-left: 10px; margin-right: 20px; font-size: 15px;">
|
||||
${message_string}
|
||||
</p>
|
||||
<button id="clear-demo" type="button"
|
||||
class="
|
||||
px-4
|
||||
py-2
|
||||
border
|
||||
border-transparent
|
||||
text-white
|
||||
"
|
||||
style="
|
||||
margin: auto 0;
|
||||
height: fit-content;
|
||||
background-color: #007bff;
|
||||
border-radius: 5px;
|
||||
margin-right: 10px
|
||||
"
|
||||
>
|
||||
Clear Demo Data
|
||||
</button>
|
||||
|
||||
<a type="button" id="dismiss-demo-banner" class="text-muted" style="align-self: center">
|
||||
<svg class="icon" style="">
|
||||
<use class="" href="#icon-close"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$("footer").append($floatingBar);
|
||||
|
||||
$("#clear-demo").on("click", function () {
|
||||
frappe.confirm(
|
||||
__("Are you sure you want to clear all demo data?"),
|
||||
() => {
|
||||
frappe.call({
|
||||
method: "erpnext.setup.demo.clear_demo_data",
|
||||
freeze: true,
|
||||
freeze_message: __("Clearing Demo Data..."),
|
||||
callback: function (r) {
|
||||
frappe.ui.toolbar.clear_cache();
|
||||
frappe.show_alert({
|
||||
message: __("Demo data cleared"),
|
||||
indicator: "green",
|
||||
});
|
||||
$("footer").remove($floatingBar);
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#dismiss-demo-banner").on("click", function () {
|
||||
$floatingBar.remove();
|
||||
});
|
||||
}
|
||||
@@ -108,18 +108,26 @@ class SalesOrder(SellingController):
|
||||
and customer = %s",
|
||||
(self.po_no, self.name, self.customer),
|
||||
)
|
||||
if (
|
||||
so
|
||||
and so[0][0]
|
||||
and not cint(
|
||||
if so and so[0][0]:
|
||||
if cint(
|
||||
frappe.db.get_single_value("Selling Settings", "allow_against_multiple_purchase_orders")
|
||||
)
|
||||
):
|
||||
frappe.msgprint(
|
||||
_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(
|
||||
so[0][0], self.po_no
|
||||
):
|
||||
frappe.msgprint(
|
||||
_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(
|
||||
frappe.bold(so[0][0]), frappe.bold(self.po_no)
|
||||
)
|
||||
)
|
||||
else:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Sales Order {0} already exists against Customer's Purchase Order {1}. To allow multiple Sales Orders, Enable {2} in {3}"
|
||||
).format(
|
||||
frappe.bold(so[0][0]),
|
||||
frappe.bold(self.po_no),
|
||||
frappe.bold(_("'Allow Multiple Sales Orders Against a Customer's Purchase Order'")),
|
||||
get_link_to_form("Selling Settings", "Selling Settings"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def validate_for_items(self):
|
||||
for d in self.get("items"):
|
||||
|
||||
@@ -2055,7 +2055,7 @@ def make_sales_order(**args):
|
||||
so.company = args.company or "_Test Company"
|
||||
so.customer = args.customer or "_Test Customer"
|
||||
so.currency = args.currency or "INR"
|
||||
so.po_no = args.po_no or "12345"
|
||||
so.po_no = args.po_no or ""
|
||||
if args.selling_price_list:
|
||||
so.selling_price_list = args.selling_price_list
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
"fieldname": "sales_update_frequency",
|
||||
"fieldtype": "Select",
|
||||
"label": "Sales Update Frequency in Company and Project",
|
||||
"options": "Each Transaction\nDaily\nMonthly",
|
||||
"options": "Monthly\nEach Transaction\nDaily",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -200,7 +200,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2023-02-04 12:37:53.380857",
|
||||
"modified": "2023-08-09 15:35:42.914354",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Selling Settings",
|
||||
@@ -229,4 +229,4 @@
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
202
erpnext/setup/demo.py
Normal file
202
erpnext/setup/demo.py
Normal file
@@ -0,0 +1,202 @@
|
||||
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import json
|
||||
import os
|
||||
from random import randint
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import add_days, getdate
|
||||
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
||||
from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account
|
||||
|
||||
|
||||
def setup_demo_data():
|
||||
from frappe.utils.telemetry import capture
|
||||
|
||||
capture("demo_data_creation_started", "erpnext")
|
||||
try:
|
||||
company = create_demo_company()
|
||||
process_masters()
|
||||
make_transactions(company)
|
||||
frappe.cache.delete_keys("bootinfo")
|
||||
frappe.publish_realtime("demo_data_complete")
|
||||
except Exception:
|
||||
frappe.log_error("Failed to create demo data")
|
||||
capture("demo_data_creation_failed", "erpnext", properties={"exception": frappe.get_traceback()})
|
||||
raise
|
||||
capture("demo_data_creation_completed", "erpnext")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def clear_demo_data():
|
||||
from frappe.utils.telemetry import capture
|
||||
|
||||
frappe.only_for("System Manager")
|
||||
|
||||
capture("demo_data_erased", "erpnext")
|
||||
try:
|
||||
company = frappe.db.get_single_value("Global Defaults", "demo_company")
|
||||
create_transaction_deletion_record(company)
|
||||
clear_masters()
|
||||
delete_company(company)
|
||||
default_company = frappe.db.get_single_value("Global Defaults", "default_company")
|
||||
frappe.db.set_default("company", default_company)
|
||||
except Exception:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error("Failed to erase demo data")
|
||||
frappe.throw(
|
||||
_("Failed to erase demo data, please delete the demo company manually."),
|
||||
title=_("Could Not Delete Demo Data"),
|
||||
)
|
||||
|
||||
|
||||
def create_demo_company():
|
||||
company = frappe.db.get_all("Company")[0].name
|
||||
company_doc = frappe.get_doc("Company", company)
|
||||
|
||||
# Make a dummy company
|
||||
new_company = frappe.new_doc("Company")
|
||||
new_company.company_name = company_doc.company_name + " (Demo)"
|
||||
new_company.abbr = company_doc.abbr + "D"
|
||||
new_company.enable_perpetual_inventory = 1
|
||||
new_company.default_currency = company_doc.default_currency
|
||||
new_company.country = company_doc.country
|
||||
new_company.chart_of_accounts_based_on = "Standard Template"
|
||||
new_company.chart_of_accounts = company_doc.chart_of_accounts
|
||||
new_company.insert()
|
||||
|
||||
# Set Demo Company as default to
|
||||
frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name)
|
||||
frappe.db.set_default("company", new_company.name)
|
||||
|
||||
bank_account = create_bank_account({"company_name": new_company.name})
|
||||
frappe.db.set_value("Company", new_company.name, "default_bank_account", bank_account.name)
|
||||
|
||||
return new_company.name
|
||||
|
||||
|
||||
def process_masters():
|
||||
for doctype in frappe.get_hooks("demo_master_doctypes"):
|
||||
data = read_data_file_using_hooks(doctype)
|
||||
if data:
|
||||
for item in json.loads(data):
|
||||
create_demo_record(item)
|
||||
|
||||
|
||||
def create_demo_record(doctype):
|
||||
frappe.get_doc(doctype).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def make_transactions(company):
|
||||
frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
|
||||
start_date = get_fiscal_year(date=getdate())[1]
|
||||
|
||||
for doctype in frappe.get_hooks("demo_transaction_doctypes"):
|
||||
data = read_data_file_using_hooks(doctype)
|
||||
if data:
|
||||
for item in json.loads(data):
|
||||
create_transaction(item, company, start_date)
|
||||
|
||||
convert_order_to_invoices()
|
||||
frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 0)
|
||||
|
||||
|
||||
def create_transaction(doctype, company, start_date):
|
||||
document_type = doctype.get("doctype")
|
||||
warehouse = get_warehouse(company)
|
||||
|
||||
if document_type == "Purchase Order":
|
||||
posting_date = get_random_date(start_date, 1, 30)
|
||||
else:
|
||||
posting_date = get_random_date(start_date, 31, 365)
|
||||
|
||||
doctype.update(
|
||||
{
|
||||
"company": company,
|
||||
"set_posting_time": 1,
|
||||
"transaction_date": posting_date,
|
||||
"schedule_date": posting_date,
|
||||
"delivery_date": posting_date,
|
||||
"set_warehouse": warehouse,
|
||||
}
|
||||
)
|
||||
|
||||
doc = frappe.get_doc(doctype)
|
||||
doc.save(ignore_permissions=True)
|
||||
doc.submit()
|
||||
|
||||
|
||||
def convert_order_to_invoices():
|
||||
for document in ["Purchase Order", "Sales Order"]:
|
||||
# Keep some orders intentionally unbilled/unpaid
|
||||
for i, order in enumerate(
|
||||
frappe.db.get_all(
|
||||
document, filters={"docstatus": 1}, fields=["name", "transaction_date"], limit=6
|
||||
)
|
||||
):
|
||||
|
||||
if document == "Purchase Order":
|
||||
invoice = make_purchase_invoice(order.name)
|
||||
elif document == "Sales Order":
|
||||
invoice = make_sales_invoice(order.name)
|
||||
|
||||
invoice.set_posting_time = 1
|
||||
invoice.posting_date = order.transaction_date
|
||||
invoice.due_date = order.transaction_date
|
||||
invoice.update_stock = 1
|
||||
invoice.submit()
|
||||
|
||||
if i % 2 != 0:
|
||||
payment = get_payment_entry(invoice.doctype, invoice.name)
|
||||
payment.reference_no = invoice.name
|
||||
payment.submit()
|
||||
|
||||
|
||||
def get_random_date(start_date, start_range, end_range):
|
||||
return add_days(start_date, randint(start_range, end_range))
|
||||
|
||||
|
||||
def create_transaction_deletion_record(company):
|
||||
transaction_deletion_record = frappe.new_doc("Transaction Deletion Record")
|
||||
transaction_deletion_record.company = company
|
||||
transaction_deletion_record.save(ignore_permissions=True)
|
||||
transaction_deletion_record.submit()
|
||||
|
||||
|
||||
def clear_masters():
|
||||
for doctype in frappe.get_hooks("demo_master_doctypes")[::-1]:
|
||||
data = read_data_file_using_hooks(doctype)
|
||||
if data:
|
||||
for item in json.loads(data):
|
||||
clear_demo_record(item)
|
||||
|
||||
|
||||
def clear_demo_record(document):
|
||||
document_type = document.get("doctype")
|
||||
del document["doctype"]
|
||||
doc = frappe.get_doc(document_type, document)
|
||||
frappe.delete_doc(doc.doctype, doc.name, ignore_permissions=True)
|
||||
|
||||
|
||||
def delete_company(company):
|
||||
frappe.db.set_single_value("Global Defaults", "demo_company", "")
|
||||
frappe.delete_doc("Company", company, ignore_permissions=True)
|
||||
|
||||
|
||||
def read_data_file_using_hooks(doctype):
|
||||
path = os.path.join(os.path.dirname(__file__), "demo_data")
|
||||
with open(os.path.join(path, doctype + ".json"), "r") as f:
|
||||
data = f.read()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_warehouse(company):
|
||||
warehouses = frappe.db.get_all("Warehouse", {"company": company, "is_group": 0})
|
||||
return warehouses[randint(0, 3)].name
|
||||
20
erpnext/setup/demo_data/customer.json
Normal file
20
erpnext/setup/demo_data/customer.json
Normal file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Customer",
|
||||
"customer_group": "Demo Customer Group",
|
||||
"territory": "All Territories",
|
||||
"customer_name": "Grant Plastics Ltd."
|
||||
},
|
||||
{
|
||||
"doctype": "Customer",
|
||||
"customer_group": "Demo Customer Group",
|
||||
"territory": "All Territories",
|
||||
"customer_name": "West View Software Ltd."
|
||||
},
|
||||
{
|
||||
"doctype": "Customer",
|
||||
"customer_group": "Demo Customer Group",
|
||||
"territory": "All Territories",
|
||||
"customer_name": "Palmer Productions Ltd."
|
||||
}
|
||||
]
|
||||
6
erpnext/setup/demo_data/customer_group.json
Normal file
6
erpnext/setup/demo_data/customer_group.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Customer Group",
|
||||
"customer_group_name": "Demo Customer Group"
|
||||
}
|
||||
]
|
||||
72
erpnext/setup/demo_data/item.json
Normal file
72
erpnext/setup/demo_data/item.json
Normal file
@@ -0,0 +1,72 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU001",
|
||||
"item_name": "T-shirt",
|
||||
"image": "https://images.pexels.com/photos/1484808/pexels-photo-1484808.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU002",
|
||||
"item_name": "Laptop",
|
||||
"image": "https://images.pexels.com/photos/3999538/pexels-photo-3999538.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU003",
|
||||
"item_name": "Book",
|
||||
"image": "https://images.pexels.com/photos/2422178/pexels-photo-2422178.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU004",
|
||||
"item_name": "Smartphone",
|
||||
"image": "https://images.pexels.com/photos/1647976/pexels-photo-1647976.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU005",
|
||||
"item_name": "Sneakers",
|
||||
"image": "https://images.pexels.com/photos/1598505/pexels-photo-1598505.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU006",
|
||||
"item_name": "Coffee Mug",
|
||||
"image": "https://images.pexels.com/photos/585753/pexels-photo-585753.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU007",
|
||||
"item_name": "Television",
|
||||
"image": "https://images.pexels.com/photos/8059376/pexels-photo-8059376.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU008",
|
||||
"item_name": "Backpack",
|
||||
"image": "https://images.pexels.com/photos/3731256/pexels-photo-3731256.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU009",
|
||||
"item_name": "Headphones",
|
||||
"image": "https://images.pexels.com/photos/3587478/pexels-photo-3587478.jpeg"
|
||||
},
|
||||
{
|
||||
"doctype": "Item",
|
||||
"item_group": "Demo Item Group",
|
||||
"item_code": "SKU010",
|
||||
"item_name": "Camera",
|
||||
"image": "https://images.pexels.com/photos/51383/photo-camera-subject-photographer-51383.jpeg"
|
||||
}
|
||||
]
|
||||
7
erpnext/setup/demo_data/item_group.json
Normal file
7
erpnext/setup/demo_data/item_group.json
Normal file
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Item Group",
|
||||
"item_group_name": "Demo Item Group",
|
||||
"parent_item_group": "All Item Groups"
|
||||
}
|
||||
]
|
||||
25
erpnext/setup/demo_data/journal_entry.json
Normal file
25
erpnext/setup/demo_data/journal_entry.json
Normal file
@@ -0,0 +1,25 @@
|
||||
[
|
||||
{
|
||||
"cheque_date": "2023-03-14",
|
||||
"cheque_no": "33",
|
||||
"doctype": "Journal Entry",
|
||||
"accounts": [
|
||||
{
|
||||
"party_type": "Customer",
|
||||
"party": "ABC Enterprises",
|
||||
"credit_in_account_currency": 40000.0,
|
||||
"debit_in_account_currency": 0.0,
|
||||
"doctype": "Journal Entry Account",
|
||||
"parentfield": "accounts",
|
||||
},
|
||||
{
|
||||
"credit_in_account_currency": 0.0,
|
||||
"debit_in_account_currency": 40000.0,
|
||||
"doctype": "Journal Entry Account",
|
||||
"parentfield": "accounts",
|
||||
}
|
||||
],
|
||||
"user_remark": "test",
|
||||
"voucher_type": "Bank Entry"
|
||||
}
|
||||
]
|
||||
57
erpnext/setup/demo_data/payment_entry.json
Normal file
57
erpnext/setup/demo_data/payment_entry.json
Normal file
@@ -0,0 +1,57 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Payment Entry",
|
||||
"payment_type": "Receive",
|
||||
"party_type": "Customer",
|
||||
"party": "ABC Enterprises",
|
||||
"paid_amount": 67000,
|
||||
"received_amount": 67000,
|
||||
"reference_no": "#ref0001",
|
||||
"source_exchange_rate": 1,
|
||||
"target_exchange_rate": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Payment Entry",
|
||||
"payment_type": "Receive",
|
||||
"party_type": "Customer",
|
||||
"party": "XYZ Corporation",
|
||||
"paid_amount": 500000,
|
||||
"received_amount": 500000,
|
||||
"reference_no": "#ref0001",
|
||||
"source_exchange_rate": 1,
|
||||
"target_exchange_rate": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Payment Entry",
|
||||
"payment_type": "Receive",
|
||||
"party_type": "Customer",
|
||||
"party": "KJPR Pvt. Ltd.",
|
||||
"paid_amount": 300000,
|
||||
"received_amount": 30000,
|
||||
"reference_no": "#ref0001",
|
||||
"source_exchange_rate": 1,
|
||||
"target_exchange_rate": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Payment Entry",
|
||||
"payment_type": "Pay",
|
||||
"party_type": "Supplier",
|
||||
"party": "DQ Industries",
|
||||
"paid_amount": 85000,
|
||||
"received_amount": 85000,
|
||||
"reference_no": "#ref0005",
|
||||
"source_exchange_rate": 1,
|
||||
"target_exchange_rate": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Payment Entry",
|
||||
"payment_type": "Pay",
|
||||
"party_type": "Supplier",
|
||||
"party": "KC Corp.",
|
||||
"paid_amount": 100000,
|
||||
"received_amount": 100000,
|
||||
"reference_no": "#ref0006",
|
||||
"source_exchange_rate": 1,
|
||||
"target_exchange_rate": 1
|
||||
}
|
||||
]
|
||||
162
erpnext/setup/demo_data/purchase_order.json
Normal file
162
erpnext/setup/demo_data/purchase_order.json
Normal file
@@ -0,0 +1,162 @@
|
||||
[
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Zuckerman Security Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU001",
|
||||
"parentfield": "items",
|
||||
"qty": 100.0,
|
||||
"rate": 400.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "MA Inc.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU002",
|
||||
"parentfield": "items",
|
||||
"qty": 50.0,
|
||||
"rate": 300.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Summit Traders Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU003",
|
||||
"parentfield": "items",
|
||||
"qty": 200.0,
|
||||
"rate": 523.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Zuckerman Security Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU004",
|
||||
"parentfield": "items",
|
||||
"qty": 60.0,
|
||||
"rate": 725.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "MA Inc.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU005",
|
||||
"parentfield": "items",
|
||||
"qty": 182.0,
|
||||
"rate": 222.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Summit Traders Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU006",
|
||||
"parentfield": "items",
|
||||
"qty": 250.0,
|
||||
"rate": 420.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Zuckerman Security Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU007",
|
||||
"parentfield": "items",
|
||||
"qty": 190.0,
|
||||
"rate": 375.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "MA Inc.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU008",
|
||||
"parentfield": "items",
|
||||
"qty": 121.0,
|
||||
"rate": 333.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Summit Traders Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU009",
|
||||
"parentfield": "items",
|
||||
"qty": 76.0,
|
||||
"rate": 700.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"supplier": "Zuckerman Security Ltd.",
|
||||
"doctype": "Purchase Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Purchase Order Item",
|
||||
"item_code": "SKU010",
|
||||
"parentfield": "items",
|
||||
"qty": 78.0,
|
||||
"rate": 500.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
122
erpnext/setup/demo_data/sales_order.json
Normal file
122
erpnext/setup/demo_data/sales_order.json
Normal file
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"customer": "Grant Plastics Ltd.",
|
||||
"doctype": "Sales Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU004",
|
||||
"parentfield": "items",
|
||||
"qty": 20.0,
|
||||
"rate": 1000.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"customer": "West View Software Ltd.",
|
||||
"doctype": "Sales Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU001",
|
||||
"parentfield": "items",
|
||||
"qty": 25.0,
|
||||
"rate": 800.0,
|
||||
"conversion_factor": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU002",
|
||||
"parentfield": "items",
|
||||
"qty": 15.0,
|
||||
"rate": 800.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"customer": "West View Software Ltd.",
|
||||
"doctype": "Sales Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU003",
|
||||
"parentfield": "items",
|
||||
"qty": 100,
|
||||
"rate": 500.0,
|
||||
"conversion_factor": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU006",
|
||||
"parentfield": "items",
|
||||
"qty": 100,
|
||||
"rate": 890.0,
|
||||
"conversion_factor": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU007",
|
||||
"parentfield": "items",
|
||||
"qty": 100,
|
||||
"rate": 900.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"customer": "Palmer Productions Ltd.",
|
||||
"doctype": "Sales Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU005",
|
||||
"parentfield": "items",
|
||||
"qty": 150.0,
|
||||
"rate": 100.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conversion_rate": 1.0,
|
||||
"customer": "Grant Plastics Ltd.",
|
||||
"doctype": "Sales Order",
|
||||
"update_stock": 1,
|
||||
"items": [
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU008",
|
||||
"parentfield": "items",
|
||||
"qty": 20.0,
|
||||
"rate": 500.0,
|
||||
"conversion_factor": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU009",
|
||||
"parentfield": "items",
|
||||
"qty": 40.0,
|
||||
"rate": 300.0,
|
||||
"conversion_factor": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "SKU010",
|
||||
"parentfield": "items",
|
||||
"qty": 50.0,
|
||||
"rate": 900.0,
|
||||
"conversion_factor": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
17
erpnext/setup/demo_data/supplier.json
Normal file
17
erpnext/setup/demo_data/supplier.json
Normal file
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Supplier",
|
||||
"supplier_group": "Demo Supplier Group",
|
||||
"supplier_name": "Zuckerman Security Ltd."
|
||||
},
|
||||
{
|
||||
"doctype": "Supplier",
|
||||
"supplier_group": "Demo Supplier Group",
|
||||
"supplier_name": "MA Inc."
|
||||
},
|
||||
{
|
||||
"doctype": "Supplier",
|
||||
"supplier_group": "Demo Supplier Group",
|
||||
"supplier_name": "Summit Traders Ltd."
|
||||
}
|
||||
]
|
||||
6
erpnext/setup/demo_data/supplier_group.json
Normal file
6
erpnext/setup/demo_data/supplier_group.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Supplier Group",
|
||||
"supplier_group_name": "Demo Supplier Group"
|
||||
}
|
||||
]
|
||||
@@ -18,6 +18,7 @@ frappe.ui.form.on("Company", {
|
||||
});
|
||||
},
|
||||
setup: function(frm) {
|
||||
frm.__rename_queue = "long";
|
||||
erpnext.company.setup_queries(frm);
|
||||
|
||||
frm.set_query("parent_company", function() {
|
||||
|
||||
@@ -195,6 +195,22 @@ class TestCompany(unittest.TestCase):
|
||||
child_company.save()
|
||||
self.test_basic_tree()
|
||||
|
||||
def test_demo_data(self):
|
||||
from erpnext.setup.demo import clear_demo_data, setup_demo_data
|
||||
|
||||
setup_demo_data()
|
||||
company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")})
|
||||
self.assertTrue(company_name)
|
||||
|
||||
for transaction in frappe.get_hooks("demo_transaction_doctypes"):
|
||||
self.assertTrue(frappe.db.exists(frappe.unscrub(transaction), {"company": company_name}))
|
||||
|
||||
clear_demo_data()
|
||||
company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")})
|
||||
self.assertFalse(company_name)
|
||||
for transaction in frappe.get_hooks("demo_transaction_doctypes"):
|
||||
self.assertFalse(frappe.db.exists(frappe.unscrub(transaction), {"company": company_name}))
|
||||
|
||||
|
||||
def create_company_communication(doctype, docname):
|
||||
comm = frappe.get_doc(
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"default_currency",
|
||||
"hide_currency_symbol",
|
||||
"disable_rounded_total",
|
||||
"disable_in_words"
|
||||
"disable_in_words",
|
||||
"demo_company"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -71,6 +72,14 @@
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Disable In Words"
|
||||
},
|
||||
{
|
||||
"fieldname": "demo_company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Demo Company",
|
||||
"options": "Company",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
|
||||
@@ -490,7 +490,7 @@ def update_stock_settings():
|
||||
|
||||
def create_bank_account(args):
|
||||
if not args.get("bank_account"):
|
||||
return
|
||||
args["bank_account"] = _("Bank Account")
|
||||
|
||||
company_name = args.get("company_name")
|
||||
bank_account_group = frappe.db.get_value(
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
from .operations import install_fixtures as fixtures
|
||||
from erpnext.setup.demo import setup_demo_data
|
||||
from erpnext.setup.setup_wizard.operations import install_fixtures as fixtures
|
||||
|
||||
|
||||
def get_setup_stages(args=None):
|
||||
@@ -36,6 +37,11 @@ def get_setup_stages(args=None):
|
||||
{"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")},
|
||||
],
|
||||
},
|
||||
{
|
||||
"status": _("Setting up demo data"),
|
||||
"fail_msg": _("Failed to setup demo data"),
|
||||
"tasks": [{"fn": setup_demo, "args": args, "fail_msg": _("Failed to setup demo data")}],
|
||||
},
|
||||
{
|
||||
"status": _("Wrapping up"),
|
||||
"fail_msg": _("Failed to login"),
|
||||
@@ -63,6 +69,11 @@ def fin(args):
|
||||
login_as_first_user(args)
|
||||
|
||||
|
||||
def setup_demo(args):
|
||||
if args.get("setup_demo"):
|
||||
frappe.enqueue(setup_demo_data, enqueue_after_commit=True, at_front=True)
|
||||
|
||||
|
||||
def login_as_first_user(args):
|
||||
if args.get("email") and hasattr(frappe.local, "login_manager"):
|
||||
frappe.local.login_manager.login_as(args.get("email"))
|
||||
|
||||
@@ -61,6 +61,8 @@ def boot_session(bootinfo):
|
||||
)
|
||||
bootinfo.party_account_types = frappe._dict(party_account_types)
|
||||
|
||||
bootinfo.sysdefaults.demo_company = frappe.db.get_single_value("Global Defaults", "demo_company")
|
||||
|
||||
|
||||
def update_page_info(bootinfo):
|
||||
bootinfo.page_info.update(
|
||||
|
||||
@@ -703,7 +703,7 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
|
||||
def test_dn_billing_status_case1(self):
|
||||
# SO -> DN -> SI
|
||||
so = make_sales_order()
|
||||
so = make_sales_order(po_no="12345")
|
||||
dn = create_dn_against_so(so.name, delivered_qty=2)
|
||||
|
||||
self.assertEqual(dn.status, "To Bill")
|
||||
@@ -730,7 +730,7 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
make_sales_invoice,
|
||||
)
|
||||
|
||||
so = make_sales_order()
|
||||
so = make_sales_order(po_no="12345")
|
||||
|
||||
si = make_sales_invoice(so.name)
|
||||
si.get("items")[0].qty = 5
|
||||
@@ -774,7 +774,7 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
|
||||
|
||||
so = make_sales_order()
|
||||
so = make_sales_order(po_no="12345")
|
||||
|
||||
dn1 = make_delivery_note(so.name)
|
||||
dn1.get("items")[0].qty = 2
|
||||
@@ -820,7 +820,7 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_delivery_note
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
||||
|
||||
so = make_sales_order()
|
||||
so = make_sales_order(po_no="12345")
|
||||
|
||||
si = make_sales_invoice(so.name)
|
||||
si.submit()
|
||||
@@ -1227,6 +1227,7 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
self.assertEqual(get_reserved_qty(item, warehouse), 0 if dont_reserve_qty else qty_to_reserve)
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.rollback()
|
||||
frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0)
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,12 @@ def get_data(filters):
|
||||
item.item_name,
|
||||
item.description,
|
||||
)
|
||||
.where((bin.projected_qty < 0) & (wh.name == bin.warehouse) & (bin.item_code == item.name))
|
||||
.where(
|
||||
(item.disabled == 0)
|
||||
& (bin.projected_qty < 0)
|
||||
& (wh.name == bin.warehouse)
|
||||
& (bin.item_code == item.name)
|
||||
)
|
||||
.orderby(bin.projected_qty)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user