mirror of
https://github.com/frappe/books.git
synced 2025-01-10 18:24:40 +00:00
Resolved merge conflicts
This commit is contained in:
commit
1798902835
@ -5,6 +5,7 @@ import { DateTime } from 'luxon';
|
|||||||
import { saveExportData } from '../reports/commonExporter';
|
import { saveExportData } from '../reports/commonExporter';
|
||||||
import { getSavePath } from '../src/utils';
|
import { getSavePath } from '../src/utils';
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
export const stateCodeMap = {
|
export const stateCodeMap = {
|
||||||
'JAMMU AND KASHMIR': '1',
|
'JAMMU AND KASHMIR': '1',
|
||||||
'HIMACHAL PRADESH': '2',
|
'HIMACHAL PRADESH': '2',
|
||||||
@ -184,7 +185,7 @@ async function generateB2clData(invoices) {
|
|||||||
for (let invoice of invoices) {
|
for (let invoice of invoices) {
|
||||||
const stateInvoiceRecord = {
|
const stateInvoiceRecord = {
|
||||||
pos: stateCodeMap[invoice.place.toUpperCase()],
|
pos: stateCodeMap[invoice.place.toUpperCase()],
|
||||||
inv: []
|
inv: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const invRecord = {
|
const invRecord = {
|
||||||
@ -194,7 +195,7 @@ async function generateB2clData(invoices) {
|
|||||||
),
|
),
|
||||||
val: invoice.invAmt,
|
val: invoice.invAmt,
|
||||||
itms: [],
|
itms: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
let items = await frappe.db
|
let items = await frappe.db
|
||||||
.knex('SalesInvoiceItem')
|
.knex('SalesInvoiceItem')
|
||||||
@ -231,22 +232,20 @@ async function generateB2csData(invoices) {
|
|||||||
const b2cs = [];
|
const b2cs = [];
|
||||||
|
|
||||||
for (let invoice of invoices) {
|
for (let invoice of invoices) {
|
||||||
|
|
||||||
const pos = invoice.place.toUpperCase();
|
const pos = invoice.place.toUpperCase();
|
||||||
|
|
||||||
const invRecord = {
|
const invRecord = {
|
||||||
"sply_ty": invoice.inState ? "INTRA" : "INTER",
|
sply_ty: invoice.inState ? 'INTRA' : 'INTER',
|
||||||
"pos": stateCodeMap[pos],
|
pos: stateCodeMap[pos],
|
||||||
// "OE" - Abbreviation for errors and omissions excepted.
|
// "OE" - Abbreviation for errors and omissions excepted.
|
||||||
// https://specialties.bayt.com/en/specialties/q/53093/what-is-meant-by-e-amp-oe-on-bill-or-invoice-or-any-document/#:~:text=E%26OE%20on,not%20purposely%20written
|
typ: 'OE',
|
||||||
"typ": "OE",
|
txval: invoice.taxVal,
|
||||||
"txval": invoice.taxVal,
|
rt: invoice.rate,
|
||||||
"rt": invoice.rate,
|
iamt: !invoice.inState ? (invoice.taxVal * invoice.rate) / 100 : 0,
|
||||||
"iamt": !invoice.inState ? (invoice.taxVal * invoice.rate / 100) : 0,
|
camt: invoice.inState ? invoice.cgstAmt : 0,
|
||||||
"camt": invoice.inState ? invoice.cgstAmt : 0,
|
samt: invoice.inState ? invoice.sgstAmt : 0,
|
||||||
"samt": invoice.inState ? invoice.sgstAmt : 0,
|
csamt: 0,
|
||||||
"csamt": 0
|
};
|
||||||
}
|
|
||||||
|
|
||||||
b2cs.push(invRecord);
|
b2cs.push(invRecord);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
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 {
|
export default {
|
||||||
name: 'Address',
|
name: 'Address',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
@ -9,7 +22,7 @@ export default {
|
|||||||
'city',
|
'city',
|
||||||
'state',
|
'state',
|
||||||
'country',
|
'country',
|
||||||
'postalCode'
|
'postalCode',
|
||||||
],
|
],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -23,69 +36,71 @@ export default {
|
|||||||
fieldname: 'addressLine2',
|
fieldname: 'addressLine2',
|
||||||
label: 'Address Line 2',
|
label: 'Address Line 2',
|
||||||
placeholder: 'Address Line 2',
|
placeholder: 'Address Line 2',
|
||||||
fieldtype: 'Data'
|
fieldtype: 'Data',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'city',
|
fieldname: 'city',
|
||||||
label: 'City / Town',
|
label: 'City / Town',
|
||||||
placeholder: 'City / Town',
|
placeholder: 'City / Town',
|
||||||
fieldtype: 'Data',
|
fieldtype: 'Data',
|
||||||
required: 1
|
required: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'state',
|
fieldname: 'state',
|
||||||
label: 'State',
|
label: 'State',
|
||||||
placeholder: 'State',
|
placeholder: 'State',
|
||||||
fieldtype: 'Data',
|
fieldtype: 'AutoComplete',
|
||||||
|
getList: getStates,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'country',
|
fieldname: 'country',
|
||||||
label: 'Country',
|
label: 'Country',
|
||||||
placeholder: 'Country',
|
placeholder: 'Country',
|
||||||
fieldtype: 'Data',
|
fieldtype: 'AutoComplete',
|
||||||
required: 1
|
getList: () => Object.keys(countryList).sort(),
|
||||||
|
required: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'postalCode',
|
fieldname: 'postalCode',
|
||||||
label: 'Postal Code',
|
label: 'Postal Code',
|
||||||
placeholder: 'Postal Code',
|
placeholder: 'Postal Code',
|
||||||
fieldtype: 'Data'
|
fieldtype: 'Data',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'emailAddress',
|
fieldname: 'emailAddress',
|
||||||
label: 'Email Address',
|
label: 'Email Address',
|
||||||
placeholder: 'Email Address',
|
placeholder: 'Email Address',
|
||||||
fieldtype: 'Data'
|
fieldtype: 'Data',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'phone',
|
fieldname: 'phone',
|
||||||
label: 'Phone',
|
label: 'Phone',
|
||||||
placeholder: 'Phone',
|
placeholder: 'Phone',
|
||||||
fieldtype: 'Data'
|
fieldtype: 'Data',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'fax',
|
fieldname: 'fax',
|
||||||
label: 'Fax',
|
label: 'Fax',
|
||||||
fieldtype: 'Data'
|
fieldtype: 'Data',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'addressDisplay',
|
fieldname: 'addressDisplay',
|
||||||
fieldtype: 'Text',
|
fieldtype: 'Text',
|
||||||
label: 'Address Display',
|
label: 'Address Display',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
formula: doc => {
|
formula: (doc) => {
|
||||||
return [
|
return [
|
||||||
doc.addressLine1,
|
doc.addressLine1,
|
||||||
doc.addressLine2,
|
doc.addressLine2,
|
||||||
doc.city,
|
doc.city,
|
||||||
doc.state,
|
doc.state,
|
||||||
doc.country,
|
doc.country,
|
||||||
doc.postalCode
|
doc.postalCode,
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(', ');
|
.join(', ');
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
quickEditFields: [
|
quickEditFields: [
|
||||||
'addressLine1',
|
'addressLine1',
|
||||||
@ -93,7 +108,7 @@ export default {
|
|||||||
'city',
|
'city',
|
||||||
'state',
|
'state',
|
||||||
'country',
|
'country',
|
||||||
'postalCode'
|
'postalCode',
|
||||||
],
|
],
|
||||||
inlineEditDisplayField: 'addressDisplay'
|
inlineEditDisplayField: 'addressDisplay',
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { cloneDeep, capitalize } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import AddressOriginal from './Address';
|
|
||||||
import { stateCodeMap } from '../../../accounting/gst';
|
import { stateCodeMap } from '../../../accounting/gst';
|
||||||
|
import { titleCase } from '../../../src/utils';
|
||||||
|
import AddressOriginal from './Address';
|
||||||
|
|
||||||
export default function getAugmentedAddress({ country }) {
|
export default function getAugmentedAddress({ country }) {
|
||||||
const Address = cloneDeep(AddressOriginal);
|
const Address = cloneDeep(AddressOriginal);
|
||||||
@ -8,22 +9,21 @@ export default function getAugmentedAddress({ country }) {
|
|||||||
return Address;
|
return Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stateList = Object.keys(stateCodeMap).map(titleCase).sort();
|
||||||
if (country === 'India') {
|
if (country === 'India') {
|
||||||
Address.fields = [
|
Address.fields = [
|
||||||
...Address.fields,
|
...Address.fields,
|
||||||
{
|
{
|
||||||
fieldname: 'pos',
|
fieldname: 'pos',
|
||||||
label: 'Place of Supply',
|
label: 'Place of Supply',
|
||||||
fieldtype: 'Select',
|
fieldtype: 'AutoComplete',
|
||||||
placeholder: 'Place of Supply',
|
placeholder: 'Place of Supply',
|
||||||
options: Object.keys(stateCodeMap).map((key) => capitalize(key)),
|
formula: (doc) => (stateList.includes(doc.state) ? doc.state : ''),
|
||||||
|
getList: () => stateList,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
Address.quickEditFields = [
|
Address.quickEditFields = [...Address.quickEditFields, 'pos'];
|
||||||
...Address.quickEditFields,
|
|
||||||
'pos',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Address;
|
return Address;
|
||||||
|
@ -26,12 +26,11 @@
|
|||||||
"csvjson-csv2json": "^5.0.6",
|
"csvjson-csv2json": "^5.0.6",
|
||||||
"electron-store": "^8.0.1",
|
"electron-store": "^8.0.1",
|
||||||
"frappe-charts": "1.6.1",
|
"frappe-charts": "1.6.1",
|
||||||
"frappejs": "https://github.com/frappe/frappejs",
|
"frappejs": "frappe/frappejs",
|
||||||
"knex": "^0.95.12",
|
"knex": "^0.95.12",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^2.0.2",
|
"luxon": "^2.0.2",
|
||||||
"portal-vue": "^2.1.7",
|
"sqlite3": "npm:@vscode/sqlite3@^5.0.7",
|
||||||
"sqlite3": "^5.0.2",
|
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
"vue-router": "^3.5.3"
|
"vue-router": "^3.5.3"
|
||||||
},
|
},
|
||||||
|
@ -1,23 +1,27 @@
|
|||||||
import frappe from 'frappejs';
|
import frappe from 'frappejs';
|
||||||
import { stateCodeMap } from '../../accounting/gst'
|
import { stateCodeMap } from '../../accounting/gst';
|
||||||
|
|
||||||
class BaseGSTR {
|
class BaseGSTR {
|
||||||
async getCompleteReport(gstrType, filters) {
|
async getCompleteReport(gstrType, filters) {
|
||||||
if (['GSTR-1', 'GSTR-2'].includes(gstrType)) {
|
if (['GSTR-1', 'GSTR-2'].includes(gstrType)) {
|
||||||
|
const place = filters.place;
|
||||||
|
delete filters.place;
|
||||||
let entries = await frappe.db.getAll({
|
let entries = await frappe.db.getAll({
|
||||||
doctype: gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice',
|
doctype: gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice',
|
||||||
filters
|
filters,
|
||||||
});
|
});
|
||||||
|
filters.place = place;
|
||||||
|
|
||||||
let tableData = [];
|
let tableData = [];
|
||||||
for (let entry of entries) {
|
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);
|
const row = await this.getRow(entry);
|
||||||
tableData.push(row);
|
tableData.push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(filters).length != 0) {
|
if (Object.keys(filters).length != 0) {
|
||||||
tableData = tableData.filter(row => {
|
tableData = tableData.filter((row) => {
|
||||||
if (filters.account) return row.account === filters.account;
|
if (filters.account) return row.account === filters.account;
|
||||||
if (filters.transferType)
|
if (filters.transferType)
|
||||||
return row.transferType === filters.transferType;
|
return row.transferType === filters.transferType;
|
||||||
@ -25,6 +29,7 @@ class BaseGSTR {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return tableData;
|
return tableData;
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
@ -32,37 +37,55 @@ class BaseGSTR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getRow(ledgerEntry) {
|
async getRow(ledgerEntry) {
|
||||||
let row = {};
|
|
||||||
ledgerEntry = await frappe.getDoc(ledgerEntry.doctype, ledgerEntry.name);
|
ledgerEntry = await frappe.getDoc(ledgerEntry.doctype, ledgerEntry.name);
|
||||||
|
|
||||||
|
const row = {};
|
||||||
const { gstin } = frappe.AccountingSettings;
|
const { gstin } = frappe.AccountingSettings;
|
||||||
|
|
||||||
let party = await frappe.getDoc(
|
let party = await frappe.getDoc(
|
||||||
'Party',
|
'Party',
|
||||||
ledgerEntry.customer || ledgerEntry.supplier
|
ledgerEntry.customer || ledgerEntry.supplier
|
||||||
);
|
);
|
||||||
|
|
||||||
if (party.address) {
|
if (party.address) {
|
||||||
let addressDetails = await frappe.getDoc('Address', party.address);
|
let addressDetails = await frappe.getDoc('Address', party.address);
|
||||||
row.place = addressDetails.pos || '';
|
row.place = addressDetails.pos || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
row.gstin = party.gstin;
|
row.gstin = party.gstin;
|
||||||
row.partyName = ledgerEntry.customer || ledgerEntry.supplier;
|
row.partyName = ledgerEntry.customer || ledgerEntry.supplier;
|
||||||
row.invNo = ledgerEntry.name;
|
row.invNo = ledgerEntry.name;
|
||||||
row.invDate = ledgerEntry.date;
|
row.invDate = ledgerEntry.date;
|
||||||
row.rate = 0;
|
row.rate = 0;
|
||||||
row.inState = gstin && gstin.substring(0, 2) === stateCodeMap[row.place.toUpperCase()];
|
row.inState =
|
||||||
|
gstin && gstin.substring(0, 2) === stateCodeMap[row.place?.toUpperCase()];
|
||||||
row.reverseCharge = !party.gstin ? 'Y' : 'N';
|
row.reverseCharge = !party.gstin ? 'Y' : 'N';
|
||||||
ledgerEntry.taxes?.forEach(tax => {
|
|
||||||
|
ledgerEntry.taxes?.forEach((tax) => {
|
||||||
row.rate += tax.rate;
|
row.rate += tax.rate;
|
||||||
const taxAmt = (tax.rate * ledgerEntry.netTotal) / 100;
|
const taxAmt = (tax.rate * ledgerEntry.netTotal) / 100;
|
||||||
if (tax.account === 'IGST') row.igstAmt = taxAmt;
|
|
||||||
if (tax.account === 'IGST') row.inState = false;
|
switch (tax.account) {
|
||||||
if (tax.account === 'CGST') row.cgstAmt = taxAmt;
|
case 'IGST': {
|
||||||
if (tax.account === 'SGST') row.sgstAmt = taxAmt;
|
row.igstAmt = taxAmt;
|
||||||
if (tax.account === 'Nil Rated') row.nilRated = true;
|
row.inState = false;
|
||||||
if (tax.account === 'Exempt') row.exempt = true;
|
}
|
||||||
if (tax.account === 'Non GST') row.nonGST = true;
|
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.invAmt = ledgerEntry.grandTotal;
|
||||||
row.taxVal = ledgerEntry.netTotal;
|
row.taxVal = ledgerEntry.netTotal;
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
import { stateCodeMap } from '../../accounting/gst';
|
||||||
|
import { titleCase } from '../../src/utils';
|
||||||
|
|
||||||
const transferTypeMap = {
|
const transferTypeMap = {
|
||||||
B2B: 'B2B',
|
B2B: 'B2B',
|
||||||
@ -6,6 +8,7 @@ const transferTypeMap = {
|
|||||||
B2CS: 'B2C-Small',
|
B2CS: 'B2C-Small',
|
||||||
NR: 'Nil Rated, Exempted and Non GST supplies',
|
NR: 'Nil Rated, Exempted and Non GST supplies',
|
||||||
};
|
};
|
||||||
|
const stateList = Object.keys(stateCodeMap).map(titleCase).sort();
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
filterFields: [
|
filterFields: [
|
||||||
@ -20,11 +23,12 @@ export default {
|
|||||||
size: 'small',
|
size: 'small',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldtype: 'Data',
|
fieldtype: 'AutoComplete',
|
||||||
label: 'Place',
|
label: 'Place',
|
||||||
size: 'small',
|
size: 'small',
|
||||||
placeholder: 'Place',
|
placeholder: 'Place',
|
||||||
fieldname: 'place',
|
fieldname: 'place',
|
||||||
|
getList: () => stateList,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldtype: 'Date',
|
fieldtype: 'Date',
|
||||||
|
@ -8,6 +8,8 @@ class GSTR1 extends BaseGSTR {
|
|||||||
filters.cancelled = 0;
|
filters.cancelled = 0;
|
||||||
if (params.toDate || params.fromDate) {
|
if (params.toDate || params.fromDate) {
|
||||||
filters.date = [];
|
filters.date = [];
|
||||||
|
|
||||||
|
if (params.place) filters.place = params.place;
|
||||||
if (params.toDate) filters.date.push('<=', params.toDate);
|
if (params.toDate) filters.date.push('<=', params.toDate);
|
||||||
if (params.fromDate) filters.date.push('>=', params.fromDate);
|
if (params.fromDate) filters.date.push('>=', params.fromDate);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
@setup-complete="showSetupWizardOrDesk(true)"
|
@setup-complete="showSetupWizardOrDesk(true)"
|
||||||
@setup-canceled="setupCanceled"
|
@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-container" class="absolute bottom-0 right-0 mr-6 mb-3">
|
||||||
<div id="toast-target" />
|
<div id="toast-target" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,6 +59,9 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
inject: {
|
||||||
|
doc: { default: null },
|
||||||
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
methods: {
|
methods: {
|
||||||
async updateSuggestions(e) {
|
async updateSuggestions(e) {
|
||||||
@ -81,7 +84,7 @@ export default {
|
|||||||
keyword = keyword.toLowerCase();
|
keyword = keyword.toLowerCase();
|
||||||
|
|
||||||
let list = this.df.getList
|
let list = this.df.getList
|
||||||
? await this.df.getList()
|
? await this.df.getList(this.doc)
|
||||||
: this.df.options || [];
|
: this.df.options || [];
|
||||||
|
|
||||||
let items = list.map((d) => {
|
let items = list.map((d) => {
|
||||||
@ -118,6 +121,12 @@ export default {
|
|||||||
async onBlur(value) {
|
async onBlur(value) {
|
||||||
if (value === '' || value == null) {
|
if (value === '' || value == null) {
|
||||||
this.triggerChange('');
|
this.triggerChange('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && this.suggestions.length === 0) {
|
||||||
|
this.triggerChange(value);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
relative
|
|
||||||
flex
|
flex
|
||||||
items-center
|
items-center
|
||||||
justify-between
|
justify-between
|
||||||
@ -38,7 +37,7 @@
|
|||||||
</select>
|
</select>
|
||||||
<svg
|
<svg
|
||||||
class="w-3 h-3"
|
class="w-3 h-3"
|
||||||
style="background: inherit; z-index: 1; transform: translateX(3px)"
|
style="background: inherit; margin-right: -3px"
|
||||||
viewBox="0 0 5 10"
|
viewBox="0 0 5 10"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
|
@ -3,17 +3,15 @@
|
|||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<slot name="target" :togglePopover="togglePopover"></slot>
|
<slot name="target" :togglePopover="togglePopover"></slot>
|
||||||
</div>
|
</div>
|
||||||
<portal to="popovers">
|
<div
|
||||||
<div
|
ref="popover"
|
||||||
ref="popover"
|
:class="popoverClass"
|
||||||
:class="popoverClass"
|
class="bg-white rounded border shadow-md popover-container relative"
|
||||||
class="bg-white rounded border shadow-md popover-container relative"
|
v-show="isOpen"
|
||||||
v-show="isOpen"
|
>
|
||||||
>
|
<div v-if="!hideArrow" class="popover-arrow" ref="popover-arrow"></div>
|
||||||
<div v-if="!hideArrow" class="popover-arrow" ref="popover-arrow"></div>
|
<slot name="content" :togglePopover="togglePopover"></slot>
|
||||||
<slot name="content" :togglePopover="togglePopover"></slot>
|
</div>
|
||||||
</div>
|
|
||||||
</portal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -25,17 +23,17 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
hideArrow: {
|
hideArrow: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
showPopup: {
|
showPopup: {
|
||||||
default: null
|
default: null,
|
||||||
},
|
},
|
||||||
right: Boolean,
|
right: Boolean,
|
||||||
placement: {
|
placement: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'bottom-start'
|
default: 'bottom-start',
|
||||||
},
|
},
|
||||||
popoverClass: [String, Object, Array]
|
popoverClass: [String, Object, Array],
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
showPopup(value) {
|
showPopup(value) {
|
||||||
@ -45,18 +43,18 @@ export default {
|
|||||||
if (value === false) {
|
if (value === false) {
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isOpen: false
|
isOpen: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let listener = e => {
|
let listener = (e) => {
|
||||||
let $els = [this.$refs.reference, this.$refs.popover];
|
let $els = [this.$refs.reference, this.$refs.popover];
|
||||||
let insideClick = $els.some(
|
let insideClick = $els.some(
|
||||||
$el => $el && (e.target === $el || $el.contains(e.target))
|
($el) => $el && (e.target === $el || $el.contains(e.target))
|
||||||
);
|
);
|
||||||
if (insideClick) {
|
if (insideClick) {
|
||||||
return;
|
return;
|
||||||
@ -83,17 +81,17 @@ export default {
|
|||||||
{
|
{
|
||||||
name: 'arrow',
|
name: 'arrow',
|
||||||
options: {
|
options: {
|
||||||
element: this.$refs['popover-arrow']
|
element: this.$refs['popover-arrow'],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'offset',
|
name: 'offset',
|
||||||
options: {
|
options: {
|
||||||
offset: [0, 10]
|
offset: [0, 10],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
: []
|
: [],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.popper.update();
|
this.popper.update();
|
||||||
@ -126,8 +124,8 @@ export default {
|
|||||||
}
|
}
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.$emit('close');
|
this.$emit('close');
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -2,7 +2,6 @@ import { ipcRenderer } from 'electron';
|
|||||||
import frappe from 'frappejs';
|
import frappe from 'frappejs';
|
||||||
import FeatherIcon from 'frappejs/ui/components/FeatherIcon';
|
import FeatherIcon from 'frappejs/ui/components/FeatherIcon';
|
||||||
import outsideClickDirective from 'frappejs/ui/plugins/outsideClickDirective';
|
import outsideClickDirective from 'frappejs/ui/plugins/outsideClickDirective';
|
||||||
import PortalVue from 'portal-vue';
|
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import models from '../models';
|
import models from '../models';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
@ -36,7 +35,6 @@ import router from './router';
|
|||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.component('feather-icon', FeatherIcon);
|
Vue.component('feather-icon', FeatherIcon);
|
||||||
Vue.directive('on-outside-click', outsideClickDirective);
|
Vue.directive('on-outside-click', outsideClickDirective);
|
||||||
Vue.use(PortalVue);
|
|
||||||
Vue.mixin({
|
Vue.mixin({
|
||||||
computed: {
|
computed: {
|
||||||
frappe() {
|
frappe() {
|
||||||
|
14
src/utils.js
14
src/utils.js
@ -4,6 +4,7 @@ import router from '@/router';
|
|||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
import frappe from 'frappejs';
|
import frappe from 'frappejs';
|
||||||
import { _ } from 'frappejs/utils';
|
import { _ } from 'frappejs/utils';
|
||||||
|
import lodash from 'lodash';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { IPC_ACTIONS, IPC_MESSAGES } from './messages';
|
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(' ');
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user