2
0
mirror of https://github.com/frappe/books.git synced 2024-12-23 11:29:03 +00:00

Reports and Models

- Models
  - Bill
  - Quotation (extended from Invoice)
  - Journal Entry

- Reports
  - Sales Register
  - Purchase Register
This commit is contained in:
Faris Ansari 2018-04-26 15:53:27 +05:30
parent 8adb52c57c
commit 17e5187c51
31 changed files with 1098 additions and 235 deletions

View File

@ -21,7 +21,7 @@ module.exports = class LedgerPosting {
if (!this.entryMap[account]) { if (!this.entryMap[account]) {
const entry = { const entry = {
account: account, account: account,
party: this.party, party: this.party || '',
date: this.date || this.reference.date, date: this.date || this.reference.date,
referenceType: referenceType || this.reference.doctype, referenceType: referenceType || this.reference.doctype,
referenceName: referenceName || this.reference.name, referenceName: referenceName || this.reference.name,

View File

@ -16,13 +16,18 @@ module.exports = {
frappe.desk.menu.addItem('Customers', '#list/Customer'); frappe.desk.menu.addItem('Customers', '#list/Customer');
frappe.desk.menu.addItem('Quotation', '#list/Quotation'); frappe.desk.menu.addItem('Quotation', '#list/Quotation');
frappe.desk.menu.addItem('Invoice', '#list/Invoice'); frappe.desk.menu.addItem('Invoice', '#list/Invoice');
frappe.desk.menu.addItem('Bill', '#list/Bill');
frappe.desk.menu.addItem('Journal Entry', '#list/JournalEntry'); frappe.desk.menu.addItem('Journal Entry', '#list/JournalEntry');
frappe.desk.menu.addItem('Address', "#list/Address"); frappe.desk.menu.addItem('Address', "#list/Address");
frappe.desk.menu.addItem('Contact', "#list/Contact"); frappe.desk.menu.addItem('Contact', "#list/Contact");
frappe.desk.menu.addItem('Settings', () => frappe.desk.showFormModal('SystemSettings')); frappe.desk.menu.addItem('Settings', () => frappe.desk.showFormModal('SystemSettings'));
// reports
frappe.desk.menu.addItem('General Ledger', '#report/general-ledger'); frappe.desk.menu.addItem('General Ledger', '#report/general-ledger');
frappe.desk.menu.addItem('Profit And Loss', '#report/profit-and-loss'); frappe.desk.menu.addItem('Profit And Loss', '#report/profit-and-loss');
frappe.desk.menu.addItem('Balance Sheet', '#report/balance-sheet'); frappe.desk.menu.addItem('Balance Sheet', '#report/balance-sheet');
frappe.desk.menu.addItem('Sales Register', '#report/sales-register');
frappe.desk.menu.addItem('Purchase Register', '#report/purchase-register');
frappe.router.default = '#tree/Account'; frappe.router.default = '#tree/Account';

View File

@ -32,8 +32,7 @@ module.exports = {
fieldname: "party", fieldname: "party",
label: "Party", label: "Party",
fieldtype: "Link", fieldtype: "Link",
target: "Party", target: "Party"
required: 1
}, },
{ {
fieldname: "debit", fieldname: "debit",
@ -48,8 +47,7 @@ module.exports = {
{ {
fieldname: "againstAccount", fieldname: "againstAccount",
label: "Against Account", label: "Against Account",
fieldtype: "Text", fieldtype: "Text"
required: 0
}, },
{ {
fieldname: "referenceType", fieldname: "referenceType",

138
models/doctype/Bill/Bill.js Normal file
View File

@ -0,0 +1,138 @@
const frappe = require('frappejs');
const utils = require('../../../accounting/utils');
module.exports = {
"name": "Bill",
"doctype": "DocType",
"documentClass": require('./BillDocument'),
"isSingle": 0,
"isChild": 0,
"isSubmittable": 1,
"keywordFields": ["name", "supplier"],
"settings": "BillSettings",
"showTitle": true,
"fields": [
{
"fieldname": "date",
"label": "Date",
"fieldtype": "Date"
},
{
"fieldname": "supplier",
"label": "Supplier",
"fieldtype": "Link",
"target": "Party",
"required": 1,
getFilters: (query, control) => {
return {
keywords: ["like", query],
supplier: 1
}
}
},
{
"fieldname": "account",
"label": "Account",
"fieldtype": "Link",
"target": "Account",
getFilters: (query, control) => {
return {
keywords: ["like", query],
isGroup: 0,
accountType: "Payable"
}
}
},
{
"fieldname": "items",
"label": "Items",
"fieldtype": "Table",
"childtype": "BillItem",
"required": true
},
{
"fieldname": "netTotal",
"label": "Net Total",
"fieldtype": "Currency",
formula: (doc) => doc.getSum('items', 'amount'),
"disabled": true
},
{
"fieldname": "taxes",
"label": "Taxes",
"fieldtype": "Table",
"childtype": "TaxSummary",
"disabled": true,
template: (doc, row) => {
return `<div class='row'>
<div class='col-6'><!-- empty left side --></div>
<div class='col-6'>${(doc.taxes || []).map(row => {
return `<div class='row'>
<div class='col-6'>${row.account} (${row.rate}%)</div>
<div class='col-6 text-right'>
${frappe.format(row.amount, 'Currency')}
</div>
</div>`
}).join('')}
</div></div>`;
}
},
{
"fieldname": "grandTotal",
"label": "Grand Total",
"fieldtype": "Currency",
formula: (doc) => doc.getGrandTotal(),
"disabled": true
},
{
"fieldname": "terms",
"label": "Terms",
"fieldtype": "Text"
}
],
layout: [
// section 1
{
columns: [
{ fields: [ "supplier", "account" ] },
{ fields: [ "date" ] }
]
},
// section 2
{ fields: [ "items" ] },
// section 3
{ fields: [ "netTotal", "taxes", "grandTotal" ] },
// section 4
{ fields: [ "terms" ] },
],
links: [
{
label: 'Make Payment',
condition: form => form.doc.submitted,
action: async form => {
const payment = await frappe.getNewDoc('Payment');
payment.party = form.doc.supplier,
payment.account = form.doc.account,
payment.for = [{referenceType: form.doc.doctype, referenceName: form.doc.name, amount: form.doc.grandTotal}]
const formModal = await frappe.desk.showFormModal('Payment', payment.name);
}
}
],
listSettings: {
getFields(list) {
return ['name', 'supplier', 'grandTotal', 'submitted'];
},
getRowHTML(list, data) {
return `<div class="col-3">${list.getNameHTML(data)}</div>
<div class="col-4 text-muted">${data.supplier}</div>
<div class="col-4 text-muted text-right">${frappe.format(data.grandTotal, "Currency")}</div>`;
}
}
}

View File

@ -0,0 +1,4 @@
const InvoiceDocument = require('../Invoice/InvoiceDocument');
const frappe = require('frappejs');
module.exports = class Bill extends InvoiceDocument { }

View File

@ -0,0 +1,29 @@
const frappe = require('frappejs');
const Bill = require('./BillDocument');
const LedgerPosting = rootRequire('accounting/ledgerPosting');
module.exports = class BillServer extends Bill {
getPosting() {
let entries = new LedgerPosting({reference: this, party: this.supplier});
entries.credit(this.account, this.grandTotal);
for (let item of this.items) {
entries.debit(item.account, item.amount);
}
if (this.taxes) {
for (let tax of this.taxes) {
entries.debit(tax.account, tax.amount);
}
}
return entries;
}
async afterSubmit() {
await this.getPosting().post();
}
async afterRevert() {
await this.getPosting().postReverse();
}
}

View File

@ -0,0 +1,67 @@
module.exports = {
name: "BillItem",
doctype: "DocType",
isSingle: 0,
isChild: 1,
keywordFields: [],
layout: 'ratio',
fields: [
{
"fieldname": "item",
"label": "Item",
"fieldtype": "Link",
"target": "Item",
"required": 1,
width: 2
},
{
"fieldname": "description",
"label": "Description",
"fieldtype": "Text",
formula: (row, doc) => doc.getFrom('Item', row.item, 'description'),
hidden: 1
},
{
"fieldname": "quantity",
"label": "Quantity",
"fieldtype": "Float",
"required": 1
},
{
"fieldname": "rate",
"label": "Rate",
"fieldtype": "Currency",
"required": 1,
formula: (row, doc) => doc.getFrom('Item', row.item, 'rate')
},
{
fieldname: "account",
label: "Account",
hidden: 1,
fieldtype: "Link",
target: "Account",
formula: (row, doc) => doc.getFrom('Item', row.item, 'expenseAccount')
},
{
"fieldname": "tax",
"label": "Tax",
"fieldtype": "Link",
"target": "Tax",
formula: (row, doc) => doc.getFrom('Item', row.item, 'tax')
},
{
"fieldname": "amount",
"label": "Amount",
"fieldtype": "Currency",
"disabled": 1,
formula: (row, doc) => row.quantity * row.rate
},
{
"fieldname": "taxAmount",
"label": "Tax Amount",
"hidden": 1,
"fieldtype": "Text",
formula: (row, doc) => doc.getRowTax(row)
}
]
}

View File

@ -0,0 +1,18 @@
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"
}
]
}

View File

@ -25,7 +25,13 @@ module.exports = {
"label": "Customer", "label": "Customer",
"fieldtype": "Link", "fieldtype": "Link",
"target": "Party", "target": "Party",
"required": 1 "required": 1,
getFilters: (query, control) => {
return {
keywords: ["like", query],
customer: 1
}
}
}, },
{ {
"fieldname": "account", "fieldname": "account",
@ -35,7 +41,8 @@ module.exports = {
getFilters: (query, control) => { getFilters: (query, control) => {
return { return {
keywords: ["like", query], keywords: ["like", query],
isGroup: 0 isGroup: 0,
accountType: "Receivable"
} }
} }
}, },

View File

@ -9,7 +9,7 @@ module.exports = {
isSubmittable: 1, isSubmittable: 1,
keywordFields: ["name"], keywordFields: ["name"],
showTitle: true, showTitle: true,
settings: "JournalEntrySetting", settings: "JournalEntrySettings",
fields: [ fields: [
{ {
fieldname: "date", fieldname: "date",

View File

@ -1,20 +1,20 @@
const JournalEntry = require('./JournalEntry');
const frappe = require('frappejs'); const frappe = require('frappejs');
const BaseDocument = require('frappejs/model/document');
const LedgerPosting = rootRequire('accounting/ledgerPosting'); const LedgerPosting = rootRequire('accounting/ledgerPosting');
module.exports = class JournalEntryServer extends BaseDocument { module.exports = class JournalEntryServer extends BaseDocument {
/**
getPosting() { getPosting() {
let entries = new LedgerPosting({reference: this, party: this.party}); let entries = new LedgerPosting({reference: this });
entries.debit(this.paymentAccount, this.amount);
for (let row of this.for) { for (let row of this.accounts) {
entries.credit(this.account, row.amount, row.referenceType, row.referenceName); if (row.debit) {
entries.debit(row.account, row.debit);
} else if (row.credit) {
entries.credit(row.account, row.credit);
}
} }
return entries; return entries;
} }
async afterSubmit() { async afterSubmit() {
@ -24,6 +24,4 @@ module.exports = class JournalEntryServer extends BaseDocument {
async afterRevert() { async afterRevert() {
await this.getPosting().postReverse(); await this.getPosting().postReverse();
} }
**/
} }

View File

@ -12,6 +12,12 @@ module.exports = {
"fieldtype": "Link", "fieldtype": "Link",
"target": "Account", "target": "Account",
"required": 1, "required": 1,
getFilters: (query, control) => {
return {
keywords: ["like", query],
isGroup: 0
}
}
}, },
{ {
"fieldname": "debit", "fieldname": "debit",

View File

@ -1,10 +1,20 @@
const deepmerge = require('deepmerge'); const model = require('frappejs/model');
const Invoice = require('../Invoice/Invoice'); const Invoice = require('../Invoice/Invoice');
const Quotation = deepmerge(Invoice, { const Quotation = model.extend(Invoice, {
name: "Quotation", name: "Quotation",
label: "Quotation", label: "Quotation",
settings: "QuotationSettings" settings: "QuotationSettings",
fields: [
{
"fieldname": "items",
"childtype": "QuotationItem"
}
],
links: []
}, {
skipFields: ['account'],
overrideProps: ['links']
}); });
module.exports = Quotation; module.exports = Quotation;

View File

@ -0,0 +1,3 @@
const InvoiceDocument = require('../Invoice/InvoiceDocument');
module.exports = class Quotation extends InvoiceDocument { }

View File

@ -0,0 +1,6 @@
const model = require('frappejs/model');
const InvoiceItem = require('../InvoiceItem/InvoiceItem');
module.exports = model.extend(InvoiceItem, {
name: "QuotationItem"
});

View File

@ -1,11 +1,13 @@
const deepmerge = require('deepmerge'); const model = require('frappejs/model');
const InvoiceSettings = require('../InvoiceSettings/InvoiceSettings'); const InvoiceSettings = require('../InvoiceSettings/InvoiceSettings');
const QuotationSettings = deepmerge(InvoiceSettings, {
module.exports = model.extend(InvoiceSettings, {
"name": "QuotationSettings", "name": "QuotationSettings",
"label": "Quotation Settings", "label": "Quotation Settings",
"fields": { "fields": [
"default": "INV" {
"fieldname": "numberSeries",
"default": "QTN"
} }
}) ]
});
module.exports = QuotationSettings;

View File

@ -15,6 +15,10 @@ module.exports = {
InvoiceItem: require('./doctype/InvoiceItem/InvoiceItem.js'), InvoiceItem: require('./doctype/InvoiceItem/InvoiceItem.js'),
InvoiceSettings: require('./doctype/InvoiceSettings/InvoiceSettings.js'), InvoiceSettings: require('./doctype/InvoiceSettings/InvoiceSettings.js'),
Bill: require('./doctype/Bill/Bill.js'),
BillItem: require('./doctype/BillItem/BillItem.js'),
BillSettings: require('./doctype/BillSettings/BillSettings.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'),
TaxSummary: require('./doctype/TaxSummary/TaxSummary.js'), TaxSummary: require('./doctype/TaxSummary/TaxSummary.js'),
@ -27,6 +31,7 @@ module.exports = {
JournalEntrySettings: require('./doctype/JournalEntrySettings/JournalEntrySettings.js'), JournalEntrySettings: require('./doctype/JournalEntrySettings/JournalEntrySettings.js'),
Quotation: require('./doctype/Quotation/Quotation.js'), Quotation: require('./doctype/Quotation/Quotation.js'),
QuotationItem: require('./doctype/QuotationItem/QuotationItem.js'),
QuotationSettings: require('./doctype/QuotationSettings/QuotationSettings.js'), QuotationSettings: require('./doctype/QuotationSettings/QuotationSettings.js'),
} }
} }

View File

@ -48,6 +48,4 @@ class BalanceSheet {
} }
} }
module.exports = function execute(params) { module.exports = BalanceSheet;
return new BalanceSheet().run(params);
}

View File

@ -7,10 +7,18 @@ module.exports = class BalanceSheetView extends FinancialStatementsView {
title: frappe._('Balance Sheet'), title: frappe._('Balance Sheet'),
method: 'balance-sheet', method: 'balance-sheet',
filterFields: [ filterFields: [
{fieldtype: 'Date', label: 'To Date', required: 1}, {fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1},
{fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'], {fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'],
label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly'} label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly'}
] ]
}); });
} }
async setDefaultFilterValues() {
const accountingSettings = await frappe.getSingle('AccountingSettings');
this.filters.setValue('toDate', accountingSettings.fiscalYearEnd);
this.filters.setValue('periodicity', 'Monthly');
this.run();
}
} }

View File

@ -42,6 +42,4 @@ class ProfitAndLoss {
} }
} }
module.exports = function execute(params) { module.exports = ProfitAndLoss;
return new ProfitAndLoss().run(params);
}

View File

@ -7,11 +7,20 @@ module.exports = class ProfitAndLossView extends FinancialStatementsView {
title: frappe._('Profit and Loss'), title: frappe._('Profit and Loss'),
method: 'profit-and-loss', method: 'profit-and-loss',
filterFields: [ filterFields: [
{fieldtype: 'Date', label: 'From Date', required: 1}, {fieldtype: 'Date', fieldname: 'fromDate', label: 'From Date', required: 1},
{fieldtype: 'Date', label: 'To Date', required: 1}, {fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1},
{fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'], {fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'],
label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly'} label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly'}
] ]
}); });
} }
async setDefaultFilterValues() {
const accountingSettings = await frappe.getSingle('AccountingSettings');
this.filters.setValue('fromDate', accountingSettings.fiscalYearStart);
this.filters.setValue('toDate', accountingSettings.fiscalYearEnd);
this.filters.setValue('periodicity', 'Monthly');
this.run();
}
} }

View File

@ -0,0 +1,43 @@
const frappe = require('frappejs');
class PurchaseRegister {
async run({ fromDate, toDate }) {
const bills = await frappe.db.getAll({
doctype: 'Bill',
fields: ['name', 'date', 'supplier', 'account', 'netTotal', 'grandTotal'],
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 };
}
}
module.exports = PurchaseRegister;

View File

@ -0,0 +1,24 @@
const frappe = require('frappejs');
const RegisterView = require('../Register/RegisterView');
module.exports = class PurchaseRegisterView extends RegisterView {
constructor() {
super({
title: frappe._('Purchase Register'),
});
this.method = 'purchase-register';
}
getColumns() {
return [
{ label: 'Bill', 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' },
];
}
}

View File

@ -0,0 +1,34 @@
const ReportPage = require('frappejs/client/desk/reportpage');
const frappe = require('frappejs');
const { DateTime } = require('luxon');
const { unique } = require('frappejs/utils');
module.exports = class RegisterView extends ReportPage {
constructor({ title }) {
super({
title,
filterFields: [
{fieldtype: 'Date', fieldname: 'fromDate', label: 'From Date', required: 1},
{fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1}
]
});
this.datatableOptions = {
layout: 'fixed'
}
}
async setDefaultFilterValues() {
const today = DateTime.local();
const oneMonthAgo = today.minus({ months: 1 });
this.filters.setValue('fromDate', oneMonthAgo.toISODate());
this.filters.setValue('toDate', today.toISODate());
this.run();
}
getRowsForDataTable(data) {
return data.rows || [];
}
}

View File

@ -0,0 +1,43 @@
const frappe = require('frappejs');
class SalesRegister {
async run({ fromDate, toDate }) {
const invoices = await frappe.db.getAll({
doctype: 'Invoice',
fields: ['name', 'date', 'customer', 'account', 'netTotal', 'grandTotal'],
filters: {
date: ['>=', fromDate, '<=', toDate],
submitted: 1
},
orderBy: 'date',
order: 'desc'
});
const invoiceNames = invoices.map(d => d.name);
const taxes = await frappe.db.getAll({
doctype: 'TaxSummary',
fields: ['parent', 'amount'],
filters: {
parenttype: 'Invoice',
parent: ['in', invoiceNames]
},
orderBy: 'name'
});
for (let invoice of invoices) {
invoice.totalTax = taxes
.filter(tax => tax.parent === invoice.name)
.reduce((acc, tax) => {
if (tax.amount) {
acc = acc + tax.amount;
}
return acc;
}, 0);
}
return { rows: invoices };
}
}
module.exports = SalesRegister;

View File

@ -0,0 +1,26 @@
const RegisterView = require('../Register/RegisterView');
const frappe = require('frappejs');
const { DateTime } = require('luxon');
const { unique } = require('frappejs/utils');
module.exports = class SalesRegisterView extends RegisterView {
constructor() {
super({
title: frappe._('Sales Register')
});
this.method = 'sales-register';
}
getColumns() {
return [
{ label: 'Invoice', fieldname: 'name' },
{ label: 'Posting Date', fieldname: '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' },
];
}
}

View File

@ -20,6 +20,4 @@ class GeneralLedger {
} }
} }
module.exports = function execute(params) { module.exports = GeneralLedger;
return new GeneralLedger().run(params);
}

View File

@ -9,21 +9,37 @@ const ProfitAndLossView = require('./ProfitAndLoss/ProfitAndLossView');
const BalanceSheet = require('./BalanceSheet/BalanceSheet'); const BalanceSheet = require('./BalanceSheet/BalanceSheet');
const BalanceSheetView = require('./BalanceSheet/BalanceSheetView'); const BalanceSheetView = require('./BalanceSheet/BalanceSheetView');
const SalesRegister = require('./SalesRegister/SalesRegister');
const SalesRegisterView = require('./SalesRegister/SalesRegisterView');
const PurchaseRegister = require('./PurchaseRegister/PurchaseRegister');
const PurchaseRegisterView = require('./PurchaseRegister/PurchaseRegisterView');
// called on server side // called on server side
function registerReportMethods() { function registerReportMethods() {
frappe.registerMethod({ frappe.registerMethod({
method: 'general-ledger', method: 'general-ledger',
handler: args => GeneralLedger(args) handler: getReportData(GeneralLedger)
}); });
frappe.registerMethod({ frappe.registerMethod({
method: 'profit-and-loss', method: 'profit-and-loss',
handler: args => ProfitAndLoss(args) handler: getReportData(ProfitAndLoss)
}); });
frappe.registerMethod({ frappe.registerMethod({
method: 'balance-sheet', method: 'balance-sheet',
handler: args => BalanceSheet(args) handler: getReportData(BalanceSheet)
});
frappe.registerMethod({
method: 'sales-register',
handler: getReportData(SalesRegister)
});
frappe.registerMethod({
method: 'purchase-register',
handler: getReportData(PurchaseRegister)
}); });
} }
@ -49,6 +65,24 @@ function registerReportRoutes() {
} }
await frappe.views.BalanceSheet.show(params); await frappe.views.BalanceSheet.show(params);
}); });
frappe.router.add('report/sales-register', async (params) => {
if (!frappe.views.SalesRegister) {
frappe.views.SalesRegister = new SalesRegisterView();
}
await frappe.views.SalesRegister.show(params);
});
frappe.router.add('report/purchase-register', async (params) => {
if (!frappe.views.PurchaseRegister) {
frappe.views.PurchaseRegister = new PurchaseRegisterView();
}
await frappe.views.PurchaseRegister.show(params);
});
}
function getReportData(ReportClass) {
return args => new ReportClass().run(args);
} }
module.exports = { module.exports = {

View File

@ -23,7 +23,8 @@ module.exports = {
// set server-side modules // set server-side modules
frappe.models.Invoice.documentClass = require('../models/doctype/Invoice/InvoiceServer.js'); frappe.models.Invoice.documentClass = require('../models/doctype/Invoice/InvoiceServer.js');
frappe.models.Payment.documentClass = require('../models/doctype/Payment/PaymentServer.js'); frappe.models.Payment.documentClass = require('../models/doctype/Payment/PaymentServer.js');
// frappe.models.JournalEntry.documentClass = require('../models/doctype/JournalEntry/JournalEntryServer.js'); frappe.models.Bill.documentClass = require('../models/doctype/Bill/BillServer.js');
frappe.models.JournalEntry.documentClass = require('../models/doctype/JournalEntry/JournalEntryServer.js');
frappe.metaCache = {}; frappe.metaCache = {};
@ -31,6 +32,7 @@ module.exports = {
// init naming series if missing // init naming series if missing
await naming.createNumberSeries('INV-', 'InvoiceSettings'); await naming.createNumberSeries('INV-', 'InvoiceSettings');
await naming.createNumberSeries('BILL-', 'BillSettings');
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');

345
www/dist/css/style.css vendored
View File

@ -7130,6 +7130,169 @@ div.CodeMirror-dragcursors {
/* Help users use markselection to safely style text background */ /* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { span.CodeMirror-selectedtext {
background: none; } background: none; }
.indicator, .indicator-right {
background: none;
vertical-align: middle; }
.indicator::before, .indicator-right::after {
content: '';
display: inline-block;
height: 8px;
width: 8px;
border-radius: 8px;
background: #dee2e6; }
.indicator::before {
margin: 0 0.5rem 0 0; }
.indicator-right::after {
margin: 0 0 0 0.5rem; }
.indicator.grey::before, .indicator-right.grey::after {
background: #dee2e6; }
.indicator.blue::before, .indicator-right.blue::after {
background: #007bff; }
.indicator.red::before, .indicator-right.red::after {
background: #dc3545; }
.indicator.green::before, .indicator-right.green::after {
background: #28a745; }
.indicator.orange::before, .indicator-right.orange::after {
background: #fd7e14; }
.indicator.purple::before, .indicator-right.purple::after {
background: #6f42c1; }
.indicator.darkgrey::before, .indicator-right.darkgrey::after {
background: #6c757d; }
.indicator.black::before, .indicator-right.black::after {
background: #343a40; }
.indicator.yellow::before, .indicator-right.yellow::after {
background: #ffc107; }
.modal-header .indicator {
float: left;
margin-top: 7.5px;
margin-right: 3px; }
html {
font-size: 12px; }
.desk-body {
border-left: 1px solid #dee2e6;
min-height: 100vh; }
.desk-center {
border-left: 1px solid #dee2e6; }
.hide {
display: none !important; }
.page {
padding-bottom: 2rem; }
.page .page-nav {
padding: 0.5rem 1rem;
background-color: #f8f9fa;
border-bottom: 1px solid #dee2e6; }
.page .page-nav .btn {
margin-left: 0.5rem; }
.page .page-title {
font-weight: bold;
padding: 2rem;
padding-bottom: 0; }
.page .page-links {
padding: 1rem 2rem; }
.page .page-error {
text-align: center;
padding: 200px 0px; }
.form-body {
padding: 1rem 2rem; }
.form-body .form-check {
margin-bottom: 0.5rem; }
.form-body .form-check .form-check-input {
margin-top: 0.25rem; }
.form-body .form-check .form-check-label {
margin-left: 0.25rem; }
.form-body .form-control.font-weight-bold {
background-color: lightyellow; }
.form-body .alert {
margin-top: 1rem; }
.form-inline .form-group {
margin-right: 1rem;
margin-bottom: 1rem; }
.list-search {
padding: 1rem 2rem; }
.list-body .list-row {
padding: 0.5rem 2rem;
border-bottom: 1px solid #e9ecef;
cursor: pointer; }
.list-body .list-row .checkbox {
margin-right: 0.5rem; }
.list-body .list-row a, .list-body .list-row a:hover, .list-body .list-row a:visited, .list-body .list-row a:active {
color: #343a40; }
.list-body .list-row:hover {
background-color: #f8f9fa; }
.list-body .list-row.active {
background-color: #e9ecef; }
.dropdown-item {
padding: 0.5rem 1rem; }
.bottom-right-float {
position: fixed;
margin-bottom: 0px;
bottom: 1rem;
right: 1rem;
max-width: 200px;
padding: 0.5rem 1rem; }
.desk-menu {
background-color: #e9ecef; }
.desk-menu .list-row {
border-bottom: 1px solid #e9ecef; }
.desk-menu .list-row:hover {
background-color: #dee2e6; }
.desk-menu .list-row.active {
background-color: #ced4da; }
.print-page {
padding: 3rem;
line-height: 1.8; }
.print-page td, .print-page th {
padding: 0.5rem; }
.table-page-wrapper {
width: 100%;
padding: 1rem 2rem; }
.filter-toolbar {
padding: 1rem 2rem; }
.table-wrapper {
margin-top: 2rem;
margin-bottom: 2rem; }
.table-toolbar {
margin-top: 0.5rem; }
.CodeMirror {
font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
padding: 0.5rem; }
.awesomplete {
display: block; }
.awesomplete ul {
max-height: 150px;
overflow: auto; }
.awesomplete > ul > li {
padding: .75rem .375rem; }
.awesomplete > ul > li:hover {
background: #dee2e6;
color: #212529; }
.awesomplete > ul > li[aria-selected="true"] {
background: #dee2e6;
color: #212529; }
.awesomplete > ul > li[aria-selected="true"]:hover {
background: #dee2e6;
color: #212529; }
.awesomplete li[aria-selected="true"] mark, .awesomplete li[aria-selected="false"] mark {
background: inherit;
color: inherit;
padding: 0px; }
mark {
padding: none;
background: inherit; }
.align-right {
text-align: right; }
.align-center {
text-align: center; }
.btn-sm, .btn-group-sm > .btn {
margin: 0.25rem; }
.vertical-margin {
margin: 1rem 0px; }
.tree-body {
padding: 1rem 2rem; }
f-tree-node {
--tree-node-hover: #f8f9fa; }
.datatable *, .datatable *::after, .datatable *::before { .datatable *, .datatable *::after, .datatable *::before {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; } box-sizing: border-box; }
@ -7310,183 +7473,27 @@ span.CodeMirror-selectedtext {
left: -999em; } left: -999em; }
body.dt-resize { body.dt-resize {
cursor: col-resize; } cursor: col-resize; }
.indicator, .indicator-right { .dt-header {
background: none;
vertical-align: middle; }
.indicator::before, .indicator-right::after {
content: '';
display: inline-block;
height: 8px;
width: 8px;
border-radius: 8px;
background: #dee2e6; }
.indicator::before {
margin: 0 0.5rem 0 0; }
.indicator-right::after {
margin: 0 0 0 0.5rem; }
.indicator.grey::before, .indicator-right.grey::after {
background: #dee2e6; }
.indicator.blue::before, .indicator-right.blue::after {
background: #007bff; }
.indicator.red::before, .indicator-right.red::after {
background: #dc3545; }
.indicator.green::before, .indicator-right.green::after {
background: #28a745; }
.indicator.orange::before, .indicator-right.orange::after {
background: #fd7e14; }
.indicator.purple::before, .indicator-right.purple::after {
background: #6f42c1; }
.indicator.darkgrey::before, .indicator-right.darkgrey::after {
background: #6c757d; }
.indicator.black::before, .indicator-right.black::after {
background: #343a40; }
.indicator.yellow::before, .indicator-right.yellow::after {
background: #ffc107; }
.modal-header .indicator {
float: left;
margin-top: 7.5px;
margin-right: 3px; }
html {
font-size: 12px; }
.desk-body {
border-left: 1px solid #dee2e6;
min-height: 100vh; }
.desk-center {
border-left: 1px solid #dee2e6; }
.hide {
display: none !important; }
.page {
padding-bottom: 2rem; }
.page .page-nav {
padding: 0.5rem 1rem;
background-color: #f8f9fa;
border-bottom: 1px solid #dee2e6; }
.page .page-nav .btn {
margin-left: 0.5rem; }
.page .page-title {
font-weight: bold;
padding: 2rem;
padding-bottom: 0; }
.page .page-links {
padding: 1rem 2rem; }
.page .page-error {
text-align: center;
padding: 200px 0px; }
.form-body {
padding: 1rem 2rem; }
.form-body .form-check {
margin-bottom: 0.5rem; }
.form-body .form-check .form-check-input {
margin-top: 0.25rem; }
.form-body .form-check .form-check-label {
margin-left: 0.25rem; }
.form-body .form-control.font-weight-bold {
background-color: lightyellow; }
.form-body .alert {
margin-top: 1rem; }
.form-inline .form-group {
margin-right: 1rem;
margin-bottom: 1rem; }
.list-search {
padding: 1rem 2rem; }
.list-body .list-row {
padding: 0.5rem 2rem;
border-bottom: 1px solid #e9ecef;
cursor: pointer; }
.list-body .list-row .checkbox {
margin-right: 0.5rem; }
.list-body .list-row a, .list-body .list-row a:hover, .list-body .list-row a:visited, .list-body .list-row a:active {
color: #343a40; }
.list-body .list-row:hover {
background-color: #f8f9fa; }
.list-body .list-row.active {
background-color: #e9ecef; }
.dropdown-item {
padding: 0.5rem 1rem; }
.bottom-right-float {
position: fixed;
margin-bottom: 0px;
bottom: 1rem;
right: 1rem;
max-width: 200px;
padding: 0.5rem 1rem; }
.desk-menu {
background-color: #e9ecef; }
.desk-menu .list-row {
border-bottom: 1px solid #e9ecef; }
.desk-menu .list-row:hover {
background-color: #dee2e6; }
.desk-menu .list-row.active {
background-color: #ced4da; }
.print-page {
padding: 3rem;
line-height: 1.8; }
.print-page td, .print-page th {
padding: 0.5rem; }
.table-page-wrapper {
width: 100%;
padding: 1rem 2rem; }
.filter-toolbar {
padding: 1rem 2rem; }
.table-wrapper {
margin-top: 2rem;
margin-bottom: 2rem; }
.table-toolbar {
margin-top: 0.5rem; }
.data-table .body-scrollable {
border-bottom: 0px !important; }
.data-table .body-scrollable tr:first-child .data-table-col {
border-top: 0px !important; }
.data-table thead td {
background-color: #e9ecef !important; } background-color: #e9ecef !important; }
.data-table .data-table-cell .edit-cell { .dt-cell__edit {
padding: 0px !important; } padding: 0px; }
.data-table .data-table-cell .edit-cell input, .data-table .data-table-cell .edit-cell textarea { .dt-cell__edit input, .dt-cell__edit textarea {
outline: none;
border-radius: none; border-radius: none;
border: none;
margin: none; margin: none;
padding: 0.5rem; } padding: 0.5rem; }
.data-table .data-table-cell .edit-cell .awesomplete > ul { .dt-cell__edit input:focus, .dt-cell__edit textarea:focus {
border: none;
-webkit-box-shadow: none;
box-shadow: none; }
.dt-cell__edit .awesomplete > ul {
position: fixed; position: fixed;
left: auto; left: auto;
width: auto; width: auto;
min-width: 120px; } min-width: 120px; }
.CodeMirror { .dt-cell--highlight {
font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace; background-color: #e9ecef; }
border: 1px solid #dee2e6;
border-radius: 0.25rem;
padding: 0.5rem; }
.awesomplete {
display: block; }
.awesomplete > ul > li {
padding: .75rem .375rem; }
.awesomplete > ul > li:hover {
background: #dee2e6;
color: #212529; }
.awesomplete > ul > li[aria-selected="true"] {
background: #dee2e6;
color: #212529; }
.awesomplete > ul > li[aria-selected="true"]:hover {
background: #dee2e6;
color: #212529; }
.awesomplete li[aria-selected="true"] mark, .awesomplete li[aria-selected="false"] mark {
background: inherit;
color: inherit;
padding: 0px; }
mark {
padding: none;
background: inherit; }
.align-right {
text-align: right; }
.align-center {
text-align: center; }
.btn-sm, .btn-group-sm > .btn {
margin: 0.25rem; }
.vertical-margin {
margin: 1rem 0px; }
.tree-body {
padding: 1rem 2rem; }
f-tree-node {
--tree-node-hover: #f8f9fa; }
.setup-container { .setup-container {
margin: 40px auto; margin: 40px auto;
padding: 20px 0px; padding: 20px 0px;

383
www/dist/js/bundle.js vendored
View File

@ -58972,9 +58972,7 @@ class GeneralLedger {
} }
} }
var GeneralLedger_1 = function execute(params) { var GeneralLedger_1 = GeneralLedger;
return new GeneralLedger().run(params);
};
var reportpage = class ReportPage extends page { var reportpage = class ReportPage extends page {
constructor({title, filterFields = []}) { constructor({title, filterFields = []}) {
@ -65181,9 +65179,7 @@ class ProfitAndLoss {
} }
} }
var ProfitAndLoss_1 = function execute(params) { var ProfitAndLoss_1 = ProfitAndLoss;
return new ProfitAndLoss().run(params);
};
var FinancialStatementsView_1 = class FinancialStatementsView extends reportpage { var FinancialStatementsView_1 = class FinancialStatementsView extends reportpage {
constructor(opts) { constructor(opts) {
@ -65287,9 +65283,7 @@ class BalanceSheet {
} }
} }
var BalanceSheet_1 = function execute(params) { var BalanceSheet_1 = BalanceSheet;
return new BalanceSheet().run(params);
};
var BalanceSheetView_1 = class BalanceSheetView extends FinancialStatementsView_1 { var BalanceSheetView_1 = class BalanceSheetView extends FinancialStatementsView_1 {
constructor() { constructor() {
@ -65305,20 +65299,100 @@ var BalanceSheetView_1 = class BalanceSheetView extends FinancialStatementsView_
} }
}; };
class SalesRegister {
async run({ fromDate, toDate }) {
const invoices = await frappejs.db.getAll({
doctype: 'Invoice',
fields: ['name', 'date', 'customer', 'account', 'netTotal', 'grandTotal'],
filters: {
date: ['>=', fromDate, '<=', toDate],
submitted: 1
},
orderBy: 'date',
order: 'desc'
});
const invoiceNames = invoices.map(d => d.name);
const taxes = await frappejs.db.getAll({
doctype: 'TaxSummary',
fields: ['parent', 'amount'],
filters: {
parenttype: 'Invoice',
parent: ['in', invoiceNames]
},
orderBy: 'name'
});
for (let invoice of invoices) {
invoice.totalTax = taxes
.filter(tax => tax.parent === invoice.name)
.reduce((acc, tax) => {
if (tax.amount) {
acc = acc + tax.amount;
}
return acc;
}, 0);
}
return { rows: invoices };
}
}
var SalesRegister_1 = SalesRegister;
var SalesRegisterView_1 = class SalesRegisterView extends reportpage {
constructor() {
super({
title: frappejs._('Sales Register'),
filterFields: [
{fieldtype: 'Date', label: 'From Date', required: 1},
{fieldtype: 'Date', label: 'To Date', required: 1}
]
});
this.method = 'sales-register';
this.datatableOptions = {
layout: 'fixed'
};
}
getRowsForDataTable(data) {
return data.rows || [];
}
getColumns() {
return [
{ label: 'Invoice', fieldname: 'name' },
{ label: 'Posting Date', fieldname: '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' },
];
}
};
function registerReportMethods() { function registerReportMethods() {
frappejs.registerMethod({ frappejs.registerMethod({
method: 'general-ledger', method: 'general-ledger',
handler: args => GeneralLedger_1(args) handler: getReportData(GeneralLedger_1)
}); });
frappejs.registerMethod({ frappejs.registerMethod({
method: 'profit-and-loss', method: 'profit-and-loss',
handler: args => ProfitAndLoss_1(args) handler: getReportData(ProfitAndLoss_1)
}); });
frappejs.registerMethod({ frappejs.registerMethod({
method: 'balance-sheet', method: 'balance-sheet',
handler: args => BalanceSheet_1(args) handler: getReportData(BalanceSheet_1)
});
frappejs.registerMethod({
method: 'sales-register',
handler: getReportData(SalesRegister_1)
}); });
} }
@ -65344,6 +65418,17 @@ function registerReportRoutes() {
} }
await frappejs.views.BalanceSheet.show(params); await frappejs.views.BalanceSheet.show(params);
}); });
frappejs.router.add('report/sales-register', async (params) => {
if (!frappejs.views.SalesRegister) {
frappejs.views.SalesRegister = new SalesRegisterView_1();
}
await frappejs.views.SalesRegister.show(params);
});
}
function getReportData(ReportClass) {
return args => new ReportClass().run(args);
} }
var reports = { var reports = {
@ -66171,8 +66256,7 @@ var AccountingLedgerEntry = {
fieldname: "party", fieldname: "party",
label: "Party", label: "Party",
fieldtype: "Link", fieldtype: "Link",
target: "Party", target: "Party"
required: 1
}, },
{ {
fieldname: "debit", fieldname: "debit",
@ -66187,8 +66271,7 @@ var AccountingLedgerEntry = {
{ {
fieldname: "againstAccount", fieldname: "againstAccount",
label: "Against Account", label: "Against Account",
fieldtype: "Text", fieldtype: "Text"
required: 0
}, },
{ {
fieldname: "referenceType", fieldname: "referenceType",
@ -66578,7 +66661,13 @@ module.exports = {
"label": "Customer", "label": "Customer",
"fieldtype": "Link", "fieldtype": "Link",
"target": "Party", "target": "Party",
"required": 1 "required": 1,
getFilters: (query, control) => {
return {
keywords: ["like", query],
customer: 1
}
}
}, },
{ {
"fieldname": "account", "fieldname": "account",
@ -66588,7 +66677,8 @@ module.exports = {
getFilters: (query, control) => { getFilters: (query, control) => {
return { return {
keywords: ["like", query], keywords: ["like", query],
isGroup: 0 isGroup: 0,
accountType: "Receivable"
} }
} }
}, },
@ -66777,6 +66867,237 @@ var InvoiceSettings = {
] ]
}; };
var BillDocument = class Bill extends InvoiceDocument { };
var Bill = createCommonjsModule(function (module) {
module.exports = {
"name": "Bill",
"doctype": "DocType",
"isSingle": 0,
"isChild": 0,
"isSubmittable": 1,
"keywordFields": ["name", "supplier"],
"settings": "BillSettings",
"showTitle": true,
"fields": [
{
"fieldname": "date",
"label": "Date",
"fieldtype": "Date"
},
{
"fieldname": "supplier",
"label": "Supplier",
"fieldtype": "Link",
"target": "Party",
"required": 1,
getFilters: (query, control) => {
return {
keywords: ["like", query],
supplier: 1
}
}
},
{
"fieldname": "account",
"label": "Account",
"fieldtype": "Link",
"target": "Account",
getFilters: (query, control) => {
return {
keywords: ["like", query],
isGroup: 0,
accountType: "Payable"
}
}
},
{
"fieldname": "items",
"label": "Items",
"fieldtype": "Table",
"childtype": "BillItem",
"required": true
},
{
"fieldname": "netTotal",
"label": "Net Total",
"fieldtype": "Currency",
formula: (doc) => doc.getSum('items', 'amount'),
"disabled": true
},
{
"fieldname": "taxes",
"label": "Taxes",
"fieldtype": "Table",
"childtype": "TaxSummary",
"disabled": true,
template: (doc, row) => {
return `<div class='row'>
<div class='col-6'><!-- empty left side --></div>
<div class='col-6'>${(doc.taxes || []).map(row => {
return `<div class='row'>
<div class='col-6'>${row.account} (${row.rate}%)</div>
<div class='col-6 text-right'>
${frappejs.format(row.amount, 'Currency')}
</div>
</div>`
}).join('')}
</div></div>`;
}
},
{
"fieldname": "grandTotal",
"label": "Grand Total",
"fieldtype": "Currency",
formula: (doc) => doc.getGrandTotal(),
"disabled": true
},
{
"fieldname": "terms",
"label": "Terms",
"fieldtype": "Text"
}
],
layout: [
// section 1
{
columns: [
{ fields: [ "supplier", "account" ] },
{ fields: [ "date" ] }
]
},
// section 2
{ fields: [ "items" ] },
// section 3
{ fields: [ "netTotal", "taxes", "grandTotal" ] },
// section 4
{ fields: [ "terms" ] },
],
links: [
{
label: 'Make Payment',
condition: form => form.doc.submitted,
action: async form => {
const payment = await frappejs.getNewDoc('Payment');
payment.party = form.doc.supplier, payment.account = form.doc.account, payment.for = [{referenceType: form.doc.doctype, referenceName: form.doc.name, amount: form.doc.grandTotal}];
const formModal = await frappejs.desk.showFormModal('Payment', payment.name);
}
}
],
listSettings: {
getFields(list) {
return ['name', 'supplier', 'grandTotal', 'submitted'];
},
getRowHTML(list, data) {
return `<div class="col-3">${list.getNameHTML(data)}</div>
<div class="col-4 text-muted">${data.supplier}</div>
<div class="col-4 text-muted text-right">${frappejs.format(data.grandTotal, "Currency")}</div>`;
}
},
documentClass: BillDocument
};
});
var Bill_1 = Bill.layout;
var Bill_2 = Bill.links;
var Bill_3 = Bill.listSettings;
var Bill_4 = Bill.documentClass;
var BillItem = {
name: "BillItem",
doctype: "DocType",
isSingle: 0,
isChild: 1,
keywordFields: [],
layout: 'ratio',
fields: [
{
"fieldname": "item",
"label": "Item",
"fieldtype": "Link",
"target": "Item",
"required": 1,
width: 2
},
{
"fieldname": "description",
"label": "Description",
"fieldtype": "Text",
formula: (row, doc) => doc.getFrom('Item', row.item, 'description'),
hidden: 1
},
{
"fieldname": "quantity",
"label": "Quantity",
"fieldtype": "Float",
"required": 1
},
{
"fieldname": "rate",
"label": "Rate",
"fieldtype": "Currency",
"required": 1,
formula: (row, doc) => doc.getFrom('Item', row.item, 'rate')
},
{
fieldname: "account",
label: "Account",
hidden: 1,
fieldtype: "Link",
target: "Account",
formula: (row, doc) => doc.getFrom('Item', row.item, 'expenseAccount')
},
{
"fieldname": "tax",
"label": "Tax",
"fieldtype": "Link",
"target": "Tax",
formula: (row, doc) => doc.getFrom('Item', row.item, 'tax')
},
{
"fieldname": "amount",
"label": "Amount",
"fieldtype": "Currency",
"disabled": 1,
formula: (row, doc) => row.quantity * row.rate
},
{
"fieldname": "taxAmount",
"label": "Tax Amount",
"hidden": 1,
"fieldtype": "Text",
formula: (row, doc) => doc.getRowTax(row)
}
]
};
var BillSettings = {
"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"
}
]
};
var Tax = { var Tax = {
"name": "Tax", "name": "Tax",
"doctype": "DocType", "doctype": "DocType",
@ -67069,7 +67390,7 @@ var JournalEntry = {
isSubmittable: 1, isSubmittable: 1,
keywordFields: ["name"], keywordFields: ["name"],
showTitle: true, showTitle: true,
settings: "JournalEntrySetting", settings: "JournalEntrySettings",
fields: [ fields: [
{ {
fieldname: "date", fieldname: "date",
@ -67142,7 +67463,8 @@ var JournalEntry = {
] ]
}; };
var JournalEntryAccount = { var JournalEntryAccount = createCommonjsModule(function (module) {
module.exports = {
name: "JournalEntryAccount", name: "JournalEntryAccount",
doctype: "DocType", doctype: "DocType",
isSingle: 0, isSingle: 0,
@ -67156,6 +67478,12 @@ var JournalEntryAccount = {
"fieldtype": "Link", "fieldtype": "Link",
"target": "Account", "target": "Account",
"required": 1, "required": 1,
getFilters: (query, control) => {
return {
keywords: ["like", query],
isGroup: 0
}
}
}, },
{ {
"fieldname": "debit", "fieldname": "debit",
@ -67169,6 +67497,15 @@ var JournalEntryAccount = {
} }
] ]
}; };
});
var JournalEntryAccount_1 = JournalEntryAccount.name;
var JournalEntryAccount_2 = JournalEntryAccount.doctype;
var JournalEntryAccount_3 = JournalEntryAccount.isSingle;
var JournalEntryAccount_4 = JournalEntryAccount.isChild;
var JournalEntryAccount_5 = JournalEntryAccount.keywordFields;
var JournalEntryAccount_6 = JournalEntryAccount.layout;
var JournalEntryAccount_7 = JournalEntryAccount.fields;
var JournalEntrySettings = { var JournalEntrySettings = {
"name": "JournalEntrySetting", "name": "JournalEntrySetting",
@ -67321,6 +67658,10 @@ var models$2 = {
InvoiceItem: InvoiceItem, InvoiceItem: InvoiceItem,
InvoiceSettings: InvoiceSettings, InvoiceSettings: InvoiceSettings,
Bill: Bill,
BillItem: BillItem,
BillSettings: BillSettings,
Tax: Tax, Tax: Tax,
TaxDetail: TaxDetail, TaxDetail: TaxDetail,
TaxSummary: TaxSummary, TaxSummary: TaxSummary,
@ -67365,6 +67706,7 @@ var client$2 = {
frappejs.desk.menu.addItem('Customers', '#list/Customer'); frappejs.desk.menu.addItem('Customers', '#list/Customer');
frappejs.desk.menu.addItem('Quotation', '#list/Quotation'); frappejs.desk.menu.addItem('Quotation', '#list/Quotation');
frappejs.desk.menu.addItem('Invoice', '#list/Invoice'); frappejs.desk.menu.addItem('Invoice', '#list/Invoice');
frappejs.desk.menu.addItem('Bill', '#list/Bill');
frappejs.desk.menu.addItem('Journal Entry', '#list/JournalEntry'); frappejs.desk.menu.addItem('Journal Entry', '#list/JournalEntry');
frappejs.desk.menu.addItem('Address', "#list/Address"); frappejs.desk.menu.addItem('Address', "#list/Address");
frappejs.desk.menu.addItem('Contact', "#list/Contact"); frappejs.desk.menu.addItem('Contact', "#list/Contact");
@ -67372,6 +67714,7 @@ var client$2 = {
frappejs.desk.menu.addItem('General Ledger', '#report/general-ledger'); frappejs.desk.menu.addItem('General Ledger', '#report/general-ledger');
frappejs.desk.menu.addItem('Profit And Loss', '#report/profit-and-loss'); frappejs.desk.menu.addItem('Profit And Loss', '#report/profit-and-loss');
frappejs.desk.menu.addItem('Balance Sheet', '#report/balance-sheet'); frappejs.desk.menu.addItem('Balance Sheet', '#report/balance-sheet');
frappejs.desk.menu.addItem('Sales Register', '#report/sales-register');
frappejs.router.default = '#tree/Account'; frappejs.router.default = '#tree/Account';