brotherton-erpnext/erpnext/regional/india/e_invoice/einvoice.js
Saqib 17e96901db feat: GST E Invoicing (#23455)
* feat: init e-invoice settings

* feat: read public key file

* feat: rsa encryption with public key

* feat: save token and sek from auth request

* chore: handle error response

* feat: AES decryption of SEK with appkey

* feat: decrypt json data with SEK

* feat: make e invoice from erpnext sales invoice

* feat: generate IRN

* feat: decode signed json and QR code

* chore: validations

* feat: cancel IRN

* feat: complete e-invoice schema

* chore: move e-invoice settings to regional

* chore: split einvoice settings and operations

* chore: rename schema to template & js cleanup

* feat: make IRN field on regional setup

* feat: Generate & Cancel IRN from Sales Invoice

* chore: minor fixes

* fix: item discount

* chore: show irn cancelled check after cancellation

* fix: hide cancel irn dialog on error

* fix: public key is required on validate

* fix: cannot find attached key file

* fix: validation if e invoicing is disabled

* fix: do not show generate irn for invalid supply type

* fix: update irn_cancelled after cancelling irn

* chore: show irn field for proper gst_category

* feat: e-way bill details in e-invoice

* fix: save e-way bill no on irn generation

* chore: no copy on e invoice custom fields

* feat: cancel e-way bill before cancelling IRN

* feat: manual download / upload json

* chore: group e-invoicing actions

* fix: fn name

* chore: save signed invoice and qrcode after uplaoding irn

* fix: fetch token if not valid

* chore: move einvoicing stuff to seperate folder

* feat: QRCode Image and E-Invoice Print Format

* fix: bug

* fix: invalid syntax

* chore: code cleanup

* chore: clean up e invoice actions

* fix: download & upload e-invoice

* fix: print format

* fix: validations

* fix: add permissions on regional setup

* feat: add patch

* fix: validate document name

* fix: return date

* fix: credit note einvoice

* fix: validations

* fix: error logging

* fix: e_invoice module not found

* fix: add missing package

* fix: rename e_invoice_utils.py

* fix: einvoice field validation

* fix: patch

* fix: invoice totals calculation

* fix: other charges calculation

* chore: improve document name validation message

* fix: qr code image string

* feat: initialize GSP connector

* chore: remove unwanted fields

* fix: qr code generation

* feat: fetch and cache GSTIN details

* feat: generate & cancel IRN

* feat: cancel eway bill

* chore: remove unwanted fuctions

* chore: clean up einvoice actions

* fix: attach qrcode on irn generation

* fix: generate & cancel IRN

* fix: show/hide eway bill fields

* fix: valiations

* feat: generate eway bill from IRN

* chore: remove unwanted imports

* chore: error logging

* feat: header & footer in GST E Invoice

* chore: remove test pincode

* fix: invalid syntax

* feat: cess non advolem on einvoice item

* chore: remove fetch token from e invocie settings

* fix: imports

* fix: error handling

* feat: update timeline on einvoice actions

* fix: qrcode image size

* fix: exclude intra company transactions

* fix: eway bill test

* fix: ewaybill mandatory conditions

* chore: add tests

* fix: returning condition

* feat: log e-invocing requests

* chore: add ack date and ack no field for print formats

* fix: sider issues

* feat: show e-invoice preview before IRN generation

* fix: use as_list for error message

* fix: minor ux issues

* fix: dialog is undefined

* fix: error handling

* feat: add docs link to e invoice settings

* feat: multiple gstins for e invoicing

* fix: uncomment test condition

* fix: remove test pincode

* fix: cannot cancel irn without submitting sales invoice

* chore: code cleanup

* fix: sider issues

* fix: e invoice request log permissions

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2020-12-25 20:55:21 +05:30

305 lines
7.8 KiB
JavaScript

erpnext.setup_einvoice_actions = (doctype) => {
frappe.ui.form.on(doctype, {
refresh(frm) {
const einvoicing_enabled = frappe.db.get_value("E Invoice Settings", "E Invoice Settings", "enable");
const supply_type = frm.doc.gst_category;
const valid_supply_type = ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type);
const company_transaction = frm.doc.billing_address_gstin == frm.doc.company_gstin;
if (!einvoicing_enabled || !valid_supply_type || company_transaction) return;
const { doctype, 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 (!irn && !__unsaved) {
const action = () => {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.get_einvoice',
args: { doctype, docname: name },
freeze: true,
callback: (res) => {
const einvoice = res.message;
show_einvoice_preview(frm, einvoice);
}
});
};
add_custom_button(__("Generate IRN"), action);
}
if (irn && !irn_cancelled && !ewaybill) {
const 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
}
];
const action = () => {
const d = new frappe.ui.Dialog({
title: __("Cancel IRN"),
fields: fields,
primary_action: function() {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_irn',
args: {
doctype,
docname: name,
irn: irn,
reason: data.reason.split('-')[0],
remark: data.remark
},
freeze: true,
callback: () => frm.reload_doc() || d.hide(),
error: () => d.hide()
});
},
primary_action_label: __('Submit')
});
d.show();
};
add_custom_button(__("Cancel IRN"), action);
}
if (irn && !irn_cancelled && !ewaybill) {
const action = () => {
const d = new frappe.ui.Dialog({
title: __('Generate E-Way Bill'),
wide: 1,
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: {
doctype,
docname: name,
irn,
...data
},
freeze: true,
callback: () => frm.reload_doc() || d.hide(),
error: () => d.hide()
});
},
primary_action_label: __('Submit')
});
d.show();
};
add_custom_button(__("Generate E-Way Bill"), action);
}
if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
const 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
}
];
const action = () => {
const d = new frappe.ui.Dialog({
title: __('Cancel E-Way Bill'),
fields: fields,
primary_action: function() {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill',
args: {
doctype,
docname: name,
eway_bill: ewaybill,
reason: data.reason.split('-')[0],
remark: data.remark
},
freeze: true,
callback: () => frm.reload_doc() || d.hide(),
error: () => d.hide()
});
},
primary_action_label: __('Submit')
});
d.show();
};
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
}
];
};
const request_irn_generation = (frm) => {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.generate_irn',
args: { doctype: frm.doc.doctype, docname: frm.doc.name },
freeze: true,
callback: () => frm.reload_doc()
});
};
const get_preview_dialog = (frm, action) => {
const dialog = new frappe.ui.Dialog({
title: __("Preview"),
wide: 1,
fields: [
{
"label": "Preview",
"fieldname": "preview_html",
"fieldtype": "HTML"
}
],
primary_action: () => action(frm) || dialog.hide(),
primary_action_label: __('Generate IRN')
});
return dialog;
};
const show_einvoice_preview = (frm, einvoice) => {
const preview_dialog = get_preview_dialog(frm, request_irn_generation);
// initialize e-invoice fields
einvoice["Irn"] = einvoice["AckNo"] = ''; einvoice["AckDt"] = frappe.datetime.nowdate();
frm.doc.signed_einvoice = JSON.stringify(einvoice);
// initialize preview wrapper
const $preview_wrapper = preview_dialog.get_field("preview_html").$wrapper;
$preview_wrapper.html(
`<div>
<div class="print-preview">
<div class="print-format"></div>
</div>
<div class="page-break-message text-muted text-center text-medium margin-top"></div>
</div>`
);
frappe.call({
method: "frappe.www.printview.get_html_and_style",
args: {
doc: frm.doc,
print_format: "GST E-Invoice",
no_letterhead: 1
},
callback: function (r) {
if (!r.exc) {
$preview_wrapper.find(".print-format").html(r.message.html);
const style = `
.print-format { box-shadow: 0px 0px 5px rgba(0,0,0,0.2); padding: 0.30in; min-height: 80vh; }
.print-preview { min-height: 0px; }
.modal-dialog { width: 720px; }`;
frappe.dom.set_style(style, "custom-print-style");
preview_dialog.show();
}
}
});
};