feat: update timeline on einvoice actions

This commit is contained in:
Saqib Ansari
2020-11-07 21:15:19 +05:30
parent 72ed0fbbb4
commit dc4b0921f6
3 changed files with 199 additions and 161 deletions

View File

@@ -32,4 +32,5 @@ def execute():
add_print_formats()
frappe.db.set_value('Custom Field', { 'fieldname': 'mode_of_transport' }, 'default', '')
frappe.db.set_value('Custom Field', { 'fieldname': 'vehicle_no' }, 'depends_on', 'eval:doc.mode_of_transport == "Road"')
frappe.db.set_value('Custom Field', { 'fieldname': 'vehicle_no' }, 'depends_on', 'eval:doc.mode_of_transport == "Road"')
frappe.db.set_value('Custom Field', { 'fieldname': 'ewaybill' }, 'depends_on', 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)')

View File

@@ -7,7 +7,13 @@ erpnext.setup_einvoice_actions = (doctype) => {
if (!einvoicing_enabled || !valid_supply_type) return;
const { docstatus, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
const { doctype, docstatus, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
const add_custom_button = (label, action) => {
if (!frm.custom_buttons[label]) {
frm.add_custom_button(label, action, __('E Invoicing'));
}
}
if (ewaybill && irn) {
frm.set_df_property('ewaybill', 'read_only', 1);
@@ -17,13 +23,13 @@ erpnext.setup_einvoice_actions = (doctype) => {
const action = () => {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.generate_irn',
args: { docname: name },
args: { doctype, docname: name },
freeze: true,
callback: () => frm.reload_doc()
})
};
frm.add_custom_button(__("Generate IRN"), action, __('E Invoicing'));
add_custom_button(__("Generate IRN"), action);
}
if (docstatus == 1 && irn && !irn_cancelled && !ewaybill) {
@@ -52,6 +58,7 @@ erpnext.setup_einvoice_actions = (doctype) => {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_irn',
args: {
doctype,
docname: name,
irn: irn,
reason: data.reason.split('-')[0],
@@ -66,105 +73,23 @@ erpnext.setup_einvoice_actions = (doctype) => {
});
d.show();
};
frm.add_custom_button(__("Cancel IRN"), action, __("E Invoicing"));
add_custom_button(__("Cancel IRN"), action);
}
if (irn && !irn_cancelled && !ewaybill) {
const fields = [
{
'fieldname': 'transporter',
'label': 'Transporter',
'fieldtype': 'Link',
'options': 'Supplier',
'default': frm.doc.transporter
},
{
'fieldname': 'gst_transporter_id',
'label': 'GST Transporter ID',
'fieldtype': 'Data',
'fetch_from': 'transporter.gst_transporter_id',
'default': frm.doc.gst_transporter_id
},
{
'fieldname': 'driver',
'label': 'Driver',
'fieldtype': 'Link',
'options': 'Driver',
'default': frm.doc.driver
},
{
'fieldname': 'lr_no',
'label': 'Transport Receipt No',
'fieldtype': 'Data',
'default': frm.doc.lr_no
},
{
'fieldname': 'vehicle_no',
'label': 'Vehicle No',
'fieldtype': 'Data',
'depends_on': 'eval:(doc.mode_of_transport === "Road")',
'default': frm.doc.vehicle_no
},
{
'fieldname': 'distance',
'label': 'Distance (in km)',
'fieldtype': 'Float',
'default': frm.doc.distance
},
{
'fieldname': 'transporter_col_break',
'fieldtype': 'Column Break',
},
{
'fieldname': 'transporter_name',
'label': 'Transporter Name',
'fieldtype': 'Data',
'fetch_from': 'transporter.name',
'read_only': 1,
'default': frm.doc.transporter_name
},
{
'fieldname': 'mode_of_transport',
'label': 'Mode of Transport',
'fieldtype': 'Select',
'options': `\nRoad\nAir\nRail\nShip`,
'default': frm.doc.mode_of_transport
},
{
'fieldname': 'driver_name',
'label': 'Driver Name',
'fieldtype': 'Data',
'fetch_from': 'driver.full_name',
'read_only': 1,
'default': frm.doc.driver_name
},
{
'fieldname': 'lr_date',
'label': 'Transport Receipt Date',
'fieldtype': 'Date',
'default': frm.doc.lr_date
},
{
'fieldname': 'gst_vehicle_type',
'label': 'GST Vehicle Type',
'fieldtype': 'Select',
'options': `Regular\nOver Dimensional Cargo (ODC)`,
'depends_on': 'eval:(doc.mode_of_transport === "Road")',
'default': frm.doc.gst_vehicle_type
}
]
const action = () => {
const d = new frappe.ui.Dialog({
title: __('Generate E-Way Bill'),
wide: 1,
fields: fields,
fields: get_ewaybill_fields(frm),
primary_action: function() {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.generate_eway_bill',
args: {
docname: name, irn,
doctype,
docname: name,
irn,
...data
},
freeze: true,
@@ -177,7 +102,7 @@ erpnext.setup_einvoice_actions = (doctype) => {
d.show();
};
frm.add_custom_button(__("Generate E-Way Bill"), action, __("E Invoicing"));
add_custom_button(__("Generate E-Way Bill"), action);
}
if (docstatus == 1 && irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
@@ -206,6 +131,7 @@ erpnext.setup_einvoice_actions = (doctype) => {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill',
args: {
doctype,
docname: name,
eway_bill: ewaybill,
reason: data.reason.split('-')[0],
@@ -220,8 +146,94 @@ erpnext.setup_einvoice_actions = (doctype) => {
});
d.show();
};
frm.add_custom_button(__("Cancel E-Way Bill"), action, __("E Invoicing"));
add_custom_button(__("Cancel E-Way Bill"), action);
}
}
})
}
const get_ewaybill_fields = (frm) => {
return [
{
'fieldname': 'transporter',
'label': 'Transporter',
'fieldtype': 'Link',
'options': 'Supplier',
'default': frm.doc.transporter
},
{
'fieldname': 'gst_transporter_id',
'label': 'GST Transporter ID',
'fieldtype': 'Data',
'fetch_from': 'transporter.gst_transporter_id',
'default': frm.doc.gst_transporter_id
},
{
'fieldname': 'driver',
'label': 'Driver',
'fieldtype': 'Link',
'options': 'Driver',
'default': frm.doc.driver
},
{
'fieldname': 'lr_no',
'label': 'Transport Receipt No',
'fieldtype': 'Data',
'default': frm.doc.lr_no
},
{
'fieldname': 'vehicle_no',
'label': 'Vehicle No',
'fieldtype': 'Data',
'depends_on': 'eval:(doc.mode_of_transport === "Road")',
'default': frm.doc.vehicle_no
},
{
'fieldname': 'distance',
'label': 'Distance (in km)',
'fieldtype': 'Float',
'default': frm.doc.distance
},
{
'fieldname': 'transporter_col_break',
'fieldtype': 'Column Break',
},
{
'fieldname': 'transporter_name',
'label': 'Transporter Name',
'fieldtype': 'Data',
'fetch_from': 'transporter.name',
'read_only': 1,
'default': frm.doc.transporter_name
},
{
'fieldname': 'mode_of_transport',
'label': 'Mode of Transport',
'fieldtype': 'Select',
'options': `\nRoad\nAir\nRail\nShip`,
'default': frm.doc.mode_of_transport
},
{
'fieldname': 'driver_name',
'label': 'Driver Name',
'fieldtype': 'Data',
'fetch_from': 'driver.full_name',
'read_only': 1,
'default': frm.doc.driver_name
},
{
'fieldname': 'lr_date',
'label': 'Transport Receipt Date',
'fieldtype': 'Date',
'default': frm.doc.lr_date
},
{
'fieldname': 'gst_vehicle_type',
'label': 'GST Vehicle Type',
'fieldtype': 'Select',
'options': `Regular\nOver Dimensional Cargo (ODC)`,
'depends_on': 'eval:(doc.mode_of_transport === "Road")',
'default': frm.doc.gst_vehicle_type
}
];
}

View File

@@ -240,9 +240,7 @@ def get_eway_bill_details(invoice):
vehicle_type=vehicle_type[invoice.gst_vehicle_type]
))
@frappe.whitelist()
def make_einvoice(doctype, name):
invoice = frappe.get_doc(doctype, name)
def make_einvoice(invoice):
schema = read_json('einv_template')
trans_details = get_trans_details(invoice)
@@ -255,7 +253,7 @@ def make_einvoice(doctype, name):
buyer_details = get_overseas_address_details(invoice.customer_address)
else:
buyer_details = get_party_details(invoice.customer_address)
place_of_supply = get_place_of_supply(invoice, doctype) or invoice.billing_address_gstin
place_of_supply = get_place_of_supply(invoice, invoice.doctype) or invoice.billing_address_gstin
place_of_supply = place_of_supply[:2]
buyer_details.update(dict(place_of_supply=place_of_supply))
@@ -351,42 +349,10 @@ def validate_einvoice(validations, einvoice, errors=[]):
return errors
def update_invoice(doctype, docname, res):
enc_signed_invoice = res.get('SignedInvoice')
dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
frappe.db.set_value(doctype, docname, 'irn', res.get('Irn'))
frappe.db.set_value(doctype, docname, 'ewaybill', res.get('EwbNo'))
frappe.db.set_value(doctype, docname, 'signed_einvoice', dec_signed_invoice)
signed_qr_code = res.get('SignedQRCode')
frappe.db.set_value(doctype, docname, 'signed_qr_code', signed_qr_code)
attach_qrcode_image(doctype, docname, signed_qr_code)
def attach_qrcode_image(doctype, docname, qrcode):
if not qrcode: return
_file = frappe.new_doc('File')
_file.update({
'file_name': f'QRCode_{docname}.png',
'attached_to_doctype': doctype,
'attached_to_name': docname,
'content': 'qrcode',
'is_private': 1
})
_file.insert()
frappe.db.commit()
url = qrcreate(qrcode)
abs_file_path = os.path.abspath(_file.get_full_path())
url.png(abs_file_path, scale=2)
frappe.db.set_value(doctype, docname, 'qrcode_image', _file.file_url)
class ResponseFailure(Exception): pass
class GSPConnector():
def __init__(self):
def __init__(self, doctype, docname):
self.credentials = frappe.get_cached_doc('E Invoice Settings')
self.base_url = 'https://gsp.adaequare.com/'
@@ -397,6 +363,8 @@ class GSPConnector():
self.cancel_irn_url = self.base_url + 'test/enriched/ei/api/invoice/cancel'
self.cancel_ewaybill_url = self.base_url + '/test/enriched/ei/api/ewayapi'
self.generate_ewaybill_url = self.base_url + 'test/enriched/ei/api/ewaybill'
self.invoice = frappe.get_cached_doc(doctype, docname)
def get_auth_token(self):
if time_diff_in_seconds(self.credentials.token_expiry, now_datetime()) < 150.0:
@@ -473,23 +441,22 @@ class GSPConnector():
frappe.cache().hset('gstin_cache', key, details)
return details
def generate_irn(self, docname):
def generate_irn(self):
headers = self.get_headers()
doctype = 'Sales Invoice'
einvoice = make_einvoice(doctype, docname)
einvoice = make_einvoice(self.invoice)
data = json.dumps(einvoice)
try:
res = make_post_request(self.generate_irn_url, headers=headers, data=data)
if res.get('success'):
update_invoice(doctype, docname, res.get('result'))
self.set_einvoice_data(res.get('result'))
elif '2150' in res.get('message'):
# IRN already generated
irn = res.get('result')[0].get('Desc').get('Irn')
irn_details = self.get_irn_details(irn)
if irn_details:
update_invoice(doctype, docname, irn_details)
self.set_einvoice_data(irn_details)
else:
self.log_error(res)
@@ -521,9 +488,8 @@ class GSPConnector():
self.log_error()
self.raise_error(True)
def cancel_irn(self, docname, irn, reason, remark):
def cancel_irn(self, irn, reason, remark):
headers = self.get_headers()
doctype = 'Sales Invoice'
data = json.dumps({
'Irn': irn,
'Cnlrsn': reason,
@@ -533,8 +499,14 @@ class GSPConnector():
try:
res = make_post_request(self.cancel_irn_url, headers=headers, data=data)
if res.get('success'):
frappe.db.set_value(doctype, docname, 'irn_cancelled', 1)
# frappe.db.set_value(doctype, docname, 'cancelled_on', res.get('CancelDate'))
self.invoice.irn_cancelled = 1
self.invoice.flags.updater_reference = {
'doctype': self.invoice.doctype,
'docname': self.invoice.name,
'label': _('IRN Cancelled - {}').format(remark)
}
self.update_invoice()
else:
self.log_error(res)
raise ResponseFailure
@@ -550,8 +522,6 @@ class GSPConnector():
args = frappe._dict(kwargs)
headers = self.get_headers()
doctype = 'Sales Invoice'
docname = args.docname
eway_bill_details = get_eway_bill_details(args)
data = json.dumps({
'Irn': args.irn,
@@ -568,12 +538,16 @@ class GSPConnector():
try:
res = make_post_request(self.generate_ewaybill_url, headers=headers, data=data)
if res.get('success'):
frappe.db.set_value(doctype, docname, 'ewaybill', res.get('result').get('EwbNo'))
frappe.db.set_value(doctype, docname, 'eway_bill_cancelled', 0)
for d in args:
if d in ['docname', 'cmd']: continue
# update eway bill details in sales invoice
frappe.db.set_value(doctype, docname, d, args[d])
self.invoice.ewaybill = res.get('result').get('EwbNo')
self.invoice.eway_bill_cancelled = 0
self.invoice.update(args)
self.invoice.flags.updater_reference = {
'doctype': self.invoice.doctype,
'docname': self.invoice.name,
'label': _('E-Way Bill Generated')
}
self.update_invoice()
else:
self.log_error(res)
raise ResponseFailure
@@ -585,7 +559,7 @@ class GSPConnector():
self.log_error(data)
self.raise_error(True)
def cancel_eway_bill(self, docname, eway_bill, reason, remark):
def cancel_eway_bill(self, eway_bill, reason, remark):
headers = self.get_headers()
doctype = 'Sales Invoice'
data = json.dumps({
@@ -597,8 +571,15 @@ class GSPConnector():
try:
res = make_post_request(self.cancel_ewaybill_url, headers=headers, data=data)
if res.get('success'):
frappe.db.set_value(doctype, docname, 'ewaybill', '')
frappe.db.set_value(doctype, docname, 'eway_bill_cancelled', 1)
self.invoice.ewaybill = ''
self.invoice.eway_bill_cancelled = 1
self.invoice.flags.updater_reference = {
'doctype': self.invoice.doctype,
'docname': self.invoice.name,
'label': _('E-Way Bill Cancelled - {}').format(remark)
}
self.update_invoice()
else:
self.log_error(res)
raise ResponseFailure
@@ -625,23 +606,67 @@ class GSPConnector():
raise_exception=raise_exception,
indicator='red'
)
def set_einvoice_data(self, res):
enc_signed_invoice = res.get('SignedInvoice')
dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
self.invoice.irn = res.get('Irn')
self.invoice.ewaybill = res.get('EwbNo')
self.invoice.signed_einvoice = dec_signed_invoice
self.invoice.signed_qr_code = res.get('SignedQRCode')
self.attach_qrcode_image()
self.invoice.flags.updater_reference = {
'doctype': self.invoice.doctype,
'docname': self.invoice.name,
'label': _('IRN Generated')
}
self.update_invoice()
def attach_qrcode_image(self):
qrcode = self.invoice.signed_qr_code
doctype = self.invoice.doctype
docname = self.invoice.name
_file = frappe.new_doc('File')
_file.update({
'file_name': f'QRCode_{docname}.png',
'attached_to_doctype': doctype,
'attached_to_name': docname,
'content': 'qrcode',
'is_private': 1
})
_file.insert()
frappe.db.commit()
url = qrcreate(qrcode)
abs_file_path = os.path.abspath(_file.get_full_path())
url.png(abs_file_path, scale=2)
self.invoice.qrcode_image = _file.file_url
def update_invoice(self):
self.invoice.flags.ignore_validate_update_after_submit = True
self.invoice.flags.ignore_validate = True
self.invoice.save()
@frappe.whitelist()
def generate_irn(docname):
gsp_connector = GSPConnector()
gsp_connector.generate_irn(docname)
def generate_irn(doctype, docname):
gsp_connector = GSPConnector(doctype, docname)
gsp_connector.generate_irn()
@frappe.whitelist()
def cancel_irn(docname, irn, reason, remark):
gsp_connector = GSPConnector()
gsp_connector.cancel_irn(docname, irn, reason, remark)
def cancel_irn(doctype, docname, irn, reason, remark):
gsp_connector = GSPConnector(doctype, docname)
gsp_connector.cancel_irn(irn, reason, remark)
@frappe.whitelist()
def generate_eway_bill(**kwargs):
gsp_connector = GSPConnector()
def generate_eway_bill(doctype, docname, **kwargs):
gsp_connector = GSPConnector(doctype, docname)
gsp_connector.generate_eway_bill(**kwargs)
@frappe.whitelist()
def cancel_eway_bill(docname, eway_bill, reason, remark):
gsp_connector = GSPConnector()
gsp_connector.cancel_eway_bill(docname, eway_bill, reason, remark)
def cancel_eway_bill(doctype, docname, eway_bill, reason, remark):
gsp_connector = GSPConnector(doctype, docname)
gsp_connector.cancel_eway_bill(eway_bill, reason, remark)