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 = {
|
||||
doctype: "PrintFormat",
|
||||
name: "Standard Invoice Format",
|
||||
for: "Invoice",
|
||||
for: "SalesInvoice",
|
||||
template: `
|
||||
<h1>{{ doc.name }}</h1>
|
||||
<div class="row py-4">
|
||||
|
@ -3,7 +3,14 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const countries = require('../../../fixtures/countryInfo.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) {
|
||||
for (let accountName in children) {
|
||||
@ -22,12 +29,12 @@ async function importAccounts(children, parent, rootType, rootAccount) {
|
||||
isGroup,
|
||||
rootType,
|
||||
balance: 0,
|
||||
accountType: child.accountType
|
||||
})
|
||||
accountType: child.accountType || child.account_type
|
||||
});
|
||||
|
||||
await doc.insert()
|
||||
await doc.insert();
|
||||
|
||||
await importAccounts(child, accountName, rootType)
|
||||
await importAccounts(child, accountName, rootType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,7 +45,7 @@ function identifyIsGroup(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) {
|
||||
return 1;
|
||||
@ -51,19 +58,17 @@ async function getCountryCOA(){
|
||||
const doc = await frappe.getDoc('AccountingSettings');
|
||||
const conCode = countries[doc.country].code;
|
||||
|
||||
const countryCOA = path.resolve(path.join('./fixtures/verified/', conCode + '.json'));
|
||||
|
||||
if(fs.existsSync(countryCOA)){
|
||||
const jsonText = fs.readFileSync(countryCOA, 'utf-8');
|
||||
const json = JSON.parse(jsonText);
|
||||
return json.tree;
|
||||
} else {
|
||||
try {
|
||||
const countryCoa = require('../../../fixtures/verified/' +
|
||||
conCode +
|
||||
'.json');
|
||||
return countryCoa.tree;
|
||||
} catch (e) {
|
||||
return standardCOA;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function importCharts() {
|
||||
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}`
|
||||
]
|
||||
};
|
||||
const invoices = frappe.db.getAll({
|
||||
doctype: 'Invoice',
|
||||
const salesInvoices = frappe.db.getAll({
|
||||
doctype: 'SalesInvoice',
|
||||
filters,
|
||||
fields: ['*']
|
||||
});
|
||||
const bills = frappe.db.getAll({
|
||||
doctype: 'Bill',
|
||||
const purchaseInvoices = frappe.db.getAll({
|
||||
doctype: 'PurchaseInvoice',
|
||||
filters,
|
||||
fields: ['*']
|
||||
});
|
||||
const [gstr1Data, gstr2Data] = await Promise.all([invoices, bills]);
|
||||
const [gstr1Data, gstr2Data] = await Promise.all([
|
||||
salesInvoices,
|
||||
purchaseInvoices
|
||||
]);
|
||||
let gstr3bData = [[], []];
|
||||
|
||||
for (let ledgerEntry of gstr1Data) {
|
||||
ledgerEntry.doctype = 'Invoice';
|
||||
ledgerEntry.doctype = 'SalesInvoice';
|
||||
gstr3bData[0].push(await this.makeGSTRow(ledgerEntry));
|
||||
}
|
||||
for (let ledgerEntry of gstr2Data) {
|
||||
ledgerEntry.doctype = 'Bill';
|
||||
ledgerEntry.doctype = 'BiPurchaseInvoicell';
|
||||
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: [
|
||||
{
|
||||
label: 'Invoices',
|
||||
label: 'Sales Invoices',
|
||||
condition: form => form.doc.customer,
|
||||
action: form => {
|
||||
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',
|
||||
condition: form => form.doc.customer,
|
||||
|
@ -15,7 +15,7 @@ module.exports = class PaymentServer extends BaseDocument {
|
||||
async beforeSubmit() {
|
||||
if (this.for.length > 0)
|
||||
for (let row of this.for) {
|
||||
if (['Invoice', 'Bill'].includes(row.referenceType)) {
|
||||
if (['SalesInvoice', 'PurchaseInvoice'].includes(row.referenceType)) {
|
||||
let { outstandingAmount, grandTotal } = await frappe.getDoc(
|
||||
row.referenceType,
|
||||
row.referenceName
|
||||
|
@ -2,14 +2,15 @@ const frappe = require('frappejs');
|
||||
const utils = require('../../../accounting/utils');
|
||||
|
||||
module.exports = {
|
||||
name: 'Bill',
|
||||
name: 'PurchaseInvoice',
|
||||
doctype: 'DocType',
|
||||
documentClass: require('./BillDocument'),
|
||||
label: 'Purchase Invoice',
|
||||
documentClass: require('./PurchaseInvoiceDocument'),
|
||||
isSingle: 0,
|
||||
isChild: 0,
|
||||
isSubmittable: 1,
|
||||
keywordFields: ['name', 'supplier'],
|
||||
settings: 'BillSettings',
|
||||
settings: 'PurchaseInvoiceSettings',
|
||||
showTitle: true,
|
||||
fields: [
|
||||
{
|
||||
@ -50,7 +51,7 @@ module.exports = {
|
||||
fieldname: 'items',
|
||||
label: 'Items',
|
||||
fieldtype: 'Table',
|
||||
childtype: 'BillItem',
|
||||
childtype: 'PurchaseInvoiceItem',
|
||||
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';
|
||||
|
||||
export default {
|
||||
doctype: 'Bill',
|
||||
title: _('Bill'),
|
||||
doctype: 'PurchaseInvoice',
|
||||
title: _('Purchase Invoice'),
|
||||
columns: [
|
||||
'supplier',
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
const frappe = require('frappejs');
|
||||
const Bill = require('./BillDocument');
|
||||
const PurchaseInvoice = require('./PurchaseInvoiceDocument');
|
||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||
|
||||
module.exports = class BillServer extends Bill {
|
||||
module.exports = class PurchaseInvoiceServer extends PurchaseInvoice {
|
||||
async getPosting() {
|
||||
let entries = new LedgerPosting({ reference: this, party: this.supplier });
|
||||
await entries.credit(this.account, this.grandTotal);
|
||||
@ -36,7 +36,7 @@ module.exports = class BillServer extends Bill {
|
||||
const entries = await this.getPosting();
|
||||
await entries.post();
|
||||
await frappe.db.setValue(
|
||||
'Bill',
|
||||
'PurchaseInvoice',
|
||||
this.name,
|
||||
'outstandingAmount',
|
||||
this.grandTotal
|
@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
name: 'BillItem',
|
||||
name: 'PurchaseInvoiceItem',
|
||||
label: 'Purchase Invoice Item',
|
||||
doctype: 'DocType',
|
||||
isSingle: 0,
|
||||
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 Bill = require('../Bill/Bill');
|
||||
const PurchaseInvoice = require('../PurchaseInvoice/PurchaseInvoice');
|
||||
|
||||
module.exports = model.extend(Bill, {
|
||||
name: "PurchaseOrder",
|
||||
label: "Purchase Order",
|
||||
settings: "PurchaseOrderSettings",
|
||||
module.exports = model.extend(
|
||||
PurchaseInvoice,
|
||||
{
|
||||
name: 'PurchaseOrder',
|
||||
label: 'Purchase Order',
|
||||
settings: 'PurchaseOrderSettings',
|
||||
fields: [
|
||||
{
|
||||
"fieldname": "items",
|
||||
"childtype": "PurchaseOrderItem"
|
||||
fieldname: 'items',
|
||||
childtype: 'PurchaseOrderItem'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
},
|
||||
{
|
||||
skipFields: ['account']
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
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"
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
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",
|
||||
"label": "Purchase Order Settings",
|
||||
"fields": [
|
||||
|
@ -2,9 +2,10 @@ const frappe = require('frappejs');
|
||||
const utils = require('../../../accounting/utils');
|
||||
|
||||
module.exports = {
|
||||
name: 'Invoice',
|
||||
name: 'SalesInvoice',
|
||||
label: 'Sales Invoice',
|
||||
doctype: 'DocType',
|
||||
documentClass: require('./InvoiceDocument.js'),
|
||||
documentClass: require('./SalesInvoiceDocument'),
|
||||
print: {
|
||||
printFormat: 'Standard Invoice Format'
|
||||
},
|
||||
@ -12,7 +13,7 @@ module.exports = {
|
||||
isChild: 0,
|
||||
isSubmittable: 1,
|
||||
keywordFields: ['name', 'customer'],
|
||||
settings: 'InvoiceSettings',
|
||||
settings: 'SalesInvoiceSettings',
|
||||
showTitle: true,
|
||||
fields: [
|
||||
{
|
||||
@ -62,7 +63,7 @@ module.exports = {
|
||||
fieldname: 'items',
|
||||
label: 'Items',
|
||||
fieldtype: 'Table',
|
||||
childtype: 'InvoiceItem',
|
||||
childtype: 'SalesInvoiceItem',
|
||||
required: true
|
||||
},
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
const BaseDocument = require('frappejs/model/document');
|
||||
const frappe = require('frappejs');
|
||||
|
||||
module.exports = class Invoice extends BaseDocument {
|
||||
module.exports = class SalesInvoice extends BaseDocument {
|
||||
async getRowTax(row) {
|
||||
if (row.tax) {
|
||||
let tax = await this.getTax(row.tax);
|
@ -2,8 +2,8 @@ import { _ } from 'frappejs/utils';
|
||||
import indicators from 'frappejs/ui/constants/indicators';
|
||||
|
||||
export default {
|
||||
doctype: 'Invoice',
|
||||
title: _('Invoice'),
|
||||
doctype: 'SalesInvoice',
|
||||
title: _('Sales Invoice'),
|
||||
columns: [
|
||||
'customer',
|
||||
{
|
@ -26,9 +26,9 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import InvoiceTemplate1 from '@/../models/doctype/Invoice/Templates/InvoiceTemplate1';
|
||||
import InvoiceTemplate2 from '@/../models/doctype/Invoice/Templates/InvoiceTemplate2';
|
||||
import InvoiceTemplate3 from '@/../models/doctype/Invoice/Templates/InvoiceTemplate3';
|
||||
import InvoiceTemplate1 from '@/../models/doctype/SalesInvoice/Templates/InvoiceTemplate1';
|
||||
import InvoiceTemplate2 from '@/../models/doctype/SalesInvoice/Templates/InvoiceTemplate2';
|
||||
import InvoiceTemplate3 from '@/../models/doctype/SalesInvoice/Templates/InvoiceTemplate3';
|
||||
import InvoiceCustomizer from '@/components/InvoiceCustomizer';
|
||||
|
||||
const invoiceTemplates = {
|
@ -1,7 +1,7 @@
|
||||
const Invoice = require('./InvoiceDocument');
|
||||
const SalesInvoice = require('./SalesInvoiceDocument');
|
||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||
|
||||
module.exports = class InvoiceServer extends Invoice {
|
||||
module.exports = class SalesInvoiceServer extends SalesInvoice {
|
||||
async getPosting() {
|
||||
let entries = new LedgerPosting({ reference: this, party: this.customer });
|
||||
await entries.debit(this.account, this.grandTotal);
|
||||
@ -35,7 +35,7 @@ module.exports = class InvoiceServer extends Invoice {
|
||||
const entries = await this.getPosting();
|
||||
await entries.post();
|
||||
await frappe.db.setValue(
|
||||
'Invoice',
|
||||
'SalesInvoice',
|
||||
this.name,
|
||||
'outstandingAmount',
|
||||
this.grandTotal
|
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
name: 'InvoiceItem',
|
||||
name: 'SalesInvoiceItem',
|
||||
doctype: 'DocType',
|
||||
isSingle: 0,
|
||||
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 = {
|
||||
models: {
|
||||
SetupWizard: require('./doctype/SetupWizard/SetupWizard'),
|
||||
DashboardSettings: require('./doctype/DashboardSettings/DashboardSettings'),
|
||||
DashboardChart: require('./doctype/DashboardChart/DashboardChart'),
|
||||
Account: require('./doctype/Account/Account.js'),
|
||||
AccountingSettings: require('./doctype/AccountingSettings/AccountingSettings'),
|
||||
CompanySettings: require('./doctype/CompanySettings/CompanySettings'),
|
||||
@ -13,13 +15,13 @@ module.exports = {
|
||||
|
||||
Item: require('./doctype/Item/Item.js'),
|
||||
|
||||
Invoice: require('./doctype/Invoice/Invoice.js'),
|
||||
InvoiceItem: require('./doctype/InvoiceItem/InvoiceItem.js'),
|
||||
InvoiceSettings: require('./doctype/InvoiceSettings/InvoiceSettings.js'),
|
||||
SalesInvoice: require('./doctype/SalesInvoice/SalesInvoice.js'),
|
||||
SalesInvoiceItem: require('./doctype/SalesInvoiceItem/SalesInvoiceItem.js'),
|
||||
SalesInvoiceSettings: require('./doctype/SalesInvoiceSettings/SalesInvoiceSettings.js'),
|
||||
|
||||
Bill: require('./doctype/Bill/Bill.js'),
|
||||
BillItem: require('./doctype/BillItem/BillItem.js'),
|
||||
BillSettings: require('./doctype/BillSettings/BillSettings.js'),
|
||||
PurchaseInvoice: require('./doctype/PurchaseInvoice/PurchaseInvoice.js'),
|
||||
PurchaseInvoiceItem: require('./doctype/PurchaseInvoiceItem/PurchaseInvoiceItem.js'),
|
||||
PurchaseInvoiceSettings: require('./doctype/PurchaseInvoiceSettings/PurchaseInvoiceSettings.js'),
|
||||
|
||||
Tax: require('./doctype/Tax/Tax.js'),
|
||||
TaxDetail: require('./doctype/TaxDetail/TaxDetail.js'),
|
||||
|
@ -60,6 +60,7 @@
|
||||
"dependencies": {
|
||||
"cross-env": "^5.2.0",
|
||||
"file-saver": "^2.0.2",
|
||||
"frappe-charts": "^1.2.4",
|
||||
"frappejs": "github:thefalconx33/frappejs#test",
|
||||
"nodemailer": "^4.7.0",
|
||||
"popper.js": "^1.14.4",
|
||||
|
@ -2,7 +2,6 @@ const frappe = require('frappejs');
|
||||
|
||||
module.exports = class AccountsReceivablePayable {
|
||||
async run(reportType, { date }) {
|
||||
|
||||
const rows = await getReceivablePayable({
|
||||
reportType,
|
||||
date
|
||||
@ -10,12 +9,13 @@ module.exports = class AccountsReceivablePayable {
|
||||
|
||||
return { rows };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||
let entries = [];
|
||||
const debitOrCredit = reportType === 'Receivable' ? 'debit' : 'credit';
|
||||
const referenceType = reportType === 'Receivable' ? 'Invoice' : 'Bill';
|
||||
const referenceType =
|
||||
reportType === 'Receivable' ? 'SalesInvoice' : 'PurchaseInvoice';
|
||||
|
||||
entries = await getLedgerEntries();
|
||||
const vouchers = await getVouchers();
|
||||
@ -29,7 +29,6 @@ async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||
let data = [];
|
||||
|
||||
for (let entry of validEntries) {
|
||||
|
||||
const { outStandingAmount, creditNoteAmount } = getOutstandingAmount(entry);
|
||||
|
||||
console.log(outStandingAmount);
|
||||
@ -81,16 +80,22 @@ async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||
return entries.filter(entry => {
|
||||
return (
|
||||
entry.date <= date &&
|
||||
entry.referenceType === referenceType && entry[debitOrCredit] > 0
|
||||
entry.referenceType === referenceType &&
|
||||
entry[debitOrCredit] > 0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getOutstandingAmount(entry) {
|
||||
let paymentAmount = 0.0, creditNoteAmount = 0.0;
|
||||
let paymentAmount = 0.0,
|
||||
creditNoteAmount = 0.0;
|
||||
let reverseDebitOrCredit = debitOrCredit === 'debit' ? 'credit' : 'debit';
|
||||
|
||||
for (let e of getEntriesFor(entry.party, entry.referenceType, entry.referenceName)) {
|
||||
for (let e of getEntriesFor(
|
||||
entry.party,
|
||||
entry.referenceType,
|
||||
entry.referenceName
|
||||
)) {
|
||||
if (e.date <= date) {
|
||||
const amount = e[reverseDebitOrCredit] - e[debitOrCredit];
|
||||
|
||||
@ -103,14 +108,18 @@ async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||
}
|
||||
|
||||
return {
|
||||
outStandingAmount: (entry[debitOrCredit] - entry[reverseDebitOrCredit]) - paymentAmount - creditNoteAmount,
|
||||
outStandingAmount:
|
||||
entry[debitOrCredit] -
|
||||
entry[reverseDebitOrCredit] -
|
||||
paymentAmount -
|
||||
creditNoteAmount,
|
||||
creditNoteAmount
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getEntriesFor(party, againstVoucherType, againstVoucher) {
|
||||
// TODO
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
|
||||
function getFutureEntries() {
|
||||
@ -131,7 +140,7 @@ async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||
return entries;
|
||||
}
|
||||
|
||||
const partyType = reportType === 'Receivable' ? 'customer': 'supplier'
|
||||
const partyType = reportType === 'Receivable' ? 'customer' : 'supplier';
|
||||
const partyList = (await frappe.db.getAll({
|
||||
doctype: 'Party',
|
||||
filters: {
|
||||
@ -141,9 +150,16 @@ async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
||||
|
||||
return await frappe.db.getAll({
|
||||
doctype: 'AccountingLedgerEntry',
|
||||
fields: ['name', 'date', 'account', 'party',
|
||||
'referenceType', 'referenceName',
|
||||
'sum(debit) as debit', 'sum(credit) as credit'],
|
||||
fields: [
|
||||
'name',
|
||||
'date',
|
||||
'account',
|
||||
'party',
|
||||
'referenceType',
|
||||
'referenceName',
|
||||
'sum(debit) as debit',
|
||||
'sum(credit) as credit'
|
||||
],
|
||||
filters: {
|
||||
party: ['in', partyList]
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ module.exports = class GeneralLedgerView extends ReportPage {
|
||||
filterFields: [
|
||||
{
|
||||
fieldtype: 'Select',
|
||||
options: ['', 'Invoice', 'Payment'],
|
||||
options: ['', 'SalesInvoice', 'Payment'],
|
||||
label: 'Reference Type',
|
||||
fieldname: 'referenceType'
|
||||
},
|
||||
|
@ -5,7 +5,7 @@ const viewConfig = {
|
||||
filterFields: [
|
||||
{
|
||||
fieldtype: 'Select',
|
||||
options: ['', 'Invoice', 'Payment', 'Bill'],
|
||||
options: ['', 'SalesInvoice', 'Payment', 'PurchaseInvoice'],
|
||||
label: 'Reference Type',
|
||||
fieldname: 'referenceType'
|
||||
},
|
||||
|
@ -4,13 +4,13 @@ class BaseGSTR {
|
||||
async getCompleteReport(gstrType, filters) {
|
||||
if (['GSTR-1', 'GSTR-2'].includes(gstrType)) {
|
||||
let entries = await frappe.db.getAll({
|
||||
doctype: gstrType === 'GSTR-1' ? 'Invoice' : 'Bill',
|
||||
doctype: gstrType === 'GSTR-1' ? 'SalesInvoice' : 'PurchaseInvoice',
|
||||
filters
|
||||
});
|
||||
|
||||
let tableData = [];
|
||||
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);
|
||||
tableData.push(row);
|
||||
}
|
||||
|
@ -1,14 +1,25 @@
|
||||
const frappe = require('frappejs');
|
||||
|
||||
class PurchaseRegister {
|
||||
async run({ fromDate, toDate }) {
|
||||
async run({ fromDate, toDate, supplier }) {
|
||||
let filters = {};
|
||||
if (supplier) {
|
||||
filters.supplier = supplier;
|
||||
}
|
||||
|
||||
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: 'Bill',
|
||||
doctype: 'PurchaseInvoice',
|
||||
fields: ['name', 'date', 'supplier', 'account', 'netTotal', 'grandTotal'],
|
||||
filters: {
|
||||
date: ['>=', fromDate, '<=', toDate],
|
||||
submitted: 1
|
||||
},
|
||||
filters,
|
||||
orderBy: 'date',
|
||||
order: 'desc'
|
||||
});
|
||||
@ -19,7 +30,7 @@ class PurchaseRegister {
|
||||
doctype: 'TaxSummary',
|
||||
fields: ['parent', 'amount'],
|
||||
filters: {
|
||||
parenttype: 'Bill',
|
||||
parenttype: 'PurchaseInvoice',
|
||||
parent: ['in', billNames]
|
||||
},
|
||||
orderBy: 'name'
|
||||
|
@ -4,7 +4,7 @@ const RegisterView = require('../Register/RegisterView');
|
||||
module.exports = class PurchaseRegisterView extends RegisterView {
|
||||
constructor() {
|
||||
super({
|
||||
title: frappe._('Purchase Register'),
|
||||
title: frappe._('Purchase Register')
|
||||
});
|
||||
|
||||
this.method = 'purchase-register';
|
||||
@ -12,13 +12,13 @@ module.exports = class PurchaseRegisterView extends RegisterView {
|
||||
|
||||
getColumns() {
|
||||
return [
|
||||
{ label: 'Bill', fieldname: 'name' },
|
||||
{ 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' },
|
||||
{ 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() {
|
||||
return [
|
||||
{ label: 'Invoice', fieldname: 'name' },
|
||||
{ label: 'SalesInvoice', fieldname: 'name' },
|
||||
{ label: 'Posting Date', fieldname: 'date' , fieldtype: 'Date' },
|
||||
{ label: 'Customer', fieldname: 'customer' },
|
||||
{ label: 'Receivable Account', fieldname: 'account' },
|
||||
|
@ -3,19 +3,40 @@ module.exports = {
|
||||
title: title,
|
||||
method: 'sales-register',
|
||||
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 }
|
||||
],
|
||||
getColumns() {
|
||||
return [
|
||||
{ label: 'Invoice', fieldname: 'name' },
|
||||
{ label: 'SalesInvoice', fieldname: 'name' },
|
||||
{ label: 'Posting Date', fieldname: 'date', fieldtype: 'Date' },
|
||||
{ label: 'Customer', fieldname: 'customer' },
|
||||
{ label: 'Receivable Account', fieldname: 'account' },
|
||||
{ label: 'Net Total', fieldname: 'netTotal', 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 = {
|
||||
'general-ledger': require('./GeneralLedger/viewConfig'),
|
||||
'sales-register': require('./SalesRegister/viewConfig'),
|
||||
'purchase-register': require('./PurchaseRegister/viewConfig'),
|
||||
'profit-and-loss': require('./ProfitAndLoss/viewConfig'),
|
||||
'trial-balance': require('./TrialBalance/viewConfig'),
|
||||
'bank-reconciliation': require('./BankReconciliation/viewConfig'),
|
||||
|
@ -4,9 +4,9 @@ const registerServerMethods = require('./registerServerMethods');
|
||||
|
||||
module.exports = async function postStart() {
|
||||
// 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.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.GSTR3B.documentClass = require('../models/doctype/GSTR3B/GSTR3BServer.js');
|
||||
|
||||
@ -15,8 +15,8 @@ module.exports = async function postStart() {
|
||||
frappe.syncDoc(require('../fixtures/invoicePrint'));
|
||||
|
||||
// init naming series if missing
|
||||
await naming.createNumberSeries('INV-', 'InvoiceSettings');
|
||||
await naming.createNumberSeries('BILL-', 'BillSettings');
|
||||
await naming.createNumberSeries('SINV-', 'SalesInvoiceSettings');
|
||||
await naming.createNumberSeries('PINV-', 'PurchaseInvoiceSettings');
|
||||
await naming.createNumberSeries('PAY-', 'PaymentSettings');
|
||||
await naming.createNumberSeries('JV-', 'JournalEntrySettings');
|
||||
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 class="row">
|
||||
<div class="col-6 text-center">
|
||||
<h4>Customizer</h4>
|
||||
<h4>Customize</h4>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<f-button secondary @click="saveAndClose">{{ _('Save & Close') }}</f-button>
|
||||
@ -36,9 +36,9 @@ export default {
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
this.doc = await frappe.getDoc('InvoiceSettings');
|
||||
this.doc = await frappe.getDoc('SalesInvoiceSettings');
|
||||
this.color.hex = this.doc.themeColor;
|
||||
const meta = frappe.getMeta('InvoiceSettings');
|
||||
const meta = frappe.getMeta('SalesInvoiceSettings');
|
||||
this.fields = meta.fields.filter(
|
||||
field => field.fieldname !== 'numberSeries'
|
||||
);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<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>
|
||||
<div v-if="breadcrumbs">
|
||||
<a v-for="(item, index) in clickableBreadcrumbs" :key="index" :href="item.route">
|
||||
@ -10,11 +12,19 @@
|
||||
</a>
|
||||
<h5 class="breadCrumbRoute">{{ lastBreadcrumb.title }}</h5>
|
||||
</div>
|
||||
<div class="col-4 p-0">
|
||||
<SearchBar />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import SearchBar from './SearchBar';
|
||||
|
||||
export default {
|
||||
props: ['title', 'breadcrumbs'],
|
||||
components: {
|
||||
SearchBar
|
||||
},
|
||||
computed: {
|
||||
clickableBreadcrumbs() {
|
||||
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>
|
||||
<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>
|
||||
<transition-group name="slide-fade" mode="out-in">
|
||||
@ -95,6 +95,9 @@ export default {
|
||||
@import '../styles/variables.scss';
|
||||
@import '../styles/animation.scss';
|
||||
|
||||
.company-name {
|
||||
cursor: pointer;
|
||||
}
|
||||
.page-sidebar {
|
||||
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="{
|
||||
fieldtype: 'Select',
|
||||
fieldname: 'referenceDoctype',
|
||||
options: ['Select a doctype...', 'ToDo', 'Item', 'Party', 'Invoice']
|
||||
options: ['Select a doctype...', 'ToDo', 'Item', 'Party', 'SalesInvoice']
|
||||
}"
|
||||
@change="doctype => showTable(doctype)"
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="row no-gutters">
|
||||
<sidebar class="col-2" />
|
||||
<div class="page-container col-10 bg-light">
|
||||
<div class="row no-gutters d-flex">
|
||||
<sidebar class="sidebar" />
|
||||
<div class="page-container bg-white">
|
||||
<router-view :key="$route.fullPath" />
|
||||
</div>
|
||||
</div>
|
||||
@ -18,7 +18,12 @@ export default {
|
||||
<style>
|
||||
.page-container {
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
padding-left: 208px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
/* flex-basis: 220px; */
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="bg-light">
|
||||
<div class="bg-white">
|
||||
<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
|
||||
v-if="shouldRenderForm"
|
||||
:doc="doc"
|
||||
@ -56,12 +56,12 @@ export default {
|
||||
if (this.doc)
|
||||
return [
|
||||
{
|
||||
title: this.doctype,
|
||||
title: this.meta.label,
|
||||
route: '#/list/' + this.doctype
|
||||
},
|
||||
{
|
||||
title: this.doc._notInserted
|
||||
? 'New ' + this.doctype
|
||||
? 'New ' + this.meta.label
|
||||
: this.doc.name,
|
||||
route: ''
|
||||
}
|
||||
|
@ -4,14 +4,14 @@
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
@import "../../styles/variables";
|
||||
@import '../../styles/variables';
|
||||
.list-row {
|
||||
cursor: pointer;
|
||||
border: 1px solid $border-color;
|
||||
background-color: var(--white);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--light);
|
||||
background-color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<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 class="col-6 d-flex flex-row-reverse">
|
||||
<f-button primary @click="$emit('newClick')">{{ _('New {0}', listConfig.title) }}</f-button>
|
||||
@ -9,22 +9,18 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import SearchInput from '@/components/SearchInput';
|
||||
import SearchBar from '@/components/SearchBar';
|
||||
|
||||
export default {
|
||||
name: 'ListToolbar',
|
||||
props: ['listConfig'],
|
||||
components: {
|
||||
SearchInput
|
||||
SearchBar
|
||||
},
|
||||
methods: {
|
||||
async newInvoice() {
|
||||
const doc = await frappe.getNewDoc('Invoice');
|
||||
this.$formModal.open(doc);
|
||||
},
|
||||
filterList(keyword) {
|
||||
frappe.listView.trigger('filterList', keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="bg-light">
|
||||
<div class="bg-white">
|
||||
<page-header :title="listConfig.title" />
|
||||
<div class="px-4 py-3">
|
||||
<list-toolbar
|
||||
@ -8,9 +8,7 @@
|
||||
@filterList="keyword => filterList(keyword)"
|
||||
class="mb-4"
|
||||
/>
|
||||
<list
|
||||
:listConfig="listConfig"
|
||||
/>
|
||||
<list :listConfig="listConfig" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -51,5 +49,5 @@ export default {
|
||||
return listConfigs[this.listName];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Invoice from '../../../models/doctype/Invoice/InvoiceList';
|
||||
import Bill from '../../../models/doctype/Bill/BillList';
|
||||
import SalesInvoice from '../../../models/doctype/SalesInvoice/SalesInvoiceList';
|
||||
import PurchaseInvoice from '../../../models/doctype/PurchaseInvoice/PurchaseInvoiceList';
|
||||
import Customer from '../../../models/doctype/Party/CustomerList';
|
||||
import Supplier from '../../../models/doctype/Party/SupplierList';
|
||||
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';
|
||||
|
||||
export default {
|
||||
Invoice,
|
||||
Bill,
|
||||
SalesInvoice,
|
||||
PurchaseInvoice,
|
||||
Customer,
|
||||
Supplier,
|
||||
Item,
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="bg-light">
|
||||
<div class="bg-white">
|
||||
<page-header :breadcrumbs="breadcrumbs" />
|
||||
<component :is="printComponent" v-if="doc" :doc="doc" @send="send" @makePDF="makePDF" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
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 EmailSend from '../Email/EmailSend';
|
||||
|
||||
const printComponents = {
|
||||
Invoice: InvoicePrint,
|
||||
SalesInvoice: SalesInvoicePrint,
|
||||
GSTR3B: GSTR3BPrintView
|
||||
};
|
||||
export default {
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="px-3">
|
||||
<div class="row pb-4">
|
||||
<page-header :class="linksExists ? 'col-6':'col-12'" :breadcrumbs="breadcrumbs" />
|
||||
<report-links class="col-6 d-flex pr-0 flex-row-reverse" v-if="linksExists" :links="links"></report-links>
|
||||
<div class="row pb-4 d-flex">
|
||||
<page-header :breadcrumbs="breadcrumbs" style="flex-grow: 1;" />
|
||||
<report-links class="d-flex flex-row-reverse" v-if="linksExists" :links="links"></report-links>
|
||||
</div>
|
||||
<div class="row pb-4">
|
||||
<report-filters
|
||||
|
@ -7,7 +7,7 @@
|
||||
class="mt-2"
|
||||
title="General Ledger"
|
||||
description="List of all ledger entries booked against all accounts"
|
||||
@click="routeTo('general-ledger', { 'referenceType': 'Invoice' })"
|
||||
@click="routeTo('general-ledger', { 'referenceType': 'SalesInvoice' })"
|
||||
/>
|
||||
<clickable-card
|
||||
class="mt-2"
|
||||
@ -33,7 +33,8 @@
|
||||
description="Bank Reconciliation statement"
|
||||
@click="routeTo('bank-reconciliation',{'toDate' : (new Date()).toISOString()})"
|
||||
/>
|
||||
<clickable-card v-if="country === 'India'"
|
||||
<clickable-card
|
||||
v-if="country === 'India'"
|
||||
class="mt-2"
|
||||
title="Goods and Service Tax"
|
||||
description="See your goods and services tax here."
|
||||
@ -52,8 +53,8 @@ export default {
|
||||
name: 'Report',
|
||||
data() {
|
||||
return {
|
||||
country: '',
|
||||
}
|
||||
country: ''
|
||||
};
|
||||
},
|
||||
components: {
|
||||
PageHeader,
|
||||
@ -62,7 +63,6 @@ export default {
|
||||
async created() {
|
||||
const doc = await frappe.getDoc('AccountingSettings');
|
||||
this.country = doc.country;
|
||||
|
||||
},
|
||||
methods: {
|
||||
routeTo(route, filters) {
|
||||
|
@ -2,14 +2,18 @@
|
||||
<div>
|
||||
<page-header title="Settings" />
|
||||
<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">
|
||||
<div class="col-9 col-lg-6 ml-1">
|
||||
<setting-section doctype="AccountingSettings" />
|
||||
<hr class="mt-4">
|
||||
<hr class="mt-4" />
|
||||
<setting-section doctype="CompanySettings" />
|
||||
<hr class="mt-4">
|
||||
<hr class="mt-4" />
|
||||
<setting-section doctype="EmailAccount" />
|
||||
<hr class="mt-4">
|
||||
<hr class="mt-4" />
|
||||
<setting-section doctype="SystemSettings" />
|
||||
<hr class="mt-4" />
|
||||
<setting-section doctype="DashboardSettings" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
|
||||
import ListView from '../pages/ListView';
|
||||
import Dashboard from '../pages/Dashboard';
|
||||
import FormView from '../pages/FormView/FormView';
|
||||
import PrintView from '../pages/PrintView';
|
||||
|
||||
@ -22,7 +23,7 @@ Vue.use(Router);
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/chartOfAccounts'
|
||||
component: Dashboard
|
||||
},
|
||||
{
|
||||
path: '/list/:listName',
|
||||
|
@ -2,10 +2,28 @@ import frappe from 'frappejs';
|
||||
import { _ } from 'frappejs/utils';
|
||||
const path = require('path');
|
||||
|
||||
export default {
|
||||
const config = {
|
||||
getTitle: async () => {
|
||||
const accountingSettings = await frappe.getSingle('AccountingSettings');
|
||||
return accountingSettings.companyName;
|
||||
const { companyName, country } = await frappe.getSingle(
|
||||
'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() {
|
||||
if (localStorage.dbPath) {
|
||||
@ -55,12 +73,12 @@ export default {
|
||||
title: _('Transactions'),
|
||||
items: [
|
||||
{
|
||||
label: _('Invoice'),
|
||||
route: '/list/Invoice'
|
||||
label: _('Sales Invoice'),
|
||||
route: '/list/SalesInvoice'
|
||||
},
|
||||
{
|
||||
label: _('Bill'),
|
||||
route: '/list/Bill'
|
||||
label: _('Purchase Invoice'),
|
||||
route: '/list/PurchaseInvoice'
|
||||
},
|
||||
{
|
||||
label: _('Journal Entry'),
|
||||
@ -87,21 +105,13 @@ export default {
|
||||
label: _('Sales Register'),
|
||||
route: '/report/sales-register'
|
||||
},
|
||||
{
|
||||
label: _('Purchase Register'),
|
||||
route: '/report/purchase-register'
|
||||
},
|
||||
{
|
||||
label: _('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