mirror of
https://github.com/frappe/books.git
synced 2024-12-23 11:29:03 +00:00
Multicurrency
This commit is contained in:
parent
562b4759e0
commit
3192cb556a
@ -41,6 +41,16 @@ module.exports = {
|
|||||||
required: 0
|
required: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
fieldname: 'numberFormat',
|
||||||
|
fieldtype: 'Data'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
fieldname: 'symbol',
|
||||||
|
fieldtype: 'Data'
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
fieldname: 'fullname',
|
fieldname: 'fullname',
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
|
53
models/doctype/Currency/Currency.js
Normal file
53
models/doctype/Currency/Currency.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: 'Currency',
|
||||||
|
label: 'Currency',
|
||||||
|
doctype: 'DocType',
|
||||||
|
isSingle: 0,
|
||||||
|
keywordFields: ['name', 'symbol'],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldname: 'name',
|
||||||
|
label: 'Currency Name',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'fraction',
|
||||||
|
label: 'Fraction',
|
||||||
|
fieldtype: 'Data'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'fractionUnits',
|
||||||
|
label: 'Fraction Units',
|
||||||
|
fieldtype: 'Int'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Smallest Currency Fraction Value',
|
||||||
|
fieldname: 'smallestValue',
|
||||||
|
fieldtype: 'Currency'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Symbol',
|
||||||
|
fieldname: 'symbol',
|
||||||
|
fieldtype: 'Data'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'numberFormat',
|
||||||
|
fieldtype: 'Select',
|
||||||
|
label: 'Number Format',
|
||||||
|
options: [
|
||||||
|
'',
|
||||||
|
'#,###.##',
|
||||||
|
'#.###,##',
|
||||||
|
'# ###.##',
|
||||||
|
'# ###,##',
|
||||||
|
"#'###.##",
|
||||||
|
'#, ###.##',
|
||||||
|
'#,##,###.##',
|
||||||
|
'#,###.###',
|
||||||
|
'#.###',
|
||||||
|
'#,###'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -29,6 +29,16 @@ module.exports = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'currency',
|
||||||
|
label: 'Currency',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
target: 'Currency',
|
||||||
|
formula: async doc => {
|
||||||
|
const { currency } = await frappe.getSingle('AccountingSettings');
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'customer',
|
fieldname: 'customer',
|
||||||
label: 'Customer',
|
label: 'Customer',
|
||||||
|
@ -3,6 +3,16 @@ const frappe = require('frappejs');
|
|||||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||||
|
|
||||||
module.exports = class PaymentServer extends BaseDocument {
|
module.exports = class PaymentServer extends BaseDocument {
|
||||||
|
async change({ changed }) {
|
||||||
|
if (changed === 'for') {
|
||||||
|
this.amount = 0;
|
||||||
|
for (let paymentReference of this.for) {
|
||||||
|
this.amount += frappe.parseNumber(paymentReference.amount);
|
||||||
|
}
|
||||||
|
this.amount = frappe.format(this.amount, 'Currency');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.party });
|
let entries = new LedgerPosting({ reference: this, party: this.party });
|
||||||
await entries.debit(this.paymentAccount, this.amount);
|
await entries.debit(this.paymentAccount, this.amount);
|
||||||
@ -23,12 +33,18 @@ module.exports = class PaymentServer extends BaseDocument {
|
|||||||
if (outstandingAmount === null) {
|
if (outstandingAmount === null) {
|
||||||
outstandingAmount = grandTotal;
|
outstandingAmount = grandTotal;
|
||||||
}
|
}
|
||||||
if (0 >= this.amount || this.amount > outstandingAmount) {
|
if (
|
||||||
|
0 >= frappe.parseNumber(this.amount) ||
|
||||||
|
frappe.parseNumber(this.amount) >
|
||||||
|
frappe.parseNumber(outstandingAmount)
|
||||||
|
) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'show-dialog',
|
method: 'show-dialog',
|
||||||
args: {
|
args: {
|
||||||
title: 'Invalid Payment Entry',
|
title: 'Invalid Payment Entry',
|
||||||
message: `Payment amount is greater than 0 and less than Outstanding amount (${outstandingAmount})`
|
message: `Payment amount (${
|
||||||
|
this.amount
|
||||||
|
}) should be greater than 0 and less than Outstanding amount (${outstandingAmount})`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
throw new Error();
|
throw new Error();
|
||||||
|
@ -48,6 +48,21 @@ module.exports = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'currency',
|
||||||
|
label: 'Customer Currency',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
target: 'Currency',
|
||||||
|
hidden: 1,
|
||||||
|
formula: doc => doc.getFrom('Party', doc.supplier, 'currency')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'exchangeRate',
|
||||||
|
label: 'Exchange Rate',
|
||||||
|
fieldtype: 'Float',
|
||||||
|
placeholder: '1 USD = [?] INR',
|
||||||
|
hidden: doc => !doc.isForeignTransaction()
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'items',
|
fieldname: 'items',
|
||||||
label: 'Items',
|
label: 'Items',
|
||||||
@ -56,10 +71,20 @@ module.exports = {
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'netTotal',
|
fieldname: 'baseNetTotal',
|
||||||
label: 'Net Total',
|
label: 'Net Total (INR)',
|
||||||
fieldtype: 'Currency',
|
fieldtype: 'Currency',
|
||||||
formula: doc => doc.getSum('items', 'amount'),
|
formula: async doc => await doc.getBaseNetTotal(),
|
||||||
|
disabled: true,
|
||||||
|
readOnly: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'netTotal',
|
||||||
|
label: 'Net Total (USD)',
|
||||||
|
fieldtype: 'Currency',
|
||||||
|
hidden: doc => !doc.isForeignTransaction(),
|
||||||
|
formula: async doc =>
|
||||||
|
await doc.formatIntoCustomerCurrency(doc.getSum('items', 'amount')),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
readOnly: 1
|
readOnly: 1
|
||||||
},
|
},
|
||||||
@ -76,7 +101,7 @@ module.exports = {
|
|||||||
<div class='row' v-for='row in value'>
|
<div class='row' v-for='row in value'>
|
||||||
<div class='col-6'>{{ row.account }} ({{row.rate}}%)</div>
|
<div class='col-6'>{{ row.account }} ({{row.rate}}%)</div>
|
||||||
<div class='col-6 text-right'>
|
<div class='col-6 text-right'>
|
||||||
{{frappe.format(row.amount, 'Currency')}}
|
{{ row.amount }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -84,10 +109,19 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'grandTotal',
|
fieldname: 'baseGrandTotal',
|
||||||
label: 'Grand Total',
|
label: 'Grand Total (INR)',
|
||||||
fieldtype: 'Currency',
|
fieldtype: 'Currency',
|
||||||
formula: doc => doc.getGrandTotal(),
|
formula: async doc => await doc.getBaseGrandTotal(),
|
||||||
|
disabled: true,
|
||||||
|
readOnly: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'grandTotal',
|
||||||
|
label: 'Grand Total (USD)',
|
||||||
|
fieldtype: 'Currency',
|
||||||
|
hidden: doc => !doc.isForeignTransaction(),
|
||||||
|
formula: async doc => await doc.getGrandTotal(),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
readOnly: 1
|
readOnly: 1
|
||||||
},
|
},
|
||||||
@ -107,7 +141,10 @@ module.exports = {
|
|||||||
layout: [
|
layout: [
|
||||||
// section 1
|
// section 1
|
||||||
{
|
{
|
||||||
columns: [{ fields: ['supplier', 'account'] }, { fields: ['date'] }]
|
columns: [
|
||||||
|
{ fields: ['supplier', 'account'] },
|
||||||
|
{ fields: ['date', 'exchangeRate'] }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// section 2
|
// section 2
|
||||||
@ -117,7 +154,17 @@ module.exports = {
|
|||||||
|
|
||||||
// section 3
|
// section 3
|
||||||
{
|
{
|
||||||
columns: [{ fields: ['netTotal', 'taxes', 'grandTotal'] }]
|
columns: [
|
||||||
|
{
|
||||||
|
fields: [
|
||||||
|
'baseNetTotal',
|
||||||
|
'netTotal',
|
||||||
|
'taxes',
|
||||||
|
'baseGrandTotal',
|
||||||
|
'grandTotal'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// section 4
|
// section 4
|
||||||
@ -141,7 +188,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
referenceType: form.doc.doctype,
|
referenceType: form.doc.doctype,
|
||||||
referenceName: form.doc.name,
|
referenceName: form.doc.name,
|
||||||
amount: form.doc.grandTotal
|
amount: form.doc.outstandingAmount
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
payment.on('afterInsert', async () => {
|
payment.on('afterInsert', async () => {
|
||||||
|
@ -5,15 +5,23 @@ const LedgerPosting = require('../../../accounting/ledgerPosting');
|
|||||||
module.exports = class PurchaseInvoiceServer extends PurchaseInvoice {
|
module.exports = class PurchaseInvoiceServer extends PurchaseInvoice {
|
||||||
async getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.supplier });
|
let entries = new LedgerPosting({ reference: this, party: this.supplier });
|
||||||
await entries.credit(this.account, this.grandTotal);
|
await entries.credit(this.account, this.baseGrandTotal);
|
||||||
|
|
||||||
for (let item of this.items) {
|
for (let item of this.items) {
|
||||||
await entries.debit(item.account, item.amount);
|
const baseItemAmount = frappe.format(
|
||||||
|
frappe.parseNumber(item.amount) * this.exchangeRate,
|
||||||
|
'Currency'
|
||||||
|
);
|
||||||
|
await entries.debit(item.account, baseItemAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.taxes) {
|
if (this.taxes) {
|
||||||
for (let tax of this.taxes) {
|
for (let tax of this.taxes) {
|
||||||
await entries.debit(tax.account, tax.amount);
|
const baseTaxAmount = frappe.format(
|
||||||
|
frappe.parseNumber(tax.amount) * this.exchangeRate,
|
||||||
|
'Currency'
|
||||||
|
);
|
||||||
|
await entries.debit(tax.account, baseTaxAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entries;
|
return entries;
|
||||||
@ -32,6 +40,11 @@ module.exports = class PurchaseInvoiceServer extends PurchaseInvoice {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async beforeInsert() {
|
||||||
|
const entries = await this.getPosting();
|
||||||
|
await entries.validateEntries();
|
||||||
|
}
|
||||||
|
|
||||||
async afterSubmit() {
|
async afterSubmit() {
|
||||||
const entries = await this.getPosting();
|
const entries = await this.getPosting();
|
||||||
await entries.post();
|
await entries.post();
|
||||||
@ -39,7 +52,7 @@ module.exports = class PurchaseInvoiceServer extends PurchaseInvoice {
|
|||||||
'PurchaseInvoice',
|
'PurchaseInvoice',
|
||||||
this.name,
|
this.name,
|
||||||
'outstandingAmount',
|
'outstandingAmount',
|
||||||
this.grandTotal
|
this.baseGrandTotal
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,11 @@ module.exports = {
|
|||||||
fieldtype: 'Currency',
|
fieldtype: 'Currency',
|
||||||
readOnly: 1,
|
readOnly: 1,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
formula: (row, doc) => row.quantity * row.rate
|
formula: async (row, doc) => {
|
||||||
|
return await doc.formatIntoCustomerCurrency(
|
||||||
|
row.quantity * frappe.parseNumber(row.rate)
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'taxAmount',
|
fieldname: 'taxAmount',
|
||||||
|
@ -47,18 +47,29 @@ module.exports = {
|
|||||||
target: 'Account',
|
target: 'Account',
|
||||||
formula: doc => doc.getFrom('Party', doc.customer, 'defaultAccount'),
|
formula: doc => doc.getFrom('Party', doc.customer, 'defaultAccount'),
|
||||||
getFilters: (query, control) => {
|
getFilters: (query, control) => {
|
||||||
if (query)
|
if (!query) return { isGroup: 0, accountType: 'Receivable' };
|
||||||
return {
|
return {
|
||||||
keywords: ['like', query],
|
keywords: ['like', query],
|
||||||
isGroup: 0,
|
isGroup: 0,
|
||||||
accountType: 'Receivable'
|
accountType: 'Receivable'
|
||||||
};
|
};
|
||||||
return {
|
|
||||||
isGroup: 0,
|
|
||||||
accountType: 'Receivable'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'currency',
|
||||||
|
label: 'Customer Currency',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
target: 'Currency',
|
||||||
|
hidden: 1,
|
||||||
|
formula: doc => doc.getFrom('Party', doc.customer, 'currency')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'exchangeRate',
|
||||||
|
label: 'Exchange Rate',
|
||||||
|
fieldtype: 'Float',
|
||||||
|
placeholder: '1 USD = [?] INR',
|
||||||
|
hidden: doc => !doc.isForeignTransaction()
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'items',
|
fieldname: 'items',
|
||||||
label: 'Items',
|
label: 'Items',
|
||||||
@ -67,10 +78,20 @@ module.exports = {
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'netTotal',
|
fieldname: 'baseNetTotal',
|
||||||
label: 'Net Total',
|
label: 'Net Total (INR)',
|
||||||
fieldtype: 'Currency',
|
fieldtype: 'Currency',
|
||||||
formula: doc => frappe.format(doc.getSum('items', 'amount'), 'Currency'),
|
formula: async doc => await doc.getBaseNetTotal(),
|
||||||
|
disabled: true,
|
||||||
|
readOnly: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'netTotal',
|
||||||
|
label: 'Net Total (USD)',
|
||||||
|
fieldtype: 'Currency',
|
||||||
|
hidden: doc => !doc.isForeignTransaction(),
|
||||||
|
formula: async doc =>
|
||||||
|
await doc.formatIntoCustomerCurrency(doc.getSum('items', 'amount')),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
readOnly: 1
|
readOnly: 1
|
||||||
},
|
},
|
||||||
@ -87,7 +108,7 @@ module.exports = {
|
|||||||
<div class='row' v-for='row in value'>
|
<div class='row' v-for='row in value'>
|
||||||
<div class='col-6'>{{ row.account }} ({{row.rate}}%)</div>
|
<div class='col-6'>{{ row.account }} ({{row.rate}}%)</div>
|
||||||
<div class='col-6 text-right'>
|
<div class='col-6 text-right'>
|
||||||
{{ frappe.format(row.amount, 'Currency')}}
|
{{ row.amount }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -95,10 +116,19 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'grandTotal',
|
fieldname: 'baseGrandTotal',
|
||||||
label: 'Grand Total',
|
label: 'Grand Total (INR)',
|
||||||
fieldtype: 'Currency',
|
fieldtype: 'Currency',
|
||||||
formula: doc => frappe.format(doc.getGrandTotal(), 'Currency'),
|
formula: async doc => await doc.getBaseGrandTotal(),
|
||||||
|
disabled: true,
|
||||||
|
readOnly: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'grandTotal',
|
||||||
|
label: 'Grand Total (USD)',
|
||||||
|
fieldtype: 'Currency',
|
||||||
|
hidden: doc => !doc.isForeignTransaction(),
|
||||||
|
formula: async doc => await doc.getGrandTotal(),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
readOnly: 1
|
readOnly: 1
|
||||||
},
|
},
|
||||||
@ -118,7 +148,10 @@ module.exports = {
|
|||||||
layout: [
|
layout: [
|
||||||
// section 1
|
// section 1
|
||||||
{
|
{
|
||||||
columns: [{ fields: ['customer', 'account'] }, { fields: ['date'] }]
|
columns: [
|
||||||
|
{ fields: ['customer', 'account'] },
|
||||||
|
{ fields: ['date', 'exchangeRate'] }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// section 2
|
// section 2
|
||||||
@ -128,7 +161,17 @@ module.exports = {
|
|||||||
|
|
||||||
// section 3
|
// section 3
|
||||||
{
|
{
|
||||||
columns: [{ fields: ['netTotal', 'taxes', 'grandTotal'] }]
|
columns: [
|
||||||
|
{
|
||||||
|
fields: [
|
||||||
|
'baseNetTotal',
|
||||||
|
'netTotal',
|
||||||
|
'taxes',
|
||||||
|
'baseGrandTotal',
|
||||||
|
'grandTotal'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// section 4
|
// section 4
|
||||||
@ -152,7 +195,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
referenceType: form.doc.doctype,
|
referenceType: form.doc.doctype,
|
||||||
referenceName: form.doc.name,
|
referenceName: form.doc.name,
|
||||||
amount: form.doc.grandTotal
|
amount: form.doc.outstandingAmount
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
payment.on('afterInsert', async () => {
|
payment.on('afterInsert', async () => {
|
||||||
|
@ -2,15 +2,98 @@ const BaseDocument = require('frappejs/model/document');
|
|||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
|
|
||||||
module.exports = class SalesInvoice extends BaseDocument {
|
module.exports = class SalesInvoice extends BaseDocument {
|
||||||
|
async change({ changed }) {
|
||||||
|
if (changed === 'items' || changed === 'exchangeRate') {
|
||||||
|
const companyCurrency = frappe.AccountingSettings.currency;
|
||||||
|
if (this.currency.length && this.currency !== companyCurrency) {
|
||||||
|
for (let item of this.items) {
|
||||||
|
if (item.rate && this.exchangeRate) {
|
||||||
|
const itemRate = await this.getFrom('Item', item.item, 'rate');
|
||||||
|
|
||||||
|
item.rate = frappe.parseNumber(itemRate) / this.exchangeRate;
|
||||||
|
if (item.quantity) {
|
||||||
|
item.amount = item.rate * item.quantity;
|
||||||
|
}
|
||||||
|
item.amount = await this.formatIntoCustomerCurrency(item.amount);
|
||||||
|
item.rate = await this.formatIntoCustomerCurrency(item.rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.netTotal = await this.formatIntoCustomerCurrency(this.netTotal);
|
||||||
|
this.grandTotal = await this.formatIntoCustomerCurrency(
|
||||||
|
this.grandTotal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed === 'customer' || changed === 'supplier') {
|
||||||
|
this.currency = await this.getFrom('Party', this[changed], 'currency');
|
||||||
|
this.exchangeRate = await this.getExchangeRate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async formatIntoCustomerCurrency(value) {
|
||||||
|
const companyCurrency = frappe.AccountingSettings.currency;
|
||||||
|
if (this.currency.length && this.currency !== companyCurrency) {
|
||||||
|
const { numberFormat, symbol } = await this.getCustomerCurrencyInfo();
|
||||||
|
return frappe.format(value, {
|
||||||
|
fieldtype: 'Currency',
|
||||||
|
currencyInfo: { numberFormat, symbol }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return frappe.format(value, 'Currency');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isForeignTransaction() {
|
||||||
|
return this.currency
|
||||||
|
? this.currency !== frappe.AccountingSettings.currency
|
||||||
|
? 1
|
||||||
|
: 0
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCustomerCurrencyInfo() {
|
||||||
|
if (this.numberFormat || this.symbol) {
|
||||||
|
return { numberFormat: this.numberFormat, symbol: this.symbol };
|
||||||
|
}
|
||||||
|
const { numberFormat, symbol } = await frappe.getDoc(
|
||||||
|
'Currency',
|
||||||
|
this.currency
|
||||||
|
);
|
||||||
|
this.numberFormat = numberFormat;
|
||||||
|
this.symbol = symbol;
|
||||||
|
|
||||||
|
return { numberFormat, symbol };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getExchangeRate() {
|
||||||
|
const companyCurrency = frappe.AccountingSettings.currency;
|
||||||
|
return this.currency === companyCurrency ? 1.0 : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBaseNetTotal() {
|
||||||
|
if (this.isForeignTransaction()) {
|
||||||
|
return frappe.format(
|
||||||
|
this.getSum('items', 'amount') * (this.exchangeRate || 0),
|
||||||
|
'Currency'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return await this.formatIntoCustomerCurrency(
|
||||||
|
this.getSum('items', 'amount')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getRowTax(row) {
|
async getRowTax(row) {
|
||||||
if (row.tax) {
|
if (row.tax) {
|
||||||
let tax = await this.getTax(row.tax);
|
let tax = await this.getTax(row.tax);
|
||||||
let taxAmount = [];
|
let taxAmount = [];
|
||||||
for (let d of tax.details || []) {
|
for (let d of tax.details || []) {
|
||||||
|
const amt = (frappe.parseNumber(row.amount) * d.rate) / 100;
|
||||||
taxAmount.push({
|
taxAmount.push({
|
||||||
account: d.account,
|
account: d.account,
|
||||||
rate: d.rate,
|
rate: d.rate,
|
||||||
amount: (row.amount * d.rate) / 100
|
amount: await this.formatIntoCustomerCurrency(amt)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return JSON.stringify(taxAmount);
|
return JSON.stringify(taxAmount);
|
||||||
@ -25,7 +108,7 @@ module.exports = class SalesInvoice extends BaseDocument {
|
|||||||
return this._taxes[tax];
|
return this._taxes[tax];
|
||||||
}
|
}
|
||||||
|
|
||||||
makeTaxSummary() {
|
async makeTaxSummary() {
|
||||||
if (!this.taxes) this.taxes = [];
|
if (!this.taxes) this.taxes = [];
|
||||||
|
|
||||||
// reset tax amount
|
// reset tax amount
|
||||||
@ -45,7 +128,12 @@ module.exports = class SalesInvoice extends BaseDocument {
|
|||||||
for (let taxDetail of this.taxes) {
|
for (let taxDetail of this.taxes) {
|
||||||
if (taxDetail.account === rowTaxDetail.account) {
|
if (taxDetail.account === rowTaxDetail.account) {
|
||||||
taxDetail.rate = rowTaxDetail.rate;
|
taxDetail.rate = rowTaxDetail.rate;
|
||||||
taxDetail.amount += rowTaxDetail.amount;
|
taxDetail.amount =
|
||||||
|
frappe.parseNumber(taxDetail.amount) +
|
||||||
|
frappe.parseNumber(rowTaxDetail.amount);
|
||||||
|
taxDetail.amount = await this.formatIntoCustomerCurrency(
|
||||||
|
taxDetail.amount
|
||||||
|
);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,16 +154,29 @@ module.exports = class SalesInvoice extends BaseDocument {
|
|||||||
this.taxes = this.taxes.filter(d => d.amount);
|
this.taxes = this.taxes.filter(d => d.amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getGrandTotal() {
|
async getGrandTotal() {
|
||||||
this.makeTaxSummary();
|
await this.makeTaxSummary();
|
||||||
let grandTotal = frappe.parseNumber(this.netTotal);
|
let grandTotal = frappe.parseNumber(this.netTotal);
|
||||||
if (this.taxes) {
|
if (this.taxes) {
|
||||||
for (let row of this.taxes) {
|
for (let row of this.taxes) {
|
||||||
grandTotal += row.amount;
|
grandTotal += frappe.parseNumber(row.amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
grandTotal = Math.floor(grandTotal * 100) / 100;
|
grandTotal = Math.floor(grandTotal * 100) / 100;
|
||||||
|
|
||||||
return grandTotal;
|
return await this.formatIntoCustomerCurrency(grandTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBaseGrandTotal() {
|
||||||
|
await this.makeTaxSummary();
|
||||||
|
let baseGrandTotal = frappe.parseNumber(this.baseNetTotal);
|
||||||
|
if (this.taxes) {
|
||||||
|
for (let row of this.taxes) {
|
||||||
|
baseGrandTotal += frappe.parseNumber(row.amount) * this.exchangeRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baseGrandTotal = Math.floor(baseGrandTotal * 100) / 100;
|
||||||
|
|
||||||
|
return frappe.format(baseGrandTotal, 'Currency');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,28 @@ const LedgerPosting = require('../../../accounting/ledgerPosting');
|
|||||||
module.exports = class SalesInvoiceServer extends SalesInvoice {
|
module.exports = class SalesInvoiceServer extends SalesInvoice {
|
||||||
async getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.customer });
|
let entries = new LedgerPosting({ reference: this, party: this.customer });
|
||||||
await entries.debit(this.account, this.grandTotal);
|
await entries.debit(this.account, this.baseGrandTotal);
|
||||||
|
|
||||||
|
if (this.isForeignTransaction()) {
|
||||||
|
for (let item of this.items) {
|
||||||
|
const baseItemAmount = frappe.format(
|
||||||
|
frappe.parseNumber(item.amount) * this.exchangeRate,
|
||||||
|
'Currency'
|
||||||
|
);
|
||||||
|
await entries.credit(item.account, baseItemAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.taxes) {
|
||||||
|
for (let tax of this.taxes) {
|
||||||
|
const baseTaxAmount = frappe.format(
|
||||||
|
frappe.parseNumber(tax.amount) * this.exchangeRate,
|
||||||
|
'Currency'
|
||||||
|
);
|
||||||
|
await entries.credit(tax.account, baseTaxAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
for (let item of this.items) {
|
for (let item of this.items) {
|
||||||
await entries.credit(item.account, item.amount);
|
await entries.credit(item.account, item.amount);
|
||||||
@ -31,6 +52,11 @@ module.exports = class SalesInvoiceServer extends SalesInvoice {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async beforeInsert() {
|
||||||
|
const entries = await this.getPosting();
|
||||||
|
await entries.validateEntries();
|
||||||
|
}
|
||||||
|
|
||||||
async afterSubmit() {
|
async afterSubmit() {
|
||||||
const entries = await this.getPosting();
|
const entries = await this.getPosting();
|
||||||
await entries.post();
|
await entries.post();
|
||||||
@ -38,7 +64,7 @@ module.exports = class SalesInvoiceServer extends SalesInvoice {
|
|||||||
'SalesInvoice',
|
'SalesInvoice',
|
||||||
this.name,
|
this.name,
|
||||||
'outstandingAmount',
|
'outstandingAmount',
|
||||||
this.grandTotal
|
this.baseGrandTotal
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div :style="$.regularFontSize" class="col-6 text-right">
|
<div :style="$.regularFontSize" class="col-6 text-right">
|
||||||
<h2 :style="$.headerFontColor">INVOICE</h2>
|
<h2 :style="$.headerFontColor">INVOICE</h2>
|
||||||
<p :style="$.paraStyle"><strong>{{ doc.name }}</strong></p>
|
<p :style="$.paraStyle">
|
||||||
|
<strong>{{ doc.name }}</strong>
|
||||||
|
</p>
|
||||||
<p :style="$.paraStyle">{{ frappe.format(doc.date, 'Date') }}</p>
|
<p :style="$.paraStyle">{{ frappe.format(doc.date, 'Date') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -21,36 +23,50 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr :style="$.showBorderBottom">
|
<tr :style="$.showBorderBottom">
|
||||||
<th :style="$.hideBorderTop" class="text-left pl-0" style="width: 10%">{{ _("NO") }}</th>
|
<th :style="$.hideBorderTop" class="text-left pl-0" style="width: 10%">{{ _("NO") }}</th>
|
||||||
<th :style="$.hideBorderTop" class="text-left" style="width: 60%">{{ _("ITEM") }}</th>
|
<th :style="$.hideBorderTop" class="text-left" style="width: 50%">{{ _("ITEM") }}</th>
|
||||||
<th :style="$.hideBorderTop" class="text-left pl-0" style="width: 20%">{{ _("RATE") }}</th>
|
<th :style="$.hideBorderTop" class="text-left pl-0" style="width: 15%">{{ _("RATE") }}</th>
|
||||||
<th :style="$.hideBorderTop" class="text-left" style="width: 15%">{{ _("QTY") }}</th>
|
<th :style="$.hideBorderTop" class="text-left" style="width: 10%">{{ _("QTY") }}</th>
|
||||||
<th :style="$.hideBorderTop" class="text-right pr-1" style="width: 20%">{{ _("AMOUNT") }}</th>
|
<th
|
||||||
|
:style="$.hideBorderTop"
|
||||||
|
class="text-right pr-1"
|
||||||
|
style="width: 30%"
|
||||||
|
>{{ _("AMOUNT") }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="row in doc.items" :key="row.idx">
|
<tr v-for="row in doc.items" :key="row.idx">
|
||||||
<td class="text-left pl-1">{{ row.idx + 1 }}</td>
|
<td class="text-left pl-1">{{ row.idx + 1 }}</td>
|
||||||
<td class="text-left">{{ row.item }}</td>
|
<td class="text-left">{{ row.item }}</td>
|
||||||
<td class="text-left pl-0">{{ frappe.format(row.rate, 'Currency') }}</td>
|
<td class="text-left pl-0">{{ row.rate }}</td>
|
||||||
<td class="text-left">{{ row.quantity }}</td>
|
<td class="text-left">{{ row.quantity }}</td>
|
||||||
<td class="text-right pr-1">{{ frappe.format(row.amount, 'Currency') }}</td>
|
<td class="text-right pr-1">{{ row.amount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" class="text-left pl-1"></td>
|
<td colspan="2" class="text-left pl-1"></td>
|
||||||
<td colspan="2" :style="$.bold" class="text-left pl-0">SUBTOTAL</td>
|
<td colspan="2" :style="$.bold" class="text-left pl-0">SUBTOTAL</td>
|
||||||
<td :style="$.bold" class="text-right pr-1">{{ frappe.format(doc.netTotal, 'Currency') }}</td>
|
<td :style="$.bold" class="text-right pr-1">{{ doc.netTotal }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="tax in doc.taxes" :key="tax.name">
|
<tr v-for="tax in doc.taxes" :key="tax.name">
|
||||||
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
||||||
<td colspan="2" :style="$.bold" class="text-left pl-0">{{ tax.account.toUpperCase() }} ({{ tax.rate }}%)</td>
|
<td
|
||||||
<td :style="$.bold" class="text-right pr-1">{{ frappe.format(tax.amount, 'Currency') }}</td>
|
colspan="2"
|
||||||
|
:style="$.bold"
|
||||||
|
class="text-left pl-0"
|
||||||
|
>{{ tax.account.toUpperCase() }} ({{ tax.rate }}%)</td>
|
||||||
|
<td :style="$.bold" class="text-right pr-1">{{ tax.amount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
||||||
<td colspan="2" :style="[$.bold, $.mediumFontSize, $.showBorderTop]" class="text-left pl-0">TOTAL</td>
|
<td
|
||||||
<td :style="[$.bold, $.mediumFontSize, $.showBorderTop]" class="text-right pr-1" style="color: green;">
|
colspan="2"
|
||||||
{{ frappe.format(doc.grandTotal, 'Currency') }}
|
:style="[$.bold, $.mediumFontSize, $.showBorderTop]"
|
||||||
</td>
|
class="text-left pl-0"
|
||||||
|
>TOTAL</td>
|
||||||
|
<td
|
||||||
|
:style="[$.bold, $.mediumFontSize, $.showBorderTop]"
|
||||||
|
class="text-right pr-1"
|
||||||
|
style="color: green;"
|
||||||
|
>{{ doc.grandTotal }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -60,8 +76,12 @@
|
|||||||
<div :style="$.regularFontSize" class="col-12">
|
<div :style="$.regularFontSize" class="col-12">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr :style="[$.bold, $.showBorderBottom]" ><td :style="$.hideBorderTop" class="pl-0">NOTICE</td></tr>
|
<tr :style="[$.bold, $.showBorderBottom]">
|
||||||
<tr><td class="pl-0">{{ doc.terms }}</td></tr>
|
<td :style="$.hideBorderTop" class="pl-0">NOTICE</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="pl-0">{{ doc.terms }}</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -82,7 +102,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
$: Styles
|
$: Styles
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
themeColor: function() {
|
themeColor: function() {
|
||||||
@ -104,5 +124,5 @@ export default {
|
|||||||
this.$.font.fontFamily = this.font;
|
this.$.font.fontFamily = this.font;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,13 +14,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<p :style="[$.bold, $.mediumFontSize]">Invoice Number</p>
|
<p :style="[$.bold, $.mediumFontSize]">Invoice Number</p>
|
||||||
<p :style="$.paraStyle">{{ doc.name }}</p><br>
|
<p :style="$.paraStyle">{{ doc.name }}</p>
|
||||||
|
<br />
|
||||||
<p :style="[$.bold, $.mediumFontSize]">Date</p>
|
<p :style="[$.bold, $.mediumFontSize]">Date</p>
|
||||||
<p :style="$.paraStyle">{{doc.date}}</p>
|
<p :style="$.paraStyle">{{doc.date}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 text-right">
|
<div class="col-4 text-right">
|
||||||
<p :style="[$.bold, $.mediumFontSize]">Invoice Total</p>
|
<p :style="[$.bold, $.mediumFontSize]">Invoice Total</p>
|
||||||
<h2 :style="$.fontColor">{{ frappe.format(doc.grandTotal, 'Currency') }}</h2>
|
<h2 :style="$.fontColor">{{ doc.grandTotal }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row pl-5 pr-5 mt-3">
|
<div class="row pl-5 pr-5 mt-3">
|
||||||
@ -29,35 +30,45 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr :style="[$.showBorderTop, $.fontColor]">
|
<tr :style="[$.showBorderTop, $.fontColor]">
|
||||||
<th class="text-left pl-0" style="width: 10%">{{ _("NO") }}</th>
|
<th class="text-left pl-0" style="width: 10%">{{ _("NO") }}</th>
|
||||||
<th class="text-left" style="width: 60%">{{ _("ITEM") }}</th>
|
<th class="text-left" style="width: 50%">{{ _("ITEM") }}</th>
|
||||||
<th class="text-left pl-0" style="width: 20%">{{ _("RATE") }}</th>
|
<th class="text-left pl-0" style="width: 15%">{{ _("RATE") }}</th>
|
||||||
<th class="text-left" style="width: 15%">{{ _("QTY") }}</th>
|
<th class="text-left" style="width: 10%">{{ _("QTY") }}</th>
|
||||||
<th class="text-right pr-1" style="width: 20%">{{ _("AMOUNT") }}</th>
|
<th class="text-right pr-1" style="width: 30%">{{ _("AMOUNT") }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr :style="$.showBorderBottom" v-for="row in doc.items" :key="row.idx">
|
<tr :style="$.showBorderBottom" v-for="row in doc.items" :key="row.idx">
|
||||||
<td class="text-left pl-1">{{ row.idx + 1 }}</td>
|
<td class="text-left pl-1">{{ row.idx + 1 }}</td>
|
||||||
<td class="text-left">{{ row.item }}</td>
|
<td class="text-left">{{ row.item }}</td>
|
||||||
<td class="text-left pl-0">{{ frappe.format(row.rate, 'Currency') }}</td>
|
<td class="text-left pl-0">{{ row.rate }}</td>
|
||||||
<td class="text-left">{{ row.quantity }}</td>
|
<td class="text-left">{{ row.quantity }}</td>
|
||||||
<td class="text-right pr-1">{{ frappe.format(row.amount, 'Currency') }}</td>
|
<td class="text-right pr-1">{{ row.amount }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" style="padding: 4%"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td colspan="5" style="padding: 4%"></td></tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" class="text-left pl-1"></td>
|
<td colspan="2" class="text-left pl-1"></td>
|
||||||
<td colspan="2" :style="[$.bold, $.fontColor]" class="text-left pl-0">SUBTOTAL</td>
|
<td colspan="2" :style="[$.bold, $.fontColor]" class="text-left pl-0">SUBTOTAL</td>
|
||||||
<td :style="$.bold" class="text-right pr-1">{{ frappe.format(doc.netTotal, 'Currency') }}</td>
|
<td :style="$.bold" class="text-right pr-1">{{ doc.netTotal }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="tax in doc.taxes" :key="tax.name">
|
<tr v-for="tax in doc.taxes" :key="tax.name">
|
||||||
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
||||||
<td colspan="2" :style="[$.bold, $.fontColor]" class="text-left pl-0">{{ tax.account.toUpperCase() }} ({{ tax.rate }}%)</td>
|
<td
|
||||||
<td :style="$.bold" class="text-right pr-1">{{ frappe.format(tax.amount, 'Currency') }}</td>
|
colspan="2"
|
||||||
|
:style="[$.bold, $.fontColor]"
|
||||||
|
class="text-left pl-0"
|
||||||
|
>{{ tax.account.toUpperCase() }} ({{ tax.rate }}%)</td>
|
||||||
|
<td :style="$.bold" class="text-right pr-1">{{ tax.amount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
<td colspan="2" :style="$.hideBorderTop" class="text-left pl-1"></td>
|
||||||
<td colspan="2" :style="[$.bold, $.fontColor, $.mediumFontSize]" class="text-left pl-0">TOTAL</td>
|
<td
|
||||||
<td :style="[$.bold, $.mediumFontSize]" class="text-right pr-1">{{ frappe.format(doc.grandTotal, 'Currency') }}</td>
|
colspan="2"
|
||||||
|
:style="[$.bold, $.fontColor, $.mediumFontSize]"
|
||||||
|
class="text-left pl-0"
|
||||||
|
>TOTAL</td>
|
||||||
|
<td :style="[$.bold, $.mediumFontSize]" class="text-right pr-1">{{ doc.grandTotal }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -67,8 +78,12 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr :style="[$.bold, $.showNoticeBorderBottom]" ><td :style="$.hideBorderTop" class="pl-0">NOTICE</td></tr>
|
<tr :style="[$.bold, $.showNoticeBorderBottom]">
|
||||||
<tr><td class="pl-0">{{ doc.terms }}</td></tr>
|
<td :style="$.hideBorderTop" class="pl-0">NOTICE</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="pl-0">{{ doc.terms }}</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -88,8 +103,8 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
$: Styles,
|
$: Styles
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
themeColor: function() {
|
themeColor: function() {
|
||||||
@ -113,5 +128,5 @@ export default {
|
|||||||
this.$.font.fontFamily = this.font;
|
this.$.font.fontFamily = this.font;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
@ -27,34 +27,64 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td :style="[$.bold, $.showBorderRight, $.tablePadding]" style="width: 15" class="pl-5">{{ _("NO") }}</td>
|
<td
|
||||||
<td :style="[$.bold, $.showBorderRight, $.tablePadding]" style="width: 40%">{{ _("ITEM") }}</td>
|
:style="[$.bold, $.showBorderRight, $.tablePadding]"
|
||||||
<td class="text-left" :style="[$.bold, $.showBorderRight, $.tablePadding]" style="width: 20%">{{ _("RATE") }}</td>
|
style="width: 15"
|
||||||
<td :style="[$.bold, $.showBorderRight, $.tablePadding]" style="width: 10%">{{ _("QTY") }}</td>
|
class="pl-5"
|
||||||
<td class="text-right pr-5" :style="[$.bold, $.tablePadding]" style="width: 20%">{{ _("AMOUNT") }}</td>
|
>{{ _("NO") }}</td>
|
||||||
|
<td
|
||||||
|
:style="[$.bold, $.showBorderRight, $.tablePadding]"
|
||||||
|
style="width: 40%"
|
||||||
|
>{{ _("ITEM") }}</td>
|
||||||
|
<td
|
||||||
|
class="text-left"
|
||||||
|
:style="[$.bold, $.showBorderRight, $.tablePadding]"
|
||||||
|
style="width: 20%"
|
||||||
|
>{{ _("RATE") }}</td>
|
||||||
|
<td
|
||||||
|
:style="[$.bold, $.showBorderRight, $.tablePadding]"
|
||||||
|
style="width: 10%"
|
||||||
|
>{{ _("QTY") }}</td>
|
||||||
|
<td
|
||||||
|
class="text-right pr-5"
|
||||||
|
:style="[$.bold, $.tablePadding]"
|
||||||
|
style="width: 20%"
|
||||||
|
>{{ _("AMOUNT") }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="row in doc.items" :key="row.idx">
|
<tr v-for="row in doc.items" :key="row.idx">
|
||||||
<td :style="$.tablePadding" class="pl-5 pr-5">{{ row.idx + 1 }}</td>
|
<td :style="$.tablePadding" class="pl-5 pr-5">{{ row.idx + 1 }}</td>
|
||||||
<td :style="$.tablePadding">{{ row.item }}</td>
|
<td :style="$.tablePadding">{{ row.item }}</td>
|
||||||
<td :style="$.tablePadding" class="text-left">{{ frappe.format(row.rate, 'Currency') }}</td>
|
<td
|
||||||
|
:style="$.tablePadding"
|
||||||
|
class="text-left"
|
||||||
|
>{{ frappe.format(row.rate, 'Currency') }}</td>
|
||||||
<td :style="$.tablePadding">{{ row.quantity }}</td>
|
<td :style="$.tablePadding">{{ row.quantity }}</td>
|
||||||
<td :style="$.tablePadding" class="text-right pr-5">{{ frappe.format(row.amount, 'Currency') }}</td>
|
<td :style="$.tablePadding" class="text-right pr-5">{{ row.amount }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" style="padding: 4%"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td colspan="5" style="padding: 4%"></td></tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" :style="[$.hideBorderTop, $.tablePadding]"></td>
|
<td colspan="2" :style="[$.hideBorderTop, $.tablePadding]"></td>
|
||||||
<td :style="$.tablePadding" colspan="2">SUBTOTAL</td>
|
<td :style="$.tablePadding" colspan="2">SUBTOTAL</td>
|
||||||
<td :style="$.tablePadding" class="text-right pr-5">{{ frappe.format(doc.netTotal, 'Currency') }}</td>
|
<td :style="$.tablePadding" class="text-right pr-5">{{ doc.netTotal }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="tax in doc.taxes" :key="tax.name">
|
<tr v-for="tax in doc.taxes" :key="tax.name">
|
||||||
<td colspan="2" :style="[$.hideBorderTop, $.tablePadding]"></td>
|
<td colspan="2" :style="[$.hideBorderTop, $.tablePadding]"></td>
|
||||||
<td :style="$.tablePadding" med colspan="2">{{ tax.account.toUpperCase() }} ({{ tax.rate }}%)</td>
|
<td
|
||||||
<td :style="$.tablePadding" class="text-right pr-5">{{ frappe.format(tax.amount, 'Currency') }}</td>
|
:style="$.tablePadding"
|
||||||
|
med
|
||||||
|
colspan="2"
|
||||||
|
>{{ tax.account.toUpperCase() }} ({{ tax.rate }}%)</td>
|
||||||
|
<td :style="$.tablePadding" class="text-right pr-5">{{ tax.amount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" :style="[$.hideBorderTop, $.tablePadding]"></td>
|
<td colspan="2" :style="[$.hideBorderTop, $.tablePadding]"></td>
|
||||||
<td :style="[$.bold, $.tablePadding, $.mediumFontSize]" colspan="2">TOTAL</td>
|
<td :style="[$.bold, $.tablePadding, $.mediumFontSize]" colspan="2">TOTAL</td>
|
||||||
<td :style="[$.bold, $.tablePadding, $.mediumFontSize]" class="text-right pr-5">{{ frappe.format(doc.grandTotal, 'Currency') }}</td>
|
<td
|
||||||
|
:style="[$.bold, $.tablePadding, $.mediumFontSize]"
|
||||||
|
class="text-right pr-5"
|
||||||
|
>{{ doc.grandTotal }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -67,7 +97,9 @@
|
|||||||
<tr :style="[$.bold, $.showBorderBottom]">
|
<tr :style="[$.bold, $.showBorderBottom]">
|
||||||
<td :style="$.hideBorderTop" class="pl-5">NOTICE</td>
|
<td :style="$.hideBorderTop" class="pl-5">NOTICE</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td class="pl-5">{{ doc.terms }}</td></tr>
|
<tr>
|
||||||
|
<td class="pl-5">{{ doc.terms }}</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -87,8 +119,8 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
$: Styles,
|
$: Styles
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
themeColor: function() {
|
themeColor: function() {
|
||||||
@ -109,5 +141,5 @@ export default {
|
|||||||
this.$.font.fontFamily = this.font;
|
this.$.font.fontFamily = this.font;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
@ -59,7 +59,11 @@ module.exports = {
|
|||||||
fieldtype: 'Currency',
|
fieldtype: 'Currency',
|
||||||
readOnly: 1,
|
readOnly: 1,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
formula: (row, doc) => row.quantity * row.rate
|
formula: async (row, doc) => {
|
||||||
|
return await doc.formatIntoCustomerCurrency(
|
||||||
|
row.quantity * frappe.parseNumber(row.rate)
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'taxAmount',
|
fieldname: 'taxAmount',
|
||||||
|
@ -3,6 +3,7 @@ module.exports = {
|
|||||||
SetupWizard: require('./doctype/SetupWizard/SetupWizard'),
|
SetupWizard: require('./doctype/SetupWizard/SetupWizard'),
|
||||||
DashboardSettings: require('./doctype/DashboardSettings/DashboardSettings'),
|
DashboardSettings: require('./doctype/DashboardSettings/DashboardSettings'),
|
||||||
DashboardChart: require('./doctype/DashboardChart/DashboardChart'),
|
DashboardChart: require('./doctype/DashboardChart/DashboardChart'),
|
||||||
|
Currency: require('./doctype/Currency/Currency'),
|
||||||
Color: require('./doctype/Color/Color'),
|
Color: require('./doctype/Color/Color'),
|
||||||
Account: require('./doctype/Account/Account.js'),
|
Account: require('./doctype/Account/Account.js'),
|
||||||
AccountingSettings: require('./doctype/AccountingSettings/AccountingSettings'),
|
AccountingSettings: require('./doctype/AccountingSettings/AccountingSettings'),
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<span
|
<span
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:class="['Float', 'Currency'].includes(column.fieldtype) ? 'text-right':''"
|
:class="['Float', 'Currency'].includes(column.fieldtype) ? 'text-right':''"
|
||||||
>{{ frappe.format(column.getValue(doc), column.fieldtype || {}) }}</span>
|
>{{ getColumnValue(column, doc) }}</span>
|
||||||
</list-cell>
|
</list-cell>
|
||||||
</list-row>
|
</list-row>
|
||||||
</div>
|
</div>
|
||||||
@ -55,6 +55,15 @@ export default {
|
|||||||
frappe.listView.on('filterList', this.updateData.bind(this));
|
frappe.listView.on('filterList', this.updateData.bind(this));
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getColumnValue(column, doc) {
|
||||||
|
// Since currency is formatted in customer currency
|
||||||
|
// frappe.format parses it back into company currency
|
||||||
|
if (['Float', 'Currency'].includes(column.fieldtype)) {
|
||||||
|
return column.getValue(doc);
|
||||||
|
} else {
|
||||||
|
return frappe.format(column.getValue(doc), column.fieldtype);
|
||||||
|
}
|
||||||
|
},
|
||||||
async setupColumnsAndData() {
|
async setupColumnsAndData() {
|
||||||
this.doctype = this.listConfig.doctype;
|
this.doctype = this.listConfig.doctype;
|
||||||
await this.updateData();
|
await this.updateData();
|
||||||
|
Loading…
Reference in New Issue
Block a user