mirror of
https://github.com/frappe/books.git
synced 2024-12-23 11:29:03 +00:00
Merge pull request #295 from ankitsinghaniyaz/feature/gstr1-b2c
Add ability to export GSTR1 B2CS and B2CL
This commit is contained in:
commit
0d2854557a
@ -5,6 +5,46 @@ import { DateTime } from 'luxon';
|
||||
import { saveExportData } from '../reports/commonExporter';
|
||||
import { getSavePath } from '../src/utils';
|
||||
|
||||
// prettier-ignore
|
||||
export const stateCodeMap = {
|
||||
'JAMMU AND KASHMIR': '1',
|
||||
'HIMACHAL PRADESH': '2',
|
||||
'PUNJAB': '3',
|
||||
'CHANDIGARH': '4',
|
||||
'UTTARAKHAND': '5',
|
||||
'HARYANA': '6',
|
||||
'DELHI': '7',
|
||||
'RAJASTHAN': '8',
|
||||
'UTTAR PRADESH': '9',
|
||||
'BIHAR': '10',
|
||||
'SIKKIM': '11',
|
||||
'ARUNACHAL PRADESH': '12',
|
||||
'NAGALAND': '13',
|
||||
'MANIPUR': '14',
|
||||
'MIZORAM': '15',
|
||||
'TRIPURA': '16',
|
||||
'MEGHALAYA': '17',
|
||||
'ASSAM': '18',
|
||||
'WEST BENGAL': '19',
|
||||
'JHARKHAND': '20',
|
||||
'ODISHA': '21',
|
||||
'CHATTISGARH': '22',
|
||||
'MADHYA PRADESH': '23',
|
||||
'GUJARAT': '24',
|
||||
'DADRA AND NAGAR HAVELI AND DAMAN AND DIU': '26',
|
||||
'MAHARASHTRA': '27',
|
||||
'KARNATAKA': '29',
|
||||
'GOA': '30',
|
||||
'LAKSHADWEEP': '31',
|
||||
'KERALA': '32',
|
||||
'TAMIL NADU': '33',
|
||||
'PUDUCHERRY': '34',
|
||||
'ANDAMAN AND NICOBAR ISLANDS': '35',
|
||||
'TELANGANA': '36',
|
||||
'ANDHRA PRADESH': '37',
|
||||
'LADAKH': '38',
|
||||
};
|
||||
|
||||
const GST = {
|
||||
'GST-0': 0,
|
||||
'GST-0.25': 0.25,
|
||||
@ -112,7 +152,7 @@ async function generateB2bData(rows) {
|
||||
|
||||
items.forEach((item) => {
|
||||
const itemRecord = {
|
||||
num: item.hsnCode || 0,
|
||||
num: item.hsnCode,
|
||||
itm_det: {
|
||||
txval: item.baseAmount,
|
||||
rt: GST[item.tax],
|
||||
@ -140,9 +180,75 @@ async function generateB2bData(rows) {
|
||||
}
|
||||
|
||||
async function generateB2clData(invoices) {
|
||||
return [];
|
||||
const b2cl = [];
|
||||
|
||||
for (let invoice of invoices) {
|
||||
const stateInvoiceRecord = {
|
||||
pos: stateCodeMap[invoice.place.toUpperCase()],
|
||||
inv: [],
|
||||
};
|
||||
|
||||
const invRecord = {
|
||||
inum: invoice.invNo,
|
||||
idt: DateTime.fromFormat(invoice.invDate, 'yyyy-MM-dd').toFormat(
|
||||
'dd-MM-yyyy'
|
||||
),
|
||||
val: invoice.invAmt,
|
||||
itms: [],
|
||||
};
|
||||
|
||||
let items = await frappe.db
|
||||
.knex('SalesInvoiceItem')
|
||||
.where('parent', invRecord.inum);
|
||||
|
||||
items.forEach((item) => {
|
||||
const itemRecord = {
|
||||
num: item.hsnCode,
|
||||
itm_det: {
|
||||
txval: item.baseAmount,
|
||||
rt: GST[item.tax],
|
||||
csamt: 0,
|
||||
iamt: ((invoice.rate || 0) * item.baseAmount) / 100,
|
||||
},
|
||||
};
|
||||
|
||||
invRecord.itms.push(itemRecord);
|
||||
});
|
||||
|
||||
const stateRecord = b2cl.find((b) => b.pos === stateCodeMap[invoice.place]);
|
||||
|
||||
if (stateRecord) {
|
||||
stateRecord.inv.push(invRecord);
|
||||
} else {
|
||||
stateInvoiceRecord.inv.push(invRecord);
|
||||
b2cl.push(stateInvoiceRecord);
|
||||
}
|
||||
}
|
||||
|
||||
return b2cl;
|
||||
}
|
||||
|
||||
async function generateB2csData(invoices) {
|
||||
return [];
|
||||
const b2cs = [];
|
||||
|
||||
for (let invoice of invoices) {
|
||||
const pos = invoice.place.toUpperCase();
|
||||
|
||||
const invRecord = {
|
||||
sply_ty: invoice.inState ? 'INTRA' : 'INTER',
|
||||
pos: stateCodeMap[pos],
|
||||
// "OE" - Abbreviation for errors and omissions excepted.
|
||||
typ: 'OE',
|
||||
txval: invoice.taxVal,
|
||||
rt: invoice.rate,
|
||||
iamt: !invoice.inState ? (invoice.taxVal * invoice.rate) / 100 : 0,
|
||||
camt: invoice.inState ? invoice.cgstAmt : 0,
|
||||
samt: invoice.inState ? invoice.sgstAmt : 0,
|
||||
csamt: 0,
|
||||
};
|
||||
|
||||
b2cs.push(invRecord);
|
||||
}
|
||||
|
||||
return b2cs;
|
||||
}
|
||||
|
@ -1,6 +1,20 @@
|
||||
import { stateCodeMap } from '../../../accounting/gst';
|
||||
import countryList from '../../../fixtures/countryInfo.json';
|
||||
import { titleCase } from '../../../src/utils';
|
||||
|
||||
function getStates(doc) {
|
||||
switch (doc.country) {
|
||||
case 'India':
|
||||
return Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Address',
|
||||
doctype: 'DocType',
|
||||
regional: 1,
|
||||
isSingle: 0,
|
||||
keywordFields: [
|
||||
'addressLine1',
|
||||
@ -8,7 +22,7 @@ export default {
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'postalCode'
|
||||
'postalCode',
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
@ -22,69 +36,71 @@ export default {
|
||||
fieldname: 'addressLine2',
|
||||
label: 'Address Line 2',
|
||||
placeholder: 'Address Line 2',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'city',
|
||||
label: 'City / Town',
|
||||
placeholder: 'City / Town',
|
||||
fieldtype: 'Data',
|
||||
required: 1
|
||||
required: 1,
|
||||
},
|
||||
{
|
||||
fieldname: 'state',
|
||||
label: 'State',
|
||||
placeholder: 'State',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'AutoComplete',
|
||||
getList: getStates,
|
||||
},
|
||||
{
|
||||
fieldname: 'country',
|
||||
label: 'Country',
|
||||
placeholder: 'Country',
|
||||
fieldtype: 'Data',
|
||||
required: 1
|
||||
fieldtype: 'AutoComplete',
|
||||
getList: () => Object.keys(countryList).sort(),
|
||||
required: 1,
|
||||
},
|
||||
{
|
||||
fieldname: 'postalCode',
|
||||
label: 'Postal Code',
|
||||
placeholder: 'Postal Code',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'emailAddress',
|
||||
label: 'Email Address',
|
||||
placeholder: 'Email Address',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'phone',
|
||||
label: 'Phone',
|
||||
placeholder: 'Phone',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'fax',
|
||||
label: 'Fax',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'addressDisplay',
|
||||
fieldtype: 'Text',
|
||||
label: 'Address Display',
|
||||
readOnly: true,
|
||||
formula: doc => {
|
||||
formula: (doc) => {
|
||||
return [
|
||||
doc.addressLine1,
|
||||
doc.addressLine2,
|
||||
doc.city,
|
||||
doc.state,
|
||||
doc.country,
|
||||
doc.postalCode
|
||||
doc.postalCode,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
quickEditFields: [
|
||||
'addressLine1',
|
||||
@ -92,7 +108,7 @@ export default {
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'postalCode'
|
||||
'postalCode',
|
||||
],
|
||||
inlineEditDisplayField: 'addressDisplay'
|
||||
inlineEditDisplayField: 'addressDisplay',
|
||||
};
|
||||
|
30
models/doctype/Address/RegionalChanges.js
Normal file
30
models/doctype/Address/RegionalChanges.js
Normal file
@ -0,0 +1,30 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { stateCodeMap } from '../../../accounting/gst';
|
||||
import { titleCase } from '../../../src/utils';
|
||||
import AddressOriginal from './Address';
|
||||
|
||||
export default function getAugmentedAddress({ country }) {
|
||||
const Address = cloneDeep(AddressOriginal);
|
||||
if (!country) {
|
||||
return Address;
|
||||
}
|
||||
|
||||
const stateList = Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
if (country === 'India') {
|
||||
Address.fields = [
|
||||
...Address.fields,
|
||||
{
|
||||
fieldname: 'pos',
|
||||
label: 'Place of Supply',
|
||||
fieldtype: 'AutoComplete',
|
||||
placeholder: 'Place of Supply',
|
||||
formula: (doc) => (stateList.includes(doc.state) ? doc.state : ''),
|
||||
getList: () => stateList,
|
||||
},
|
||||
];
|
||||
|
||||
Address.quickEditFields = [...Address.quickEditFields, 'pos'];
|
||||
}
|
||||
|
||||
return Address;
|
||||
}
|
@ -30,7 +30,6 @@
|
||||
"knex": "^0.95.12",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^2.0.2",
|
||||
"portal-vue": "^2.1.7",
|
||||
"sqlite3": "^5.0.2",
|
||||
"vue": "^2.6.14",
|
||||
"vue-router": "^3.5.3"
|
||||
|
@ -27,7 +27,7 @@ export default {
|
||||
},
|
||||
],
|
||||
actions: getCommonExportActions('balance-sheet'),
|
||||
getColumns(data) {
|
||||
getColumns({ data }) {
|
||||
const columns = [
|
||||
{ label: 'Account', fieldtype: 'Data', fieldname: 'account', width: 2 },
|
||||
];
|
||||
|
@ -1,22 +1,27 @@
|
||||
import frappe from 'frappejs';
|
||||
import { stateCodeMap } from '../../accounting/gst';
|
||||
|
||||
class BaseGSTR {
|
||||
async getCompleteReport(gstrType, filters) {
|
||||
if (['GSTR-1', 'GSTR-2'].includes(gstrType)) {
|
||||
const place = filters.place;
|
||||
delete filters.place;
|
||||
let entries = await frappe.db.getAll({
|
||||
doctype: gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice',
|
||||
filters
|
||||
filters,
|
||||
});
|
||||
filters.place = place;
|
||||
|
||||
let tableData = [];
|
||||
for (let entry of entries) {
|
||||
entry.doctype = gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice';
|
||||
entry.doctype =
|
||||
gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice';
|
||||
const row = await this.getRow(entry);
|
||||
tableData.push(row);
|
||||
}
|
||||
|
||||
if (Object.keys(filters).length != 0) {
|
||||
tableData = tableData.filter(row => {
|
||||
tableData = tableData.filter((row) => {
|
||||
if (filters.account) return row.account === filters.account;
|
||||
if (filters.transferType)
|
||||
return row.transferType === filters.transferType;
|
||||
@ -24,6 +29,7 @@ class BaseGSTR {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return tableData;
|
||||
} else {
|
||||
return [];
|
||||
@ -31,36 +37,55 @@ class BaseGSTR {
|
||||
}
|
||||
|
||||
async getRow(ledgerEntry) {
|
||||
let row = {};
|
||||
ledgerEntry = await frappe.getDoc(ledgerEntry.doctype, ledgerEntry.name);
|
||||
|
||||
const row = {};
|
||||
const { gstin } = frappe.AccountingSettings;
|
||||
|
||||
let party = await frappe.getDoc(
|
||||
'Party',
|
||||
ledgerEntry.customer || ledgerEntry.supplier
|
||||
);
|
||||
|
||||
if (party.address) {
|
||||
let addressDetails = await frappe.getDoc('Address', party.address);
|
||||
row.place = addressDetails.state || '';
|
||||
row.place = addressDetails.pos || '';
|
||||
}
|
||||
|
||||
row.gstin = party.gstin;
|
||||
row.partyName = ledgerEntry.customer || ledgerEntry.supplier;
|
||||
row.invNo = ledgerEntry.name;
|
||||
row.invDate = ledgerEntry.date;
|
||||
row.rate = 0;
|
||||
row.inState = true;
|
||||
row.inState =
|
||||
gstin && gstin.substring(0, 2) === stateCodeMap[row.place?.toUpperCase()];
|
||||
row.reverseCharge = !party.gstin ? 'Y' : 'N';
|
||||
ledgerEntry.taxes?.forEach(tax => {
|
||||
|
||||
ledgerEntry.taxes?.forEach((tax) => {
|
||||
row.rate += tax.rate;
|
||||
const taxAmt = (tax.rate * ledgerEntry.netTotal) / 100;
|
||||
if (tax.account === 'IGST') row.igstAmt = taxAmt;
|
||||
if (tax.account === 'IGST') row.inState = false;
|
||||
if (tax.account === 'CGST') row.cgstAmt = taxAmt;
|
||||
if (tax.account === 'SGST') row.sgstAmt = taxAmt;
|
||||
if (tax.account === 'Nil Rated') row.nilRated = true;
|
||||
if (tax.account === 'Exempt') row.exempt = true;
|
||||
if (tax.account === 'Non GST') row.nonGST = true;
|
||||
|
||||
switch (tax.account) {
|
||||
case 'IGST': {
|
||||
row.igstAmt = taxAmt;
|
||||
row.inState = false;
|
||||
}
|
||||
case 'CGST':
|
||||
row.cgstAmt = taxAmt;
|
||||
case 'SGST':
|
||||
row.sgstAmt = taxAmt;
|
||||
case 'Nil Rated':
|
||||
row.nilRated = true;
|
||||
case 'Exempt':
|
||||
row.exempt = true;
|
||||
case 'Non GST':
|
||||
row.nonGST = true;
|
||||
}
|
||||
});
|
||||
|
||||
row.invAmt = ledgerEntry.grandTotal;
|
||||
row.taxVal = ledgerEntry.netTotal;
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DateTime } from 'luxon';
|
||||
import { generateGstr1Json } from '../../accounting/gst';
|
||||
import { generateGstr1Json, stateCodeMap } from '../../accounting/gst';
|
||||
import { titleCase } from '../../src/utils';
|
||||
|
||||
const transferTypeMap = {
|
||||
B2B: 'B2B',
|
||||
@ -7,6 +8,7 @@ const transferTypeMap = {
|
||||
B2CS: 'B2C-Small',
|
||||
NR: 'Nil Rated, Exempted and Non GST supplies',
|
||||
};
|
||||
const stateList = Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
|
||||
export default {
|
||||
filterFields: [
|
||||
@ -21,11 +23,12 @@ export default {
|
||||
size: 'small',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Data',
|
||||
fieldtype: 'AutoComplete',
|
||||
label: 'Place',
|
||||
size: 'small',
|
||||
placeholder: 'Place',
|
||||
fieldname: 'place',
|
||||
getList: () => stateList,
|
||||
},
|
||||
{
|
||||
fieldtype: 'Date',
|
||||
@ -55,14 +58,8 @@ export default {
|
||||
},
|
||||
],
|
||||
|
||||
getColumns() {
|
||||
return [
|
||||
{
|
||||
label: 'GSTIN No.',
|
||||
fieldname: 'gstin',
|
||||
fieldtype: 'Data',
|
||||
width: 1.5,
|
||||
},
|
||||
getColumns({ filters }) {
|
||||
const columns = [
|
||||
{
|
||||
label: 'Party',
|
||||
fieldtype: 'Data',
|
||||
@ -121,5 +118,17 @@ export default {
|
||||
fieldtype: 'Currency',
|
||||
},
|
||||
];
|
||||
|
||||
const transferType = filters.transferType || 'B2B';
|
||||
if (transferType === 'B2B') {
|
||||
columns.unshift({
|
||||
label: 'GSTIN No.',
|
||||
fieldname: 'gstin',
|
||||
fieldtype: 'Data',
|
||||
width: 1.5,
|
||||
});
|
||||
}
|
||||
|
||||
return columns;
|
||||
},
|
||||
};
|
||||
|
@ -8,6 +8,8 @@ class GSTR1 extends BaseGSTR {
|
||||
filters.cancelled = 0;
|
||||
if (params.toDate || params.fromDate) {
|
||||
filters.date = [];
|
||||
|
||||
if (params.place) filters.place = params.place;
|
||||
if (params.toDate) filters.date.push('<=', params.toDate);
|
||||
if (params.fromDate) filters.date.push('>=', params.fromDate);
|
||||
}
|
||||
@ -18,7 +20,7 @@ class GSTR1 extends BaseGSTR {
|
||||
const conditions = {
|
||||
'B2B': row => row.gstin,
|
||||
'B2CL': row => !row.gstin && !row.inState && row.invAmt >= 250000,
|
||||
'B2CS': row => !row.gstin && (row.inState || (row.inState && row.invAmt < 250000)),
|
||||
'B2CS': row => !row.gstin && (row.inState || row.invAmt < 250000),
|
||||
'NR': row => (row.rate === 0), // this takes care of both nil rated, exempted goods
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ export default {
|
||||
},
|
||||
],
|
||||
actions: getCommonExportActions('profit-and-loss'),
|
||||
getColumns(data) {
|
||||
getColumns({ data }) {
|
||||
const columns = [
|
||||
{ label: 'Account', fieldtype: 'Data', fieldname: 'account', width: 2 },
|
||||
];
|
||||
|
@ -32,7 +32,7 @@ export default {
|
||||
},
|
||||
],
|
||||
actions: getCommonExportActions('trial-balance'),
|
||||
getColumns(data) {
|
||||
getColumns() {
|
||||
const columns = [
|
||||
{ label: 'Account', fieldtype: 'Data', fieldname: 'account', width: 2 },
|
||||
{
|
||||
|
@ -18,7 +18,6 @@
|
||||
@setup-complete="showSetupWizardOrDesk(true)"
|
||||
@setup-canceled="setupCanceled"
|
||||
/>
|
||||
<portal-target name="popovers" multiple></portal-target>
|
||||
<div id="toast-container" class="absolute bottom-0 right-0 mr-6 mb-3">
|
||||
<div id="toast-target" />
|
||||
</div>
|
||||
|
@ -59,6 +59,9 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
inject: {
|
||||
doc: { default: null },
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
async updateSuggestions(e) {
|
||||
@ -81,7 +84,7 @@ export default {
|
||||
keyword = keyword.toLowerCase();
|
||||
|
||||
let list = this.df.getList
|
||||
? await this.df.getList()
|
||||
? await this.df.getList(this.doc)
|
||||
: this.df.options || [];
|
||||
|
||||
let items = list.map((d) => {
|
||||
@ -118,6 +121,12 @@ export default {
|
||||
async onBlur(value) {
|
||||
if (value === '' || value == null) {
|
||||
this.triggerChange('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (value && this.suggestions.length === 0) {
|
||||
this.triggerChange(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -31,6 +31,7 @@
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
class="text-black"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
|
@ -3,17 +3,15 @@
|
||||
<div class="h-full">
|
||||
<slot name="target" :togglePopover="togglePopover"></slot>
|
||||
</div>
|
||||
<portal to="popovers">
|
||||
<div
|
||||
ref="popover"
|
||||
:class="popoverClass"
|
||||
class="bg-white rounded border shadow-md popover-container relative"
|
||||
v-show="isOpen"
|
||||
>
|
||||
<div v-if="!hideArrow" class="popover-arrow" ref="popover-arrow"></div>
|
||||
<slot name="content" :togglePopover="togglePopover"></slot>
|
||||
</div>
|
||||
</portal>
|
||||
<div
|
||||
ref="popover"
|
||||
:class="popoverClass"
|
||||
class="bg-white rounded border shadow-md popover-container relative"
|
||||
v-show="isOpen"
|
||||
>
|
||||
<div v-if="!hideArrow" class="popover-arrow" ref="popover-arrow"></div>
|
||||
<slot name="content" :togglePopover="togglePopover"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -25,17 +23,17 @@ export default {
|
||||
props: {
|
||||
hideArrow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
showPopup: {
|
||||
default: null
|
||||
default: null,
|
||||
},
|
||||
right: Boolean,
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'bottom-start'
|
||||
default: 'bottom-start',
|
||||
},
|
||||
popoverClass: [String, Object, Array]
|
||||
popoverClass: [String, Object, Array],
|
||||
},
|
||||
watch: {
|
||||
showPopup(value) {
|
||||
@ -45,18 +43,18 @@ export default {
|
||||
if (value === false) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: false
|
||||
isOpen: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
let listener = e => {
|
||||
let listener = (e) => {
|
||||
let $els = [this.$refs.reference, this.$refs.popover];
|
||||
let insideClick = $els.some(
|
||||
$el => $el && (e.target === $el || $el.contains(e.target))
|
||||
($el) => $el && (e.target === $el || $el.contains(e.target))
|
||||
);
|
||||
if (insideClick) {
|
||||
return;
|
||||
@ -83,17 +81,17 @@ export default {
|
||||
{
|
||||
name: 'arrow',
|
||||
options: {
|
||||
element: this.$refs['popover-arrow']
|
||||
}
|
||||
element: this.$refs['popover-arrow'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 10]
|
||||
}
|
||||
}
|
||||
offset: [0, 10],
|
||||
},
|
||||
},
|
||||
]
|
||||
: []
|
||||
: [],
|
||||
});
|
||||
} else {
|
||||
this.popper.update();
|
||||
@ -126,8 +124,8 @@ export default {
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
|
@ -2,7 +2,6 @@ import { ipcRenderer } from 'electron';
|
||||
import frappe from 'frappejs';
|
||||
import FeatherIcon from 'frappejs/ui/components/FeatherIcon';
|
||||
import outsideClickDirective from 'frappejs/ui/plugins/outsideClickDirective';
|
||||
import PortalVue from 'portal-vue';
|
||||
import Vue from 'vue';
|
||||
import models from '../models';
|
||||
import App from './App';
|
||||
@ -36,7 +35,6 @@ import router from './router';
|
||||
Vue.config.productionTip = false;
|
||||
Vue.component('feather-icon', FeatherIcon);
|
||||
Vue.directive('on-outside-click', outsideClickDirective);
|
||||
Vue.use(PortalVue);
|
||||
Vue.mixin({
|
||||
computed: {
|
||||
frappe() {
|
||||
|
@ -138,7 +138,7 @@ export default {
|
||||
};
|
||||
},
|
||||
async activated() {
|
||||
this.reportData.columns = this.report.getColumns();
|
||||
this.reportData.columns = this.report.getColumns({ filters: this.filters });
|
||||
await this.setDefaultFilters();
|
||||
await this.fetchReportData();
|
||||
},
|
||||
@ -161,9 +161,7 @@ export default {
|
||||
rows = data;
|
||||
}
|
||||
|
||||
if (data.columns) {
|
||||
this.reportData.columns = this.report.getColumns(data);
|
||||
}
|
||||
this.reportData.columns = this.report.getColumns({ filters: this.filters, data });
|
||||
|
||||
if (!rows) {
|
||||
rows = [];
|
||||
|
14
src/utils.js
14
src/utils.js
@ -4,6 +4,7 @@ import router from '@/router';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import frappe from 'frappejs';
|
||||
import { _ } from 'frappejs/utils';
|
||||
import lodash from 'lodash';
|
||||
import Vue from 'vue';
|
||||
import { IPC_ACTIONS, IPC_MESSAGES } from './messages';
|
||||
|
||||
@ -337,3 +338,16 @@ export function showToast(props) {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function titleCase(phrase) {
|
||||
return phrase
|
||||
.split(' ')
|
||||
.map((word) => {
|
||||
const wordLower = word.toLowerCase();
|
||||
if (['and', 'an', 'a', 'from', 'by', 'on'].includes(wordLower)) {
|
||||
return wordLower;
|
||||
}
|
||||
return lodash.capitalize(wordLower);
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
|
@ -9523,11 +9523,6 @@ popper.js@^1.14.3:
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
|
||||
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
|
||||
|
||||
portal-vue@^2.1.7:
|
||||
version "2.1.7"
|
||||
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
|
||||
integrity sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==
|
||||
|
||||
portfinder@^1.0.16, portfinder@^1.0.26:
|
||||
version "1.0.28"
|
||||
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
|
||||
|
Loading…
Reference in New Issue
Block a user