mirror of
https://github.com/frappe/books.git
synced 2025-01-03 15:17:30 +00:00
- Dashboard
- SearchBar - Invoice & Bill Rename
This commit is contained in:
parent
ed164a492e
commit
86d0ef3d06
@ -1,7 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
doctype: "PrintFormat",
|
doctype: "PrintFormat",
|
||||||
name: "Standard Invoice Format",
|
name: "Standard Invoice Format",
|
||||||
for: "Invoice",
|
for: "SalesInvoice",
|
||||||
template: `
|
template: `
|
||||||
<h1>{{ doc.name }}</h1>
|
<h1>{{ doc.name }}</h1>
|
||||||
<div class="row py-4">
|
<div class="row py-4">
|
||||||
|
@ -3,67 +3,72 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const countries = require('../../../fixtures/countryInfo.json');
|
const countries = require('../../../fixtures/countryInfo.json');
|
||||||
const standardCOA = require('../../../fixtures/verified/standardCOA.json');
|
const standardCOA = require('../../../fixtures/verified/standardCOA.json');
|
||||||
const accountFields = ['accountType', 'rootType', 'isGroup', 'account_type', 'root_type', 'is_group'];
|
const accountFields = [
|
||||||
|
'accountType',
|
||||||
|
'rootType',
|
||||||
|
'isGroup',
|
||||||
|
'account_type',
|
||||||
|
'root_type',
|
||||||
|
'is_group'
|
||||||
|
];
|
||||||
|
|
||||||
async function importAccounts(children, parent, rootType, rootAccount) {
|
async function importAccounts(children, parent, rootType, rootAccount) {
|
||||||
for (let accountName in children) {
|
for (let accountName in children) {
|
||||||
const child = children[accountName];
|
const child = children[accountName];
|
||||||
|
|
||||||
if (rootAccount) {
|
if (rootAccount) {
|
||||||
rootType = child.rootType || child.root_type;
|
rootType = child.rootType || child.root_type;
|
||||||
}
|
|
||||||
|
|
||||||
if (!accountFields.includes(accountName)) {
|
|
||||||
let isGroup = identifyIsGroup(child);
|
|
||||||
const doc = frappe.newDoc({
|
|
||||||
doctype: 'Account',
|
|
||||||
name: accountName,
|
|
||||||
parentAccount: parent,
|
|
||||||
isGroup,
|
|
||||||
rootType,
|
|
||||||
balance: 0,
|
|
||||||
accountType: child.accountType
|
|
||||||
})
|
|
||||||
|
|
||||||
await doc.insert()
|
|
||||||
|
|
||||||
await importAccounts(child, accountName, rootType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!accountFields.includes(accountName)) {
|
||||||
|
let isGroup = identifyIsGroup(child);
|
||||||
|
const doc = frappe.newDoc({
|
||||||
|
doctype: 'Account',
|
||||||
|
name: accountName,
|
||||||
|
parentAccount: parent,
|
||||||
|
isGroup,
|
||||||
|
rootType,
|
||||||
|
balance: 0,
|
||||||
|
accountType: child.accountType || child.account_type
|
||||||
|
});
|
||||||
|
|
||||||
|
await doc.insert();
|
||||||
|
|
||||||
|
await importAccounts(child, accountName, rootType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function identifyIsGroup(child) {
|
function identifyIsGroup(child) {
|
||||||
if (child.isGroup || child.is_group) {
|
if (child.isGroup || child.is_group) {
|
||||||
return child.isGroup || child.is_group;
|
return child.isGroup || child.is_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = Object.keys(child);
|
const keys = Object.keys(child);
|
||||||
const children = keys.filter(key => !accountFields.includes(key))
|
const children = keys.filter(key => !accountFields.includes(key));
|
||||||
|
|
||||||
if (children.length) {
|
if (children.length) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCountryCOA(){
|
async function getCountryCOA() {
|
||||||
const doc = await frappe.getDoc('AccountingSettings');
|
const doc = await frappe.getDoc('AccountingSettings');
|
||||||
const conCode = countries[doc.country].code;
|
const conCode = countries[doc.country].code;
|
||||||
|
|
||||||
const countryCOA = path.resolve(path.join('./fixtures/verified/', conCode + '.json'));
|
try {
|
||||||
|
const countryCoa = require('../../../fixtures/verified/' +
|
||||||
if(fs.existsSync(countryCOA)){
|
conCode +
|
||||||
const jsonText = fs.readFileSync(countryCOA, 'utf-8');
|
'.json');
|
||||||
const json = JSON.parse(jsonText);
|
return countryCoa.tree;
|
||||||
return json.tree;
|
} catch (e) {
|
||||||
} else {
|
return standardCOA;
|
||||||
return standardCOA;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = async function importCharts() {
|
module.exports = async function importCharts() {
|
||||||
const chart = await getCountryCOA();
|
const chart = await getCountryCOA();
|
||||||
await importAccounts(chart, '', '', true)
|
await importAccounts(chart, '', '', true);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
const InvoiceDocument = require('../Invoice/InvoiceDocument');
|
|
||||||
const frappe = require('frappejs');
|
|
||||||
|
|
||||||
module.exports = class Bill extends InvoiceDocument { }
|
|
@ -1,18 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"name": "BillSettings",
|
|
||||||
"label": "Bill Settings",
|
|
||||||
"doctype": "DocType",
|
|
||||||
"isSingle": 1,
|
|
||||||
"isChild": 0,
|
|
||||||
"keywordFields": [],
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldname": "numberSeries",
|
|
||||||
"label": "Number Series",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"target": "NumberSeries",
|
|
||||||
"required": 1,
|
|
||||||
"default": "BILL"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
24
models/doctype/DashboardChart/DashboardChart.js
Normal file
24
models/doctype/DashboardChart/DashboardChart.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: 'DashboardChart',
|
||||||
|
doctype: 'DocType',
|
||||||
|
isChild: 1,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldname: 'account',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
label: 'Account',
|
||||||
|
target: 'Account'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'type',
|
||||||
|
fieldtype: 'Select',
|
||||||
|
options: ['', 'Bar', 'Line', 'Percentage'],
|
||||||
|
label: 'Chart Type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'color',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
label: 'Color'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
19
models/doctype/DashboardSettings/DashboardSettings.js
Normal file
19
models/doctype/DashboardSettings/DashboardSettings.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: 'Dashboard',
|
||||||
|
label: 'Dashboard Settings',
|
||||||
|
doctype: 'DocType',
|
||||||
|
isSingle: 1,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldname: 'name',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
label: 'Dashboard Name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'charts',
|
||||||
|
fieldtype: 'Table',
|
||||||
|
label: 'Charts',
|
||||||
|
childtype: 'DashboardChart'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -28,25 +28,28 @@ module.exports = class GSTR3B extends BaseDocument {
|
|||||||
`${this.year}-${month}-${lastDate}`
|
`${this.year}-${month}-${lastDate}`
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
const invoices = frappe.db.getAll({
|
const salesInvoices = frappe.db.getAll({
|
||||||
doctype: 'Invoice',
|
doctype: 'SalesInvoice',
|
||||||
filters,
|
filters,
|
||||||
fields: ['*']
|
fields: ['*']
|
||||||
});
|
});
|
||||||
const bills = frappe.db.getAll({
|
const purchaseInvoices = frappe.db.getAll({
|
||||||
doctype: 'Bill',
|
doctype: 'PurchaseInvoice',
|
||||||
filters,
|
filters,
|
||||||
fields: ['*']
|
fields: ['*']
|
||||||
});
|
});
|
||||||
const [gstr1Data, gstr2Data] = await Promise.all([invoices, bills]);
|
const [gstr1Data, gstr2Data] = await Promise.all([
|
||||||
|
salesInvoices,
|
||||||
|
purchaseInvoices
|
||||||
|
]);
|
||||||
let gstr3bData = [[], []];
|
let gstr3bData = [[], []];
|
||||||
|
|
||||||
for (let ledgerEntry of gstr1Data) {
|
for (let ledgerEntry of gstr1Data) {
|
||||||
ledgerEntry.doctype = 'Invoice';
|
ledgerEntry.doctype = 'SalesInvoice';
|
||||||
gstr3bData[0].push(await this.makeGSTRow(ledgerEntry));
|
gstr3bData[0].push(await this.makeGSTRow(ledgerEntry));
|
||||||
}
|
}
|
||||||
for (let ledgerEntry of gstr2Data) {
|
for (let ledgerEntry of gstr2Data) {
|
||||||
ledgerEntry.doctype = 'Bill';
|
ledgerEntry.doctype = 'BiPurchaseInvoicell';
|
||||||
gstr3bData[1].push(await this.makeGSTRow(ledgerEntry));
|
gstr3bData[1].push(await this.makeGSTRow(ledgerEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: "InvoiceSettings",
|
|
||||||
label: "Invoice Settings",
|
|
||||||
doctype: "DocType",
|
|
||||||
isSingle: 1,
|
|
||||||
isChild: 0,
|
|
||||||
keywordFields: [],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
fieldname: "numberSeries",
|
|
||||||
label: "Number Series",
|
|
||||||
fieldtype: "Link",
|
|
||||||
target: "NumberSeries",
|
|
||||||
required: 1,
|
|
||||||
default: "INV"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldname: "template",
|
|
||||||
label: "Template",
|
|
||||||
fieldtype: "Select",
|
|
||||||
options: ["Basic I", "Basic II", "Modern"],
|
|
||||||
required: 1,
|
|
||||||
default: "Basic I"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldname: "font",
|
|
||||||
label: "Font",
|
|
||||||
fieldtype: "Select",
|
|
||||||
options: ["Montserrat", "Open Sans", "Oxygen", "Merriweather"],
|
|
||||||
required: 1,
|
|
||||||
default: "Montserrat"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldname: "themeColor",
|
|
||||||
label: "Theme Color",
|
|
||||||
fieldtype: "Data",
|
|
||||||
required: 1,
|
|
||||||
default: "#000000",
|
|
||||||
hidden: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ module.exports = {
|
|||||||
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'Invoices',
|
label: 'Sales Invoices',
|
||||||
condition: form => form.doc.customer,
|
condition: form => form.doc.customer,
|
||||||
action: form => {
|
action: form => {
|
||||||
form.$router.push({
|
form.$router.push({
|
||||||
@ -52,6 +52,15 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Purchase Invoices',
|
||||||
|
condition: form => form.doc.supplier,
|
||||||
|
action: form => {
|
||||||
|
form.$router.push({
|
||||||
|
path: `/report/purchase-register?&supplier=${form.doc.name}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
condition: form => form.doc.customer,
|
condition: form => form.doc.customer,
|
||||||
|
@ -15,7 +15,7 @@ module.exports = class PaymentServer extends BaseDocument {
|
|||||||
async beforeSubmit() {
|
async beforeSubmit() {
|
||||||
if (this.for.length > 0)
|
if (this.for.length > 0)
|
||||||
for (let row of this.for) {
|
for (let row of this.for) {
|
||||||
if (['Invoice', 'Bill'].includes(row.referenceType)) {
|
if (['SalesInvoice', 'PurchaseInvoice'].includes(row.referenceType)) {
|
||||||
let { outstandingAmount, grandTotal } = await frappe.getDoc(
|
let { outstandingAmount, grandTotal } = await frappe.getDoc(
|
||||||
row.referenceType,
|
row.referenceType,
|
||||||
row.referenceName
|
row.referenceName
|
||||||
|
@ -2,14 +2,15 @@ const frappe = require('frappejs');
|
|||||||
const utils = require('../../../accounting/utils');
|
const utils = require('../../../accounting/utils');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'Bill',
|
name: 'PurchaseInvoice',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
documentClass: require('./BillDocument'),
|
label: 'Purchase Invoice',
|
||||||
|
documentClass: require('./PurchaseInvoiceDocument'),
|
||||||
isSingle: 0,
|
isSingle: 0,
|
||||||
isChild: 0,
|
isChild: 0,
|
||||||
isSubmittable: 1,
|
isSubmittable: 1,
|
||||||
keywordFields: ['name', 'supplier'],
|
keywordFields: ['name', 'supplier'],
|
||||||
settings: 'BillSettings',
|
settings: 'PurchaseInvoiceSettings',
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -50,7 +51,7 @@ module.exports = {
|
|||||||
fieldname: 'items',
|
fieldname: 'items',
|
||||||
label: 'Items',
|
label: 'Items',
|
||||||
fieldtype: 'Table',
|
fieldtype: 'Table',
|
||||||
childtype: 'BillItem',
|
childtype: 'PurchaseInvoiceItem',
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
@ -0,0 +1,4 @@
|
|||||||
|
const SalesInvoiceDocument = require('../SalesInvoice/SalesInvoiceDocument');
|
||||||
|
const frappe = require('frappejs');
|
||||||
|
|
||||||
|
module.exports = class PurchaseInvoice extends SalesInvoiceDocument {};
|
@ -2,8 +2,8 @@ import { _ } from 'frappejs/utils';
|
|||||||
import indicators from 'frappejs/ui/constants/indicators';
|
import indicators from 'frappejs/ui/constants/indicators';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
doctype: 'Bill',
|
doctype: 'PurchaseInvoice',
|
||||||
title: _('Bill'),
|
title: _('Purchase Invoice'),
|
||||||
columns: [
|
columns: [
|
||||||
'supplier',
|
'supplier',
|
||||||
{
|
{
|
@ -1,8 +1,8 @@
|
|||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
const Bill = require('./BillDocument');
|
const PurchaseInvoice = require('./PurchaseInvoiceDocument');
|
||||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||||
|
|
||||||
module.exports = class BillServer extends Bill {
|
module.exports = class PurchaseInvoiceServer extends PurchaseInvoice {
|
||||||
async getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.supplier });
|
let entries = new LedgerPosting({ reference: this, party: this.supplier });
|
||||||
await entries.credit(this.account, this.grandTotal);
|
await entries.credit(this.account, this.grandTotal);
|
||||||
@ -36,7 +36,7 @@ module.exports = class BillServer extends Bill {
|
|||||||
const entries = await this.getPosting();
|
const entries = await this.getPosting();
|
||||||
await entries.post();
|
await entries.post();
|
||||||
await frappe.db.setValue(
|
await frappe.db.setValue(
|
||||||
'Bill',
|
'PurchaseInvoice',
|
||||||
this.name,
|
this.name,
|
||||||
'outstandingAmount',
|
'outstandingAmount',
|
||||||
this.grandTotal
|
this.grandTotal
|
@ -1,5 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'BillItem',
|
name: 'PurchaseInvoiceItem',
|
||||||
|
label: 'Purchase Invoice Item',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
isSingle: 0,
|
isSingle: 0,
|
||||||
isChild: 1,
|
isChild: 1,
|
@ -0,0 +1,18 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: 'PurchaseInvoiceSettings',
|
||||||
|
label: 'Purchase Invoice Settings',
|
||||||
|
doctype: 'DocType',
|
||||||
|
isSingle: 1,
|
||||||
|
isChild: 0,
|
||||||
|
keywordFields: [],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldname: 'numberSeries',
|
||||||
|
label: 'Number Series',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
target: 'NumberSeries',
|
||||||
|
required: 1,
|
||||||
|
default: 'PINV'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -1,16 +1,20 @@
|
|||||||
const model = require('frappejs/model');
|
const model = require('frappejs/model');
|
||||||
const Bill = require('../Bill/Bill');
|
const PurchaseInvoice = require('../PurchaseInvoice/PurchaseInvoice');
|
||||||
|
|
||||||
module.exports = model.extend(Bill, {
|
module.exports = model.extend(
|
||||||
name: "PurchaseOrder",
|
PurchaseInvoice,
|
||||||
label: "Purchase Order",
|
{
|
||||||
settings: "PurchaseOrderSettings",
|
name: 'PurchaseOrder',
|
||||||
|
label: 'Purchase Order',
|
||||||
|
settings: 'PurchaseOrderSettings',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
"fieldname": "items",
|
fieldname: 'items',
|
||||||
"childtype": "PurchaseOrderItem"
|
childtype: 'PurchaseOrderItem'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
skipFields: ['account']
|
skipFields: ['account']
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const model = require('frappejs/model');
|
const model = require('frappejs/model');
|
||||||
const BillItem = require('../BillItem/BillItem');
|
const PurchaseInvoiceItem = require('../PurchaseInvoiceItem/PurchaseInvoiceItem');
|
||||||
|
|
||||||
module.exports = model.extend(BillItem, {
|
module.exports = model.extend(PurchaseInvoiceItem, {
|
||||||
name: "PurchaseOrderItem"
|
name: "PurchaseOrderItem"
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const model = require('frappejs/model');
|
const model = require('frappejs/model');
|
||||||
const BillSettings = require('../BillSettings/BillSettings');
|
const PurchaseInvoiceSettings = require('../PurchaseInvoiceSettings/PurchaseInvoiceSettings');
|
||||||
|
|
||||||
module.exports = model.extend(BillSettings, {
|
module.exports = model.extend(PurchaseInvoiceSettings, {
|
||||||
"name": "PurchaseOrderSettings",
|
"name": "PurchaseOrderSettings",
|
||||||
"label": "Purchase Order Settings",
|
"label": "Purchase Order Settings",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
@ -2,9 +2,10 @@ const frappe = require('frappejs');
|
|||||||
const utils = require('../../../accounting/utils');
|
const utils = require('../../../accounting/utils');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'Invoice',
|
name: 'SalesInvoice',
|
||||||
|
label: 'Sales Invoice',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
documentClass: require('./InvoiceDocument.js'),
|
documentClass: require('./SalesInvoiceDocument'),
|
||||||
print: {
|
print: {
|
||||||
printFormat: 'Standard Invoice Format'
|
printFormat: 'Standard Invoice Format'
|
||||||
},
|
},
|
||||||
@ -12,7 +13,7 @@ module.exports = {
|
|||||||
isChild: 0,
|
isChild: 0,
|
||||||
isSubmittable: 1,
|
isSubmittable: 1,
|
||||||
keywordFields: ['name', 'customer'],
|
keywordFields: ['name', 'customer'],
|
||||||
settings: 'InvoiceSettings',
|
settings: 'SalesInvoiceSettings',
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -62,7 +63,7 @@ module.exports = {
|
|||||||
fieldname: 'items',
|
fieldname: 'items',
|
||||||
label: 'Items',
|
label: 'Items',
|
||||||
fieldtype: 'Table',
|
fieldtype: 'Table',
|
||||||
childtype: 'InvoiceItem',
|
childtype: 'SalesInvoiceItem',
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
const BaseDocument = require('frappejs/model/document');
|
const BaseDocument = require('frappejs/model/document');
|
||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
|
|
||||||
module.exports = class Invoice extends BaseDocument {
|
module.exports = class SalesInvoice extends BaseDocument {
|
||||||
async getRowTax(row) {
|
async getRowTax(row) {
|
||||||
if (row.tax) {
|
if (row.tax) {
|
||||||
let tax = await this.getTax(row.tax);
|
let tax = await this.getTax(row.tax);
|
@ -2,8 +2,8 @@ import { _ } from 'frappejs/utils';
|
|||||||
import indicators from 'frappejs/ui/constants/indicators';
|
import indicators from 'frappejs/ui/constants/indicators';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
doctype: 'Invoice',
|
doctype: 'SalesInvoice',
|
||||||
title: _('Invoice'),
|
title: _('Sales Invoice'),
|
||||||
columns: [
|
columns: [
|
||||||
'customer',
|
'customer',
|
||||||
{
|
{
|
@ -26,9 +26,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import InvoiceTemplate1 from '@/../models/doctype/Invoice/Templates/InvoiceTemplate1';
|
import InvoiceTemplate1 from '@/../models/doctype/SalesInvoice/Templates/InvoiceTemplate1';
|
||||||
import InvoiceTemplate2 from '@/../models/doctype/Invoice/Templates/InvoiceTemplate2';
|
import InvoiceTemplate2 from '@/../models/doctype/SalesInvoice/Templates/InvoiceTemplate2';
|
||||||
import InvoiceTemplate3 from '@/../models/doctype/Invoice/Templates/InvoiceTemplate3';
|
import InvoiceTemplate3 from '@/../models/doctype/SalesInvoice/Templates/InvoiceTemplate3';
|
||||||
import InvoiceCustomizer from '@/components/InvoiceCustomizer';
|
import InvoiceCustomizer from '@/components/InvoiceCustomizer';
|
||||||
|
|
||||||
const invoiceTemplates = {
|
const invoiceTemplates = {
|
@ -1,7 +1,7 @@
|
|||||||
const Invoice = require('./InvoiceDocument');
|
const SalesInvoice = require('./SalesInvoiceDocument');
|
||||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||||
|
|
||||||
module.exports = class InvoiceServer extends Invoice {
|
module.exports = class SalesInvoiceServer extends SalesInvoice {
|
||||||
async getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.customer });
|
let entries = new LedgerPosting({ reference: this, party: this.customer });
|
||||||
await entries.debit(this.account, this.grandTotal);
|
await entries.debit(this.account, this.grandTotal);
|
||||||
@ -35,7 +35,7 @@ module.exports = class InvoiceServer extends Invoice {
|
|||||||
const entries = await this.getPosting();
|
const entries = await this.getPosting();
|
||||||
await entries.post();
|
await entries.post();
|
||||||
await frappe.db.setValue(
|
await frappe.db.setValue(
|
||||||
'Invoice',
|
'SalesInvoice',
|
||||||
this.name,
|
this.name,
|
||||||
'outstandingAmount',
|
'outstandingAmount',
|
||||||
this.grandTotal
|
this.grandTotal
|
@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'InvoiceItem',
|
name: 'SalesInvoiceItem',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
isSingle: 0,
|
isSingle: 0,
|
||||||
isChild: 1,
|
isChild: 1,
|
42
models/doctype/SalesInvoiceSettings/SalesInvoiceSettings.js
Normal file
42
models/doctype/SalesInvoiceSettings/SalesInvoiceSettings.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: 'SalesInvoiceSettings',
|
||||||
|
label: 'SalesInvoice Settings',
|
||||||
|
doctype: 'DocType',
|
||||||
|
isSingle: 1,
|
||||||
|
isChild: 0,
|
||||||
|
keywordFields: [],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldname: 'numberSeries',
|
||||||
|
label: 'Number Series',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
target: 'NumberSeries',
|
||||||
|
required: 1,
|
||||||
|
default: 'SINV'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'template',
|
||||||
|
label: 'Template',
|
||||||
|
fieldtype: 'Select',
|
||||||
|
options: ['Basic I', 'Basic II', 'Modern'],
|
||||||
|
required: 1,
|
||||||
|
default: 'Basic I'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'font',
|
||||||
|
label: 'Font',
|
||||||
|
fieldtype: 'Select',
|
||||||
|
options: ['Montserrat', 'Open Sans', 'Oxygen', 'Merriweather'],
|
||||||
|
required: 1,
|
||||||
|
default: 'Montserrat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'themeColor',
|
||||||
|
label: 'Theme Color',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1,
|
||||||
|
default: '#000000',
|
||||||
|
hidden: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -1,6 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
models: {
|
models: {
|
||||||
SetupWizard: require('./doctype/SetupWizard/SetupWizard'),
|
SetupWizard: require('./doctype/SetupWizard/SetupWizard'),
|
||||||
|
DashboardSettings: require('./doctype/DashboardSettings/DashboardSettings'),
|
||||||
|
DashboardChart: require('./doctype/DashboardChart/DashboardChart'),
|
||||||
Account: require('./doctype/Account/Account.js'),
|
Account: require('./doctype/Account/Account.js'),
|
||||||
AccountingSettings: require('./doctype/AccountingSettings/AccountingSettings'),
|
AccountingSettings: require('./doctype/AccountingSettings/AccountingSettings'),
|
||||||
CompanySettings: require('./doctype/CompanySettings/CompanySettings'),
|
CompanySettings: require('./doctype/CompanySettings/CompanySettings'),
|
||||||
@ -13,13 +15,13 @@ module.exports = {
|
|||||||
|
|
||||||
Item: require('./doctype/Item/Item.js'),
|
Item: require('./doctype/Item/Item.js'),
|
||||||
|
|
||||||
Invoice: require('./doctype/Invoice/Invoice.js'),
|
SalesInvoice: require('./doctype/SalesInvoice/SalesInvoice.js'),
|
||||||
InvoiceItem: require('./doctype/InvoiceItem/InvoiceItem.js'),
|
SalesInvoiceItem: require('./doctype/SalesInvoiceItem/SalesInvoiceItem.js'),
|
||||||
InvoiceSettings: require('./doctype/InvoiceSettings/InvoiceSettings.js'),
|
SalesInvoiceSettings: require('./doctype/SalesInvoiceSettings/SalesInvoiceSettings.js'),
|
||||||
|
|
||||||
Bill: require('./doctype/Bill/Bill.js'),
|
PurchaseInvoice: require('./doctype/PurchaseInvoice/PurchaseInvoice.js'),
|
||||||
BillItem: require('./doctype/BillItem/BillItem.js'),
|
PurchaseInvoiceItem: require('./doctype/PurchaseInvoiceItem/PurchaseInvoiceItem.js'),
|
||||||
BillSettings: require('./doctype/BillSettings/BillSettings.js'),
|
PurchaseInvoiceSettings: require('./doctype/PurchaseInvoiceSettings/PurchaseInvoiceSettings.js'),
|
||||||
|
|
||||||
Tax: require('./doctype/Tax/Tax.js'),
|
Tax: require('./doctype/Tax/Tax.js'),
|
||||||
TaxDetail: require('./doctype/TaxDetail/TaxDetail.js'),
|
TaxDetail: require('./doctype/TaxDetail/TaxDetail.js'),
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
|
"frappe-charts": "^1.2.4",
|
||||||
"frappejs": "github:thefalconx33/frappejs#test",
|
"frappejs": "github:thefalconx33/frappejs#test",
|
||||||
"nodemailer": "^4.7.0",
|
"nodemailer": "^4.7.0",
|
||||||
"popper.js": "^1.14.4",
|
"popper.js": "^1.14.4",
|
||||||
|
@ -1,154 +1,170 @@
|
|||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
|
|
||||||
module.exports = class AccountsReceivablePayable {
|
module.exports = class AccountsReceivablePayable {
|
||||||
async run(reportType, { date }) {
|
async run(reportType, { date }) {
|
||||||
|
const rows = await getReceivablePayable({
|
||||||
|
reportType,
|
||||||
|
date
|
||||||
|
});
|
||||||
|
|
||||||
const rows = await getReceivablePayable({
|
return { rows };
|
||||||
reportType,
|
}
|
||||||
date
|
};
|
||||||
});
|
|
||||||
|
|
||||||
return { rows };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||||
let entries = [];
|
let entries = [];
|
||||||
const debitOrCredit = reportType === 'Receivable' ? 'debit' : 'credit';
|
const debitOrCredit = reportType === 'Receivable' ? 'debit' : 'credit';
|
||||||
const referenceType = reportType === 'Receivable' ? 'Invoice' : 'Bill';
|
const referenceType =
|
||||||
|
reportType === 'Receivable' ? 'SalesInvoice' : 'PurchaseInvoice';
|
||||||
|
|
||||||
entries = await getLedgerEntries();
|
entries = await getLedgerEntries();
|
||||||
const vouchers = await getVouchers();
|
const vouchers = await getVouchers();
|
||||||
|
|
||||||
const futureEntries = getFutureEntries();
|
const futureEntries = getFutureEntries();
|
||||||
const returnEntries = getReturnEntries();
|
const returnEntries = getReturnEntries();
|
||||||
const pdc = getPDC();
|
const pdc = getPDC();
|
||||||
|
|
||||||
const validEntries = getValidEntries();
|
const validEntries = getValidEntries();
|
||||||
|
|
||||||
let data = [];
|
let data = [];
|
||||||
|
|
||||||
for (let entry of validEntries) {
|
for (let entry of validEntries) {
|
||||||
|
const { outStandingAmount, creditNoteAmount } = getOutstandingAmount(entry);
|
||||||
|
|
||||||
const { outStandingAmount, creditNoteAmount } = getOutstandingAmount(entry);
|
console.log(outStandingAmount);
|
||||||
|
|
||||||
console.log(outStandingAmount);
|
if (outStandingAmount > 0.1 / 10) {
|
||||||
|
const row = {
|
||||||
|
date: entry.date,
|
||||||
|
party: entry.party
|
||||||
|
};
|
||||||
|
|
||||||
if (outStandingAmount > 0.1 / 10) {
|
// due date / bill date
|
||||||
const row = {
|
|
||||||
date: entry.date,
|
|
||||||
party: entry.party
|
|
||||||
};
|
|
||||||
|
|
||||||
// due date / bill date
|
row.voucherType = entry.referenceType;
|
||||||
|
row.voucherNo = entry.referenceName;
|
||||||
|
|
||||||
row.voucherType = entry.referenceType;
|
// bill details
|
||||||
row.voucherNo = entry.referenceName;
|
|
||||||
|
|
||||||
// bill details
|
const invoicedAmount = entry[debitOrCredit] || 0;
|
||||||
|
const paidAmount = invoicedAmount - outStandingAmount - creditNoteAmount;
|
||||||
|
|
||||||
const invoicedAmount = entry[debitOrCredit] || 0;
|
Object.assign(row, {
|
||||||
const paidAmount = invoicedAmount - outStandingAmount - creditNoteAmount;
|
invoicedAmount,
|
||||||
|
paidAmount,
|
||||||
|
outStandingAmount,
|
||||||
|
creditNoteAmount
|
||||||
|
});
|
||||||
|
|
||||||
Object.assign(row, {
|
// ageing
|
||||||
invoicedAmount,
|
|
||||||
paidAmount,
|
|
||||||
outStandingAmount,
|
|
||||||
creditNoteAmount
|
|
||||||
});
|
|
||||||
|
|
||||||
// ageing
|
data.push(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data.push(row);
|
return data;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
|
||||||
|
async function getVouchers() {
|
||||||
|
return await frappe.db.getAll({
|
||||||
|
doctype: referenceType,
|
||||||
|
fields: ['name', 'date'],
|
||||||
|
filters: {
|
||||||
|
submitted: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValidEntries() {
|
||||||
|
return entries.filter(entry => {
|
||||||
|
return (
|
||||||
|
entry.date <= date &&
|
||||||
|
entry.referenceType === referenceType &&
|
||||||
|
entry[debitOrCredit] > 0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOutstandingAmount(entry) {
|
||||||
|
let paymentAmount = 0.0,
|
||||||
|
creditNoteAmount = 0.0;
|
||||||
|
let reverseDebitOrCredit = debitOrCredit === 'debit' ? 'credit' : 'debit';
|
||||||
|
|
||||||
|
for (let e of getEntriesFor(
|
||||||
|
entry.party,
|
||||||
|
entry.referenceType,
|
||||||
|
entry.referenceName
|
||||||
|
)) {
|
||||||
|
if (e.date <= date) {
|
||||||
|
const amount = e[reverseDebitOrCredit] - e[debitOrCredit];
|
||||||
|
|
||||||
|
if (!Object.keys(returnEntries).includes(e.referenceName)) {
|
||||||
|
paymentAmount += amount;
|
||||||
|
} else {
|
||||||
|
creditNoteAmount += amount;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return {
|
||||||
|
outStandingAmount:
|
||||||
|
entry[debitOrCredit] -
|
||||||
|
entry[reverseDebitOrCredit] -
|
||||||
|
paymentAmount -
|
||||||
|
creditNoteAmount,
|
||||||
|
creditNoteAmount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// helpers
|
function getEntriesFor(party, againstVoucherType, againstVoucher) {
|
||||||
|
// TODO
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
async function getVouchers() {
|
function getFutureEntries() {
|
||||||
return await frappe.db.getAll({
|
return entries.filter(entry => entry.date > date);
|
||||||
doctype: referenceType,
|
}
|
||||||
fields: ['name', 'date'],
|
|
||||||
filters: {
|
function getReturnEntries() {
|
||||||
submitted: 1
|
// TODO
|
||||||
}
|
return {};
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function getPDC() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLedgerEntries() {
|
||||||
|
if (entries.length) {
|
||||||
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getValidEntries() {
|
const partyType = reportType === 'Receivable' ? 'customer' : 'supplier';
|
||||||
return entries.filter(entry => {
|
const partyList = (await frappe.db.getAll({
|
||||||
return (
|
doctype: 'Party',
|
||||||
entry.date <= date &&
|
filters: {
|
||||||
entry.referenceType === referenceType && entry[debitOrCredit] > 0
|
[partyType]: 1
|
||||||
);
|
}
|
||||||
});
|
})).map(d => d.name);
|
||||||
}
|
|
||||||
|
|
||||||
function getOutstandingAmount(entry) {
|
return await frappe.db.getAll({
|
||||||
let paymentAmount = 0.0, creditNoteAmount = 0.0;
|
doctype: 'AccountingLedgerEntry',
|
||||||
let reverseDebitOrCredit = debitOrCredit === 'debit' ? 'credit' : 'debit';
|
fields: [
|
||||||
|
'name',
|
||||||
for (let e of getEntriesFor(entry.party, entry.referenceType, entry.referenceName)) {
|
'date',
|
||||||
if (e.date <= date) {
|
'account',
|
||||||
const amount = e[reverseDebitOrCredit] - e[debitOrCredit];
|
'party',
|
||||||
|
'referenceType',
|
||||||
if (!Object.keys(returnEntries).includes(e.referenceName)) {
|
'referenceName',
|
||||||
paymentAmount += amount;
|
'sum(debit) as debit',
|
||||||
} else {
|
'sum(credit) as credit'
|
||||||
creditNoteAmount += amount;
|
],
|
||||||
}
|
filters: {
|
||||||
}
|
party: ['in', partyList]
|
||||||
}
|
},
|
||||||
|
groupBy: ['referenceType', 'referenceName', 'party'],
|
||||||
return {
|
orderBy: 'date'
|
||||||
outStandingAmount: (entry[debitOrCredit] - entry[reverseDebitOrCredit]) - paymentAmount - creditNoteAmount,
|
});
|
||||||
creditNoteAmount
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEntriesFor(party, againstVoucherType, againstVoucher) {
|
|
||||||
// TODO
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFutureEntries() {
|
|
||||||
return entries.filter(entry => entry.date > date);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getReturnEntries() {
|
|
||||||
// TODO
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPDC() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLedgerEntries() {
|
|
||||||
if (entries.length) {
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
const partyType = reportType === 'Receivable' ? 'customer': 'supplier'
|
|
||||||
const partyList = (await frappe.db.getAll({
|
|
||||||
doctype: 'Party',
|
|
||||||
filters: {
|
|
||||||
[partyType]: 1
|
|
||||||
}
|
|
||||||
})).map(d => d.name);
|
|
||||||
|
|
||||||
return await frappe.db.getAll({
|
|
||||||
doctype: 'AccountingLedgerEntry',
|
|
||||||
fields: ['name', 'date', 'account', 'party',
|
|
||||||
'referenceType', 'referenceName',
|
|
||||||
'sum(debit) as debit', 'sum(credit) as credit'],
|
|
||||||
filters: {
|
|
||||||
party: ['in', partyList]
|
|
||||||
},
|
|
||||||
groupBy: ['referenceType', 'referenceName', 'party'],
|
|
||||||
orderBy: 'date'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ module.exports = class GeneralLedgerView extends ReportPage {
|
|||||||
filterFields: [
|
filterFields: [
|
||||||
{
|
{
|
||||||
fieldtype: 'Select',
|
fieldtype: 'Select',
|
||||||
options: ['', 'Invoice', 'Payment'],
|
options: ['', 'SalesInvoice', 'Payment'],
|
||||||
label: 'Reference Type',
|
label: 'Reference Type',
|
||||||
fieldname: 'referenceType'
|
fieldname: 'referenceType'
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@ const viewConfig = {
|
|||||||
filterFields: [
|
filterFields: [
|
||||||
{
|
{
|
||||||
fieldtype: 'Select',
|
fieldtype: 'Select',
|
||||||
options: ['', 'Invoice', 'Payment', 'Bill'],
|
options: ['', 'SalesInvoice', 'Payment', 'PurchaseInvoice'],
|
||||||
label: 'Reference Type',
|
label: 'Reference Type',
|
||||||
fieldname: 'referenceType'
|
fieldname: 'referenceType'
|
||||||
},
|
},
|
||||||
|
@ -4,13 +4,13 @@ class BaseGSTR {
|
|||||||
async getCompleteReport(gstrType, filters) {
|
async getCompleteReport(gstrType, filters) {
|
||||||
if (['GSTR-1', 'GSTR-2'].includes(gstrType)) {
|
if (['GSTR-1', 'GSTR-2'].includes(gstrType)) {
|
||||||
let entries = await frappe.db.getAll({
|
let entries = await frappe.db.getAll({
|
||||||
doctype: gstrType === 'GSTR-1' ? 'Invoice' : 'Bill',
|
doctype: gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice',
|
||||||
filters
|
filters
|
||||||
});
|
});
|
||||||
|
|
||||||
let tableData = [];
|
let tableData = [];
|
||||||
for (let entry of entries) {
|
for (let entry of entries) {
|
||||||
entry.doctype = gstrType === 'GSTR-1' ? 'Invoice' : 'Bill';
|
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);
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,54 @@
|
|||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
|
|
||||||
class PurchaseRegister {
|
class PurchaseRegister {
|
||||||
async run({ fromDate, toDate }) {
|
async run({ fromDate, toDate, supplier }) {
|
||||||
const bills = await frappe.db.getAll({
|
let filters = {};
|
||||||
doctype: 'Bill',
|
if (supplier) {
|
||||||
fields: ['name', 'date', 'supplier', 'account', 'netTotal', 'grandTotal'],
|
filters.supplier = supplier;
|
||||||
filters: {
|
|
||||||
date: ['>=', fromDate, '<=', toDate],
|
|
||||||
submitted: 1
|
|
||||||
},
|
|
||||||
orderBy: 'date',
|
|
||||||
order: 'desc'
|
|
||||||
});
|
|
||||||
|
|
||||||
const billNames = bills.map(d => d.name);
|
|
||||||
|
|
||||||
const taxes = await frappe.db.getAll({
|
|
||||||
doctype: 'TaxSummary',
|
|
||||||
fields: ['parent', 'amount'],
|
|
||||||
filters: {
|
|
||||||
parenttype: 'Bill',
|
|
||||||
parent: ['in', billNames]
|
|
||||||
},
|
|
||||||
orderBy: 'name'
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let bill of bills) {
|
|
||||||
bill.totalTax = taxes
|
|
||||||
.filter(tax => tax.parent === bill.name)
|
|
||||||
.reduce((acc, tax) => {
|
|
||||||
if (tax.amount) {
|
|
||||||
acc = acc + tax.amount;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { rows: bills };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fromDate && toDate) {
|
||||||
|
filters.date = ['>=', fromDate, '<=', toDate];
|
||||||
|
} else if (fromDate) {
|
||||||
|
filters.date = ['>=', fromDate];
|
||||||
|
} else if (toDate) {
|
||||||
|
filters.date = ['<=', toDate];
|
||||||
|
}
|
||||||
|
filters.submitted = 1;
|
||||||
|
|
||||||
|
const bills = await frappe.db.getAll({
|
||||||
|
doctype: 'PurchaseInvoice',
|
||||||
|
fields: ['name', 'date', 'supplier', 'account', 'netTotal', 'grandTotal'],
|
||||||
|
filters,
|
||||||
|
orderBy: 'date',
|
||||||
|
order: 'desc'
|
||||||
|
});
|
||||||
|
|
||||||
|
const billNames = bills.map(d => d.name);
|
||||||
|
|
||||||
|
const taxes = await frappe.db.getAll({
|
||||||
|
doctype: 'TaxSummary',
|
||||||
|
fields: ['parent', 'amount'],
|
||||||
|
filters: {
|
||||||
|
parenttype: 'PurchaseInvoice',
|
||||||
|
parent: ['in', billNames]
|
||||||
|
},
|
||||||
|
orderBy: 'name'
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let bill of bills) {
|
||||||
|
bill.totalTax = taxes
|
||||||
|
.filter(tax => tax.parent === bill.name)
|
||||||
|
.reduce((acc, tax) => {
|
||||||
|
if (tax.amount) {
|
||||||
|
acc = acc + tax.amount;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { rows: bills };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = PurchaseRegister;
|
module.exports = PurchaseRegister;
|
||||||
|
@ -2,23 +2,23 @@ const frappe = require('frappejs');
|
|||||||
const RegisterView = require('../Register/RegisterView');
|
const RegisterView = require('../Register/RegisterView');
|
||||||
|
|
||||||
module.exports = class PurchaseRegisterView extends RegisterView {
|
module.exports = class PurchaseRegisterView extends RegisterView {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
title: frappe._('Purchase Register'),
|
title: frappe._('Purchase Register')
|
||||||
});
|
});
|
||||||
|
|
||||||
this.method = 'purchase-register';
|
this.method = 'purchase-register';
|
||||||
}
|
}
|
||||||
|
|
||||||
getColumns() {
|
getColumns() {
|
||||||
return [
|
return [
|
||||||
{ label: 'Bill', fieldname: 'name' },
|
{ label: 'PurchaseInvoice', fieldname: 'name' },
|
||||||
{ label: 'Posting Date', fieldname: 'date' },
|
{ label: 'Posting Date', fieldname: 'date' },
|
||||||
{ label: 'Supplier', fieldname: 'supplier' },
|
{ label: 'Supplier', fieldname: 'supplier' },
|
||||||
{ label: 'Payable Account', fieldname: 'account' },
|
{ label: 'Payable Account', fieldname: 'account' },
|
||||||
{ label: 'Net Total', fieldname: 'netTotal', fieldtype: 'Currency' },
|
{ label: 'Net Total', fieldname: 'netTotal', fieldtype: 'Currency' },
|
||||||
{ label: 'Total Tax', fieldname: 'totalTax', fieldtype: 'Currency' },
|
{ label: 'Total Tax', fieldname: 'totalTax', fieldtype: 'Currency' },
|
||||||
{ label: 'Grand Total', fieldname: 'grandTotal', fieldtype: 'Currency' },
|
{ label: 'Grand Total', fieldname: 'grandTotal', fieldtype: 'Currency' }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
42
reports/PurchaseRegister/viewConfig.js
Normal file
42
reports/PurchaseRegister/viewConfig.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const title = 'Purchase Register';
|
||||||
|
module.exports = {
|
||||||
|
title: title,
|
||||||
|
method: 'purchase-register',
|
||||||
|
filterFields: [
|
||||||
|
{
|
||||||
|
fieldtype: 'Link',
|
||||||
|
target: 'Party',
|
||||||
|
label: 'Supplier Name',
|
||||||
|
fieldname: 'supplier',
|
||||||
|
getFilters: query => {
|
||||||
|
if (query)
|
||||||
|
return {
|
||||||
|
keywords: ['like', query],
|
||||||
|
supplier: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
supplier: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: 'Date',
|
||||||
|
fieldname: 'fromDate',
|
||||||
|
label: 'From Date',
|
||||||
|
required: 1
|
||||||
|
},
|
||||||
|
{ fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1 }
|
||||||
|
],
|
||||||
|
getColumns() {
|
||||||
|
return [
|
||||||
|
{ label: 'PurchaseInvoice', fieldname: 'name' },
|
||||||
|
{ label: 'Posting Date', fieldname: 'date' },
|
||||||
|
{ label: 'Supplier', fieldname: 'supplier' },
|
||||||
|
{ label: 'Payable Account', fieldname: 'account' },
|
||||||
|
{ label: 'Net Total', fieldname: 'netTotal', fieldtype: 'Currency' },
|
||||||
|
{ label: 'Total Tax', fieldname: 'totalTax', fieldtype: 'Currency' },
|
||||||
|
{ label: 'Grand Total', fieldname: 'grandTotal', fieldtype: 'Currency' }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
@ -19,7 +19,7 @@ module.exports = class SalesRegisterView extends RegisterView {
|
|||||||
|
|
||||||
getColumns() {
|
getColumns() {
|
||||||
return [
|
return [
|
||||||
{ label: 'Invoice', fieldname: 'name' },
|
{ label: 'SalesInvoice', fieldname: 'name' },
|
||||||
{ label: 'Posting Date', fieldname: 'date' , fieldtype: 'Date' },
|
{ label: 'Posting Date', fieldname: 'date' , fieldtype: 'Date' },
|
||||||
{ label: 'Customer', fieldname: 'customer' },
|
{ label: 'Customer', fieldname: 'customer' },
|
||||||
{ label: 'Receivable Account', fieldname: 'account' },
|
{ label: 'Receivable Account', fieldname: 'account' },
|
||||||
|
@ -3,19 +3,40 @@ module.exports = {
|
|||||||
title: title,
|
title: title,
|
||||||
method: 'sales-register',
|
method: 'sales-register',
|
||||||
filterFields: [
|
filterFields: [
|
||||||
{ fieldtype: 'Link', target: 'Party', label: 'Customer Name', fieldname: 'customer' },
|
{
|
||||||
{ fieldtype: 'Date', fieldname: 'fromDate', label: 'From Date', required: 1 },
|
fieldtype: 'Link',
|
||||||
|
target: 'Party',
|
||||||
|
label: 'Customer Name',
|
||||||
|
fieldname: 'customer',
|
||||||
|
getFilters: query => {
|
||||||
|
if (query)
|
||||||
|
return {
|
||||||
|
keywords: ['like', query],
|
||||||
|
customer: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
customer: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: 'Date',
|
||||||
|
fieldname: 'fromDate',
|
||||||
|
label: 'From Date',
|
||||||
|
required: 1
|
||||||
|
},
|
||||||
{ fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1 }
|
{ fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1 }
|
||||||
],
|
],
|
||||||
getColumns() {
|
getColumns() {
|
||||||
return [
|
return [
|
||||||
{ label: 'Invoice', fieldname: 'name' },
|
{ label: 'SalesInvoice', fieldname: 'name' },
|
||||||
{ label: 'Posting Date', fieldname: 'date' , fieldtype: 'Date' },
|
{ label: 'Posting Date', fieldname: 'date', fieldtype: 'Date' },
|
||||||
{ label: 'Customer', fieldname: 'customer' },
|
{ label: 'Customer', fieldname: 'customer' },
|
||||||
{ label: 'Receivable Account', fieldname: 'account' },
|
{ label: 'Receivable Account', fieldname: 'account' },
|
||||||
{ label: 'Net Total', fieldname: 'netTotal', fieldtype: 'Currency' },
|
{ label: 'Net Total', fieldname: 'netTotal', fieldtype: 'Currency' },
|
||||||
{ label: 'Total Tax', fieldname: 'totalTax', fieldtype: 'Currency' },
|
{ label: 'Total Tax', fieldname: 'totalTax', fieldtype: 'Currency' },
|
||||||
{ label: 'Grand Total', fieldname: 'grandTotal', fieldtype: 'Currency' },
|
{ label: 'Grand Total', fieldname: 'grandTotal', fieldtype: 'Currency' }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
'general-ledger': require('./GeneralLedger/viewConfig'),
|
'general-ledger': require('./GeneralLedger/viewConfig'),
|
||||||
'sales-register': require('./SalesRegister/viewConfig'),
|
'sales-register': require('./SalesRegister/viewConfig'),
|
||||||
|
'purchase-register': require('./PurchaseRegister/viewConfig'),
|
||||||
'profit-and-loss': require('./ProfitAndLoss/viewConfig'),
|
'profit-and-loss': require('./ProfitAndLoss/viewConfig'),
|
||||||
'trial-balance': require('./TrialBalance/viewConfig'),
|
'trial-balance': require('./TrialBalance/viewConfig'),
|
||||||
'bank-reconciliation': require('./BankReconciliation/viewConfig'),
|
'bank-reconciliation': require('./BankReconciliation/viewConfig'),
|
||||||
|
@ -4,9 +4,9 @@ const registerServerMethods = require('./registerServerMethods');
|
|||||||
|
|
||||||
module.exports = async function postStart() {
|
module.exports = async function postStart() {
|
||||||
// set server-side modules
|
// set server-side modules
|
||||||
frappe.models.Invoice.documentClass = require('../models/doctype/Invoice/InvoiceServer.js');
|
frappe.models.SalesInvoice.documentClass = require('../models/doctype/SalesInvoice/SalesInvoiceServer.js');
|
||||||
frappe.models.Payment.documentClass = require('../models/doctype/Payment/PaymentServer.js');
|
frappe.models.Payment.documentClass = require('../models/doctype/Payment/PaymentServer.js');
|
||||||
frappe.models.Bill.documentClass = require('../models/doctype/Bill/BillServer.js');
|
frappe.models.PurchaseInvoice.documentClass = require('../models/doctype/PurchaseInvoice/PurchaseInvoiceServer.js');
|
||||||
frappe.models.JournalEntry.documentClass = require('../models/doctype/JournalEntry/JournalEntryServer.js');
|
frappe.models.JournalEntry.documentClass = require('../models/doctype/JournalEntry/JournalEntryServer.js');
|
||||||
frappe.models.GSTR3B.documentClass = require('../models/doctype/GSTR3B/GSTR3BServer.js');
|
frappe.models.GSTR3B.documentClass = require('../models/doctype/GSTR3B/GSTR3BServer.js');
|
||||||
|
|
||||||
@ -15,8 +15,8 @@ module.exports = async function postStart() {
|
|||||||
frappe.syncDoc(require('../fixtures/invoicePrint'));
|
frappe.syncDoc(require('../fixtures/invoicePrint'));
|
||||||
|
|
||||||
// init naming series if missing
|
// init naming series if missing
|
||||||
await naming.createNumberSeries('INV-', 'InvoiceSettings');
|
await naming.createNumberSeries('SINV-', 'SalesInvoiceSettings');
|
||||||
await naming.createNumberSeries('BILL-', 'BillSettings');
|
await naming.createNumberSeries('PINV-', 'PurchaseInvoiceSettings');
|
||||||
await naming.createNumberSeries('PAY-', 'PaymentSettings');
|
await naming.createNumberSeries('PAY-', 'PaymentSettings');
|
||||||
await naming.createNumberSeries('JV-', 'JournalEntrySettings');
|
await naming.createNumberSeries('JV-', 'JournalEntrySettings');
|
||||||
await naming.createNumberSeries('QTN-', 'QuotationSettings');
|
await naming.createNumberSeries('QTN-', 'QuotationSettings');
|
||||||
|
26
src/components/DashboardCard.vue
Normal file
26
src/components/DashboardCard.vue
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="card mx-2 my-2">
|
||||||
|
<div class="card-body">
|
||||||
|
<div :ref="chartData.title"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Chart } from 'frappe-charts';
|
||||||
|
export default {
|
||||||
|
name: 'DashboardCard',
|
||||||
|
props: ['chartData'],
|
||||||
|
mounted() {
|
||||||
|
const chart = new Chart(this.$refs[this.chartData.title], {
|
||||||
|
title: this.chartData.title,
|
||||||
|
data: this.chartData.data,
|
||||||
|
type: this.chartData.type, // or 'bar', 'line', 'scatter', 'pie', 'percentage'
|
||||||
|
height: 250,
|
||||||
|
colors: [this.chartData.color]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -3,7 +3,7 @@
|
|||||||
<div v-if="doc" class="p-4">
|
<div v-if="doc" class="p-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 text-center">
|
<div class="col-6 text-center">
|
||||||
<h4>Customizer</h4>
|
<h4>Customize</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 text-right">
|
<div class="col-6 text-right">
|
||||||
<f-button secondary @click="saveAndClose">{{ _('Save & Close') }}</f-button>
|
<f-button secondary @click="saveAndClose">{{ _('Save & Close') }}</f-button>
|
||||||
@ -36,9 +36,9 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
this.doc = await frappe.getDoc('InvoiceSettings');
|
this.doc = await frappe.getDoc('SalesInvoiceSettings');
|
||||||
this.color.hex = this.doc.themeColor;
|
this.color.hex = this.doc.themeColor;
|
||||||
const meta = frappe.getMeta('InvoiceSettings');
|
const meta = frappe.getMeta('SalesInvoiceSettings');
|
||||||
this.fields = meta.fields.filter(
|
this.fields = meta.fields.filter(
|
||||||
field => field.fieldname !== 'numberSeries'
|
field => field.fieldname !== 'numberSeries'
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-header px-4 py-3 border-bottom bg-white d-flex align-items-center">
|
<div
|
||||||
|
class="page-header px-4 py-2 border-bottom bg-white d-flex align-items-center justify-content-between"
|
||||||
|
>
|
||||||
<h5 class="m-0" v-if="title">{{ title }}</h5>
|
<h5 class="m-0" v-if="title">{{ title }}</h5>
|
||||||
<div v-if="breadcrumbs">
|
<div v-if="breadcrumbs">
|
||||||
<a v-for="(item, index) in clickableBreadcrumbs" :key="index" :href="item.route">
|
<a v-for="(item, index) in clickableBreadcrumbs" :key="index" :href="item.route">
|
||||||
@ -10,11 +12,19 @@
|
|||||||
</a>
|
</a>
|
||||||
<h5 class="breadCrumbRoute">{{ lastBreadcrumb.title }}</h5>
|
<h5 class="breadCrumbRoute">{{ lastBreadcrumb.title }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-4 p-0">
|
||||||
|
<SearchBar />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import SearchBar from './SearchBar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['title', 'breadcrumbs'],
|
props: ['title', 'breadcrumbs'],
|
||||||
|
components: {
|
||||||
|
SearchBar
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
clickableBreadcrumbs() {
|
clickableBreadcrumbs() {
|
||||||
return this.breadcrumbs.slice(0, this.breadcrumbs.length - 1);
|
return this.breadcrumbs.slice(0, this.breadcrumbs.length - 1);
|
||||||
|
152
src/components/SearchBar.vue
Normal file
152
src/components/SearchBar.vue
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text pt-0">
|
||||||
|
<feather-icon name="search" style="color: #212529 !important;"></feather-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Search..."
|
||||||
|
autocomplete="off"
|
||||||
|
spellcheck="false"
|
||||||
|
v-model="inputValue"
|
||||||
|
@keyup.enter="search"
|
||||||
|
aria-label="Recipient's username"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="inputValue" class="suggestion-list position-absolute shadow-sm" style="width: 100%">
|
||||||
|
<list-row
|
||||||
|
v-for="doc in suggestion"
|
||||||
|
:key="doc.name"
|
||||||
|
:class="doc.sep ? 'seperator': ''"
|
||||||
|
class="d-flex align-items-center"
|
||||||
|
@click.native="routeTo(doc.route)"
|
||||||
|
>
|
||||||
|
<span v-if="!doc.sep">
|
||||||
|
<feather-icon class="mr-1" name="minus" />
|
||||||
|
</span>
|
||||||
|
<div :class="doc.sep ? 'small' : ''">{{ doc.name }}</div>
|
||||||
|
<div class="small ml-auto">{{ doc.doctype }}</div>
|
||||||
|
</list-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import frappe from 'frappejs';
|
||||||
|
import ListRow from '../pages/ListView/ListRow';
|
||||||
|
import ListCell from '../pages/ListView/ListCell';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inputValue: '',
|
||||||
|
suggestion: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ListRow,
|
||||||
|
ListCell
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
inputValue() {
|
||||||
|
if (!this.inputValue.length) this.suggestion = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async search() {
|
||||||
|
const searchableDoctypes = frappe.getDoctypeList({
|
||||||
|
isSingle: 0,
|
||||||
|
isChild: 0
|
||||||
|
});
|
||||||
|
const documents = await this.getSearchedDocuments(searchableDoctypes);
|
||||||
|
const doctypes = await this.getSearchedDoctypes(searchableDoctypes);
|
||||||
|
this.suggestion = documents.concat(doctypes);
|
||||||
|
if (this.suggestion.length === 0)
|
||||||
|
this.suggestion = [{ sep: true, name: 'No results found.' }];
|
||||||
|
},
|
||||||
|
clearInput() {
|
||||||
|
this.inputValue = '';
|
||||||
|
this.$emit('change', null);
|
||||||
|
},
|
||||||
|
async getSearchedDocuments(searchableDoctypes) {
|
||||||
|
const promises = searchableDoctypes.map(doctype => {
|
||||||
|
return frappe.db.getAll({
|
||||||
|
doctype,
|
||||||
|
filters: { name: ['includes', this.inputValue] },
|
||||||
|
fields: ['name']
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const data = await Promise.all(promises);
|
||||||
|
// data contains list of documents, sorted according to position of its doctype in searchableDoctypes
|
||||||
|
const items = [];
|
||||||
|
items.push({
|
||||||
|
sep: true,
|
||||||
|
name: 'Documents'
|
||||||
|
});
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
// i represents doctype position in searchableDoctypes
|
||||||
|
if (data[i].length > 0) {
|
||||||
|
for (let doc of data[i]) {
|
||||||
|
let doctype = searchableDoctypes[i];
|
||||||
|
items.push({
|
||||||
|
doctype,
|
||||||
|
name: doc.name,
|
||||||
|
route: `/edit/${doctype}/${doc.name}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (items.length !== 1) return items;
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
getSearchedDoctypes(searchableDoctypes) {
|
||||||
|
const items = [{ sep: true, name: 'DocTypes' }];
|
||||||
|
let filteredDoctypes = searchableDoctypes.filter(doctype => {
|
||||||
|
return doctype.indexOf(this.inputValue) != -1;
|
||||||
|
});
|
||||||
|
filteredDoctypes = filteredDoctypes.map(doctype => {
|
||||||
|
return {
|
||||||
|
name: doctype,
|
||||||
|
route: `/list/${doctype}`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (filteredDoctypes.length > 0) return items.concat(filteredDoctypes);
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
routeTo(route) {
|
||||||
|
this.$router.push(route);
|
||||||
|
this.inputValue = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../styles/variables';
|
||||||
|
.input-group-text {
|
||||||
|
background-color: var(--white);
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
.seperator {
|
||||||
|
background-color: var(--light);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border-left: none;
|
||||||
|
height: 27px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-left: none;
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.suggestion-list {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="input-group">
|
|
||||||
<input
|
|
||||||
type="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="Search..."
|
|
||||||
autocomplete="off"
|
|
||||||
spellcheck="false"
|
|
||||||
v-model="inputValue"
|
|
||||||
@keyup.enter="$emit('change', inputValue)"
|
|
||||||
aria-label="Recipient's username"
|
|
||||||
>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
type="button"
|
|
||||||
:disabled="!inputValue"
|
|
||||||
@click="clearInput"
|
|
||||||
>
|
|
||||||
{{ _('Clear') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
inputValue: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
clearInput() {
|
|
||||||
this.inputValue = '';
|
|
||||||
this.$emit('change', null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -2,7 +2,7 @@
|
|||||||
<div class="page-sidebar bg-dark p-2 text-light d-flex flex-column justify-content-between">
|
<div class="page-sidebar bg-dark p-2 text-light d-flex flex-column justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<div class="company-name px-3 py-2 my-2">
|
<div class="company-name px-3 py-2 my-2">
|
||||||
<h6 class="m-0">{{ companyName }}</h6>
|
<h6 class="m-0" @click="$router.push('/')">{{ companyName }}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<transition-group name="slide-fade" mode="out-in">
|
<transition-group name="slide-fade" mode="out-in">
|
||||||
@ -95,6 +95,9 @@ export default {
|
|||||||
@import '../styles/variables.scss';
|
@import '../styles/variables.scss';
|
||||||
@import '../styles/animation.scss';
|
@import '../styles/animation.scss';
|
||||||
|
|
||||||
|
.company-name {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.page-sidebar {
|
.page-sidebar {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
119
src/pages/Dashboard.vue
Normal file
119
src/pages/Dashboard.vue
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<PageHeader title="Dashboard" />
|
||||||
|
<div class="container mt-3">
|
||||||
|
<div class="row no-gutters">
|
||||||
|
<DashboardCard v-for="chart in chartData" :key="chart.title" :chartData="chart" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PageHeader from '../components/PageHeader';
|
||||||
|
import DashboardCard from '../components/DashboardCard';
|
||||||
|
import frappe from 'frappejs';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Dashboard',
|
||||||
|
components: {
|
||||||
|
PageHeader,
|
||||||
|
DashboardCard
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
chartData: [],
|
||||||
|
charts: undefined
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async beforeMount() {
|
||||||
|
const dashboardSettings = await frappe.getDoc('DashboardSettings');
|
||||||
|
this.charts = dashboardSettings.charts;
|
||||||
|
this.charts.forEach(async c => {
|
||||||
|
const { labels, datasets } = await this.getAccountData(c.account, c.type);
|
||||||
|
this.chartData.push({
|
||||||
|
title: c.account,
|
||||||
|
type: c.type.toLowerCase(),
|
||||||
|
color: c.color,
|
||||||
|
data: {
|
||||||
|
labels,
|
||||||
|
datasets
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async getAccountData(account, chartType) {
|
||||||
|
let entriesArray = [];
|
||||||
|
let accountType;
|
||||||
|
async function getAccountEntries(accountName) {
|
||||||
|
const account = await frappe.getDoc('Account', accountName);
|
||||||
|
accountType = account.rootType;
|
||||||
|
if (account.isGroup != 1) {
|
||||||
|
const ledgerEntries = await frappe.db.getAll({
|
||||||
|
doctype: 'AccountingLedgerEntry',
|
||||||
|
filters: { account: account.name },
|
||||||
|
fields: ['*']
|
||||||
|
});
|
||||||
|
entriesArray = entriesArray.concat(ledgerEntries);
|
||||||
|
} else {
|
||||||
|
const children = await frappe.db.getAll({
|
||||||
|
doctype: 'Account',
|
||||||
|
filters: { parentAccount: account.name }
|
||||||
|
});
|
||||||
|
if (children.length)
|
||||||
|
for (let account of children) {
|
||||||
|
entriesArray = await getAccountEntries(account.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entriesArray;
|
||||||
|
}
|
||||||
|
let ledgerEntries = await getAccountEntries(account);
|
||||||
|
accountType = ['Asset', 'Expense'].includes(accountType)
|
||||||
|
? 'debit'
|
||||||
|
: 'credit';
|
||||||
|
let { labels, datasets } = this.createLabelsAndDataSet(chartType);
|
||||||
|
const currentMonthIndex = new Date().getMonth();
|
||||||
|
for (let entry of ledgerEntries) {
|
||||||
|
let monthIndex = parseInt(entry.date.split('-')[1]) - 1;
|
||||||
|
let pos = (monthIndex + currentMonthIndex) % 13;
|
||||||
|
if (accountType === 'debit')
|
||||||
|
datasets[0].values[pos] += entry.debit || -entry.credit;
|
||||||
|
else if (accountType === 'credit')
|
||||||
|
datasets[0].values[pos] += -entry.debit || entry.credit;
|
||||||
|
}
|
||||||
|
return { labels, datasets };
|
||||||
|
},
|
||||||
|
createLabelsAndDataSet(chartType) {
|
||||||
|
const currentMonthIndex = new Date().getMonth();
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
const monthName = [
|
||||||
|
'Jan',
|
||||||
|
'Feb',
|
||||||
|
'Mar',
|
||||||
|
'Apr',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'Aug',
|
||||||
|
'Sept',
|
||||||
|
'Oct',
|
||||||
|
'Nov',
|
||||||
|
'Dec'
|
||||||
|
];
|
||||||
|
let labels = [];
|
||||||
|
let datasets = [
|
||||||
|
{
|
||||||
|
type: chartType,
|
||||||
|
values: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
for (let i = 0; i < 13; i++) {
|
||||||
|
let year = i + currentMonthIndex >= 12 ? currentYear : currentYear - 1;
|
||||||
|
labels.push(monthName[(i + currentMonthIndex) % 12]);
|
||||||
|
}
|
||||||
|
return { labels, datasets };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -6,7 +6,7 @@
|
|||||||
:docfield="{
|
:docfield="{
|
||||||
fieldtype: 'Select',
|
fieldtype: 'Select',
|
||||||
fieldname: 'referenceDoctype',
|
fieldname: 'referenceDoctype',
|
||||||
options: ['Select a doctype...', 'ToDo', 'Item', 'Party', 'Invoice']
|
options: ['Select a doctype...', 'ToDo', 'Item', 'Party', 'SalesInvoice']
|
||||||
}"
|
}"
|
||||||
@change="doctype => showTable(doctype)"
|
@change="doctype => showTable(doctype)"
|
||||||
/>
|
/>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row no-gutters">
|
<div class="row no-gutters d-flex">
|
||||||
<sidebar class="col-2" />
|
<sidebar class="sidebar" />
|
||||||
<div class="page-container col-10 bg-light">
|
<div class="page-container bg-white">
|
||||||
<router-view :key="$route.fullPath" />
|
<router-view :key="$route.fullPath" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -18,7 +18,12 @@ export default {
|
|||||||
<style>
|
<style>
|
||||||
.page-container {
|
.page-container {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow: auto;
|
width: 100%;
|
||||||
overflow-x: hidden;
|
padding-left: 208px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
/* flex-basis: 220px; */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-light">
|
<div class="bg-white">
|
||||||
<page-header :breadcrumbs="breadcrumbs" />
|
<page-header :breadcrumbs="breadcrumbs" />
|
||||||
<div class="form-container col-10 bg-white mt-4 ml-auto mr-auto border p-5">
|
<div class="form-container col-sm-8 col-lg-6 mx-2 mt-4">
|
||||||
<form-actions
|
<form-actions
|
||||||
v-if="shouldRenderForm"
|
v-if="shouldRenderForm"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
@ -56,12 +56,12 @@ export default {
|
|||||||
if (this.doc)
|
if (this.doc)
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: this.doctype,
|
title: this.meta.label,
|
||||||
route: '#/list/' + this.doctype
|
route: '#/list/' + this.doctype
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: this.doc._notInserted
|
title: this.doc._notInserted
|
||||||
? 'New ' + this.doctype
|
? 'New ' + this.meta.label
|
||||||
: this.doc.name,
|
: this.doc.name,
|
||||||
route: ''
|
route: ''
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../styles/variables";
|
@import '../../styles/variables';
|
||||||
.list-row {
|
.list-row {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid $border-color;
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--light);
|
background-color: var(--white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 d-flex">
|
<div class="col-6 d-flex">
|
||||||
<search-input class="mr-2" @change="keyword => filterList(keyword)"/>
|
<!-- <search-bar class="mr-2" @change="keyword => filterList(keyword)" /> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 d-flex flex-row-reverse">
|
<div class="col-6 d-flex flex-row-reverse">
|
||||||
<f-button primary @click="$emit('newClick')">{{ _('New {0}', listConfig.title) }}</f-button>
|
<f-button primary @click="$emit('newClick')">{{ _('New {0}', listConfig.title) }}</f-button>
|
||||||
@ -9,22 +9,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import SearchInput from '@/components/SearchInput';
|
import SearchBar from '@/components/SearchBar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ListToolbar',
|
name: 'ListToolbar',
|
||||||
props: ['listConfig'],
|
props: ['listConfig'],
|
||||||
components: {
|
components: {
|
||||||
SearchInput
|
SearchBar
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async newInvoice() {
|
|
||||||
const doc = await frappe.getNewDoc('Invoice');
|
|
||||||
this.$formModal.open(doc);
|
|
||||||
},
|
|
||||||
filterList(keyword) {
|
filterList(keyword) {
|
||||||
frappe.listView.trigger('filterList', keyword);
|
frappe.listView.trigger('filterList', keyword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-light">
|
<div class="bg-white">
|
||||||
<page-header :title="listConfig.title" />
|
<page-header :title="listConfig.title" />
|
||||||
<div class="px-4 py-3">
|
<div class="px-4 py-3">
|
||||||
<list-toolbar
|
<list-toolbar
|
||||||
@ -8,9 +8,7 @@
|
|||||||
@filterList="keyword => filterList(keyword)"
|
@filterList="keyword => filterList(keyword)"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
/>
|
/>
|
||||||
<list
|
<list :listConfig="listConfig" />
|
||||||
:listConfig="listConfig"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -51,5 +49,5 @@ export default {
|
|||||||
return listConfigs[this.listName];
|
return listConfigs[this.listName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Invoice from '../../../models/doctype/Invoice/InvoiceList';
|
import SalesInvoice from '../../../models/doctype/SalesInvoice/SalesInvoiceList';
|
||||||
import Bill from '../../../models/doctype/Bill/BillList';
|
import PurchaseInvoice from '../../../models/doctype/PurchaseInvoice/PurchaseInvoiceList';
|
||||||
import Customer from '../../../models/doctype/Party/CustomerList';
|
import Customer from '../../../models/doctype/Party/CustomerList';
|
||||||
import Supplier from '../../../models/doctype/Party/SupplierList';
|
import Supplier from '../../../models/doctype/Party/SupplierList';
|
||||||
import Item from '../../../models/doctype/Item/ItemList';
|
import Item from '../../../models/doctype/Item/ItemList';
|
||||||
@ -10,8 +10,8 @@ import Account from '../../../models/doctype/Account/AccountList';
|
|||||||
import GSTR3B from '../../../models/doctype/GSTR3B/GSTR3BList';
|
import GSTR3B from '../../../models/doctype/GSTR3B/GSTR3BList';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Invoice,
|
SalesInvoice,
|
||||||
Bill,
|
PurchaseInvoice,
|
||||||
Customer,
|
Customer,
|
||||||
Supplier,
|
Supplier,
|
||||||
Item,
|
Item,
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-light">
|
<div class="bg-white">
|
||||||
<page-header :breadcrumbs="breadcrumbs" />
|
<page-header :breadcrumbs="breadcrumbs" />
|
||||||
<component :is="printComponent" v-if="doc" :doc="doc" @send="send" @makePDF="makePDF" />
|
<component :is="printComponent" v-if="doc" :doc="doc" @send="send" @makePDF="makePDF" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import PageHeader from '@/components/PageHeader';
|
import PageHeader from '@/components/PageHeader';
|
||||||
import InvoicePrint from '@/../models/doctype/Invoice/InvoicePrint';
|
import SalesInvoicePrint from '@/../models/doctype/SalesInvoice/SalesInvoicePrint';
|
||||||
import GSTR3BPrintView from '@/../models/doctype/GSTR3B/GSTR3BPrintView';
|
import GSTR3BPrintView from '@/../models/doctype/GSTR3B/GSTR3BPrintView';
|
||||||
import EmailSend from '../Email/EmailSend';
|
import EmailSend from '../Email/EmailSend';
|
||||||
|
|
||||||
const printComponents = {
|
const printComponents = {
|
||||||
Invoice: InvoicePrint,
|
SalesInvoice: SalesInvoicePrint,
|
||||||
GSTR3B: GSTR3BPrintView
|
GSTR3B: GSTR3BPrintView
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="px-3">
|
<div class="px-3">
|
||||||
<div class="row pb-4">
|
<div class="row pb-4 d-flex">
|
||||||
<page-header :class="linksExists ? 'col-6':'col-12'" :breadcrumbs="breadcrumbs" />
|
<page-header :breadcrumbs="breadcrumbs" style="flex-grow: 1;" />
|
||||||
<report-links class="col-6 d-flex pr-0 flex-row-reverse" v-if="linksExists" :links="links"></report-links>
|
<report-links class="d-flex flex-row-reverse" v-if="linksExists" :links="links"></report-links>
|
||||||
</div>
|
</div>
|
||||||
<div class="row pb-4">
|
<div class="row pb-4">
|
||||||
<report-filters
|
<report-filters
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-header title="Reports"/>
|
<page-header title="Reports" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-8 mx-auto">
|
<div class="col-8 mx-auto">
|
||||||
<clickable-card
|
<clickable-card
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
title="General Ledger"
|
title="General Ledger"
|
||||||
description="List of all ledger entries booked against all accounts"
|
description="List of all ledger entries booked against all accounts"
|
||||||
@click="routeTo('general-ledger', { 'referenceType': 'Invoice' })"
|
@click="routeTo('general-ledger', { 'referenceType': 'SalesInvoice' })"
|
||||||
/>
|
/>
|
||||||
<clickable-card
|
<clickable-card
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
@ -27,13 +27,14 @@
|
|||||||
description="Sales transactions for a given period with invoiced amount and tax details"
|
description="Sales transactions for a given period with invoiced amount and tax details"
|
||||||
@click="routeTo('sales-register')"
|
@click="routeTo('sales-register')"
|
||||||
/>
|
/>
|
||||||
<clickable-card
|
<clickable-card
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
title="Bank Reconciliation"
|
title="Bank Reconciliation"
|
||||||
description="Bank Reconciliation statement"
|
description="Bank Reconciliation statement"
|
||||||
@click="routeTo('bank-reconciliation',{'toDate' : (new Date()).toISOString()})"
|
@click="routeTo('bank-reconciliation',{'toDate' : (new Date()).toISOString()})"
|
||||||
/>
|
/>
|
||||||
<clickable-card v-if="country === 'India'"
|
<clickable-card
|
||||||
|
v-if="country === 'India'"
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
title="Goods and Service Tax"
|
title="Goods and Service Tax"
|
||||||
description="See your goods and services tax here."
|
description="See your goods and services tax here."
|
||||||
@ -52,8 +53,8 @@ export default {
|
|||||||
name: 'Report',
|
name: 'Report',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
country: '',
|
country: ''
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
PageHeader,
|
PageHeader,
|
||||||
@ -62,7 +63,6 @@ export default {
|
|||||||
async created() {
|
async created() {
|
||||||
const doc = await frappe.getDoc('AccountingSettings');
|
const doc = await frappe.getDoc('AccountingSettings');
|
||||||
this.country = doc.country;
|
this.country = doc.country;
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
routeTo(route, filters) {
|
routeTo(route, filters) {
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-header title="Settings"/>
|
<page-header title="Settings" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-8 bg-white mt-4 mx-auto border p-5">
|
<div class="col-12 bg-white border p-5">
|
||||||
<setting-section doctype="AccountingSettings"/>
|
<div class="col-9 col-lg-6 ml-1">
|
||||||
<hr class="mt-4">
|
<setting-section doctype="AccountingSettings" />
|
||||||
<setting-section doctype="CompanySettings"/>
|
<hr class="mt-4" />
|
||||||
<hr class="mt-4">
|
<setting-section doctype="CompanySettings" />
|
||||||
<setting-section doctype="EmailAccount"/>
|
<hr class="mt-4" />
|
||||||
<hr class="mt-4">
|
<setting-section doctype="EmailAccount" />
|
||||||
<setting-section doctype="SystemSettings"/>
|
<hr class="mt-4" />
|
||||||
|
<setting-section doctype="SystemSettings" />
|
||||||
|
<hr class="mt-4" />
|
||||||
|
<setting-section doctype="DashboardSettings" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
|||||||
import Router from 'vue-router';
|
import Router from 'vue-router';
|
||||||
|
|
||||||
import ListView from '../pages/ListView';
|
import ListView from '../pages/ListView';
|
||||||
|
import Dashboard from '../pages/Dashboard';
|
||||||
import FormView from '../pages/FormView/FormView';
|
import FormView from '../pages/FormView/FormView';
|
||||||
import PrintView from '../pages/PrintView';
|
import PrintView from '../pages/PrintView';
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ Vue.use(Router);
|
|||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: '/chartOfAccounts'
|
component: Dashboard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/list/:listName',
|
path: '/list/:listName',
|
||||||
|
@ -2,10 +2,28 @@ import frappe from 'frappejs';
|
|||||||
import { _ } from 'frappejs/utils';
|
import { _ } from 'frappejs/utils';
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
export default {
|
const config = {
|
||||||
getTitle: async () => {
|
getTitle: async () => {
|
||||||
const accountingSettings = await frappe.getSingle('AccountingSettings');
|
const { companyName, country } = await frappe.getSingle(
|
||||||
return accountingSettings.companyName;
|
'AccountingSettings'
|
||||||
|
);
|
||||||
|
if (country === 'India') {
|
||||||
|
config.groups[2].items.push(
|
||||||
|
{
|
||||||
|
label: _('GSTR 1'),
|
||||||
|
route: '/report/gstr-1?transferType=B2B'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: _('GSTR 2'),
|
||||||
|
route: '/report/gstr-2?transferType=B2B'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: _('GSTR 3B'),
|
||||||
|
route: '/list/GSTR3B'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return companyName;
|
||||||
},
|
},
|
||||||
getDbName() {
|
getDbName() {
|
||||||
if (localStorage.dbPath) {
|
if (localStorage.dbPath) {
|
||||||
@ -55,12 +73,12 @@ export default {
|
|||||||
title: _('Transactions'),
|
title: _('Transactions'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: _('Invoice'),
|
label: _('Sales Invoice'),
|
||||||
route: '/list/Invoice'
|
route: '/list/SalesInvoice'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: _('Bill'),
|
label: _('Purchase Invoice'),
|
||||||
route: '/list/Bill'
|
route: '/list/PurchaseInvoice'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: _('Journal Entry'),
|
label: _('Journal Entry'),
|
||||||
@ -87,21 +105,13 @@ export default {
|
|||||||
label: _('Sales Register'),
|
label: _('Sales Register'),
|
||||||
route: '/report/sales-register'
|
route: '/report/sales-register'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: _('Purchase Register'),
|
||||||
|
route: '/report/purchase-register'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: _('Bank Reconciliation'),
|
label: _('Bank Reconciliation'),
|
||||||
route: '/report/bank-reconciliation'
|
route: '/report/bank-reconciliation'
|
||||||
},
|
|
||||||
{
|
|
||||||
label: _('GSTR 1'),
|
|
||||||
route: '/report/gstr-1?transferType=B2B'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: _('GSTR 2'),
|
|
||||||
route: '/report/gstr-2?transferType=B2B'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: _('GSTR 3B'),
|
|
||||||
route: '/list/GSTR3B'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -120,3 +130,5 @@ export default {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
Loading…
Reference in New Issue
Block a user