mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-09 00:01:18 +00:00
Merge branch 'enconnex_erpnext' of https://github.com/frappe/erpnext into enconnex_erpnext
This commit is contained in:
@@ -1333,15 +1333,9 @@
|
||||
"label": "Project",
|
||||
"options": "Project"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Taxes paid while advance payment will be adjusted against this invoice",
|
||||
"fieldname": "adjust_advance_taxes",
|
||||
"fieldtype": "Check",
|
||||
"label": "Adjust Advance Taxes"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_internal_supplier",
|
||||
"description": "Unrealized Profit / Loss account for intra-company transfers",
|
||||
"fieldname": "unrealized_profit_loss_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Unrealized Profit / Loss Account",
|
||||
@@ -1349,6 +1343,7 @@
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_internal_supplier",
|
||||
"description": "Company which internal supplier represents",
|
||||
"fetch_from": "supplier.represents_company",
|
||||
"fieldname": "represents_company",
|
||||
"fieldtype": "Link",
|
||||
@@ -1360,7 +1355,7 @@
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-29 19:47:04.827315",
|
||||
"modified": "2020-12-11 12:46:12.796378",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -1954,6 +1954,7 @@
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_internal_customer",
|
||||
"description": "Unrealized Profit / Loss account for intra-company transfers",
|
||||
"fieldname": "unrealized_profit_loss_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Unrealized Profit / Loss Account",
|
||||
@@ -1961,6 +1962,7 @@
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_internal_customer",
|
||||
"description": "Company which internal customer represents",
|
||||
"fetch_from": "customer.represents_company",
|
||||
"fieldname": "represents_company",
|
||||
"fieldtype": "Link",
|
||||
@@ -1973,7 +1975,7 @@
|
||||
"idx": 181,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-29 18:48:15.012300",
|
||||
"modified": "2020-12-11 12:48:31.769958",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -1613,7 +1613,9 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
if source_doc.get('update_stock'):
|
||||
item_field_map.update({
|
||||
'field_map': {
|
||||
source_document_warehouse_field: target_document_warehouse_field
|
||||
source_document_warehouse_field: target_document_warehouse_field,
|
||||
'batch_no': 'batch_no',
|
||||
'serial_no': 'serial_no'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -2110,10 +2110,11 @@ def create_internal_customer(customer_name, represents_company, allowed_to_inter
|
||||
})
|
||||
|
||||
customer.insert()
|
||||
customer_name = customer.name
|
||||
else:
|
||||
customer = frappe.db.get_value("Customer", customer_name)
|
||||
customer_name = frappe.db.get_value("Customer", customer_name)
|
||||
|
||||
return customer
|
||||
return customer_name
|
||||
|
||||
def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with):
|
||||
if not frappe.db.exists("Supplier", supplier_name):
|
||||
@@ -2130,10 +2131,11 @@ def create_internal_supplier(supplier_name, represents_company, allowed_to_inter
|
||||
})
|
||||
|
||||
supplier.insert()
|
||||
supplier_name = supplier.name
|
||||
else:
|
||||
supplier = frappe.db.exists("Supplier", supplier_name)
|
||||
supplier_name = frappe.db.exists("Supplier", supplier_name)
|
||||
|
||||
return supplier
|
||||
return supplier_name
|
||||
|
||||
def add_taxes(doc):
|
||||
doc.append('taxes', {
|
||||
@@ -2142,4 +2144,4 @@ def add_taxes(doc):
|
||||
"cost_center": "Main - TCP1",
|
||||
"description": "Excise Duty",
|
||||
"rate": 12
|
||||
})
|
||||
})
|
||||
|
||||
@@ -105,6 +105,8 @@ class AccountsController(TransactionBase):
|
||||
else:
|
||||
self.validate_deferred_start_and_end_date()
|
||||
|
||||
self.set_inter_company_account()
|
||||
|
||||
validate_regional(self)
|
||||
|
||||
validate_einvoice_fields(self)
|
||||
@@ -921,6 +923,38 @@ class AccountsController(TransactionBase):
|
||||
else:
|
||||
return frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
|
||||
|
||||
def set_inter_company_account(self):
|
||||
"""
|
||||
Set intercompany account for inter warehouse transactions
|
||||
This account will be used in case billing company and internal customer's
|
||||
representation company is same
|
||||
"""
|
||||
|
||||
if self.is_internal_transfer() and not self.unrealized_profit_loss_account:
|
||||
unrealized_profit_loss_account = frappe.db.get_value('Company', self.company, 'unrealized_profit_loss_account')
|
||||
|
||||
if not unrealized_profit_loss_account:
|
||||
msg = _("Please select Unrealized Profit / Loss account or add default Unrealized Profit / Loss account account for company {0}").format(
|
||||
frappe.bold(self.company))
|
||||
frappe.throw(msg)
|
||||
|
||||
self.unrealized_profit_loss_account = unrealized_profit_loss_account
|
||||
|
||||
def is_internal_transfer(self):
|
||||
"""
|
||||
It will an internal transfer if its an internal customer and representation
|
||||
company is same as billing company
|
||||
"""
|
||||
if self.doctype == 'Sales Invoice':
|
||||
internal_party_field = 'is_internal_customer'
|
||||
else:
|
||||
internal_party_field = 'is_internal_supplier'
|
||||
|
||||
if self.get(internal_party_field) and (self.represents_company == self.company):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_tax_rate(account_head):
|
||||
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
|
||||
|
||||
@@ -42,6 +42,7 @@ class BuyingController(StockController):
|
||||
self.validate_items()
|
||||
self.set_qty_as_per_stock_uom()
|
||||
self.validate_stock_or_nonstock_items()
|
||||
self.update_tax_category_for_internal_transfer()
|
||||
self.validate_warehouse()
|
||||
self.validate_from_warehouse()
|
||||
self.set_supplier_address()
|
||||
@@ -94,13 +95,23 @@ class BuyingController(StockController):
|
||||
|
||||
def validate_stock_or_nonstock_items(self):
|
||||
if self.meta.get_field("taxes") and not self.get_stock_items() and not self.get_asset_items():
|
||||
tax_for_valuation = [d for d in self.get("taxes")
|
||||
msg = _('Tax Category has been changed to "Total" because all the Items are non-stock items')
|
||||
self.update_tax_category(msg)
|
||||
|
||||
def update_tax_category_for_internal_transfer(self):
|
||||
if self.doctype == 'Purchase Invoice' and self.is_internal_transfer():
|
||||
msg = _('Tax Category has been changed to "Total" as its an internal purchase.')
|
||||
self.update_tax_category(msg)
|
||||
|
||||
def update_tax_category(self, msg):
|
||||
tax_for_valuation = [d for d in self.get("taxes")
|
||||
if d.category in ["Valuation", "Valuation and Total"]]
|
||||
|
||||
if tax_for_valuation:
|
||||
for d in tax_for_valuation:
|
||||
d.category = 'Total'
|
||||
msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
|
||||
if tax_for_valuation:
|
||||
for d in tax_for_valuation:
|
||||
d.category = 'Total'
|
||||
|
||||
msgprint(msg)
|
||||
|
||||
def validate_asset_return(self):
|
||||
if self.doctype not in ['Purchase Receipt', 'Purchase Invoice'] or not self.is_return:
|
||||
|
||||
@@ -92,16 +92,6 @@ class StockController(AccountsController):
|
||||
|
||||
sle = self.update_stock_ledger_entries(sle)
|
||||
|
||||
gl_list.append(self.get_gl_dict({
|
||||
"account": warehouse_account[sle.warehouse]["account"],
|
||||
"against": item_row.expense_account,
|
||||
"cost_center": item_row.cost_center,
|
||||
"project": item_row.project or self.get('project'),
|
||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||
"debit": flt(sle.stock_value_difference, precision),
|
||||
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
|
||||
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
|
||||
|
||||
# expense account/ target_warehouse / source_warehouse
|
||||
if item_row.get('target_warehouse'):
|
||||
warehouse = item_row.get('target_warehouse')
|
||||
@@ -109,6 +99,16 @@ class StockController(AccountsController):
|
||||
else:
|
||||
expense_account = item_row.expense_account
|
||||
|
||||
gl_list.append(self.get_gl_dict({
|
||||
"account": warehouse_account[sle.warehouse]["account"],
|
||||
"against": expense_account,
|
||||
"cost_center": item_row.cost_center,
|
||||
"project": item_row.project or self.get('project'),
|
||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||
"debit": flt(sle.stock_value_difference, precision),
|
||||
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
|
||||
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
|
||||
|
||||
gl_list.append(self.get_gl_dict({
|
||||
"account": expense_account,
|
||||
"against": warehouse_account[sle.warehouse]["account"],
|
||||
|
||||
@@ -15,20 +15,27 @@ from Crypto.Util.Padding import pad, unpad
|
||||
from frappe.model.document import Document
|
||||
from frappe import _, get_module_path, scrub
|
||||
from erpnext.regional.india.utils import get_gst_accounts
|
||||
from frappe.utils.data import get_datetime, cstr, cint, format_date, flt
|
||||
from frappe.integrations.utils import make_post_request, make_get_request
|
||||
from frappe.utils.data import get_datetime, cstr, cint, format_date, flt, time_diff_in_seconds, now_datetime
|
||||
|
||||
def validate_einvoice_fields(doc):
|
||||
e_invoice_enabled = frappe.db.get_value("E Invoice Settings", "E Invoice Settings", "enable")
|
||||
if not doc.doctype in ['Sales Invoice', 'Purchase Invoice'] or not e_invoice_enabled: return
|
||||
|
||||
if doc.docstatus == 1 and doc._action == 'submit' and not doc.irn:
|
||||
if doc.docstatus == 0 and doc._action == 'save' and doc.irn:
|
||||
frappe.throw(_("You cannot edit the invoice after generating IRN"), title=_("Edit Not Allowed"))
|
||||
elif doc.docstatus == 1 and doc._action == 'submit' and not doc.irn:
|
||||
frappe.throw(_("You must generate IRN before submitting the document."), title=_("Missing IRN"))
|
||||
elif doc.docstatus == 2 and doc._action == 'cancel' and not doc.irn_cancelled:
|
||||
frappe.throw(_("You must cancel IRN before cancelling the document."), title=_("Not Allowed"))
|
||||
frappe.throw(_("You must cancel IRN before cancelling the document."), title=_("Cancel Not Allowed"))
|
||||
|
||||
def get_einv_credentials():
|
||||
return frappe.get_doc("E Invoice Settings")
|
||||
def get_einv_credentials(for_token=False):
|
||||
creds = frappe.get_doc("E Invoice Settings")
|
||||
if not for_token and (not creds.token_expiry or time_diff_in_seconds(now_datetime(), creds.token_expiry) > 5.0):
|
||||
fetch_token()
|
||||
creds.load_from_db()
|
||||
|
||||
return creds
|
||||
|
||||
def rsa_encrypt(msg, key):
|
||||
if not (isinstance(msg, bytes) or isinstance(msg, bytearray)):
|
||||
@@ -76,7 +83,7 @@ def get_header(creds):
|
||||
|
||||
@frappe.whitelist()
|
||||
def fetch_token():
|
||||
einv_creds = get_einv_credentials()
|
||||
einv_creds = get_einv_credentials(for_token=True)
|
||||
|
||||
endpoint = 'https://einv-apisandbox.nic.in/eivital/v1.03/auth'
|
||||
headers = { 'content-type': 'application/json' }
|
||||
@@ -266,20 +273,26 @@ def get_doc_details(invoice):
|
||||
))
|
||||
|
||||
def get_party_gstin_details(party_address):
|
||||
gstin, address_line1, address_line2, phone, email_id = frappe.db.get_value(
|
||||
"Address", party_address, ["gstin", "address_line1", "address_line2", "phone", "email_id"]
|
||||
)
|
||||
address = frappe.get_all("Address", filters={"name": party_address}, fields=["*"])[0]
|
||||
|
||||
gstin = address.get('gstin')
|
||||
gstin_details = get_gstin_details(gstin)
|
||||
# legal_name = address.get('address_title')
|
||||
legal_name = gstin_details.get('LegalName')
|
||||
trade_name = gstin_details.get('TradeName')
|
||||
location = gstin_details.get('AddrLoc')
|
||||
state_code = gstin_details.get('StateCode')
|
||||
pincode = cint(gstin_details.get('AddrPncd'))
|
||||
# location = address.get('city')
|
||||
location = gstin_details.get('Loc')
|
||||
state_code = address.get('gst_state_number')
|
||||
pincode = cint(address.get('pincode'))
|
||||
address_line1 = address.get('address_line1')
|
||||
address_line2 = address.get('address_line2')
|
||||
email_id = address.get('email_id')
|
||||
phone = address.get('phone')
|
||||
if state_code == 97:
|
||||
pincode = 999999
|
||||
|
||||
return frappe._dict(dict(
|
||||
gstin=gstin, legal_name=legal_name, trade_name=trade_name, location=location,
|
||||
gstin=gstin, legal_name=legal_name, location=location,
|
||||
pincode=pincode, state_code=state_code, address_line1=address_line1,
|
||||
address_line2=address_line2, email=email_id, phone=phone
|
||||
))
|
||||
@@ -338,8 +351,6 @@ def get_item_list(invoice):
|
||||
e_inv_item = item_schema.format(item=item)
|
||||
item_list.append(e_inv_item)
|
||||
|
||||
print(e_inv_item)
|
||||
|
||||
return ", ".join(item_list)
|
||||
|
||||
def get_value_details(invoice):
|
||||
@@ -404,10 +415,11 @@ def get_eway_bill_details(invoice):
|
||||
vehicle_type=vehicle_type[invoice.gst_vehicle_type]
|
||||
))
|
||||
|
||||
def make_e_invoice(invoice):
|
||||
@frappe.whitelist()
|
||||
def make_e_invoice(doctype, name):
|
||||
invoice = frappe.get_doc(doctype, name)
|
||||
schema = read_json("einv_template")
|
||||
validations = read_json("einv_validation")
|
||||
validations = json.loads(validations)
|
||||
validations = json.loads(read_json("einv_validation"))
|
||||
|
||||
trans_details = get_trans_details(invoice)
|
||||
doc_details = get_doc_details(invoice)
|
||||
@@ -451,13 +463,17 @@ def make_e_invoice(invoice):
|
||||
)
|
||||
e_invoice = json.loads(e_invoice)
|
||||
|
||||
error_msgs = run_e_invoice_validations(validations, e_invoice, [])
|
||||
error_msgs = validate_einvoice(validations, e_invoice, [])
|
||||
if error_msgs:
|
||||
frappe.throw(_("{}").format("<br>".join(error_msgs)), title=_("E Invoice Validation"))
|
||||
if len(error_msgs) > 1:
|
||||
li = ["<li>"+ d +"</li>" for d in error_msgs]
|
||||
frappe.throw(_("""<ul style="padding-left: 20px">{}</ul>""").format("".join(li)), title=_("E Invoice Validation Failed"))
|
||||
else:
|
||||
frappe.throw(_("{}").format(error_msgs[0]), title=_("E Invoice Validation Failed"))
|
||||
|
||||
return json.dumps(e_invoice)
|
||||
return {'einvoice': json.dumps([e_invoice])}
|
||||
|
||||
def run_e_invoice_validations(validations, e_invoice, error_msgs=[]):
|
||||
def validate_einvoice(validations, e_invoice, error_msgs=[]):
|
||||
type_map = {
|
||||
"string": cstr,
|
||||
"number": cint,
|
||||
@@ -478,9 +494,9 @@ def run_e_invoice_validations(validations, e_invoice, error_msgs=[]):
|
||||
|
||||
if isinstance(invoice_value, list):
|
||||
for d in invoice_value:
|
||||
run_e_invoice_validations(properties, d, error_msgs)
|
||||
validate_einvoice(properties, d, error_msgs)
|
||||
else:
|
||||
run_e_invoice_validations(properties, invoice_value, error_msgs)
|
||||
validate_einvoice(properties, invoice_value, error_msgs)
|
||||
# remove keys with empty dicts
|
||||
if not invoice_value:
|
||||
e_invoice.pop(field, None)
|
||||
@@ -507,6 +523,56 @@ def run_e_invoice_validations(validations, e_invoice, error_msgs=[]):
|
||||
if value.get('type').lower() == 'number' and not (flt(invoice_value) <= should_be_less_than):
|
||||
error_msgs.append("{} should be less than {}".format(field_label, should_be_less_than))
|
||||
if pattern_str and not pattern.match(invoice_value):
|
||||
error_msgs.append("{} should match {}".format(field_label, pattern_str))
|
||||
error_msgs.append(value.get('validationMsg'))
|
||||
|
||||
return error_msgs
|
||||
return error_msgs
|
||||
|
||||
@frappe.whitelist()
|
||||
def download_einvoice():
|
||||
data = frappe._dict(frappe.local.form_dict)
|
||||
einvoice = data['einvoice']
|
||||
name = data['name']
|
||||
|
||||
frappe.response['filename'] = "E-Invoice-" + name + ".json"
|
||||
frappe.response['filecontent'] = einvoice
|
||||
frappe.response['content_type'] = 'application/json'
|
||||
frappe.response['type'] = 'download'
|
||||
|
||||
@frappe.whitelist()
|
||||
def upload_einvoice():
|
||||
signed_einvoice = json.loads(frappe.local.uploaded_file)
|
||||
data = frappe._dict(frappe.local.form_dict)
|
||||
doctype = data['doctype']
|
||||
name = data['docname']
|
||||
|
||||
enc_signed_invoice = signed_einvoice.get('SignedInvoice')
|
||||
decrypted_signed_invoice = jwt_decrypt(enc_signed_invoice)['data']
|
||||
|
||||
frappe.db.set_value(doctype, name, 'irn', signed_einvoice.get('Irn'))
|
||||
frappe.db.set_value(doctype, name, 'ewaybill', signed_einvoice.get('EwbNo'))
|
||||
frappe.db.set_value(doctype, name, 'signed_qr_code', signed_einvoice.get('SignedQRCode'))
|
||||
frappe.db.set_value(doctype, name, 'signed_einvoice', decrypted_signed_invoice)
|
||||
|
||||
@frappe.whitelist()
|
||||
def download_cancel_einvoice():
|
||||
data = frappe._dict(frappe.local.form_dict)
|
||||
name = data['name']
|
||||
irn = data['irn']
|
||||
reason = data['reason']
|
||||
remark = data['remark']
|
||||
|
||||
cancel_einvoice = json.dumps([dict(Irn=irn, CnlRsn=reason, CnlRem=remark)])
|
||||
|
||||
frappe.response['filename'] = "Cancel E-Invoice " + name + ".json"
|
||||
frappe.response['filecontent'] = cancel_einvoice
|
||||
frappe.response['content_type'] = 'application/json'
|
||||
frappe.response['type'] = 'download'
|
||||
|
||||
@frappe.whitelist()
|
||||
def upload_cancel_ack():
|
||||
cancel_ack = json.loads(frappe.local.uploaded_file)
|
||||
data = frappe._dict(frappe.local.form_dict)
|
||||
doctype = data['doctype']
|
||||
name = data['docname']
|
||||
|
||||
frappe.db.set_value(doctype, name, "irn_cancelled", 1)
|
||||
@@ -59,13 +59,15 @@
|
||||
"minLength": 1,
|
||||
"maxLength": 16,
|
||||
"pattern": "^([A-Z1-9]{1}[A-Z0-9/-]{0,15})$",
|
||||
"label": "Document Name"
|
||||
"label": "Document Name",
|
||||
"validationMsg": "Document name should not be starting with 0, / and -"
|
||||
},
|
||||
"Dt": {
|
||||
"type": "string",
|
||||
"minLength": 10,
|
||||
"maxLength": 10,
|
||||
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]"
|
||||
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
|
||||
"validationMsg": "Document Date is invalid"
|
||||
}
|
||||
},
|
||||
"required": ["Typ", "No", "Dt"]
|
||||
@@ -77,7 +79,8 @@
|
||||
"type": "string",
|
||||
"minLength": 15,
|
||||
"maxLength": 15,
|
||||
"pattern": "([0-9]{2}[0-9A-Z]{13})"
|
||||
"pattern": "([0-9]{2}[0-9A-Z]{13})",
|
||||
"validationMsg": "Seller GSTIN is invalid"
|
||||
},
|
||||
"LglNm": {
|
||||
"type": "string",
|
||||
@@ -134,7 +137,8 @@
|
||||
"type": "string",
|
||||
"minLength": 3,
|
||||
"maxLength": 15,
|
||||
"pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$"
|
||||
"pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
|
||||
"validationMsg": "Buyer GSTIN is invalid"
|
||||
},
|
||||
"LglNm": {
|
||||
"type": "string",
|
||||
@@ -232,7 +236,8 @@
|
||||
"type": "string",
|
||||
"maxLength": 15,
|
||||
"minLength": 3,
|
||||
"pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$"
|
||||
"pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
|
||||
"validationMsg": "Shipping Address GSTIN is invalid"
|
||||
},
|
||||
"LglNm": {
|
||||
"type": "string",
|
||||
@@ -429,13 +434,15 @@
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"minLength": 10,
|
||||
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]"
|
||||
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
|
||||
"validationMsg": "Expiry Date is invalid"
|
||||
},
|
||||
"WrDt": {
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"minLength": 10,
|
||||
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]"
|
||||
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
|
||||
"validationMsg": "Warranty Date is invalid"
|
||||
}
|
||||
},
|
||||
"required": ["Nm"]
|
||||
|
||||
@@ -7,27 +7,127 @@ erpnext.setup_einvoice_actions = (doctype) => {
|
||||
|| !['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type)) {
|
||||
return;
|
||||
}
|
||||
// if (frm.doc.docstatus == 0 && !frm.doc.irn && !frm.doc.__unsaved) {
|
||||
// frm.add_custom_button(
|
||||
// "Generate IRN",
|
||||
// () => {
|
||||
// frappe.call({
|
||||
// method: 'erpnext.regional.india.e_invoice_utils.generate_irn',
|
||||
// args: { doctype: frm.doc.doctype, name: frm.doc.name },
|
||||
// freeze: true,
|
||||
// callback: (res) => {
|
||||
// console.log(res.message);
|
||||
// frm.set_value('irn', res.message['Irn']);
|
||||
// frm.set_value('signed_einvoice', JSON.stringify(res.message['DecryptedSignedInvoice']));
|
||||
// frm.set_value('signed_qr_code', JSON.stringify(res.message['DecryptedSignedQRCode']));
|
||||
|
||||
// if (res.message['EwbNo']) frm.set_value('ewaybill', res.message['EwbNo']);
|
||||
// frm.save();
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
|
||||
// if (frm.doc.docstatus == 1 && frm.doc.irn && !frm.doc.irn_cancelled) {
|
||||
// frm.add_custom_button(
|
||||
// "Cancel IRN",
|
||||
// () => {
|
||||
// const d = new frappe.ui.Dialog({
|
||||
// title: __('Cancel IRN'),
|
||||
// fields: [
|
||||
// { "label" : "Reason", "fieldname": "reason", "fieldtype": "Select", "reqd": 1, "default": "1-Duplicate",
|
||||
// "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"] },
|
||||
// { "label": "Remark", "fieldname": "remark", "fieldtype": "Data", "reqd": 1 }
|
||||
// ],
|
||||
// primary_action: function() {
|
||||
// const data = d.get_values();
|
||||
// frappe.call({
|
||||
// method: 'erpnext.regional.india.e_invoice_utils.cancel_irn',
|
||||
// args: { irn: frm.doc.irn, reason: data.reason.split('-')[0], remark: data.remark },
|
||||
// freeze: true,
|
||||
// callback: () => {
|
||||
// frm.set_value('irn_cancelled', 1);
|
||||
// frm.save("Update");
|
||||
// d.hide()
|
||||
// },
|
||||
// error: () => d.hide()
|
||||
// })
|
||||
// },
|
||||
// primary_action_label: __('Submit')
|
||||
// });
|
||||
// d.show();
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
|
||||
// if (frm.doc.docstatus == 1 && frm.doc.irn && !frm.doc.irn_cancelled && !frm.doc.eway_bill_cancelled) {
|
||||
// frm.add_custom_button(
|
||||
// "Cancel E-Way Bill",
|
||||
// () => {
|
||||
// const d = new frappe.ui.Dialog({
|
||||
// title: __('Cancel E-Way Bill'),
|
||||
// fields: [
|
||||
// { "label" : "Reason", "fieldname": "reason", "fieldtype": "Select", "reqd": 1, "default": "1-Duplicate",
|
||||
// "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"] },
|
||||
// { "label": "Remark", "fieldname": "remark", "fieldtype": "Data", "reqd": 1 }
|
||||
// ],
|
||||
// primary_action: function() {
|
||||
// const data = d.get_values();
|
||||
// frappe.call({
|
||||
// method: 'erpnext.regional.india.e_invoice_utils.cancel_eway_bill',
|
||||
// args: { eway_bill: frm.doc.ewaybill, reason: data.reason.split('-')[0], remark: data.remark },
|
||||
// freeze: true,
|
||||
// callback: () => {
|
||||
// frm.set_value('eway_bill_cancelled', 1);
|
||||
// frm.save("Update");
|
||||
// d.hide()
|
||||
// },
|
||||
// error: () => d.hide()
|
||||
// })
|
||||
// },
|
||||
// primary_action_label: __('Submit')
|
||||
// });
|
||||
// d.show();
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
|
||||
if (frm.doc.docstatus == 0 && !frm.doc.irn && !frm.doc.__unsaved) {
|
||||
frm.add_custom_button(
|
||||
"Generate IRN",
|
||||
"Download E-Invoice",
|
||||
() => {
|
||||
frappe.call({
|
||||
method: 'erpnext.regional.india.e_invoice_utils.generate_irn',
|
||||
method: 'erpnext.regional.india.e_invoice_utils.make_e_invoice',
|
||||
args: { doctype: frm.doc.doctype, name: frm.doc.name },
|
||||
freeze: true,
|
||||
callback: (res) => {
|
||||
console.log(res.message);
|
||||
frm.set_value('irn', res.message['Irn']);
|
||||
frm.set_value('signed_einvoice', JSON.stringify(res.message['DecryptedSignedInvoice']));
|
||||
frm.set_value('signed_qr_code', JSON.stringify(res.message['DecryptedSignedQRCode']));
|
||||
|
||||
if (res.message['EwbNo']) frm.set_value('ewaybill', res.message['EwbNo']);
|
||||
frm.save();
|
||||
if (!res.exc) {
|
||||
const args = {
|
||||
cmd: 'erpnext.regional.india.e_invoice_utils.download_einvoice',
|
||||
einvoice: res.message.einvoice,
|
||||
name: frm.doc.name
|
||||
};
|
||||
open_url_post(frappe.request.url, args);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}, "E-Invoicing");
|
||||
frm.add_custom_button(
|
||||
"Upload Signed E-Invoice",
|
||||
() => {
|
||||
new frappe.ui.FileUploader({
|
||||
method: 'erpnext.regional.india.e_invoice_utils.upload_einvoice',
|
||||
allow_multiple: 0,
|
||||
doctype: frm.doc.doctype,
|
||||
docname: frm.doc.name,
|
||||
on_success: (attachment, r) => {
|
||||
if (!r.exc) {
|
||||
frm.reload_doc();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, "E-Invoicing");
|
||||
}
|
||||
if (frm.doc.docstatus == 1 && frm.doc.irn && !frm.doc.irn_cancelled) {
|
||||
frm.add_custom_button(
|
||||
@@ -36,62 +136,45 @@ erpnext.setup_einvoice_actions = (doctype) => {
|
||||
const d = new frappe.ui.Dialog({
|
||||
title: __('Cancel IRN'),
|
||||
fields: [
|
||||
{ "label" : "Reason", "fieldname": "reason", "fieldtype": "Select", "reqd": 1, "default": "1-Duplicate",
|
||||
"options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"] },
|
||||
{ "label": "Remark", "fieldname": "remark", "fieldtype": "Data", "reqd": 1 }
|
||||
{
|
||||
"label" : "Reason", "fieldname": "reason",
|
||||
"fieldtype": "Select", "reqd": 1, "default": "1-Duplicate",
|
||||
"options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
|
||||
},
|
||||
{
|
||||
"label": "Remark", "fieldname": "remark", "fieldtype": "Data", "reqd": 1
|
||||
}
|
||||
],
|
||||
primary_action: function() {
|
||||
const data = d.get_values();
|
||||
frappe.call({
|
||||
method: 'erpnext.regional.india.e_invoice_utils.cancel_irn',
|
||||
args: { irn: frm.doc.irn, reason: data.reason.split('-')[0], remark: data.remark },
|
||||
freeze: true,
|
||||
callback: () => {
|
||||
frm.set_value('irn_cancelled', 1);
|
||||
frm.save("Update");
|
||||
d.hide()
|
||||
},
|
||||
error: () => d.hide()
|
||||
})
|
||||
const args = {
|
||||
cmd: 'erpnext.regional.india.e_invoice_utils.download_cancel_einvoice',
|
||||
irn: frm.doc.irn, reason: data.reason.split('-')[0], remark: data.remark, name: frm.doc.name
|
||||
};
|
||||
open_url_post(frappe.request.url, args);
|
||||
d.hide();
|
||||
},
|
||||
primary_action_label: __('Submit')
|
||||
primary_action_label: __('Download JSON')
|
||||
});
|
||||
d.show();
|
||||
}
|
||||
)
|
||||
}
|
||||
if (frm.doc.docstatus == 1 && frm.doc.irn && !frm.doc.irn_cancelled && !frm.doc.eway_bill_cancelled) {
|
||||
}, "E-Invoicing");
|
||||
|
||||
frm.add_custom_button(
|
||||
"Cancel E-Way Bill",
|
||||
"Upload Cancel JSON",
|
||||
() => {
|
||||
const d = new frappe.ui.Dialog({
|
||||
title: __('Cancel E-Way Bill'),
|
||||
fields: [
|
||||
{ "label" : "Reason", "fieldname": "reason", "fieldtype": "Select", "reqd": 1, "default": "1-Duplicate",
|
||||
"options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"] },
|
||||
{ "label": "Remark", "fieldname": "remark", "fieldtype": "Data", "reqd": 1 }
|
||||
],
|
||||
primary_action: function() {
|
||||
const data = d.get_values();
|
||||
frappe.call({
|
||||
method: 'erpnext.regional.india.e_invoice_utils.cancel_eway_bill',
|
||||
args: { eway_bill: frm.doc.ewaybill, reason: data.reason.split('-')[0], remark: data.remark },
|
||||
freeze: true,
|
||||
callback: () => {
|
||||
frm.set_value('eway_bill_cancelled', 1);
|
||||
frm.save("Update");
|
||||
d.hide()
|
||||
},
|
||||
error: () => d.hide()
|
||||
})
|
||||
},
|
||||
primary_action_label: __('Submit')
|
||||
new frappe.ui.FileUploader({
|
||||
method: 'erpnext.regional.india.e_invoice_utils.upload_cancel_ack',
|
||||
allow_multiple: 0,
|
||||
doctype: frm.doc.doctype,
|
||||
docname: frm.doc.name,
|
||||
on_success: (attachment, r) => {
|
||||
if (!r.exc) {
|
||||
frm.reload_doc();
|
||||
}
|
||||
}
|
||||
});
|
||||
d.show();
|
||||
}
|
||||
)
|
||||
}, "E-Invoicing");
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
@@ -404,7 +404,7 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
|
||||
# form a list of emails and names to show to the user
|
||||
credit_controller_users_formatted = [get_formatted_email(user).replace("<", "(").replace(">", ")") for user in credit_controller_users]
|
||||
if not credit_controller_users_formatted:
|
||||
frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.".format(customer)))
|
||||
frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.").format(customer))
|
||||
|
||||
message = """Please contact any of the following users to extend the credit limits for {0}:
|
||||
<br><br><ul><li>{1}</li></ul>""".format(customer, '<li>'.join(credit_controller_users_formatted))
|
||||
|
||||
Reference in New Issue
Block a user