mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-17 02:26:33 +00:00
Merge branch 'develop' of https://github.com/frappe/erpnext into loan_refund_jv
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company or not frappe.db.count('E Invoice User'):
|
||||
return
|
||||
|
||||
frappe.reload_doc("regional", "doctype", "e_invoice_user")
|
||||
for creds in frappe.db.get_all('E Invoice User', fields=['name', 'gstin']):
|
||||
company_name = frappe.db.sql("""
|
||||
select dl.link_name from `tabAddress` a, `tabDynamic Link` dl
|
||||
where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
|
||||
""", (creds.get('gstin')))
|
||||
if company_name and len(company_name) > 0:
|
||||
frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])
|
||||
72
erpnext/patches/v12_0/add_einvoice_status_field.py
Normal file
72
erpnext/patches/v12_0/add_einvoice_status_field.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
# move hidden einvoice fields to a different section
|
||||
custom_fields = {
|
||||
'Sales Invoice': [
|
||||
dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
|
||||
print_hide=1, hidden=1),
|
||||
|
||||
dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
|
||||
no_copy=1, print_hide=1),
|
||||
|
||||
dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
|
||||
|
||||
dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
|
||||
no_copy=1, print_hide=1),
|
||||
|
||||
dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
|
||||
no_copy=1, print_hide=1, read_only=1),
|
||||
|
||||
dict(fieldname='signed_qr_code', label='Signed QRCode', fieldtype='Code', options='JSON', hidden=1, insert_after='signed_einvoice',
|
||||
no_copy=1, print_hide=1, read_only=1),
|
||||
|
||||
dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, insert_after='signed_qr_code',
|
||||
no_copy=1, print_hide=1, read_only=1),
|
||||
|
||||
dict(fieldname='einvoice_status', label='E-Invoice Status', fieldtype='Select', insert_after='qrcode_image',
|
||||
options='\nPending\nGenerated\nCancelled\nFailed', default=None, hidden=1, no_copy=1, print_hide=1, read_only=1),
|
||||
|
||||
dict(fieldname='failure_description', label='E-Invoice Failure Description', fieldtype='Code', options='JSON',
|
||||
hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
|
||||
]
|
||||
}
|
||||
create_custom_fields(custom_fields, update=True)
|
||||
|
||||
if frappe.db.exists('E Invoice Settings') and frappe.db.get_single_value('E Invoice Settings', 'enable'):
|
||||
frappe.db.sql('''
|
||||
UPDATE `tabSales Invoice` SET einvoice_status = 'Pending'
|
||||
WHERE
|
||||
posting_date >= '2021-04-01'
|
||||
AND ifnull(irn, '') = ''
|
||||
AND ifnull(`billing_address_gstin`, '') != ifnull(`company_gstin`, '')
|
||||
AND ifnull(gst_category, '') in ('Registered Regular', 'SEZ', 'Overseas', 'Deemed Export')
|
||||
''')
|
||||
|
||||
# set appropriate statuses
|
||||
frappe.db.sql('''UPDATE `tabSales Invoice` SET einvoice_status = 'Generated'
|
||||
WHERE ifnull(irn, '') != '' AND ifnull(irn_cancelled, 0) = 0''')
|
||||
|
||||
frappe.db.sql('''UPDATE `tabSales Invoice` SET einvoice_status = 'Cancelled'
|
||||
WHERE ifnull(irn_cancelled, 0) = 1''')
|
||||
|
||||
# set correct acknowledgement in e-invoices
|
||||
einvoices = frappe.get_all('Sales Invoice', {'irn': ['is', 'set']}, ['name', 'signed_einvoice'])
|
||||
|
||||
if einvoices:
|
||||
for inv in einvoices:
|
||||
signed_einvoice = inv.get('signed_einvoice')
|
||||
if signed_einvoice:
|
||||
signed_einvoice = json.loads(signed_einvoice)
|
||||
frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_no', signed_einvoice.get('AckNo'), update_modified=False)
|
||||
frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_date', signed_einvoice.get('AckDt'), update_modified=False)
|
||||
@@ -0,0 +1,20 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
if frappe.db.exists('Report', 'E-Invoice Summary') and \
|
||||
not frappe.db.get_value('Custom Role', dict(report='E-Invoice Summary')):
|
||||
frappe.get_doc(dict(
|
||||
doctype='Custom Role',
|
||||
report='E-Invoice Summary',
|
||||
roles= [
|
||||
dict(role='Accounts User'),
|
||||
dict(role='Accounts Manager')
|
||||
]
|
||||
)).insert()
|
||||
18
erpnext/patches/v12_0/add_ewaybill_validity_field.py
Normal file
18
erpnext/patches/v12_0/add_ewaybill_validity_field.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
custom_fields = {
|
||||
'Sales Invoice': [
|
||||
dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
|
||||
depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
|
||||
]
|
||||
}
|
||||
create_custom_fields(custom_fields, update=True)
|
||||
59
erpnext/patches/v12_0/setup_einvoice_fields.py
Normal file
59
erpnext/patches/v12_0/setup_einvoice_fields.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
from erpnext.regional.india.setup import add_permissions, add_print_formats
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
frappe.reload_doc("custom", "doctype", "custom_field")
|
||||
frappe.reload_doc("regional", "doctype", "e_invoice_settings")
|
||||
custom_fields = {
|
||||
'Sales Invoice': [
|
||||
dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
|
||||
depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
|
||||
|
||||
dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
|
||||
|
||||
dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
|
||||
|
||||
dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
|
||||
depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
|
||||
|
||||
dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
|
||||
depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
|
||||
|
||||
dict(fieldname='signed_einvoice', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
|
||||
|
||||
dict(fieldname='signed_qr_code', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
|
||||
|
||||
dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, no_copy=1, print_hide=1, read_only=1)
|
||||
]
|
||||
}
|
||||
create_custom_fields(custom_fields, update=True)
|
||||
add_permissions()
|
||||
add_print_formats()
|
||||
|
||||
einvoice_cond = 'in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
|
||||
t = {
|
||||
'mode_of_transport': [{'default': None}],
|
||||
'distance': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.transporter'}],
|
||||
'gst_vehicle_type': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
|
||||
'lr_date': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
|
||||
'lr_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
|
||||
'vehicle_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
|
||||
'ewaybill': [
|
||||
{'read_only_depends_on': 'eval:doc.irn && doc.ewaybill'},
|
||||
{'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)'}
|
||||
]
|
||||
}
|
||||
|
||||
for field, conditions in t.items():
|
||||
for c in conditions:
|
||||
[(prop, value)] = c.items()
|
||||
frappe.db.set_value('Custom Field', { 'fieldname': field }, prop, value)
|
||||
14
erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
Normal file
14
erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
irn_cancelled_field = frappe.db.exists('Custom Field', {'dt': 'Sales Invoice', 'fieldname': 'irn_cancelled'})
|
||||
if irn_cancelled_field:
|
||||
frappe.db.set_value('Custom Field', irn_cancelled_field, 'depends_on', 'eval: doc.irn')
|
||||
frappe.db.set_value('Custom Field', irn_cancelled_field, 'read_only', 0)
|
||||
@@ -2,14 +2,28 @@ import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
try:
|
||||
frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')")
|
||||
frappe.db.sql("UPDATE `tabSerial No` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')")
|
||||
#handle type casting for is_cancelled field
|
||||
module_doctypes = (
|
||||
('stock', 'Stock Ledger Entry'),
|
||||
('stock', 'Serial No'),
|
||||
('accounts', 'GL Entry')
|
||||
)
|
||||
|
||||
frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 1 where is_cancelled = 'Yes'")
|
||||
frappe.db.sql("UPDATE `tabSerial No` SET is_cancelled = 1 where is_cancelled = 'Yes'")
|
||||
for module, doctype in module_doctypes:
|
||||
if (not frappe.db.has_column(doctype, "is_cancelled")
|
||||
or frappe.db.get_column_type(doctype, "is_cancelled").lower() == "int(1)"
|
||||
):
|
||||
continue
|
||||
|
||||
frappe.reload_doc("stock", "doctype", "stock_ledger_entry")
|
||||
frappe.reload_doc("stock", "doctype", "serial_no")
|
||||
except Exception:
|
||||
pass
|
||||
frappe.db.sql("""
|
||||
UPDATE `tab{doctype}`
|
||||
SET is_cancelled = 0
|
||||
where is_cancelled in ('', NULL, 'No')"""
|
||||
.format(doctype=doctype))
|
||||
frappe.db.sql("""
|
||||
UPDATE `tab{doctype}`
|
||||
SET is_cancelled = 1
|
||||
where is_cancelled = 'Yes'"""
|
||||
.format(doctype=doctype))
|
||||
|
||||
frappe.reload_doc(module, "doctype", frappe.scrub(doctype))
|
||||
|
||||
63
erpnext/patches/v13_0/add_bin_unique_constraint.py
Normal file
63
erpnext/patches/v13_0/add_bin_unique_constraint.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import frappe
|
||||
|
||||
from erpnext.stock.stock_balance import (
|
||||
get_balance_qty_from_sle,
|
||||
get_indented_qty,
|
||||
get_ordered_qty,
|
||||
get_planned_qty,
|
||||
get_reserved_qty,
|
||||
)
|
||||
from erpnext.stock.utils import get_bin
|
||||
|
||||
|
||||
def execute():
|
||||
delete_broken_bins()
|
||||
delete_and_patch_duplicate_bins()
|
||||
|
||||
def delete_broken_bins():
|
||||
# delete useless bins
|
||||
frappe.db.sql("delete from `tabBin` where item_code is null or warehouse is null")
|
||||
|
||||
def delete_and_patch_duplicate_bins():
|
||||
|
||||
duplicate_bins = frappe.db.sql("""
|
||||
SELECT
|
||||
item_code, warehouse, count(*) as bin_count
|
||||
FROM
|
||||
tabBin
|
||||
GROUP BY
|
||||
item_code, warehouse
|
||||
HAVING
|
||||
bin_count > 1
|
||||
""", as_dict=1)
|
||||
|
||||
for duplicate_bin in duplicate_bins:
|
||||
item_code = duplicate_bin.item_code
|
||||
warehouse = duplicate_bin.warehouse
|
||||
existing_bins = frappe.get_list("Bin",
|
||||
filters={
|
||||
"item_code": item_code,
|
||||
"warehouse": warehouse
|
||||
},
|
||||
fields=["name"],
|
||||
order_by="creation",)
|
||||
|
||||
# keep last one
|
||||
existing_bins.pop()
|
||||
|
||||
for broken_bin in existing_bins:
|
||||
frappe.delete_doc("Bin", broken_bin.name)
|
||||
|
||||
qty_dict = {
|
||||
"reserved_qty": get_reserved_qty(item_code, warehouse),
|
||||
"indented_qty": get_indented_qty(item_code, warehouse),
|
||||
"ordered_qty": get_ordered_qty(item_code, warehouse),
|
||||
"planned_qty": get_planned_qty(item_code, warehouse),
|
||||
"actual_qty": get_balance_qty_from_sle(item_code, warehouse)
|
||||
}
|
||||
|
||||
bin = get_bin(item_code, warehouse)
|
||||
bin.update(qty_dict)
|
||||
bin.update_reserved_qty_for_production()
|
||||
bin.update_reserved_qty_for_sub_contracting()
|
||||
bin.db_update()
|
||||
@@ -0,0 +1,57 @@
|
||||
import json
|
||||
from typing import List, Union
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
|
||||
|
||||
|
||||
def execute():
|
||||
"""
|
||||
Convert all Item links to Website Item link values in
|
||||
exisitng 'Item Card Group' Web Page Block data.
|
||||
"""
|
||||
frappe.reload_doc("e_commerce", "web_template", "item_card_group")
|
||||
|
||||
blocks = frappe.db.get_all(
|
||||
"Web Page Block",
|
||||
filters={"web_template": "Item Card Group"},
|
||||
fields=["parent", "web_template_values", "name"]
|
||||
)
|
||||
|
||||
fields = generate_fields_to_edit()
|
||||
|
||||
for block in blocks:
|
||||
web_template_value = json.loads(block.get('web_template_values'))
|
||||
|
||||
for field in fields:
|
||||
item = web_template_value.get(field)
|
||||
if not item:
|
||||
continue
|
||||
|
||||
if frappe.db.exists("Website Item", {"item_code": item}):
|
||||
website_item = frappe.db.get_value("Website Item", {"item_code": item})
|
||||
else:
|
||||
website_item = make_new_website_item(item)
|
||||
|
||||
if website_item:
|
||||
web_template_value[field] = website_item
|
||||
|
||||
frappe.db.set_value("Web Page Block", block.name, "web_template_values", json.dumps(web_template_value))
|
||||
|
||||
def generate_fields_to_edit() -> List:
|
||||
fields = []
|
||||
for i in range(1, 13):
|
||||
fields.append(f"card_{i}_item") # fields like 'card_1_item', etc.
|
||||
|
||||
return fields
|
||||
|
||||
def make_new_website_item(item: str) -> Union[str, None]:
|
||||
try:
|
||||
doc = frappe.get_doc("Item", item)
|
||||
web_item = make_website_item(doc) # returns [website_item.name, item_name]
|
||||
return web_item[0]
|
||||
except Exception:
|
||||
title = f"{item}: Error while converting to Website Item "
|
||||
frappe.log_error(title + "for Item Card Group Template" + "\n\n" + frappe.get_traceback(), title=title)
|
||||
return None
|
||||
72
erpnext/patches/v13_0/create_website_items.py
Normal file
72
erpnext/patches/v13_0/create_website_items.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import frappe
|
||||
|
||||
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("e_commerce", "doctype", "website_item")
|
||||
frappe.reload_doc("e_commerce", "doctype", "website_item_tabbed_section")
|
||||
frappe.reload_doc("e_commerce", "doctype", "website_offer")
|
||||
frappe.reload_doc("e_commerce", "doctype", "recommended_items")
|
||||
frappe.reload_doc("e_commerce", "doctype", "e_commerce_settings")
|
||||
frappe.reload_doc("stock", "doctype", "item")
|
||||
|
||||
item_fields = ["item_code", "item_name", "item_group", "stock_uom", "brand", "image",
|
||||
"has_variants", "variant_of", "description", "weightage"]
|
||||
web_fields_to_map = ["route", "slideshow", "website_image_alt",
|
||||
"website_warehouse", "web_long_description", "website_content", "thumbnail"]
|
||||
|
||||
# get all valid columns (fields) from Item master DB schema
|
||||
item_table_fields = frappe.db.sql("desc `tabItem`", as_dict=1) # nosemgrep
|
||||
item_table_fields = [d.get('Field') for d in item_table_fields]
|
||||
|
||||
# prepare fields to query from Item, check if the web field exists in Item master
|
||||
web_query_fields = []
|
||||
for web_field in web_fields_to_map:
|
||||
if web_field in item_table_fields:
|
||||
web_query_fields.append(web_field)
|
||||
item_fields.append(web_field)
|
||||
|
||||
# check if the filter fields exist in Item master
|
||||
or_filters = {}
|
||||
for field in ["show_in_website", "show_variant_in_website"]:
|
||||
if field in item_table_fields:
|
||||
or_filters[field] = 1
|
||||
|
||||
if not web_query_fields or not or_filters:
|
||||
# web fields to map are not present in Item master schema
|
||||
# most likely a fresh installation that doesnt need this patch
|
||||
return
|
||||
|
||||
items = frappe.db.get_all(
|
||||
"Item",
|
||||
fields=item_fields,
|
||||
or_filters=or_filters
|
||||
)
|
||||
total_count = len(items)
|
||||
|
||||
for count, item in enumerate(items, start=1):
|
||||
if frappe.db.exists("Website Item", {"item_code": item.item_code}):
|
||||
continue
|
||||
|
||||
# make new website item from item (publish item)
|
||||
website_item = make_website_item(item, save=False)
|
||||
website_item.ranking = item.get("weightage")
|
||||
|
||||
for field in web_fields_to_map:
|
||||
website_item.update({field: item.get(field)})
|
||||
|
||||
website_item.save()
|
||||
|
||||
# move Website Item Group & Website Specification table to Website Item
|
||||
for doctype in ("Website Item Group", "Item Website Specification"):
|
||||
frappe.db.set_value(
|
||||
doctype,
|
||||
{"parenttype": "Item", "parent": item.item_code}, # filters
|
||||
{"parenttype": "Website Item", "parent": website_item.name} # value dict
|
||||
)
|
||||
|
||||
if count % 20 == 0: # commit after every 20 items
|
||||
frappe.db.commit()
|
||||
|
||||
frappe.utils.update_progress_bar('Creating Website Items', count, total_count)
|
||||
13
erpnext/patches/v13_0/delete_bank_reconciliation_detail.py
Normal file
13
erpnext/patches/v13_0/delete_bank_reconciliation_detail.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2019, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
|
||||
if frappe.db.exists('DocType', 'Bank Reconciliation Detail') and \
|
||||
frappe.db.exists('DocType', 'Bank Clearance Detail'):
|
||||
|
||||
frappe.delete_doc("DocType", 'Bank Reconciliation Detail', force=1)
|
||||
@@ -12,6 +12,7 @@ def execute():
|
||||
|
||||
for report in reports_to_delete:
|
||||
if frappe.db.exists("Report", report):
|
||||
delete_links_from_desktop_icons(report)
|
||||
delete_auto_email_reports(report)
|
||||
check_and_delete_linked_reports(report)
|
||||
|
||||
@@ -22,3 +23,9 @@ def delete_auto_email_reports(report):
|
||||
auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"])
|
||||
for auto_email_report in auto_email_reports:
|
||||
frappe.delete_doc("Auto Email Report", auto_email_report[0])
|
||||
|
||||
def delete_links_from_desktop_icons(report):
|
||||
""" Check for one or multiple Desktop Icons and delete """
|
||||
desktop_icons = frappe.db.get_values("Desktop Icon", {"_report": report}, ["name"])
|
||||
for desktop_icon in desktop_icons:
|
||||
frappe.delete_doc("Desktop Icon", desktop_icon[0])
|
||||
@@ -1,9 +0,0 @@
|
||||
import click
|
||||
|
||||
|
||||
def execute():
|
||||
click.secho(
|
||||
"Indian E-Invoicing integration is moved to a separate app and will be removed from ERPNext in version-14.\n"
|
||||
"Please install the app to continue using the integration: https://github.com/frappe/erpnext_gst_compliance",
|
||||
fg="yellow",
|
||||
)
|
||||
19
erpnext/patches/v13_0/enable_provisional_accounting.py
Normal file
19
erpnext/patches/v13_0/enable_provisional_accounting.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("setup", "doctype", "company")
|
||||
|
||||
company = frappe.qb.DocType("Company")
|
||||
|
||||
frappe.qb.update(
|
||||
company
|
||||
).set(
|
||||
company.enable_provisional_accounting_for_non_stock_items, company.enable_perpetual_inventory_for_non_stock_items
|
||||
).set(
|
||||
company.default_provisional_account, company.service_received_but_not_billed
|
||||
).where(
|
||||
company.enable_perpetual_inventory_for_non_stock_items == 1
|
||||
).where(
|
||||
company.service_received_but_not_billed.isnotnull()
|
||||
).run()
|
||||
16
erpnext/patches/v13_0/fetch_thumbnail_in_website_items.py
Normal file
16
erpnext/patches/v13_0/fetch_thumbnail_in_website_items.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
if frappe.db.has_column("Item", "thumbnail"):
|
||||
website_item = frappe.qb.DocType("Website Item").as_("wi")
|
||||
item = frappe.qb.DocType("Item")
|
||||
|
||||
frappe.qb.update(website_item).inner_join(item).on(
|
||||
website_item.item_code == item.item_code
|
||||
).set(
|
||||
website_item.thumbnail, item.thumbnail
|
||||
).where(
|
||||
website_item.website_image.notnull()
|
||||
& website_item.thumbnail.isnull()
|
||||
).run()
|
||||
10
erpnext/patches/v13_0/hospitality_deprecation_warning.py
Normal file
10
erpnext/patches/v13_0/hospitality_deprecation_warning.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import click
|
||||
|
||||
|
||||
def execute():
|
||||
|
||||
click.secho(
|
||||
"Hospitality domain is moved to a separate app and will be removed from ERPNext in version-14.\n"
|
||||
"When upgrading to ERPNext version-14, please install the app to continue using the Hospitality domain: https://github.com/frappe/hospitality",
|
||||
fg="yellow",
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
homepage = frappe.get_doc("Homepage")
|
||||
|
||||
for row in homepage.products:
|
||||
web_item = frappe.db.get_value("Website Item", {"item_code": row.item_code}, "name")
|
||||
if not web_item:
|
||||
continue
|
||||
|
||||
row.item_code = web_item
|
||||
|
||||
homepage.flags.ignore_mandatory = True
|
||||
homepage.save()
|
||||
@@ -10,8 +10,15 @@ from erpnext.setup.install import add_non_standard_user_types
|
||||
def execute():
|
||||
doctype_dict = {
|
||||
'projects': ['Timesheet'],
|
||||
'payroll': ['Salary Slip', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission'],
|
||||
'hr': ['Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request']
|
||||
'payroll': [
|
||||
'Salary Slip', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission',
|
||||
'Employee Benefit Application', 'Employee Benefit Claim'
|
||||
],
|
||||
'hr': [
|
||||
'Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request',
|
||||
'Holiday List', 'Employee Advance', 'Training Program', 'Training Feedback',
|
||||
'Shift Request', 'Employee Grievance', 'Employee Referral', 'Travel Request'
|
||||
]
|
||||
}
|
||||
|
||||
for module, doctypes in doctype_dict.items():
|
||||
|
||||
62
erpnext/patches/v13_0/populate_e_commerce_settings.py
Normal file
62
erpnext/patches/v13_0/populate_e_commerce_settings.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import frappe
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("e_commerce", "doctype", "e_commerce_settings")
|
||||
frappe.reload_doc("portal", "doctype", "website_filter_field")
|
||||
frappe.reload_doc("portal", "doctype", "website_attribute")
|
||||
|
||||
products_settings_fields = [
|
||||
"hide_variants", "products_per_page",
|
||||
"enable_attribute_filters", "enable_field_filters"
|
||||
]
|
||||
|
||||
shopping_cart_settings_fields = [
|
||||
"enabled", "show_attachments", "show_price",
|
||||
"show_stock_availability", "enable_variants", "show_contact_us_button",
|
||||
"show_quantity_in_website", "show_apply_coupon_code_in_website",
|
||||
"allow_items_not_in_stock", "company", "price_list", "default_customer_group",
|
||||
"quotation_series", "enable_checkout", "payment_success_url",
|
||||
"payment_gateway_account", "save_quotations_as_draft"
|
||||
]
|
||||
|
||||
settings = frappe.get_doc("E Commerce Settings")
|
||||
|
||||
def map_into_e_commerce_settings(doctype, fields):
|
||||
singles = frappe.qb.DocType("Singles")
|
||||
query = (
|
||||
frappe.qb.from_(singles)
|
||||
.select(
|
||||
singles["field"], singles.value
|
||||
).where(
|
||||
(singles.doctype == doctype)
|
||||
& (singles["field"].isin(fields))
|
||||
)
|
||||
)
|
||||
data = query.run(as_dict=True)
|
||||
|
||||
# {'enable_attribute_filters': '1', ...}
|
||||
mapper = {row.field: row.value for row in data}
|
||||
|
||||
for key, value in mapper.items():
|
||||
value = cint(value) if (value and value.isdigit()) else value
|
||||
settings.update({key: value})
|
||||
|
||||
settings.save()
|
||||
|
||||
# shift data to E Commerce Settings
|
||||
map_into_e_commerce_settings("Products Settings", products_settings_fields)
|
||||
map_into_e_commerce_settings("Shopping Cart Settings", shopping_cart_settings_fields)
|
||||
|
||||
# move filters and attributes tables to E Commerce Settings from Products Settings
|
||||
for doctype in ("Website Filter Field", "Website Attribute"):
|
||||
frappe.db.set_value(
|
||||
doctype,
|
||||
{"parent": "Products Settings"},
|
||||
{
|
||||
"parenttype": "E Commerce Settings",
|
||||
"parent": "E Commerce Settings"
|
||||
},
|
||||
update_modified=False
|
||||
)
|
||||
@@ -3,6 +3,7 @@ from frappe import _
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doctype('Selling Settings')
|
||||
selling_settings = frappe.get_single("Selling Settings")
|
||||
|
||||
if selling_settings.customer_group in (_("All Customer Groups"), "All Customer Groups"):
|
||||
|
||||
@@ -5,6 +5,9 @@ from erpnext.regional.india.setup import make_custom_fields
|
||||
|
||||
def execute():
|
||||
if frappe.get_all('Company', filters = {'country': 'India'}):
|
||||
frappe.reload_doc('accounts', 'doctype', 'POS Invoice')
|
||||
frappe.reload_doc('accounts', 'doctype', 'POS Invoice Item')
|
||||
|
||||
make_custom_fields()
|
||||
|
||||
if not frappe.db.exists('Party Type', 'Donor'):
|
||||
|
||||
29
erpnext/patches/v13_0/shopping_cart_to_ecommerce.py
Normal file
29
erpnext/patches/v13_0/shopping_cart_to_ecommerce.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import click
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
|
||||
frappe.delete_doc("DocType", "Shopping Cart Settings", ignore_missing=True)
|
||||
frappe.delete_doc("DocType", "Products Settings", ignore_missing=True)
|
||||
frappe.delete_doc("DocType", "Supplier Item Group", ignore_missing=True)
|
||||
|
||||
if frappe.db.get_single_value("E Commerce Settings", "enabled"):
|
||||
notify_users()
|
||||
|
||||
|
||||
def notify_users():
|
||||
|
||||
click.secho(
|
||||
"Shopping cart and Product settings are merged into E-commerce settings.\n"
|
||||
"Checkout the documentation to learn more:"
|
||||
"https://docs.erpnext.com/docs/v13/user/manual/en/e_commerce/set_up_e_commerce",
|
||||
fg="yellow",
|
||||
)
|
||||
|
||||
note = frappe.new_doc("Note")
|
||||
note.title = "New E-Commerce Module"
|
||||
note.public = 1
|
||||
note.notify_on_login = 1
|
||||
note.content = """<div class="ql-editor read-mode"><p>You are seeing this message because Shopping Cart is enabled on your site. </p><p><br></p><p>Shopping Cart Settings and Products settings are now merged into "E Commerce Settings". </p><p><br></p><p>You can learn about new and improved E-Commerce features in the official documentation.</p><ol><li data-list="bullet"><span class="ql-ui" contenteditable="false"></span><a href="https://docs.erpnext.com/docs/v13/user/manual/en/e_commerce/set_up_e_commerce" rel="noopener noreferrer">https://docs.erpnext.com/docs/v13/user/manual/en/e_commerce/set_up_e_commerce</a></li></ol><p><br></p></div>"""
|
||||
note.insert(ignore_mandatory=True)
|
||||
@@ -9,13 +9,15 @@ def execute():
|
||||
from `tabStock Ledger Entry`
|
||||
where
|
||||
is_cancelled = 0
|
||||
and (serial_no like %s or serial_no like %s or serial_no like %s or serial_no like %s)
|
||||
and ( serial_no like %s or serial_no like %s or serial_no like %s or serial_no like %s
|
||||
or serial_no = %s )
|
||||
""",
|
||||
(
|
||||
" %", # leading whitespace
|
||||
"% ", # trailing whitespace
|
||||
"%\n %", # leading whitespace on newline
|
||||
"% \n%", # trailing whitespace on newline
|
||||
"\n", # just new line
|
||||
),
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
@@ -37,4 +37,4 @@ def execute():
|
||||
jc.production_item = wo.production_item, jc.item_name = wo.item_name
|
||||
WHERE
|
||||
jc.work_order = wo.name and IFNULL(jc.production_item, "") = ""
|
||||
""")
|
||||
""")
|
||||
8
erpnext/patches/v13_0/update_asset_quantity_field.py
Normal file
8
erpnext/patches/v13_0/update_asset_quantity_field.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
if frappe.db.count('Asset'):
|
||||
frappe.reload_doc("assets", "doctype", "Asset")
|
||||
asset = frappe.qb.DocType('Asset')
|
||||
frappe.qb.update(asset).set(asset.asset_quantity, 1).run()
|
||||
@@ -1,31 +0,0 @@
|
||||
# Copyright (c) 2020, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
for document in ["bom", "bom_item", "bom_explosion_item"]:
|
||||
frappe.reload_doc('manufacturing', 'doctype', document)
|
||||
|
||||
frappe.db.sql(" update `tabBOM` set bom_level = 0 where docstatus = 1")
|
||||
|
||||
bom_list = 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 ifnull(bom_no, '')!='')""")
|
||||
|
||||
count = 0
|
||||
while(count < len(bom_list)):
|
||||
for parent_bom in get_parent_boms(bom_list[count]):
|
||||
bom_doc = frappe.get_cached_doc("BOM", parent_bom)
|
||||
bom_doc.set_bom_level(update=True)
|
||||
bom_list.append(parent_bom)
|
||||
count += 1
|
||||
|
||||
def get_parent_boms(bom_no):
|
||||
return frappe.db.sql_list("""
|
||||
select distinct bom_item.parent from `tabBOM Item` bom_item
|
||||
where bom_item.bom_no = %s and bom_item.docstatus=1 and bom_item.parenttype='BOM'
|
||||
and exists(select bom.name from `tabBOM` bom where bom.name=bom_item.parent and bom.is_active=1)
|
||||
""", bom_no)
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doctype('Maintenance Visit')
|
||||
frappe.reload_doctype('Maintenance Visit Purpose')
|
||||
|
||||
# Updates the Maintenance Schedule link to fetch serial nos
|
||||
from frappe.query_builder.functions import Coalesce
|
||||
mvp = frappe.qb.DocType('Maintenance Visit Purpose')
|
||||
mv = frappe.qb.DocType('Maintenance Visit')
|
||||
|
||||
frappe.qb.update(
|
||||
mv
|
||||
).join(
|
||||
mvp
|
||||
).on(mvp.parent == mv.name).set(
|
||||
mv.maintenance_schedule,
|
||||
Coalesce(mvp.prevdoc_docname, '')
|
||||
).where(
|
||||
(mv.maintenance_type == "Scheduled")
|
||||
& (mvp.prevdoc_docname.notnull())
|
||||
& (mv.docstatus < 2)
|
||||
).run(as_dict=1)
|
||||
11
erpnext/patches/v13_0/update_sane_transfer_against.py
Normal file
11
erpnext/patches/v13_0/update_sane_transfer_against.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
bom = frappe.qb.DocType("BOM")
|
||||
|
||||
(frappe.qb
|
||||
.update(bom)
|
||||
.set(bom.transfer_material_against, "Work Order")
|
||||
.where(bom.with_operations == 0)
|
||||
).run()
|
||||
18
erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py
Normal file
18
erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
|
||||
doctype = "Stock Reconciliation Item"
|
||||
|
||||
if not frappe.db.has_column(doctype, "current_serial_no"):
|
||||
# nothing to fix if column doesn't exist
|
||||
return
|
||||
|
||||
sr_item = frappe.qb.DocType(doctype)
|
||||
|
||||
(frappe.qb
|
||||
.update(sr_item)
|
||||
.set(sr_item.current_serial_no, None)
|
||||
.where(sr_item.current_qty == 0)
|
||||
).run()
|
||||
@@ -5,9 +5,6 @@ from frappe import _
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("email", "doctype", "email_template")
|
||||
frappe.reload_doc("hr", "doctype", "hr_settings")
|
||||
|
||||
template = frappe.db.exists("Email Template", _("Exit Questionnaire Notification"))
|
||||
if not template:
|
||||
base_path = frappe.get_app_path("erpnext", "hr", "doctype")
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.delete_doc('DocType', 'E Invoice Settings', ignore_missing=True)
|
||||
frappe.delete_doc('DocType', 'E Invoice User', ignore_missing=True)
|
||||
frappe.delete_doc('Report', 'E-Invoice Summary', ignore_missing=True)
|
||||
frappe.delete_doc('Print Format', 'GST E-Invoice', ignore_missing=True)
|
||||
frappe.delete_doc('Custom Field', 'Sales Invoice-eway_bill_cancelled', ignore_missing=True)
|
||||
frappe.delete_doc('Custom Field', 'Sales Invoice-irn_cancelled', ignore_missing=True)
|
||||
@@ -47,3 +47,18 @@ def execute():
|
||||
frappe.delete_doc("DocType", doctype, ignore_missing=True)
|
||||
|
||||
frappe.delete_doc("Module Def", "Healthcare", ignore_missing=True, force=True)
|
||||
|
||||
custom_fields = {
|
||||
'Sales Invoice': ['patient', 'patient_name', 'ref_practitioner'],
|
||||
'Sales Invoice Item': ['reference_dt', 'reference_dn'],
|
||||
'Stock Entry': ['inpatient_medication_entry'],
|
||||
'Stock Entry Detail': ['patient', 'inpatient_medication_entry_child'],
|
||||
}
|
||||
for doc, fields in custom_fields.items():
|
||||
filters = {
|
||||
'dt': doc,
|
||||
'fieldname': ['in', fields]
|
||||
}
|
||||
records = frappe.get_all('Custom Field', filters=filters, pluck='name')
|
||||
for record in records:
|
||||
frappe.delete_doc('Custom Field', record, ignore_missing=True, force=True)
|
||||
|
||||
32
erpnext/patches/v14_0/delete_hospitality_doctypes.py
Normal file
32
erpnext/patches/v14_0/delete_hospitality_doctypes.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
modules = ['Hotels', 'Restaurant']
|
||||
|
||||
for module in modules:
|
||||
frappe.delete_doc("Module Def", module, ignore_missing=True, force=True)
|
||||
|
||||
frappe.delete_doc("Workspace", module, ignore_missing=True, force=True)
|
||||
|
||||
reports = frappe.get_all("Report", {"module": module, "is_standard": "Yes"}, pluck='name')
|
||||
for report in reports:
|
||||
frappe.delete_doc("Report", report, ignore_missing=True, force=True)
|
||||
|
||||
dashboards = frappe.get_all("Dashboard", {"module": module, "is_standard": 1}, pluck='name')
|
||||
for dashboard in dashboards:
|
||||
frappe.delete_doc("Dashboard", dashboard, ignore_missing=True, force=True)
|
||||
|
||||
doctypes = frappe.get_all("DocType", {"module": module, "custom": 0}, pluck='name')
|
||||
for doctype in doctypes:
|
||||
frappe.delete_doc("DocType", doctype, ignore_missing=True)
|
||||
|
||||
custom_fields = [
|
||||
{"dt": "Sales Invoice", "fieldname": "restaurant"},
|
||||
{"dt": "Sales Invoice", "fieldname": "restaurant_table"},
|
||||
{"dt": "Price List", "fieldname": "restaurant_menu"},
|
||||
]
|
||||
|
||||
for field in custom_fields:
|
||||
custom_field = frappe.db.get_value("Custom Field", field)
|
||||
frappe.delete_doc("Custom Field", custom_field, ignore_missing=True)
|
||||
48
erpnext/patches/v14_0/migrate_cost_center_allocations.py
Normal file
48
erpnext/patches/v14_0/migrate_cost_center_allocations.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import frappe
|
||||
from frappe.utils import today
|
||||
|
||||
|
||||
def execute():
|
||||
for dt in ("cost_center_allocation", "cost_center_allocation_percentage"):
|
||||
frappe.reload_doc('accounts', 'doctype', dt)
|
||||
|
||||
cc_allocations = get_existing_cost_center_allocations()
|
||||
if cc_allocations:
|
||||
create_new_cost_center_allocation_records(cc_allocations)
|
||||
|
||||
frappe.delete_doc('DocType', 'Distributed Cost Center', ignore_missing=True)
|
||||
|
||||
def create_new_cost_center_allocation_records(cc_allocations):
|
||||
for main_cc, allocations in cc_allocations.items():
|
||||
cca = frappe.new_doc("Cost Center Allocation")
|
||||
cca.main_cost_center = main_cc
|
||||
cca.valid_from = today()
|
||||
|
||||
for child_cc, percentage in allocations.items():
|
||||
cca.append("allocation_percentages", ({
|
||||
"cost_center": child_cc,
|
||||
"percentage": percentage
|
||||
}))
|
||||
cca.save()
|
||||
cca.submit()
|
||||
|
||||
def get_existing_cost_center_allocations():
|
||||
if not frappe.db.exists("DocType", "Distributed Cost Center"):
|
||||
return
|
||||
|
||||
par = frappe.qb.DocType("Cost Center")
|
||||
child = frappe.qb.DocType("Distributed Cost Center")
|
||||
|
||||
records = (
|
||||
frappe.qb.from_(par)
|
||||
.inner_join(child).on(par.name == child.parent)
|
||||
.select(par.name, child.cost_center, child.percentage_allocation)
|
||||
.where(par.enable_distributed_cost_center == 1)
|
||||
).run(as_dict=True)
|
||||
|
||||
cc_allocations = frappe._dict()
|
||||
for d in records:
|
||||
cc_allocations.setdefault(d.name, frappe._dict())\
|
||||
.setdefault(d.cost_center, d.percentage_allocation)
|
||||
|
||||
return cc_allocations
|
||||
@@ -9,8 +9,9 @@ def execute():
|
||||
], as_dict=True)
|
||||
|
||||
frappe.reload_doc('crm', 'doctype', 'crm_settings')
|
||||
frappe.db.set_value('CRM Settings', 'CRM Settings', {
|
||||
'campaign_naming_by': settings.campaign_naming_by,
|
||||
'close_opportunity_after_days': settings.close_opportunity_after_days,
|
||||
'default_valid_till': settings.default_valid_till
|
||||
})
|
||||
if settings:
|
||||
frappe.db.set_value('CRM Settings', 'CRM Settings', {
|
||||
'campaign_naming_by': settings.campaign_naming_by,
|
||||
'close_opportunity_after_days': settings.close_opportunity_after_days,
|
||||
'default_valid_till': settings.default_valid_till
|
||||
})
|
||||
|
||||
28
erpnext/patches/v14_0/rearrange_company_fields.py
Normal file
28
erpnext/patches/v14_0/rearrange_company_fields.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
|
||||
def execute():
|
||||
custom_fields = {
|
||||
'Company': [
|
||||
dict(fieldname='hra_section', label='HRA Settings',
|
||||
fieldtype='Section Break', insert_after='asset_received_but_not_billed', collapsible=1),
|
||||
dict(fieldname='basic_component', label='Basic Component',
|
||||
fieldtype='Link', options='Salary Component', insert_after='hra_section'),
|
||||
dict(fieldname='hra_component', label='HRA Component',
|
||||
fieldtype='Link', options='Salary Component', insert_after='basic_component'),
|
||||
dict(fieldname='hra_column_break', fieldtype='Column Break', insert_after='hra_component'),
|
||||
dict(fieldname='arrear_component', label='Arrear Component',
|
||||
fieldtype='Link', options='Salary Component', insert_after='hra_column_break'),
|
||||
dict(fieldname='non_profit_section', label='Non Profit Settings',
|
||||
fieldtype='Section Break', insert_after='arrear_component', collapsible=1),
|
||||
dict(fieldname='company_80g_number', label='80G Number',
|
||||
fieldtype='Data', insert_after='non_profit_section'),
|
||||
dict(fieldname='with_effect_from', label='80G With Effect From',
|
||||
fieldtype='Date', insert_after='company_80g_number'),
|
||||
dict(fieldname='non_profit_column_break', fieldtype='Column Break', insert_after='with_effect_from'),
|
||||
dict(fieldname='pan_details', label='PAN Number',
|
||||
fieldtype='Data', insert_after='non_profit_column_break')
|
||||
]
|
||||
}
|
||||
|
||||
create_custom_fields(custom_fields, update=True)
|
||||
24
erpnext/patches/v14_0/restore_einvoice_fields.py
Normal file
24
erpnext/patches/v14_0/restore_einvoice_fields.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
from erpnext.regional.india.setup import add_permissions, add_print_formats
|
||||
|
||||
|
||||
def execute():
|
||||
# restores back the 2 custom fields that was deleted while removing e-invoicing from v14
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
custom_fields = {
|
||||
'Sales Invoice': [
|
||||
dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
|
||||
depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
|
||||
|
||||
dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
|
||||
depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
|
||||
]
|
||||
}
|
||||
create_custom_fields(custom_fields, update=True)
|
||||
add_permissions()
|
||||
add_print_formats()
|
||||
17
erpnext/patches/v14_0/update_leave_notification_template.py
Normal file
17
erpnext/patches/v14_0/update_leave_notification_template.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import os
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
|
||||
def execute():
|
||||
base_path = frappe.get_app_path("erpnext", "hr", "doctype")
|
||||
response = frappe.read_file(os.path.join(base_path, "leave_application/leave_application_email_template.html"))
|
||||
|
||||
template = frappe.db.exists("Email Template", _("Leave Approval Notification"))
|
||||
if template:
|
||||
frappe.db.set_value("Email Template", template, "response", response)
|
||||
|
||||
template = frappe.db.exists("Email Template", _("Leave Status Notification"))
|
||||
if template:
|
||||
frappe.db.set_value("Email Template", template, "response", response)
|
||||
Reference in New Issue
Block a user