2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 03:58:26 +00:00

Code Refactoring

This commit is contained in:
Piyush Singhania 2021-12-10 21:56:02 +05:30 committed by Alan
parent f4fa8a6d88
commit 228e069096
6 changed files with 192 additions and 217 deletions

178
accounting/gst.js Normal file
View File

@ -0,0 +1,178 @@
import frappe from 'frappejs';
import { _ } from 'frappejs/utils';
import { IPC_ACTIONS } from '@/messages';
import { ipcRenderer } from 'electron';
import { DateTime } from 'luxon';
import { sleep } from 'frappejs/utils';
import { makeJSON } from '@/utils';
/**
* GST is a map which gives a final rate for any given gst item
* eg: IGST-18 = 18
* eg: GST-18 = CGST-9 + SGST-9 = 18
*/
const GST = {
'GST-0': 0,
'GST-0.25': 0.25,
'GST-3': 3,
'GST-5': 5,
'GST-6': 6,
'GST-12': 12,
'GST-18': 18,
'GST-28': 28,
'IGST-0': 0,
'IGST-0.25': 0.25,
'IGST-3': 3,
'IGST-5': 5,
'IGST-6': 6,
'IGST-12': 12,
'IGST-18': 18,
'IGST-28': 28,
};
/**
* CSGST is a map which return the tax rate component for state or central
* eg: GST-12 = 6
*/
const CSGST = {
'GST-0': 0,
'GST-0.25': 0.125,
'GST-3': 1.5,
'GST-5': 2.5,
'GST-6': 3,
'GST-12': 6,
'GST-18': 9,
'GST-28': 14,
};
/**
* IGST is a map which return the tax rate for the igst item
* eg: IGST-18 = 18
*/
const IGST = {
'IGST-0.25': 0.25,
'IGST-3': 3,
'IGST-5': 5,
'IGST-6': 6,
'IGST-12': 12,
'IGST-18': 18,
'IGST-28': 28,
};
export async function generateGstr1Json(report, transferType) {
const printSettings = await frappe.getSingle('PrintSettings');
// TODO: if self gstin is not provided throw an error message
// telling that that report cannot be exported if company gst details are not configured
// avoiding hiding the button because that can feel like a bug
const savePath = await getSavePath();
if (!savePath) return;
const gstData = {
version: 'GST3.0.4',
hash: 'hash',
// fp is the the MMYYYY for the last month of the report
// for example if you are extracting report for 1st July 2020 to 31st September 2020 then
// fb = 092020
// TODO: fix this value to match the last date of range
fp: DateTime.local().toFormat('MMyyyy'),
gstin: printSettings.gstin,
};
// based condition we need to triggered different methods
if (transferType === 'B2B') {
gstData.b2b = await getB2bData(report.rows);
} else if (transferType === 'B2CL') {
gstData.b2cl = await getB2clData(report.rows);
} else if (transferType === 'B2CS') {
gstData.b2cs = await getB2csData(report.rows);
}
await sleep(1);
const jsonData = JSON.stringify(gstData);
makeJSON(jsonData, savePath);
}
async function getB2bData(invoices) {
const b2b = [];
invoices.forEach(async (row) => {
// it's must for the customer to have a gstin, if not it should not be here
const customer = {
ctin: row.gstin,
inv: [],
};
const invRecord = {
inum: row.invNo,
idt: DateTime.fromFormat(row.invDate, 'yyyy-MM-dd').toFormat('dd-MM-yyyy'),
value: row.invAmt,
pos: row.gstin && row.gstin.substring(0, 2),
rchrg: row.reverseCharge,
itms: [],
};
let items = await frappe.db
.knex('SalesInvoiceItem')
.where('parent', invRecord.inum);
items.forEach((item) => {
const itemRecord = {
num: item.item_code || 1801, // TODO: will be replaced by HSN CODE (item code)
itm_det: {
txval: item.baseAmount,
rt: GST[item.tax],
csamt: 0,
camt: ((CSGST[item.tax] || 0) * item.baseAmount) / 100,
samt: ((CSGST[item.tax] || 0) * item.baseAmount) / 100,
iamt: ((IGST[item.tax] || 0) * item.baseAmount) / 100,
},
};
invRecord.itms.push(itemRecord);
});
const customerRecord = b2b.find((b) => b.ctin === row.gstin);
if (customerRecord) {
customerRecord.inv.push(invRecord);
} else {
customer.inv.push(invRecord);
b2b.push(customer);
}
});
return b2b;
}
async function getB2clData(invoices) {
return [];
}
async function getB2csData(invoices) {
return [];
}
async function getSavePath(name='gstr1') {
const options = {
title: _('Select folder'),
defaultPath: `${name}.json`,
};
let {
filePath
} = await ipcRenderer.invoke(
IPC_ACTIONS.GET_SAVE_FILEPATH,
options
);
if (filePath) {
if (!filePath.endsWith('.json')) {
filePath = filePath + '.json';
}
}
return filePath;
}

View File

@ -67,21 +67,7 @@ const viewConfig = {
},
],
method: 'general-ledger',
linkFields: [
{
label: 'Clear Filters',
type: 'secondary',
action: async (report) => {
await report.getReportData({});
report.usedToReRender += 1;
},
},
{
label: 'Export',
type: 'primary',
action: () => {},
},
],
linkFields: [],
getColumns() {
return [
{

View File

@ -1,4 +1,5 @@
import ExportWizard from '../../src/components/ExportWizard';
import { generateGstr1Json } from '../../accounting/gst';
export default {
filterFields: [
@ -8,12 +9,12 @@ export default {
placeholder: 'Transfer Type',
fieldname: 'transferType',
options: [
'',
'B2B',
'B2C-Large',
'B2C-Small',
'Nil Rated, Exempted and Non GST supplies',
],
default: 'B2B',
size: 'small',
},
{
@ -40,42 +41,10 @@ export default {
],
linkFields: [
{
label: 'Export',
label: 'Export as JSON',
type: 'primary',
action: async (report) => {
async function getReportDetails() {
let [rows, columns] = await report.getReportData(
report.currentFilters
);
let columnData = columns.map((column) => {
return {
id: column.id,
content: column.content,
checked: true,
};
});
return {
title: title,
rows: rows,
columnData: columnData,
};
}
report.$modal.show({
modalProps: {
title: `Export ${title}`,
noFooter: true,
},
component: ExportWizard,
props: await getReportDetails(),
});
},
},
{
label: 'Clear Filters',
type: 'secondary',
action: async (report) => {
await report.getReportData({});
report.usedToReRender += 1;
action: async (report, transferType) => {
generateGstr1Json(report, transferType);
},
},
],

View File

@ -17,6 +17,7 @@ class GSTR1 extends BaseGSTR {
'B2B': row => row.gstin,
'B2C-Large': row => !row.gstin && !row.inState && row.invAmt >= 250000,
'B2C-Small': row => !row.gstin && (row.inState || (row.inState && row.invAmt < 250000)),
// TODO: fix the condition for nil rated
'Nil Rated, Exempted and Non GST supplies': row => row
};

View File

@ -30,16 +30,7 @@ export default {
}
}
],
linkFields: [
{
label: 'Clear Filters',
type: 'secondary',
action: async report => {
await report.getReportData({});
report.usedToReRender += 1;
}
}
],
linkFields: [],
getColumns(data) {
const columns = [
{ label: 'Account', fieldtype: 'Data', fieldname: 'account', width: 2 },

View File

@ -2,15 +2,15 @@
<div class="flex flex-col max-w-full">
<PageHeader>
<h1 slot="title" class="text-2xl font-bold">{{ report.title }}</h1>
<template slot="actions">
<template slot="actions">
<Button
:icon="true"
@click="downloadAsJson"
@click="link.action(reportData, filters.transferType)"
v-for="link of report.linkFields"
:key="link.label"
type="primary"
v-if="isGstReportsPage"
class="ml-2 text-white text-xs"
>
{{ _('Download as JSON') }}
{{ link.label }}
</Button>
<SearchBar class="ml-2" />
</template>
@ -102,11 +102,6 @@ import Row from '@/components/Row';
import WithScroll from '@/components/WithScroll';
import FormControl from '@/components/Controls/FormControl';
import reportViewConfig from '@/../reports/view';
import { makeJSON } from '@/utils';
import { ipcRenderer } from 'electron';
import { IPC_ACTIONS } from '@/messages';
import { DateTime } from 'luxon';
import { sleep } from 'frappejs/utils';
export default {
name: 'Report',
@ -137,7 +132,6 @@ export default {
rows: [],
columns: [],
},
printSettings: null,
};
},
async activated() {
@ -145,9 +139,6 @@ export default {
await this.setDefaultFilters();
await this.fetchReportData();
},
async mounted() {
this.printSettings = await frappe.getSingle('PrintSettings');
},
methods: {
onBodyScroll({ scrollLeft }) {
this.$nextTick(() => {
@ -280,147 +271,6 @@ export default {
this.loading ? 'text-gray-100' : 'text-gray-900',
];
},
async downloadAsJson() {
const savePath = await this.getSavePath();
if (!savePath) return;
const gstRates = {
'GST-0': 0,
'GST-0.25': 0.25,
'GST-3': 3,
'GST-5': 5,
'GST-6': 6,
'GST-12': 12,
'GST-18': 18,
'GST-28': 28,
'IGST-0': 0,
'IGST-0.25': 0.25,
'IGST-3': 3,
'IGST-5': 5,
'IGST-6': 6,
'IGST-12': 12,
'IGST-18': 18,
'IGST-28': 28,
};
const csgstRates = {
'GST-0': 0,
'GST-0.25': 0.125,
'GST-3': 1.5,
'GST-5': 2.5,
'GST-6': 3,
'GST-12': 6,
'GST-18': 9,
'GST-28': 14,
'IGST-0': 0,
'IGST-0.25': 0,
'IGST-3': 0,
'IGST-5': 0,
'IGST-6': 0,
'IGST-12': 0,
'IGST-18': 0,
'IGST-28': 0,
};
const igstRates = {
'GST-0': 0,
'GST-0.25': 0,
'GST-3': 0,
'GST-5': 0,
'GST-6': 0,
'GST-12': 0,
'GST-18': 0,
'GST-28': 0,
'IGST-0': 0,
'IGST-0.25': 0.25,
'IGST-3': 3,
'IGST-5': 5,
'IGST-6': 6,
'IGST-12': 12,
'IGST-18': 18,
'IGST-28': 28,
};
const gstData = {
version: 'GST3.0.4',
hash: 'hash',
fp: DateTime.local().toFormat('MMyyyy'),
gstin: this.printSettings.gstin,
b2b: [],
};
let rows = this.reportData.rows;
rows.forEach(async (values) => {
const b2bRecord = {
ctin: values.gstin,
inv: [],
};
const invRecord = {
inum: values.invNo,
idt: values.invDate,
value: values.invAmt,
pos: values.gstin.substring(0, 2),
rchrg: values.reverseCharge,
itms: [],
};
let items = await frappe.db
.knex('SalesInvoiceItem')
.where('parent', invRecord.inum);
items.forEach((_item) => {
const item = {
num: 1801, // will be replaced by HSN CODE
itm_det: {
txval: _item.baseAmount,
rt: gstRates[_item.tax],
cess: 0,
camt: (csgstRates[_item.tax] * _item.baseAmount) / 100,
samt: (csgstRates[_item.tax] * _item.baseAmount) / 100,
iamt: (igstRates[_item.tax] * _item.baseAmount) / 100,
},
};
invRecord.itms.push(item);
});
let found = false;
found = gstData.b2b.find((_b2bRecord) => {
if(_b2bRecord.ctin === values.gstin) {
_b2bRecord.inv.push(invRecord);
return true;
}
});
if (!found) {
b2bRecord.inv.push(invRecord);
gstData.b2b.push(b2bRecord);
}
});
await sleep(1);
const jsonData = JSON.stringify(gstData);
makeJSON(jsonData, savePath);
},
async getSavePath() {
const options = {
title: this._('Select folder'),
defaultPath: `${this.reportName}.json`,
};
let { filePath } = await ipcRenderer.invoke(
IPC_ACTIONS.GET_SAVE_FILEPATH,
options
);
if (filePath) {
if (!filePath.endsWith('.json')) {
filePath = filePath + '.json';
}
}
return filePath;
},
},
computed: {
columns() {
@ -495,4 +345,4 @@ export default {
.report-scroll-container::-webkit-scrollbar-track {
background-color: white;
}
</style>
</style>