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:
parent
8adb52c57c
commit
17e5187c51
@ -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,
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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
138
models/doctype/Bill/Bill.js
Normal 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>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
models/doctype/Bill/BillDocument.js
Normal file
4
models/doctype/Bill/BillDocument.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
const InvoiceDocument = require('../Invoice/InvoiceDocument');
|
||||||
|
const frappe = require('frappejs');
|
||||||
|
|
||||||
|
module.exports = class Bill extends InvoiceDocument { }
|
29
models/doctype/Bill/BillServer.js
Normal file
29
models/doctype/Bill/BillServer.js
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
67
models/doctype/BillItem/BillItem.js
Normal file
67
models/doctype/BillItem/BillItem.js
Normal 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)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
18
models/doctype/BillSettings/BillSettings.js
Normal file
18
models/doctype/BillSettings/BillSettings.js
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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",
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
**/
|
|
||||||
}
|
}
|
@ -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",
|
||||||
|
@ -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;
|
||||||
|
3
models/doctype/Quotation/QuotationDocument.js
Normal file
3
models/doctype/Quotation/QuotationDocument.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const InvoiceDocument = require('../Invoice/InvoiceDocument');
|
||||||
|
|
||||||
|
module.exports = class Quotation extends InvoiceDocument { }
|
6
models/doctype/QuotationItem/QuotationItem.js
Normal file
6
models/doctype/QuotationItem/QuotationItem.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const model = require('frappejs/model');
|
||||||
|
const InvoiceItem = require('../InvoiceItem/InvoiceItem');
|
||||||
|
|
||||||
|
module.exports = model.extend(InvoiceItem, {
|
||||||
|
name: "QuotationItem"
|
||||||
|
});
|
@ -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;
|
|
||||||
|
@ -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'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,4 @@ class BalanceSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function execute(params) {
|
module.exports = BalanceSheet;
|
||||||
return new BalanceSheet().run(params);
|
|
||||||
}
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,4 @@ class ProfitAndLoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function execute(params) {
|
module.exports = ProfitAndLoss;
|
||||||
return new ProfitAndLoss().run(params);
|
|
||||||
}
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
43
reports/PurchaseRegister/PurchaseRegister.js
Normal file
43
reports/PurchaseRegister/PurchaseRegister.js
Normal 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;
|
24
reports/PurchaseRegister/PurchaseRegisterView.js
Normal file
24
reports/PurchaseRegister/PurchaseRegisterView.js
Normal 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' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
34
reports/Register/RegisterView.js
Normal file
34
reports/Register/RegisterView.js
Normal 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 || [];
|
||||||
|
}
|
||||||
|
}
|
43
reports/SalesRegister/SalesRegister.js
Normal file
43
reports/SalesRegister/SalesRegister.js
Normal 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;
|
26
reports/SalesRegister/SalesRegisterView.js
Normal file
26
reports/SalesRegister/SalesRegisterView.js
Normal 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' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,4 @@ class GeneralLedger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function execute(params) {
|
module.exports = GeneralLedger;
|
||||||
return new GeneralLedger().run(params);
|
|
||||||
}
|
|
||||||
|
@ -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 = {
|
||||||
|
@ -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
345
www/dist/css/style.css
vendored
@ -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
383
www/dist/js/bundle.js
vendored
@ -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';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user