2
0
mirror of https://github.com/frappe/books.git synced 2024-11-12 16:36:27 +00:00

Purchase Cycle

This commit is contained in:
thefalconx33 2019-07-19 18:54:31 +05:30
parent e4c2bd3dda
commit 466597459a
24 changed files with 687 additions and 515 deletions

View File

@ -2,137 +2,152 @@ 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>`;
}
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) => {
if (!query) return { supplier: 1 };
return {
keywords: ['like', query],
supplier: 1
};
}
},
{
fieldname: 'account',
label: 'Account',
fieldtype: 'Link',
target: 'Account',
formula: doc => doc.getFrom('Party', doc.supplier, 'defaultAccount'),
getFilters: (query, control) => {
if (!query) return { isGroup: 0, accountType: 'Payable' };
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,
readOnly: 1
},
{
fieldname: 'taxes',
label: 'Taxes',
fieldtype: 'Table',
childtype: 'TaxSummary',
readOnly: 1,
template: (doc, row) => {
return `<div class='row'>
<div class='col-6'></div>
<div class='col-6'>
<div class='row' v-for='row in value'>
<div class='col-6'>{{row.account}} ({{row.rate}}%)</div>
<div class='col-6 text-right'>
{{frappe.format(row.amount, 'Currency')}}
</div>
</div>
</div>
</div>`;
}
},
{
fieldname: 'grandTotal',
label: 'Grand Total',
fieldtype: 'Currency',
formula: doc => doc.getGrandTotal(),
disabled: true,
readOnly: 1
},
{
fieldname: 'terms',
label: 'Terms',
fieldtype: 'Text'
},
{
fieldname: 'outstandingAmount',
label: 'Outstanding Amount',
fieldtype: 'Currency',
hidden: 1
}
}
],
layout: [
// section 1
{
columns: [{ fields: ['supplier', 'account'] }, { fields: ['date'] }]
},
// section 2
{
columns: [{ fields: ['items'] }]
},
// section 3
{
columns: [{ fields: ['netTotal', 'taxes', 'grandTotal'] }]
},
// section 4
{
columns: [{ fields: ['terms'] }]
}
],
links: [
{
label: 'Make Payment',
condition: form => form.doc.submitted,
action: async form => {
const payment = await frappe.getNewDoc('Payment');
payment.paymentType = 'Pay';
payment.party = form.doc.supplier;
payment.paymentAccount = form.doc.account;
payment.for = [
{
referenceType: form.doc.doctype,
referenceName: form.doc.name,
amount: form.doc.grandTotal
}
];
payment.on('afterInsert', async () => {
form.$formModal.close();
form.$router.push({
path: `/edit/Payment/${payment.name}`
});
});
await form.$formModal.open(payment);
}
}
]
};

View File

@ -0,0 +1,28 @@
import { _ } from 'frappejs/utils';
import indicators from 'frappejs/ui/constants/indicators';
export default {
doctype: 'Bill',
title: _('Bill'),
columns: [
'supplier',
{
label: 'Status',
getValue(doc) {
if (doc.submitted === 1 && doc.outstandingAmount === 0.0) {
return 'Paid';
}
return 'Pending';
},
getIndicator(doc) {
if (doc.submitted === 1 && doc.outstandingAmount === 0.0) {
return indicators.GREEN;
}
return indicators.ORANGE;
}
},
'grandTotal',
'date',
'outstandingAmount'
]
};

View File

@ -3,27 +3,57 @@ const Bill = require('./BillDocument');
const LedgerPosting = require('../../../accounting/ledgerPosting');
module.exports = class BillServer extends Bill {
getPosting() {
let entries = new LedgerPosting({reference: this, party: this.supplier});
entries.credit(this.account, this.grandTotal);
async getPosting() {
let entries = new LedgerPosting({ reference: this, party: this.supplier });
await 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;
for (let item of this.items) {
await entries.debit(item.account, item.amount);
}
async afterSubmit() {
await this.getPosting().post();
if (this.taxes) {
for (let tax of this.taxes) {
await entries.debit(tax.account, tax.amount);
}
}
return entries;
}
async afterRevert() {
await this.getPosting().postReverse();
async getPayments() {
let payments = await frappe.db.getAll({
doctype: 'PaymentFor',
fields: ['parent'],
filters: { referenceName: this.name },
orderBy: 'name'
});
if (payments.length != 0) {
return payments;
}
}
return [];
}
async afterSubmit() {
const entries = await this.getPosting();
await entries.post();
await frappe.db.setValue(
'Bill',
this.name,
'outstandingAmount',
this.grandTotal
);
}
async afterRevert() {
let paymentRefList = await this.getPayments();
for (let paymentFor of paymentRefList) {
const paymentReference = paymentFor.parent;
const payment = await frappe.getDoc('Payment', paymentReference);
const paymentEntries = await payment.getPosting();
await paymentEntries.postReverse();
// To set the payment status as unsubmitted.
payment.revert();
}
const entries = await this.getPosting();
await entries.postReverse();
}
};

View File

@ -1,67 +1,72 @@
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)
}
]
}
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',
fieldtype: 'Link',
target: 'Account',
required: 1,
formula: (row, doc) => doc.getFrom('Item', row.item, 'expenseAccount')
},
{
fieldname: 'tax',
label: 'Tax',
fieldtype: 'Link',
target: 'Tax',
formula: (row, doc) => {
if (row.tax) return row.tax;
return doc.getFrom('Item', row.item, 'tax');
}
},
{
fieldname: 'amount',
label: 'Amount',
fieldtype: 'Currency',
readOnly: 1,
disabled: true,
formula: (row, doc) => row.quantity * row.rate
},
{
fieldname: 'taxAmount',
label: 'Tax Amount',
hidden: 1,
readOnly: 1,
fieldtype: 'Text',
formula: (row, doc) => doc.getRowTax(row)
}
]
};

View File

@ -144,6 +144,7 @@ module.exports = {
form.doc.submitted && form.doc.outstandingAmount !== 0.0,
action: async form => {
const payment = await frappe.getNewDoc('Payment');
payment.paymentType = 'Recieve';
payment.party = form.doc.customer;
payment.account = form.doc.account;
payment.for = [
@ -155,9 +156,9 @@ module.exports = {
];
payment.on('afterInsert', async () => {
form.$formModal.close();
const _payment = await frappe.getDoc('Payment', payment.name);
await _payment.submit();
form.$router.push({
path: `/edit/Payment/${payment.name}`
});
});
await form.$formModal.open(payment);
}

View File

@ -2,71 +2,79 @@ const BaseDocument = require('frappejs/model/document');
const frappe = require('frappejs');
module.exports = class Invoice extends BaseDocument {
async getRowTax(row) {
if (row.tax) {
let tax = await this.getTax(row.tax);
let taxAmount = [];
for (let d of (tax.details || [])) {
taxAmount.push({account: d.account, rate: d.rate, amount: row.amount * d.rate / 100});
async getRowTax(row) {
if (row.tax) {
let tax = await this.getTax(row.tax);
let taxAmount = [];
for (let d of tax.details || []) {
taxAmount.push({
account: d.account,
rate: d.rate,
amount: (row.amount * d.rate) / 100
});
}
return JSON.stringify(taxAmount);
} else {
return '';
}
}
async getTax(tax) {
if (!this._taxes) this._taxes = {};
if (!this._taxes[tax]) this._taxes[tax] = await frappe.getDoc('Tax', tax);
return this._taxes[tax];
}
makeTaxSummary() {
if (!this.taxes) this.taxes = [];
// reset tax amount
this.taxes.map(d => {
d.amount = 0;
d.rate = 0;
});
// calculate taxes
for (let row of this.items) {
if (row.taxAmount) {
let taxAmount = JSON.parse(row.taxAmount);
for (let rowTaxDetail of taxAmount) {
let found = false;
// check if added in summary
for (let taxDetail of this.taxes) {
if (taxDetail.account === rowTaxDetail.account) {
taxDetail.rate = rowTaxDetail.rate;
taxDetail.amount += rowTaxDetail.amount;
found = true;
}
return JSON.stringify(taxAmount);
} else {
return '';
}
// add new row
if (!found) {
this.taxes.push({
account: rowTaxDetail.account,
rate: rowTaxDetail.rate,
amount: rowTaxDetail.amount
});
}
}
}
}
async getTax(tax) {
if (!this._taxes) this._taxes = {};
if (!this._taxes[tax]) this._taxes[tax] = await frappe.getDoc('Tax', tax);
return this._taxes[tax];
// clear no taxes
this.taxes = this.taxes.filter(d => d.amount);
}
getGrandTotal() {
this.makeTaxSummary();
let grandTotal = this.netTotal;
if (this.taxes) {
for (let row of this.taxes) {
grandTotal += row.amount;
}
}
makeTaxSummary() {
if (!this.taxes) this.taxes = [];
// reset tax amount
this.taxes.map(d => { d.amount = 0; d.rate = 0; });
// calculate taxes
for (let row of this.items) {
if (row.taxAmount) {
let taxAmount = JSON.parse(row.taxAmount);
for (let rowTaxDetail of taxAmount) {
let found = false;
// check if added in summary
for (let taxDetail of this.taxes) {
if (taxDetail.account === rowTaxDetail.account) {
taxDetail.rate = rowTaxDetail.rate;
taxDetail.amount += rowTaxDetail.amount;
found = true;
}
}
// add new row
if (!found) {
this.taxes.push({
account: rowTaxDetail.account,
rate: rowTaxDetail.rate,
amount: rowTaxDetail.amount
});
}
}
}
}
// clear no taxes
this.taxes = this.taxes.filter(d => d.amount);
}
getGrandTotal() {
this.makeTaxSummary();
let grandTotal = this.netTotal;
if (this.taxes) {
for (let row of this.taxes) {
grandTotal += row.amount;
}
}
return grandTotal;
}
}
grandTotal = Math.floor(grandTotal * 100) / 100;
return grandTotal;
}
};

View File

@ -5,7 +5,8 @@ module.exports = {
isChild: 1,
keywordFields: [],
layout: 'ratio',
fields: [{
fields: [
{
fieldname: 'item',
label: 'Item',
fieldtype: 'Link',
@ -39,6 +40,7 @@ module.exports = {
hidden: 1,
fieldtype: 'Link',
target: 'Account',
required: 1,
formula: (row, doc) => doc.getFrom('Item', row.item, 'incomeAccount')
},
{

View File

@ -28,7 +28,7 @@ module.exports = {
fieldtype: 'Link',
target: 'Account',
required: 1,
getFilters: (query, control) => {
getFilters: query => {
return {
isGroup: 0,
accountType: 'Income Account'
@ -39,7 +39,21 @@ module.exports = {
fieldname: 'expenseAccount',
label: 'Expense Account',
fieldtype: 'Link',
target: 'Account'
target: 'Account',
required: 1,
getFilters: query => {
return {
isGroup: 0,
accountType: [
'in',
[
'Cost of Goods Sold',
'Expense Account',
'Stock Received But Not Billed'
]
]
};
}
},
{
fieldname: 'tax',

View File

@ -13,7 +13,7 @@ module.exports = {
fieldname: 'date',
label: 'Posting Date',
fieldtype: 'Date'
// default: (new Date()).toISOString()
// default: new Date().toISOString().substring(0, 10)
},
{
fieldname: 'party',
@ -24,14 +24,21 @@ module.exports = {
},
{
fieldname: 'account',
label: 'Account',
label: 'From Account',
fieldtype: 'Link',
target: 'Account',
required: 1
},
{
fieldname: 'paymentType',
label: 'Payment Type',
fieldtype: 'Select',
options: ['Recieve', 'Pay'],
required: 1
},
{
fieldname: 'paymentAccount',
label: 'Payment Account',
label: 'To Account',
fieldtype: 'Link',
target: 'Account',
required: 1,
@ -41,11 +48,17 @@ module.exports = {
};
}
},
{
fieldname: 'paymentMethod',
label: 'Payment Method',
fieldtype: 'Select',
options: ['', 'Cash', 'Cheque'],
required: 1
},
{
fieldname: 'referenceId',
label: 'Ref. / Cheque No.',
fieldtype: 'Data',
default: 'ABC',
required: 1 // TODO: UNIQUE
},
{
@ -56,7 +69,10 @@ module.exports = {
{
fieldname: 'clearanceDate',
label: 'Clearance Date',
fieldtype: 'Date'
fieldtype: 'Date',
hidden: doc => {
return doc.paymentMethod === 'Cheque' ? 0 : 1;
}
},
{
fieldname: 'amount',
@ -84,18 +100,28 @@ module.exports = {
{
columns: [
{
fields: ['date', 'party']
fields: ['date', 'account']
},
{
fields: ['account', 'paymentAccount']
fields: ['party', 'paymentAccount']
}
]
},
{
columns: [
{
fields: ['referenceId']
fields: ['paymentMethod']
},
{
fields: ['paymentType']
},
{
fields: ['referenceId']
}
]
},
{
columns: [
{
fields: ['referenceDate']
},

View File

@ -9,13 +9,19 @@ export default {
{
label: 'Payment',
getValue(doc) {
if (doc.submitted === 1 && doc.clearanceDate !== null) {
if (
doc.submitted === 1 &&
(doc.clearanceDate !== null || doc.paymentMethod === 'Cash')
) {
return 'Reconciled';
}
return 'Not Reconciled';
},
getIndicator(doc) {
if (doc.submitted === 1 && doc.clearanceDate !== null) {
if (
doc.submitted === 1 &&
(doc.clearanceDate !== null || doc.paymentMethod === 'Cash')
) {
return indicators.GREEN;
}
return indicators.ORANGE;
@ -27,4 +33,4 @@ export default {
'clearanceDate',
'name'
]
}
};

View File

@ -6,30 +6,28 @@ module.exports = class PaymentServer extends BaseDocument {
async getPosting() {
let entries = new LedgerPosting({ reference: this, party: this.party });
await entries.debit(this.paymentAccount, this.amount);
for (let row of this.for) {
await entries.credit(
this.account,
row.amount,
row.referenceType,
row.referenceName
);
await entries.credit(this.account, row.amount);
}
return entries;
}
async afterSubmit() {
for (let row of this.for) {
if (row.referenceType === 'Invoice') {
const { outstandingAmount } = await frappe.getDoc(
'Invoice',
if (['Invoice', 'Bill'].includes(row.referenceType)) {
const { outstandingAmount, grandTotal } = await frappe.getDoc(
row.referenceType,
row.referenceName
);
if (outstandingAmount === null) {
outstandingAmount = grandTotal;
console.log('Outstanding null');
}
if (this.amount > outstandingAmount) {
console.log('Over Payment');
} else {
await frappe.db.setValue(
'Invoice',
row.referenceType,
row.referenceName,
'outstandingAmount',
outstandingAmount - this.amount

View File

@ -0,0 +1,41 @@
module.exports = async function generateTaxes(country) {
if (country === 'India') {
const GSTs = {
GST: [28, 18, 12, 6, 5, 3, 0.25, 0],
IGST: [28, 18, 12, 6, 5, 3, 0.25, 0],
'Exempt-GST': [0],
'Exempt-IGST': [0]
};
let newTax = await frappe.getNewDoc('Tax');
for (const type of Object.keys(GSTs)) {
for (const percent of GSTs[type]) {
if (type === 'GST') {
await newTax.set({
name: `${type}-${percent}`,
details: [
{
account: 'CGST',
rate: percent / 2
},
{
account: 'SGST',
rate: percent / 2
}
]
});
} else {
await newTax.set({
name: `${type}-${percent}`,
details: [
{
account: type.toString().split('-')[0],
rate: percent
}
]
});
}
await newTax.insert();
}
}
}
};

View File

View File

@ -2,7 +2,7 @@ let title = 'General Ledger';
let filterFields = [
{
fieldtype: 'Select',
options: ['', 'Invoice', 'Payment'],
options: ['', 'Invoice', 'Payment', 'Bill'],
label: 'Reference Type',
fieldname: 'referenceType'
},
@ -74,7 +74,7 @@ const viewConfig = {
label: 'Clear Filters',
type: 'secondary',
action: async report => {
await report.getReportData({});
await report.$router.replace(`/report/general-ledger`);
}
}
],

View File

@ -17,43 +17,55 @@ class GoodsAndServiceTax {
let tableData = [];
for (let invoice of invoiceNames) {
const row = await this.getRow(invoice.name)
tableData.push(row)
}
const row = await this.getRow(invoice.name);
tableData.push(row);
}
if(Object.keys(filters).length != 0){
tableData = tableData.filter((row) => {
if(filters.account) return row.account === filters.account
if(filters.transferType) return row.transferType === filters.transferType
if(filters.place) return row.place === filters.place
return true
})
if (Object.keys(filters).length != 0) {
tableData = tableData.filter(row => {
if (filters.account) return row.account === filters.account;
if (filters.transferType)
return row.transferType === filters.transferType;
if (filters.place) return row.place === filters.place;
return true;
});
}
return tableData;
}
async getRow(name) {
let row = {}
let invoiceDetails = await frappe.getDoc('Invoice', name);
async getRow(invoiceName) {
let row = {};
let invoiceDetails = await frappe.getDoc('Invoice', invoiceName);
let customerDetails = await frappe.getDoc('Party', invoiceDetails.customer);
let addressDetails = await frappe.getDoc('Address', customerDetails.address);
row.gstin = customerDetails.gstin
row.cusName = invoiceDetails.customer
row.invNo = invoiceDetails.name
row.invDate = invoiceDetails.date
row.place = addressDetails.state
row.rate = 0
if (customerDetails.address) {
let addressDetails = await frappe.getDoc(
'Address',
customerDetails.address
);
row.place = addressDetails.state || '';
}
row.gstin = customerDetails.gstin;
row.cusName = invoiceDetails.customer;
row.invNo = invoiceDetails.name;
row.invDate = invoiceDetails.date;
row.rate = 0;
row.transferType = 'In State';
invoiceDetails.taxes.forEach(tax => {
row.rate += tax.rate
if (tax.account === 'IGST') row.transferType = 'Out of State';
row.rate += tax.rate;
const taxAmt = (tax.rate * invoiceDetails.netTotal) / 100;
if (tax.account === 'IGST') {
row.transferType = 'Out of State';
row.igstAmt = taxAmt;
}
if (tax.account === 'CGST') row.cgstAmt = taxAmt;
if (tax.account === 'SGST') row.sgstAmt = taxAmt;
});
row.invAmt = invoiceDetails.grandTotal
row.taxAmt = invoiceDetails.netTotal
return row
row.invAmt = invoiceDetails.grandTotal;
row.taxAmt = invoiceDetails.netTotal;
return row;
}
}
module.exports = GoodsAndServiceTax;

View File

@ -8,7 +8,8 @@ module.exports = class GoodsAndServiceTaxView extends ReportPage {
filterFields: [
{
fieldtype: 'Data',
label: 'Transfer Type'
label: 'Transfer Type',
options: ['In State', 'Out of State']
},
{
fieldtype: 'Data',
@ -29,46 +30,62 @@ module.exports = class GoodsAndServiceTaxView extends ReportPage {
}
getColumns() {
return [{
label: 'GSTIN No.',
fieldname: 'gstin',
fieldtype: 'Data'
},
{
fieldtype: 'Data',
fieldname: 'cusName',
label: 'Customer Name'
},
{
label: 'Invoice No.',
fieldname: 'invNo',
fieldtype: 'Data'
},
{
label: 'Invoice Value',
fieldname: 'invAmt',
fieldtype: 'Data'
},
{
label: 'Invoice Date',
fieldname: 'invDate',
fieldtype: 'Date'
},
{
label: 'Place of supply',
fieldname: 'place',
fieldtype: 'Data'
},
{
label: 'Rate',
fieldname: 'rate',
fieldtype: 'Data'
},
{
label: 'Taxable Amount',
fieldname: 'taxAmt',
fieldtype: 'Data'
}
return [
{
label: 'GSTIN No.',
fieldname: 'gstin',
fieldtype: 'Data'
},
{
fieldtype: 'Data',
fieldname: 'cusName',
label: 'Customer Name'
},
{
label: 'Invoice No.',
fieldname: 'invNo',
fieldtype: 'Data'
},
{
label: 'Invoice Value',
fieldname: 'invAmt',
fieldtype: 'Currency'
},
{
label: 'Invoice Date',
fieldname: 'invDate',
fieldtype: 'Date'
},
{
label: 'Place of supply',
fieldname: 'place',
fieldtype: 'Data'
},
{
label: 'Rate',
fieldname: 'rate',
fieldtype: 'Data'
},
{
label: 'Taxable Amount',
fieldname: 'taxAmt',
fieldtype: 'Currency'
},
{
label: 'Intergrated Tax',
fieldname: 'igstAmt',
fieldtype: 'Currency'
},
{
label: 'Central Tax',
fieldname: 'cgstAmt',
fieldtype: 'Currency'
},
{
label: 'State Tax',
fieldname: 'sgstAmt',
fieldtype: 'Currency'
}
];
}
};

View File

@ -2,68 +2,97 @@ const title = 'Goods and Service Tax';
module.exports = {
title: title,
method: 'gst-taxes',
filterFields: [{
fieldtype: 'Data',
label: 'Transfer Type',
fieldname: 'transferType'
},
{
fieldtype: 'Data',
label: 'Place',
fieldname: 'place'
},
{
fieldtype: 'Date',
label: 'From Date',
fieldname: 'fromDate'
},
{
fieldtype: 'Date',
label: 'To Date',
fieldname: 'toDate'
}],
getColumns() {
return [{
label: 'GSTIN No.',
fieldname: 'gstin',
fieldtype: 'Data'
filterFields: [
{
fieldtype: 'Data',
label: 'Transfer Type',
fieldname: 'transferType'
},
{
fieldtype: 'Data',
fieldname: 'cusName',
label: 'Customer Name'
label: 'Place',
fieldname: 'place'
},
{
label: 'Invoice No.',
fieldname: 'invNo',
fieldtype: 'Data'
fieldtype: 'Date',
label: 'From Date',
fieldname: 'fromDate'
},
{
label: 'Invoice Value',
fieldname: 'invAmt',
fieldtype: 'Data'
},
{
label: 'Invoice Date',
fieldname: 'invDate',
fieldtype: 'Date'
},
{
label: 'Place of supply',
fieldname: 'place',
fieldtype: 'Data'
},
{
label: 'Rate',
fieldname: 'rate',
fieldtype: 'Data'
},
{
label: 'Taxable Amount',
fieldname: 'taxAmt',
fieldtype: 'Data'
fieldtype: 'Date',
label: 'To Date',
fieldname: 'toDate'
}
],
getColumns() {
return [
{
label: 'GSTIN No.',
fieldname: 'gstin',
fieldtype: 'Data',
width: 100
},
{
fieldtype: 'Data',
fieldname: 'cusName',
label: 'Customer Name',
width: 100
},
{
label: 'Invoice No.',
fieldname: 'invNo',
fieldtype: 'Data',
width: 100
},
{
label: 'Invoice Value',
fieldname: 'invAmt',
fieldtype: 'Currency',
width: 100
},
{
label: 'Invoice Date',
fieldname: 'invDate',
fieldtype: 'Date',
width: 100
},
{
label: 'Place of supply',
fieldname: 'place',
fieldtype: 'Data',
width: 100
},
{
label: 'Rate',
fieldname: 'rate',
fieldtype: 'Data',
width: 80
},
{
label: 'Taxable Amount',
fieldname: 'taxAmt',
fieldtype: 'Currency',
width: 100
},
{
label: 'Intergrated Tax',
fieldname: 'igstAmt',
fieldtype: 'Currency',
width: 100
},
{
label: 'Central Tax',
fieldname: 'cgstAmt',
fieldtype: 'Currency',
width: 100
},
{
label: 'State Tax',
fieldname: 'sgstAmt',
fieldtype: 'Currency',
width: 100
}
];
}
};
};

View File

@ -77,62 +77,14 @@ import Toasted from 'vue-toasted';
await frappe.call({
method: 'import-coa'
});
const generateRegionalTaxes = require('../models/doctype/Tax/RegionalChanges');
await generateRegionalTaxes(country);
if (country === 'India') {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js');
frappe.models.Party = require('../models/doctype/Party/RegionalChanges');
await frappe.db.migrate();
await generateGstTaxes();
}
frappe.events.trigger('show-desk');
});
async function generateGstTaxes() {
const gstPercents = [5, 12, 18, 28];
const gstTypes = ['Out of State', 'In State'];
let newTax = await frappe.getNewDoc('Tax');
for (const type of gstTypes) {
for (const percent of gstPercents) {
switch (type) {
case 'Out of State':
await newTax.set({
name: `${type}-${percent}`,
details: [
{
account: 'IGST',
rate: percent
}
]
});
break;
case 'In State':
await newTax.set({
name: `${type}-${percent}`,
details: [
{
account: 'CGST',
rate: percent / 2
},
{
account: 'SGST',
rate: percent / 2
}
]
});
break;
}
await newTax.insert();
}
}
await newTax.set({
name: `Exempt-0`,
details: [
{
account: 'Exempt',
rate: 0
}
]
});
await newTax.insert();
}
async function connectToLocalDatabase(filepath) {
try {

View File

@ -21,6 +21,7 @@
:parentValue="child.name"
:doctype="doctype"
:currency="currency"
:rootType="child.rootType"
@updateBalance="updateBalance"
/>
</div>
@ -28,7 +29,7 @@
</template>
<script>
const Branch = {
props: ['label', 'parentValue', 'doctype', 'balance', 'currency'],
props: ['label', 'parentValue', 'doctype', 'balance', 'currency', 'rootType'],
data() {
return {
expanded: false,
@ -50,7 +51,7 @@ const Branch = {
},
async mounted() {
this.settings = frappe.getMeta(this.doctype).treeSettings;
if (this.nodeBalance > 0) {
if (this.nodeBalance != 0) {
this.$emit('updateBalance', this.nodeBalance);
}
await this.toggleChildren();
@ -64,7 +65,7 @@ const Branch = {
await this.getChildren();
this.expanded = !this.expanded;
},
updateBalance(balance) {
async updateBalance(balance) {
this.nodeBalance += balance;
this.$emit('updateBalance', this.nodeBalance);
},
@ -80,7 +81,13 @@ const Branch = {
const children = await frappe.db.getAll({
doctype: this.doctype,
filters,
fields: [this.settings.parentField, 'isGroup', 'name', 'balance'],
fields: [
this.settings.parentField,
'isGroup',
'name',
'balance',
'rootType'
],
orderBy: 'name',
order: 'asc'
});
@ -88,6 +95,7 @@ const Branch = {
this.children = children.map(c => {
c.label = c.name;
c.balance = c.balance;
c.rootType = c.rootType;
return c;
});
}

View File

@ -40,25 +40,6 @@ export default {
};
},
methods: {
async getChildren(parentValue) {
let filters = {
[this.settings.parentField]: parentValue
};
const children = await frappe.db.getAll({
doctype: this.doctype,
filters,
fields: [this.settings.parentField, 'isGroup', 'name', 'balance'],
orderBy: 'name',
order: 'asc'
});
return children.map(c => {
c.label = c.name;
c.balance = c.balance;
return c;
});
},
updateBalance(balance) {
this.root.balance += balance;
}

View File

@ -2,7 +2,7 @@
<div class="row no-gutters">
<sidebar class="col-2" />
<div class="page-container col-10 bg-light">
<router-view />
<router-view :key="$route.fullPath" />
</div>
</div>
</template>
@ -13,7 +13,7 @@ export default {
components: {
Sidebar
}
}
};
</script>
<style>
.page-container {

View File

@ -150,13 +150,6 @@ export default {
};
</script>
<style>
/* FIX: For table cell expanding when active */
.table-cell {
min-height: 58px;
}
.table-cell > div {
margin-top: 6px;
}
.table th,
.table td {
vertical-align: middle;

View File

@ -1,4 +1,5 @@
import Invoice from '../../../models/doctype/Invoice/InvoiceList';
import Bill from '../../../models/doctype/Bill/BillList';
import Customer from '../../../models/doctype/Party/CustomerList';
import Supplier from '../../../models/doctype/Party/SupplierList';
import Item from '../../../models/doctype/Item/ItemList';
@ -9,6 +10,7 @@ import Account from '../../../models/doctype/Account/AccountList';
export default {
Invoice,
Bill,
Customer,
Supplier,
Item,

View File

@ -58,6 +58,10 @@ export default {
label: _('Invoice'),
route: '/list/Invoice'
},
{
label: _('Bill'),
route: '/list/Bill'
},
{
label: _('Journal Entry'),
route: '/list/JournalEntry'