Compare commits
8 Commits
@bigcapita
...
style-fina
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a04fe3734 | ||
|
|
1ed1c9ea1d | ||
|
|
d40de4d22b | ||
|
|
ee62e3e1c2 | ||
|
|
5df454dd30 | ||
|
|
07628ddc37 | ||
|
|
69afa07e3b | ||
|
|
b1a043f699 |
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
|
"version": "independent",
|
||||||
|
"npmClient": "pnpm",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"version": "0.9.6",
|
"packages": ["packages/*"]
|
||||||
"npmClient": "npm"
|
}
|
||||||
}
|
|
||||||
5730
package-lock.json
generated
5730
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@
|
|||||||
"name": "bigcapital-monorepo",
|
"name": "bigcapital-monorepo",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "lerna exec npm install",
|
|
||||||
"dev": "lerna run dev",
|
"dev": "lerna run dev",
|
||||||
"build": "lerna run build",
|
"build": "lerna run build",
|
||||||
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\"",
|
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\"",
|
||||||
@@ -13,10 +12,6 @@
|
|||||||
"test:e2e": "playwright test",
|
"test:e2e": "playwright test",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
|
||||||
"packages/*",
|
|
||||||
"shared/*"
|
|
||||||
],
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.4.2",
|
"@commitlint/cli": "^17.4.2",
|
||||||
"@commitlint/config-conventional": "^17.4.2",
|
"@commitlint/config-conventional": "^17.4.2",
|
||||||
@@ -27,7 +22,7 @@
|
|||||||
"lerna": "^6.4.1"
|
"lerna": "^6.4.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "14.x"
|
"node": "16.x || 17.x || 18.x"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|||||||
3
packages/server/.gitignore
vendored
3
packages/server/.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
/node_modules/
|
/node_modules/
|
||||||
/.env
|
/.env
|
||||||
/storage
|
/storage
|
||||||
package-lock.json
|
|
||||||
stdout.log
|
stdout.log
|
||||||
/dist
|
/dist
|
||||||
/build
|
/build
|
||||||
|
|||||||
13663
packages/server/package-lock.json
generated
Normal file
13663
packages/server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bigcapital/server",
|
"name": "@bigcapital/server",
|
||||||
"version": "0.10.0",
|
"version": "0.10.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "src/server.ts",
|
"main": "src/server.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
|
"body-parser": "^1.20.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"country-codes-list": "^1.6.8",
|
"country-codes-list": "^1.6.8",
|
||||||
"cpy": "^8.1.2",
|
"cpy": "^8.1.2",
|
||||||
@@ -72,6 +73,8 @@
|
|||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"moment-range": "^4.0.2",
|
"moment-range": "^4.0.2",
|
||||||
|
"moment-timezone": "^0.5.43",
|
||||||
|
"mongodb": "^6.1.0",
|
||||||
"mongoose": "^5.10.0",
|
"mongoose": "^5.10.0",
|
||||||
"mustache": "^3.0.3",
|
"mustache": "^3.0.3",
|
||||||
"mysql": "^2.17.1",
|
"mysql": "^2.17.1",
|
||||||
@@ -131,7 +134,7 @@
|
|||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rtlcss": "^3.3.0",
|
"rtlcss": "^3.3.0",
|
||||||
"run-script-webpack-plugin": "^0.1.1",
|
"run-script-webpack-plugin": "^0.1.1",
|
||||||
"sass": "^1.37.5",
|
"sass": "^1.58.0",
|
||||||
"sinon": "^7.4.2",
|
"sinon": "^7.4.2",
|
||||||
"start-server-webpack-plugin": "^2.2.5",
|
"start-server-webpack-plugin": "^2.2.5",
|
||||||
"ts-loader": "^9.4.2",
|
"ts-loader": "^9.4.2",
|
||||||
|
|||||||
@@ -149,6 +149,11 @@ export default class ItemsController extends BaseController {
|
|||||||
.trim()
|
.trim()
|
||||||
.escape()
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
|
check('sell_tax_rate_id').optional({ nullable: true }).isInt().toInt(),
|
||||||
|
check('purchase_tax_rate_id')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.isInt()
|
||||||
|
.toInt(),
|
||||||
check('category_id')
|
check('category_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
|
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
|
||||||
@@ -508,6 +513,28 @@ export default class ItemsController extends BaseController {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (error.errorType === 'PURCHASE_TAX_RATE_NOT_FOUND') {
|
||||||
|
return res.status(400).send({
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
type: 'PURCHASE_TAX_RATE_NOT_FOUND',
|
||||||
|
message: 'Purchase tax rate has not found.',
|
||||||
|
code: 410,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (error.errorType === 'SELL_TAX_RATE_NOT_FOUND') {
|
||||||
|
return res.status(400).send({
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
type: 'SELL_TAX_RATE_NOT_FOUND',
|
||||||
|
message: 'Sell tax rate is not found.',
|
||||||
|
code: 420,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ export default class BillsController extends BaseController {
|
|||||||
check('note').optional().trim().escape(),
|
check('note').optional().trim().escape(),
|
||||||
check('open').default(false).isBoolean().toBoolean(),
|
check('open').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
|
check('is_inclusive_tax').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('entries').isArray({ min: 1 }),
|
check('entries').isArray({ min: 1 }),
|
||||||
|
|
||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
@@ -137,6 +139,15 @@ export default class BillsController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
|
check('entries.*.tax_code')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape()
|
||||||
|
.isString(),
|
||||||
|
check('entries.*.tax_rate_id')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.isNumeric()
|
||||||
|
.toInt(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,6 +553,16 @@ export default class BillsController extends BaseController {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (error.errorType === 'ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND') {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: 'ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND', code: 1800 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (error.errorType === 'ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND') {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: 'ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND', code: 1900 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
exports.up = (knex) => {
|
||||||
|
return knex.schema.table('bills', (table) => {
|
||||||
|
table.boolean('is_inclusive_tax').defaultTo(false);
|
||||||
|
table.decimal('tax_amount_withheld');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = (knex) => {
|
||||||
|
return knex.schema.table('bills', () => {});
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
exports.up = (knex) => {
|
||||||
|
return knex.schema.table('items', (table) => {
|
||||||
|
table
|
||||||
|
.integer('sell_tax_rate_id')
|
||||||
|
.unsigned()
|
||||||
|
.references('id')
|
||||||
|
.inTable('tax_rates');
|
||||||
|
table
|
||||||
|
.integer('purchase_tax_rate_id')
|
||||||
|
.unsigned()
|
||||||
|
.references('id')
|
||||||
|
.inTable('tax_rates');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = (knex) => {
|
||||||
|
return knex.schema.dropTableIfExists('tax_rates');
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import { Knex } from 'knex';
|
|||||||
import { IDynamicListFilterDTO } from './DynamicFilter';
|
import { IDynamicListFilterDTO } from './DynamicFilter';
|
||||||
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
||||||
import { IBillLandedCost } from './LandedCost';
|
import { IBillLandedCost } from './LandedCost';
|
||||||
|
|
||||||
export interface IBillDTO {
|
export interface IBillDTO {
|
||||||
vendorId: number;
|
vendorId: number;
|
||||||
billNumber: string;
|
billNumber: string;
|
||||||
@@ -15,10 +16,10 @@ export interface IBillDTO {
|
|||||||
exchangeRate?: number;
|
exchangeRate?: number;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
entries: IItemEntryDTO[];
|
entries: IItemEntryDTO[];
|
||||||
|
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
projectId?: number;
|
projectId?: number;
|
||||||
|
isInclusiveTax?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBillEditDTO {
|
export interface IBillEditDTO {
|
||||||
@@ -80,6 +81,15 @@ export interface IBill {
|
|||||||
|
|
||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
locatedLandedCosts?: IBillLandedCost[];
|
locatedLandedCosts?: IBillLandedCost[];
|
||||||
|
|
||||||
|
amountLocal: number;
|
||||||
|
subtotal: number;
|
||||||
|
subtotalLocal: number;
|
||||||
|
subtotalExcludingTax: number;
|
||||||
|
taxAmountWithheld: number;
|
||||||
|
taxAmountWithheldLocal: number;
|
||||||
|
total: number;
|
||||||
|
totalLocal: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBillsFilter extends IDynamicListFilterDTO {
|
export interface IBillsFilter extends IDynamicListFilterDTO {
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ export interface IItem {
|
|||||||
sellDescription: string;
|
sellDescription: string;
|
||||||
purchaseDescription: string;
|
purchaseDescription: string;
|
||||||
|
|
||||||
|
sellTaxRateId: number;
|
||||||
|
purchaseTaxRateId: number;
|
||||||
|
|
||||||
quantityOnHand: number;
|
quantityOnHand: number;
|
||||||
|
|
||||||
note: string;
|
note: string;
|
||||||
@@ -54,6 +57,9 @@ export interface IItemDTO {
|
|||||||
sellDescription: string;
|
sellDescription: string;
|
||||||
purchaseDescription: string;
|
purchaseDescription: string;
|
||||||
|
|
||||||
|
sellTaxRateId: number;
|
||||||
|
purchaseTaxRateId: number;
|
||||||
|
|
||||||
quantityOnHand: number;
|
quantityOnHand: number;
|
||||||
|
|
||||||
note: string;
|
note: string;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export interface ITaxRateCreatedPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ITaxRateEditingPayload {
|
export interface ITaxRateEditingPayload {
|
||||||
|
oldTaxRate: ITaxRate;
|
||||||
editTaxRateDTO: IEditTaxRateDTO;
|
editTaxRateDTO: IEditTaxRateDTO;
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ import { ProjectBillableBillSubscriber } from '@/services/Projects/Projects/Proj
|
|||||||
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
|
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
|
||||||
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
||||||
import { WriteInvoiceTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteInvoiceTaxTransactionsSubscriber';
|
import { WriteInvoiceTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteInvoiceTaxTransactionsSubscriber';
|
||||||
|
import { BillTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/BillTaxRateValidateSubscriber';
|
||||||
|
import { WriteBillTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteBillTaxTransactionsSubscriber';
|
||||||
|
import { SyncItemTaxRateOnEditTaxSubscriber } from '@/services/TaxRates/SyncItemTaxRateOnEditTaxSubscriber';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -188,8 +191,14 @@ export const susbcribers = () => {
|
|||||||
ProjectBillableExpensesSubscriber,
|
ProjectBillableExpensesSubscriber,
|
||||||
ProjectBillableBillSubscriber,
|
ProjectBillableBillSubscriber,
|
||||||
|
|
||||||
// Tax Rates
|
// Tax Rates - Sale Invoice
|
||||||
SaleInvoiceTaxRateValidateSubscriber,
|
SaleInvoiceTaxRateValidateSubscriber,
|
||||||
WriteInvoiceTaxTransactionsSubscriber,
|
WriteInvoiceTaxTransactionsSubscriber,
|
||||||
|
|
||||||
|
// Tax Rates - Bills
|
||||||
|
BillTaxRateValidateSubscriber,
|
||||||
|
WriteBillTaxTransactionsSubscriber,
|
||||||
|
|
||||||
|
SyncItemTaxRateOnEditTaxSubscriber
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,109 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
public amount: number;
|
||||||
|
public paymentAmount: number;
|
||||||
|
public landedCostAmount: number;
|
||||||
|
public allocatedCostAmount: number;
|
||||||
|
public isInclusiveTax: boolean;
|
||||||
|
public taxAmountWithheld: number;
|
||||||
|
public exchangeRate: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamps columns.
|
||||||
|
*/
|
||||||
|
get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual attributes.
|
||||||
|
*/
|
||||||
|
static get virtualAttributes() {
|
||||||
|
return [
|
||||||
|
'balance',
|
||||||
|
'dueAmount',
|
||||||
|
'isOpen',
|
||||||
|
'isPartiallyPaid',
|
||||||
|
'isFullyPaid',
|
||||||
|
'isPaid',
|
||||||
|
'remainingDays',
|
||||||
|
'overdueDays',
|
||||||
|
'isOverdue',
|
||||||
|
'unallocatedCostAmount',
|
||||||
|
'localAmount',
|
||||||
|
'localAllocatedCostAmount',
|
||||||
|
'billableAmount',
|
||||||
|
'amountLocal',
|
||||||
|
'subtotal',
|
||||||
|
'subtotalLocal',
|
||||||
|
'subtotalExludingTax',
|
||||||
|
'taxAmountWithheldLocal',
|
||||||
|
'total',
|
||||||
|
'totalLocal',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice amount in base currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get amountLocal() {
|
||||||
|
return this.amount * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtotal. (Tax inclusive) if the tax inclusive is enabled.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotal() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtotal in base currency. (Tax inclusive) if the tax inclusive is enabled.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalLocal() {
|
||||||
|
return this.amountLocal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sale invoice amount excluding tax.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalExcludingTax() {
|
||||||
|
return this.isInclusiveTax
|
||||||
|
? this.subtotal - this.taxAmountWithheld
|
||||||
|
: this.subtotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax amount withheld in base currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get taxAmountWithheldLocal() {
|
||||||
|
return this.taxAmountWithheld * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice total. (Tax included)
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get total() {
|
||||||
|
return this.isInclusiveTax
|
||||||
|
? this.subtotal
|
||||||
|
: this.subtotal + this.taxAmountWithheld;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice total in local currency. (Tax included)
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalLocal() {
|
||||||
|
return this.total * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -158,40 +261,13 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamps columns.
|
|
||||||
*/
|
|
||||||
get timestamps() {
|
|
||||||
return ['createdAt', 'updatedAt'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual attributes.
|
|
||||||
*/
|
|
||||||
static get virtualAttributes() {
|
|
||||||
return [
|
|
||||||
'balance',
|
|
||||||
'dueAmount',
|
|
||||||
'isOpen',
|
|
||||||
'isPartiallyPaid',
|
|
||||||
'isFullyPaid',
|
|
||||||
'isPaid',
|
|
||||||
'remainingDays',
|
|
||||||
'overdueDays',
|
|
||||||
'isOverdue',
|
|
||||||
'unallocatedCostAmount',
|
|
||||||
'localAmount',
|
|
||||||
'localAllocatedCostAmount',
|
|
||||||
'billableAmount',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice amount in organization base currency.
|
* Invoice amount in organization base currency.
|
||||||
|
* @deprecated
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get localAmount() {
|
get localAmount() {
|
||||||
return this.amount * this.exchangeRate;
|
return this.amountLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,7 +307,7 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
get dueAmount() {
|
get dueAmount() {
|
||||||
return Math.max(this.amount - this.balance, 0);
|
return Math.max(this.total - this.balance, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -247,7 +323,7 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
get isPartiallyPaid() {
|
get isPartiallyPaid() {
|
||||||
return this.dueAmount !== this.amount && this.dueAmount > 0;
|
return this.dueAmount !== this.total && this.dueAmount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -308,7 +384,7 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
* Retrieves the calculated amount which have not been invoiced.
|
* Retrieves the calculated amount which have not been invoiced.
|
||||||
*/
|
*/
|
||||||
get billableAmount() {
|
get billableAmount() {
|
||||||
return Math.max(this.amount - this.invoicedAmount, 0);
|
return Math.max(this.total - this.invoicedAmount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -326,6 +402,7 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
const ItemEntry = require('models/ItemEntry');
|
const ItemEntry = require('models/ItemEntry');
|
||||||
const BillLandedCost = require('models/BillLandedCost');
|
const BillLandedCost = require('models/BillLandedCost');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
|
const TaxRateTransaction = require('models/TaxRateTransaction');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vendor: {
|
vendor: {
|
||||||
@@ -373,6 +450,21 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
to: 'branches.id',
|
to: 'branches.id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bill may has associated tax rate transactions.
|
||||||
|
*/
|
||||||
|
taxes: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: TaxRateTransaction.default,
|
||||||
|
join: {
|
||||||
|
from: 'bills.id',
|
||||||
|
to: 'tax_rate_transactions.referenceId',
|
||||||
|
},
|
||||||
|
filter(builder) {
|
||||||
|
builder.where('reference_type', 'Bill');
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export default class Item extends mixin(TenantModel, [
|
|||||||
const ItemEntry = require('models/ItemEntry');
|
const ItemEntry = require('models/ItemEntry');
|
||||||
const WarehouseTransferEntry = require('models/WarehouseTransferEntry');
|
const WarehouseTransferEntry = require('models/WarehouseTransferEntry');
|
||||||
const InventoryAdjustmentEntry = require('models/InventoryAdjustmentEntry');
|
const InventoryAdjustmentEntry = require('models/InventoryAdjustmentEntry');
|
||||||
|
const TaxRate = require('models/TaxRate');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -178,11 +179,35 @@ export default class Item extends mixin(TenantModel, [
|
|||||||
to: 'media.id',
|
to: 'media.id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item may has sell tax rate.
|
||||||
|
*/
|
||||||
|
sellTaxRate: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TaxRate.default,
|
||||||
|
join: {
|
||||||
|
from: 'items.sellTaxRateId',
|
||||||
|
to: 'tax_rates.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item may has purchase tax rate.
|
||||||
|
*/
|
||||||
|
purchaseTaxRate: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TaxRate.default,
|
||||||
|
join: {
|
||||||
|
from: 'items.purchaseTaxRateId',
|
||||||
|
to: 'tax_rates.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static get secureDeleteRelations() {
|
static get secureDeleteRelations() {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -99,6 +99,13 @@ export default class ItemEntry extends TenantModel {
|
|||||||
: getExlusiveTaxAmount(this.amount, this.taxRate);
|
: getExlusiveTaxAmount(this.amount, this.taxRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static calcAmount(itemEntry) {
|
||||||
|
const { discount, quantity, rate } = itemEntry;
|
||||||
|
const total = quantity * rate;
|
||||||
|
|
||||||
|
return discount ? total - total * discount * 0.01 : total;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item entry relations.
|
* Item entry relations.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -55,6 +55,18 @@ export class CreateItem {
|
|||||||
itemDTO.inventoryAccountId
|
itemDTO.inventoryAccountId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (itemDTO.purchaseTaxRateId) {
|
||||||
|
await this.validators.validatePurchaseTaxRateExistance(
|
||||||
|
tenantId,
|
||||||
|
itemDTO.purchaseTaxRateId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (itemDTO.sellTaxRateId) {
|
||||||
|
await this.validators.validateSellTaxRateExistance(
|
||||||
|
tenantId,
|
||||||
|
itemDTO.sellTaxRateId
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -76,6 +76,20 @@ export class EditItem {
|
|||||||
itemDTO.inventoryAccountId
|
itemDTO.inventoryAccountId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Validate the purchase tax rate id existance.
|
||||||
|
if (itemDTO.purchaseTaxRateId) {
|
||||||
|
await this.validators.validatePurchaseTaxRateExistance(
|
||||||
|
tenantId,
|
||||||
|
itemDTO.purchaseTaxRateId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Validate the sell tax rate id existance.
|
||||||
|
if (itemDTO.sellTaxRateId) {
|
||||||
|
await this.validators.validateSellTaxRateExistance(
|
||||||
|
tenantId,
|
||||||
|
itemDTO.sellTaxRateId
|
||||||
|
);
|
||||||
|
}
|
||||||
// Validate inventory account should be modified in inventory item
|
// Validate inventory account should be modified in inventory item
|
||||||
// has inventory transactions.
|
// has inventory transactions.
|
||||||
await this.validators.validateItemInvnetoryAccountModified(
|
await this.validators.validateItemInvnetoryAccountModified(
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ export class GetItem {
|
|||||||
.withGraphFetched('category')
|
.withGraphFetched('category')
|
||||||
.withGraphFetched('costAccount')
|
.withGraphFetched('costAccount')
|
||||||
.withGraphFetched('itemWarehouses.warehouse')
|
.withGraphFetched('itemWarehouses.warehouse')
|
||||||
|
.withGraphFetched('sellTaxRate')
|
||||||
|
.withGraphFetched('purchaseTaxRate')
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
return this.transformer.transform(tenantId, item, new ItemTransformer());
|
return this.transformer.transform(tenantId, item, new ItemTransformer());
|
||||||
|
|||||||
@@ -241,4 +241,40 @@ export class ItemsValidators {
|
|||||||
throw new ServiceError(ERRORS.ITEM_CANNOT_CHANGE_INVENTORY_TYPE);
|
throw new ServiceError(ERRORS.ITEM_CANNOT_CHANGE_INVENTORY_TYPE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the purchase tax rate id existance.
|
||||||
|
* @param {number} tenantId -
|
||||||
|
* @param {number} taxRateId -
|
||||||
|
*/
|
||||||
|
public async validatePurchaseTaxRateExistance(
|
||||||
|
tenantId: number,
|
||||||
|
taxRateId: number
|
||||||
|
) {
|
||||||
|
const { TaxRate } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const foundTaxRate = await TaxRate.query().findById(taxRateId);
|
||||||
|
|
||||||
|
if (!foundTaxRate) {
|
||||||
|
throw new ServiceError(ERRORS.PURCHASE_TAX_RATE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the sell tax rate id existance.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} taxRateId
|
||||||
|
*/
|
||||||
|
public async validateSellTaxRateExistance(
|
||||||
|
tenantId: number,
|
||||||
|
taxRateId: number
|
||||||
|
) {
|
||||||
|
const { TaxRate } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const foundTaxRate = await TaxRate.query().findById(taxRateId);
|
||||||
|
|
||||||
|
if (!foundTaxRate) {
|
||||||
|
throw new ServiceError(ERRORS.SELL_TAX_RATE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ export const ERRORS = {
|
|||||||
TYPE_CANNOT_CHANGE_WITH_ITEM_HAS_TRANSACTIONS: 'TYPE_CANNOT_CHANGE_WITH_ITEM_HAS_TRANSACTIONS',
|
TYPE_CANNOT_CHANGE_WITH_ITEM_HAS_TRANSACTIONS: 'TYPE_CANNOT_CHANGE_WITH_ITEM_HAS_TRANSACTIONS',
|
||||||
INVENTORY_ACCOUNT_CANNOT_MODIFIED: 'INVENTORY_ACCOUNT_CANNOT_MODIFIED',
|
INVENTORY_ACCOUNT_CANNOT_MODIFIED: 'INVENTORY_ACCOUNT_CANNOT_MODIFIED',
|
||||||
|
|
||||||
ITEM_HAS_ASSOCIATED_TRANSACTIONS: 'ITEM_HAS_ASSOCIATED_TRANSACTIONS'
|
ITEM_HAS_ASSOCIATED_TRANSACTIONS: 'ITEM_HAS_ASSOCIATED_TRANSACTIONS',
|
||||||
|
|
||||||
|
PURCHASE_TAX_RATE_NOT_FOUND: 'PURCHASE_TAX_RATE_NOT_FOUND',
|
||||||
|
SELL_TAX_RATE_NOT_FOUND: 'SELL_TAX_RATE_NOT_FOUND',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_VIEW_COLUMNS = [];
|
export const DEFAULT_VIEW_COLUMNS = [];
|
||||||
|
|||||||
@@ -203,8 +203,8 @@ export class BillPaymentGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the payment GL payable entry.
|
* Retrieves the payment GL payable entry.
|
||||||
* @param {IBillPayment} billPayment
|
* @param {IBillPayment} billPayment
|
||||||
* @param {number} APAccountId
|
* @param {number} APAccountId
|
||||||
* @returns {ILedgerEntry}
|
* @returns {ILedgerEntry}
|
||||||
*/
|
*/
|
||||||
private getPaymentGLPayableEntry = (
|
private getPaymentGLPayableEntry = (
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
|
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class BillDTOTransformer {
|
export class BillDTOTransformer {
|
||||||
@@ -23,6 +24,9 @@ export class BillDTOTransformer {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private warehouseDTOTransform: WarehouseTransactionDTOTransform;
|
private warehouseDTOTransform: WarehouseTransactionDTOTransform;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private taxDTOTransformer: ItemEntriesTaxTransactions;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
@@ -73,14 +77,24 @@ export class BillDTOTransformer {
|
|||||||
const billNumber = billDTO.billNumber || oldBill?.billNumber;
|
const billNumber = billDTO.billNumber || oldBill?.billNumber;
|
||||||
|
|
||||||
const initialEntries = billDTO.entries.map((entry) => ({
|
const initialEntries = billDTO.entries.map((entry) => ({
|
||||||
reference_type: 'Bill',
|
referenceType: 'Bill',
|
||||||
|
isInclusiveTax: billDTO.isInclusiveTax,
|
||||||
...omit(entry, ['amount']),
|
...omit(entry, ['amount']),
|
||||||
}));
|
}));
|
||||||
const entries = await composeAsync(
|
const asyncEntries = await composeAsync(
|
||||||
|
// Associate tax rate from tax id to entries.
|
||||||
|
this.taxDTOTransformer.assocTaxRateFromTaxIdToEntries(tenantId),
|
||||||
|
// Associate tax rate id from tax code to entries.
|
||||||
|
this.taxDTOTransformer.assocTaxRateIdFromCodeToEntries(tenantId),
|
||||||
// Sets the default cost account to the bill entries.
|
// Sets the default cost account to the bill entries.
|
||||||
this.setBillEntriesDefaultAccounts(tenantId)
|
this.setBillEntriesDefaultAccounts(tenantId)
|
||||||
)(initialEntries);
|
)(initialEntries);
|
||||||
|
|
||||||
|
const entries = R.compose(
|
||||||
|
// Remove tax code from entries.
|
||||||
|
R.map(R.omit(['taxCode']))
|
||||||
|
)(asyncEntries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
...formatDateFields(omit(billDTO, ['open', 'entries']), [
|
...formatDateFields(omit(billDTO, ['open', 'entries']), [
|
||||||
'billDate',
|
'billDate',
|
||||||
@@ -100,6 +114,8 @@ export class BillDTOTransformer {
|
|||||||
userId: authorizedUser.id,
|
userId: authorizedUser.id,
|
||||||
};
|
};
|
||||||
return R.compose(
|
return R.compose(
|
||||||
|
// Associates tax amount withheld to the model.
|
||||||
|
this.taxDTOTransformer.assocTaxAmountWithheldFromEntries,
|
||||||
this.branchDTOTransform.transformDTO(tenantId),
|
this.branchDTOTransform.transformDTO(tenantId),
|
||||||
this.warehouseDTOTransform.transformDTO(tenantId)
|
this.warehouseDTOTransform.transformDTO(tenantId)
|
||||||
)(initialDTO);
|
)(initialDTO);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { AccountNormal, IBill, IItemEntry, ILedgerEntry } from '@/interfaces';
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import Ledger from '@/services/Accounting/Ledger';
|
import Ledger from '@/services/Accounting/Ledger';
|
||||||
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||||
|
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class BillGLEntries {
|
export class BillGLEntries {
|
||||||
@@ -16,6 +17,9 @@ export class BillGLEntries {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private ledgerStorage: LedgerStorageService;
|
private ledgerStorage: LedgerStorageService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private itemsEntriesService: ItemsEntriesService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates bill GL entries.
|
* Creates bill GL entries.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
@@ -43,8 +47,16 @@ export class BillGLEntries {
|
|||||||
{},
|
{},
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
const billLedger = this.getBillLedger(bill, APAccount.id);
|
// Find or create tax payable account.
|
||||||
|
const taxPayableAccount = await accountRepository.findOrCreateTaxPayable(
|
||||||
|
{},
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
const billLedger = this.getBillLedger(
|
||||||
|
bill,
|
||||||
|
APAccount.id,
|
||||||
|
taxPayableAccount.id
|
||||||
|
);
|
||||||
// Commit the GL enties on the storage.
|
// Commit the GL enties on the storage.
|
||||||
await this.ledgerStorage.commit(tenantId, billLedger, trx);
|
await this.ledgerStorage.commit(tenantId, billLedger, trx);
|
||||||
};
|
};
|
||||||
@@ -83,7 +95,7 @@ export class BillGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the bill common entry.
|
* Retrieves the bill common entry.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
* @returns {ILedgerEntry}
|
* @returns {ILedgerEntry}
|
||||||
*/
|
*/
|
||||||
private getBillCommonEntry = (bill: IBill) => {
|
private getBillCommonEntry = (bill: IBill) => {
|
||||||
@@ -119,7 +131,7 @@ export class BillGLEntries {
|
|||||||
(bill: IBill, entry: IItemEntry, index: number): ILedgerEntry => {
|
(bill: IBill, entry: IItemEntry, index: number): ILedgerEntry => {
|
||||||
const commonJournalMeta = this.getBillCommonEntry(bill);
|
const commonJournalMeta = this.getBillCommonEntry(bill);
|
||||||
|
|
||||||
const localAmount = bill.exchangeRate * entry.amount;
|
const localAmount = bill.exchangeRate * entry.amountExludingTax;
|
||||||
const landedCostAmount = sumBy(entry.allocatedCostEntries, 'cost');
|
const landedCostAmount = sumBy(entry.allocatedCostEntries, 'cost');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -173,7 +185,7 @@ export class BillGLEntries {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...commonJournalMeta,
|
...commonJournalMeta,
|
||||||
credit: bill.localAmount,
|
credit: bill.totalLocal,
|
||||||
accountId: payableAccountId,
|
accountId: payableAccountId,
|
||||||
contactId: bill.vendorId,
|
contactId: bill.vendorId,
|
||||||
accountNormal: AccountNormal.CREDIT,
|
accountNormal: AccountNormal.CREDIT,
|
||||||
@@ -182,15 +194,62 @@ export class BillGLEntries {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the bill tax GL entry.
|
||||||
|
* @param {IBill} bill -
|
||||||
|
* @param {number} taxPayableAccountId -
|
||||||
|
* @param {IItemEntry} entry -
|
||||||
|
* @param {number} index -
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getBillTaxEntry = R.curry(
|
||||||
|
(
|
||||||
|
bill: IBill,
|
||||||
|
taxPayableAccountId: number,
|
||||||
|
entry: IItemEntry,
|
||||||
|
index: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonJournalMeta = this.getBillCommonEntry(bill);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonJournalMeta,
|
||||||
|
debit: entry.taxAmount,
|
||||||
|
index,
|
||||||
|
indexGroup: 30,
|
||||||
|
accountId: taxPayableAccountId,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
taxRateId: entry.taxRateId,
|
||||||
|
taxRate: entry.taxRate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the bill tax GL entries.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @param {number} taxPayableAccountId
|
||||||
|
* @returns {ILedgerEntry[]}
|
||||||
|
*/
|
||||||
|
private getBillTaxEntries = (bill: IBill, taxPayableAccountId: number) => {
|
||||||
|
// Retrieves the non-zero tax entries.
|
||||||
|
const nonZeroTaxEntries = this.itemsEntriesService.getNonZeroEntries(
|
||||||
|
bill.entries
|
||||||
|
);
|
||||||
|
const transformTaxEntry = this.getBillTaxEntry(bill, taxPayableAccountId);
|
||||||
|
|
||||||
|
return nonZeroTaxEntries.map(transformTaxEntry);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the given bill GL entries.
|
* Retrieves the given bill GL entries.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
* @param {number} payableAccountId
|
* @param {number} payableAccountId
|
||||||
* @returns {ILedgerEntry[]}
|
* @returns {ILedgerEntry[]}
|
||||||
*/
|
*/
|
||||||
private getBillGLEntries = (
|
private getBillGLEntries = (
|
||||||
bill: IBill,
|
bill: IBill,
|
||||||
payableAccountId: number
|
payableAccountId: number,
|
||||||
|
taxPayableAccountId: number
|
||||||
): ILedgerEntry[] => {
|
): ILedgerEntry[] => {
|
||||||
const payableEntry = this.getBillPayableEntry(payableAccountId, bill);
|
const payableEntry = this.getBillPayableEntry(payableAccountId, bill);
|
||||||
|
|
||||||
@@ -201,18 +260,28 @@ export class BillGLEntries {
|
|||||||
const landedCostEntries = bill.locatedLandedCosts.map(
|
const landedCostEntries = bill.locatedLandedCosts.map(
|
||||||
landedCostTransformer
|
landedCostTransformer
|
||||||
);
|
);
|
||||||
|
const taxEntries = this.getBillTaxEntries(bill, taxPayableAccountId);
|
||||||
|
|
||||||
// Allocate cost entries journal entries.
|
// Allocate cost entries journal entries.
|
||||||
return [payableEntry, ...itemsEntries, ...landedCostEntries];
|
return [payableEntry, ...itemsEntries, ...landedCostEntries, ...taxEntries];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the given bill ledger.
|
* Retrieves the given bill ledger.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
* @param {number} payableAccountId
|
* @param {number} payableAccountId
|
||||||
* @returns {Ledger}
|
* @returns {Ledger}
|
||||||
*/
|
*/
|
||||||
private getBillLedger = (bill: IBill, payableAccountId: number) => {
|
private getBillLedger = (
|
||||||
const entries = this.getBillGLEntries(bill, payableAccountId);
|
bill: IBill,
|
||||||
|
payableAccountId: number,
|
||||||
|
taxPayableAccountId: number
|
||||||
|
) => {
|
||||||
|
const entries = this.getBillGLEntries(
|
||||||
|
bill,
|
||||||
|
payableAccountId,
|
||||||
|
taxPayableAccountId
|
||||||
|
);
|
||||||
|
|
||||||
return new Ledger(entries);
|
return new Ledger(entries);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ export class GetBill {
|
|||||||
.findById(billId)
|
.findById(billId)
|
||||||
.withGraphFetched('vendor')
|
.withGraphFetched('vendor')
|
||||||
.withGraphFetched('entries.item')
|
.withGraphFetched('entries.item')
|
||||||
.withGraphFetched('branch');
|
.withGraphFetched('branch')
|
||||||
|
.withGraphFetched('taxes.taxRate');
|
||||||
|
|
||||||
// Validates the bill existance.
|
// Validates the bill existance.
|
||||||
this.validators.validateBillExistance(bill);
|
this.validators.validateBillExistance(bill);
|
||||||
|
|||||||
@@ -1,27 +1,42 @@
|
|||||||
import { IBill } from '@/interfaces';
|
import { IBill } from '@/interfaces';
|
||||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||||
|
import { SaleInvoiceTaxEntryTransformer } from '@/services/Sales/Invoices/SaleInvoiceTaxEntryTransformer';
|
||||||
import { formatNumber } from 'utils';
|
import { formatNumber } from 'utils';
|
||||||
|
|
||||||
export class PurchaseInvoiceTransformer extends Transformer {
|
export class PurchaseInvoiceTransformer extends Transformer {
|
||||||
/**
|
/**
|
||||||
* Include these attributes to sale invoice object.
|
* Include these attributes to sale bill object.
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return [
|
return [
|
||||||
'formattedBillDate',
|
'formattedBillDate',
|
||||||
'formattedDueDate',
|
'formattedDueDate',
|
||||||
'formattedAmount',
|
|
||||||
'formattedPaymentAmount',
|
'formattedPaymentAmount',
|
||||||
'formattedBalance',
|
'formattedBalance',
|
||||||
'formattedDueAmount',
|
'formattedDueAmount',
|
||||||
'formattedExchangeRate',
|
'formattedExchangeRate',
|
||||||
|
'subtotalFormatted',
|
||||||
|
'subtotalLocalFormatted',
|
||||||
|
'subtotalExcludingTaxFormatted',
|
||||||
|
'taxAmountWithheldLocalFormatted',
|
||||||
|
'totalFormatted',
|
||||||
|
'totalLocalFormatted',
|
||||||
|
'taxes',
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted invoice date.
|
* Excluded attributes.
|
||||||
* @param {IBill} invoice
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
public excludeAttributes = (): string[] => {
|
||||||
|
return ['amount', 'amountLocal', 'localAmount'];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve formatted bill date.
|
||||||
|
* @param {IBill} bill
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
protected formattedBillDate = (bill: IBill): string => {
|
protected formattedBillDate = (bill: IBill): string => {
|
||||||
@@ -29,8 +44,8 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted invoice date.
|
* Retrieve formatted bill date.
|
||||||
* @param {IBill} invoice
|
* @param {IBill} bill
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
protected formattedDueDate = (bill: IBill): string => {
|
protected formattedDueDate = (bill: IBill): string => {
|
||||||
@@ -39,7 +54,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted bill amount.
|
* Retrieve formatted bill amount.
|
||||||
* @param {IBill} invoice
|
* @param {IBill} bill
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedAmount = (bill): string => {
|
protected formattedAmount = (bill): string => {
|
||||||
@@ -48,7 +63,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted bill amount.
|
* Retrieve formatted bill amount.
|
||||||
* @param {IBill} invoice
|
* @param {IBill} bill
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedPaymentAmount = (bill): string => {
|
protected formattedPaymentAmount = (bill): string => {
|
||||||
@@ -59,7 +74,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted bill amount.
|
* Retrieve formatted bill amount.
|
||||||
* @param {IBill} invoice
|
* @param {IBill} bill
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedDueAmount = (bill): string => {
|
protected formattedDueAmount = (bill): string => {
|
||||||
@@ -77,10 +92,90 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the formatted exchange rate.
|
* Retrieve the formatted exchange rate.
|
||||||
* @param {ISaleInvoice} invoice
|
* @param {IBill} bill
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedExchangeRate = (invoice): string => {
|
protected formattedExchangeRate = (bill): string => {
|
||||||
return formatNumber(invoice.exchangeRate, { money: false });
|
return formatNumber(bill.exchangeRate, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted subtotal.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected subtotalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.subtotal, {
|
||||||
|
currencyCode: bill.currencyCode,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the local subtotal formatted.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected subtotalLocalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.subtotalLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted subtotal tax excluded.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected subtotalExcludingTaxFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.subtotalExludingTax, {
|
||||||
|
currencyCode: bill.currencyCode,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the local formatted tax amount withheld
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected taxAmountWithheldLocalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.taxAmountWithheldLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the total formatted.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.total, {
|
||||||
|
currencyCode: bill.currencyCode,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the local total formatted.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalLocalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.totalLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the taxes lines of bill.
|
||||||
|
* @param {Bill} bill
|
||||||
|
*/
|
||||||
|
protected taxes = (bill) => {
|
||||||
|
return this.item(bill.taxes, new SaleInvoiceTaxEntryTransformer(), {
|
||||||
|
subtotal: bill.subtotal,
|
||||||
|
isInclusiveTax: bill.isInclusiveTax,
|
||||||
|
currencyCode: bill.currencyCode,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,8 @@ export class SaleInvoiceGLEntries {
|
|||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: entry.taxAmount,
|
credit: entry.taxAmount,
|
||||||
accountId: taxPayableAccountId,
|
accountId: taxPayableAccountId,
|
||||||
index: index + 3,
|
index: index + 1,
|
||||||
|
indexGroup: 30,
|
||||||
accountNormal: AccountNormal.CREDIT,
|
accountNormal: AccountNormal.CREDIT,
|
||||||
taxRateId: entry.taxRateId,
|
taxRateId: entry.taxRateId,
|
||||||
taxRate: entry.taxRate,
|
taxRate: entry.taxRate,
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ export class SaleInvoiceTaxEntryTransformer extends Transformer {
|
|||||||
const taxRate = this.taxRate(taxEntry);
|
const taxRate = this.taxRate(taxEntry);
|
||||||
|
|
||||||
return this.options.isInclusiveTax
|
return this.options.isInclusiveTax
|
||||||
? getInclusiveTaxAmount(this.options.amount, taxRate)
|
? getInclusiveTaxAmount(this.options.subtotal, taxRate)
|
||||||
: getExlusiveTaxAmount(this.options.amount, taxRate);
|
: getExlusiveTaxAmount(this.options.subtotal, taxRate);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ export class SaleInvoiceTransformer extends Transformer {
|
|||||||
*/
|
*/
|
||||||
protected taxes = (invoice) => {
|
protected taxes = (invoice) => {
|
||||||
return this.item(invoice.taxes, new SaleInvoiceTaxEntryTransformer(), {
|
return this.item(invoice.taxes, new SaleInvoiceTaxEntryTransformer(), {
|
||||||
amount: invoice.amount,
|
subtotal: invoice.subtotal,
|
||||||
isInclusiveTax: invoice.isInclusiveTax,
|
isInclusiveTax: invoice.isInclusiveTax,
|
||||||
currencyCode: invoice.currencyCode,
|
currencyCode: invoice.currencyCode,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ export class EditTaxRateService {
|
|||||||
// Triggers `onTaxRateEdited` event.
|
// Triggers `onTaxRateEdited` event.
|
||||||
await this.eventPublisher.emitAsync(events.taxRates.onEdited, {
|
await this.eventPublisher.emitAsync(events.taxRates.onEdited, {
|
||||||
editTaxRateDTO,
|
editTaxRateDTO,
|
||||||
|
oldTaxRate,
|
||||||
taxRate,
|
taxRate,
|
||||||
tenantId,
|
tenantId,
|
||||||
trx,
|
trx,
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SyncItemTaxRateOnEditTaxRate {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the new tax rate created to item default sell tax rate.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} itemId
|
||||||
|
* @param {number} sellTaxRateId
|
||||||
|
*/
|
||||||
|
public updateItemSellTaxRate = async (
|
||||||
|
tenantId: number,
|
||||||
|
oldSellTaxRateId: number,
|
||||||
|
sellTaxRateId: number,
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) => {
|
||||||
|
const { Item } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
// Can't continue if the old and new sell tax rate id are equal.
|
||||||
|
if (oldSellTaxRateId === sellTaxRateId) return;
|
||||||
|
|
||||||
|
await Item.query().where('sellTaxRateId', oldSellTaxRateId).update({
|
||||||
|
sellTaxRateId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the new tax rate created to item default purchase tax rate.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} itemId
|
||||||
|
* @param {number} purchaseTaxRateId
|
||||||
|
*/
|
||||||
|
public updateItemPurchaseTaxRate = async (
|
||||||
|
tenantId: number,
|
||||||
|
oldPurchaseTaxRateId: number,
|
||||||
|
purchaseTaxRateId: number,
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) => {
|
||||||
|
const { Item } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
// Can't continue if the old and new sell tax rate id are equal.
|
||||||
|
if (oldPurchaseTaxRateId === purchaseTaxRateId) return;
|
||||||
|
|
||||||
|
await Item.query(trx)
|
||||||
|
.where('purchaseTaxRateId', oldPurchaseTaxRateId)
|
||||||
|
.update({
|
||||||
|
purchaseTaxRateId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { ITaxRateEditedPayload } from '@/interfaces';
|
||||||
|
import { runAfterTransaction } from '../UnitOfWork/TransactionsHooks';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SyncItemTaxRateOnEditTaxSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private syncItemRateOnEdit: SyncItemTaxRateOnEditTaxRate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches events with handles.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.taxRates.onEdited,
|
||||||
|
this.handleSyncNewTaxRateToItemTaxRate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the new tax rate created to default item tax rates.
|
||||||
|
* @param {ITaxRateEditedPayload} payload -
|
||||||
|
*/
|
||||||
|
private handleSyncNewTaxRateToItemTaxRate = async ({
|
||||||
|
taxRate,
|
||||||
|
tenantId,
|
||||||
|
oldTaxRate,
|
||||||
|
trx,
|
||||||
|
}: ITaxRateEditedPayload) => {
|
||||||
|
runAfterTransaction(trx, async () => {
|
||||||
|
await this.syncItemRateOnEdit.updateItemPurchaseTaxRate(
|
||||||
|
tenantId,
|
||||||
|
oldTaxRate.id,
|
||||||
|
taxRate.id
|
||||||
|
);
|
||||||
|
await this.syncItemRateOnEdit.updateItemSellTaxRate(
|
||||||
|
tenantId,
|
||||||
|
oldTaxRate.id,
|
||||||
|
taxRate.id
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { IBillCreatingPayload, IBillEditingPayload } from '@/interfaces';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { CommandTaxRatesValidators } from '../CommandTaxRatesValidators';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class BillTaxRateValidateSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private taxRateDTOValidator: CommandTaxRatesValidators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches events with handlers.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onCreating,
|
||||||
|
this.validateBillEntriesTaxCodeExistanceOnCreating
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onCreating,
|
||||||
|
this.validateBillEntriesTaxIdExistanceOnCreating
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onEditing,
|
||||||
|
this.validateBillEntriesTaxCodeExistanceOnEditing
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onEditing,
|
||||||
|
this.validateBillEntriesTaxIdExistanceOnEditing
|
||||||
|
);
|
||||||
|
return bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate bill entries tax rate code existance when creating.
|
||||||
|
* @param {IBillCreatingPayload}
|
||||||
|
*/
|
||||||
|
private validateBillEntriesTaxCodeExistanceOnCreating = async ({
|
||||||
|
billDTO,
|
||||||
|
tenantId,
|
||||||
|
}: IBillCreatingPayload) => {
|
||||||
|
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||||
|
tenantId,
|
||||||
|
billDTO.entries
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the tax rate id existance when creating.
|
||||||
|
* @param {IBillCreatingPayload}
|
||||||
|
*/
|
||||||
|
private validateBillEntriesTaxIdExistanceOnCreating = async ({
|
||||||
|
billDTO,
|
||||||
|
tenantId,
|
||||||
|
}: IBillCreatingPayload) => {
|
||||||
|
await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||||
|
tenantId,
|
||||||
|
billDTO.entries
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate bill entries tax rate code existance when editing.
|
||||||
|
* @param {IBillEditingPayload}
|
||||||
|
*/
|
||||||
|
private validateBillEntriesTaxCodeExistanceOnEditing = async ({
|
||||||
|
tenantId,
|
||||||
|
billDTO,
|
||||||
|
}: IBillEditingPayload) => {
|
||||||
|
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||||
|
tenantId,
|
||||||
|
billDTO.entries
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the bill entries tax rate id existance when editing.
|
||||||
|
* @param {ISaleInvoiceEditingPayload} payload -
|
||||||
|
*/
|
||||||
|
private validateBillEntriesTaxIdExistanceOnEditing = async ({
|
||||||
|
tenantId,
|
||||||
|
billDTO,
|
||||||
|
}: IBillEditingPayload) => {
|
||||||
|
await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||||
|
tenantId,
|
||||||
|
billDTO.entries
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import {
|
||||||
|
IBIllEventDeletedPayload,
|
||||||
|
IBillCreatedPayload,
|
||||||
|
IBillEditedPayload,
|
||||||
|
ISaleInvoiceCreatedPayload,
|
||||||
|
ISaleInvoiceDeletedPayload,
|
||||||
|
ISaleInvoiceEditedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class WriteBillTaxTransactionsSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private writeTaxTransactions: WriteTaxTransactionsItemEntries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches events with handlers.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onCreated,
|
||||||
|
this.writeInvoiceTaxTransactionsOnCreated
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onEdited,
|
||||||
|
this.rewriteInvoiceTaxTransactionsOnEdited
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bill.onDeleted,
|
||||||
|
this.removeInvoiceTaxTransactionsOnDeleted
|
||||||
|
);
|
||||||
|
return bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the bill tax transactions on invoice created.
|
||||||
|
* @param {ISaleInvoiceCreatingPaylaod}
|
||||||
|
*/
|
||||||
|
private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||||
|
tenantId,
|
||||||
|
bill,
|
||||||
|
trx,
|
||||||
|
}: IBillCreatedPayload) => {
|
||||||
|
await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||||
|
tenantId,
|
||||||
|
bill.entries,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewrites the bill tax transactions on invoice edited.
|
||||||
|
* @param {IBillEditedPayload} payload -
|
||||||
|
*/
|
||||||
|
private rewriteInvoiceTaxTransactionsOnEdited = async ({
|
||||||
|
tenantId,
|
||||||
|
bill,
|
||||||
|
trx,
|
||||||
|
}: IBillEditedPayload) => {
|
||||||
|
await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||||
|
tenantId,
|
||||||
|
bill.entries,
|
||||||
|
'Bill',
|
||||||
|
bill.id,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the invoice tax transactions on invoice deleted.
|
||||||
|
* @param {IBIllEventDeletedPayload}
|
||||||
|
*/
|
||||||
|
private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||||
|
tenantId,
|
||||||
|
oldBill,
|
||||||
|
trx,
|
||||||
|
}: IBIllEventDeletedPayload) => {
|
||||||
|
await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||||
|
tenantId,
|
||||||
|
oldBill.id,
|
||||||
|
'Bill',
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import events from '@/subscribers/events';
|
|
||||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
|
||||||
import BillsService from '@/services/Purchases/Bills';
|
|
||||||
import {
|
|
||||||
IBillCreatedPayload,
|
|
||||||
IBillEditedPayload,
|
|
||||||
IBIllEventDeletedPayload,
|
|
||||||
} from '@/interfaces';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export default class BillWriteGLEntriesSubscriber {
|
|
||||||
@Inject()
|
|
||||||
tenancy: TenancyService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
billsService: BillsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attaches events with handles.
|
|
||||||
*/
|
|
||||||
public attach(bus) {
|
|
||||||
bus.subscribe(
|
|
||||||
events.bill.onCreated,
|
|
||||||
this.handlerWriteJournalEntriesOnCreate
|
|
||||||
);
|
|
||||||
bus.subscribe(
|
|
||||||
events.bill.onEdited,
|
|
||||||
this.handleOverwriteJournalEntriesOnEdit
|
|
||||||
);
|
|
||||||
bus.subscribe(events.bill.onDeleted, this.handlerDeleteJournalEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles writing journal entries once bill created.
|
|
||||||
* @param {IBillCreatedPayload} payload -
|
|
||||||
*/
|
|
||||||
private handlerWriteJournalEntriesOnCreate = async ({
|
|
||||||
tenantId,
|
|
||||||
billId,
|
|
||||||
bill,
|
|
||||||
trx,
|
|
||||||
}: IBillCreatedPayload) => {
|
|
||||||
// Can't continue if the bill is not opened yet.
|
|
||||||
if (!bill.openedAt) return null;
|
|
||||||
|
|
||||||
await this.billsService.recordJournalTransactions(
|
|
||||||
tenantId,
|
|
||||||
billId,
|
|
||||||
false,
|
|
||||||
trx
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the overwriting journal entries once bill edited.
|
|
||||||
* @param {IBillEditedPayload} payload -
|
|
||||||
*/
|
|
||||||
private handleOverwriteJournalEntriesOnEdit = async ({
|
|
||||||
tenantId,
|
|
||||||
billId,
|
|
||||||
bill,
|
|
||||||
trx,
|
|
||||||
}: IBillEditedPayload) => {
|
|
||||||
// Can't continue if the bill is not opened yet.
|
|
||||||
if (!bill.openedAt) return null;
|
|
||||||
|
|
||||||
await this.billsService.recordJournalTransactions(
|
|
||||||
tenantId,
|
|
||||||
billId,
|
|
||||||
true,
|
|
||||||
trx
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles revert journal entries on bill deleted.
|
|
||||||
* @param {IBIllEventDeletedPayload} payload -
|
|
||||||
*/
|
|
||||||
private handlerDeleteJournalEntries = async ({
|
|
||||||
tenantId,
|
|
||||||
billId,
|
|
||||||
trx,
|
|
||||||
}: IBIllEventDeletedPayload) => {
|
|
||||||
await this.billsService.revertJournalEntries(tenantId, billId, trx);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
@bigcapitalhq:registry=https://npm.pkg.github.com
|
|
||||||
@@ -1,18 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
|
||||||
const dotenv = require('dotenv-webpack');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
webpack: {
|
webpack: {
|
||||||
plugins: [
|
|
||||||
new dotenv(),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
MONOREPO_VERSION: JSON.stringify(require('../../lerna.json').version),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
|
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(__dirname, 'src'),
|
'@': path.resolve(__dirname, 'src'),
|
||||||
},
|
},
|
||||||
|
|||||||
17753
packages/webapp/package-lock.json
generated
17753
packages/webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "@bigcapital/webapp",
|
"name": "@bigcapital/webapp",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blueprintjs-formik/core": "^0.3.4",
|
"@blueprintjs-formik/core": "^0.3.6",
|
||||||
"@blueprintjs-formik/datetime": "^0.3.4",
|
"@blueprintjs-formik/datetime": "^0.3.7",
|
||||||
"@blueprintjs-formik/select": "^0.3.2",
|
"@blueprintjs-formik/select": "^0.3.5",
|
||||||
"@blueprintjs/core": "^3.50.2",
|
"@blueprintjs/colors": "4.1.19",
|
||||||
"@blueprintjs/datetime": "^3.23.12",
|
"@blueprintjs/core": "^4.20.2",
|
||||||
|
"@blueprintjs/datetime": "^4.4.37",
|
||||||
"@blueprintjs/popover2": "^0.11.1",
|
"@blueprintjs/popover2": "^0.11.1",
|
||||||
"@blueprintjs/select": "^3.11.2",
|
"@blueprintjs/select": "^4.9.24",
|
||||||
"@blueprintjs/table": "^3.8.3",
|
"@blueprintjs/table": "^4.10.12",
|
||||||
"@blueprintjs/timezone": "^3.6.2",
|
"@blueprintjs/timezone": "^4.5.43",
|
||||||
"@casl/ability": "^5.4.3",
|
"@casl/ability": "^5.4.3",
|
||||||
"@casl/react": "^2.3.0",
|
"@casl/react": "^2.3.0",
|
||||||
"@craco/craco": "^5.9.0",
|
"@craco/craco": "^5.9.0",
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
"@types/ramda": "^0.28.14",
|
"@types/ramda": "^0.28.14",
|
||||||
"@types/react": "^16.14.28",
|
"@types/react": "^16.14.28",
|
||||||
"@types/react-body-classname": "^1.1.7",
|
"@types/react-body-classname": "^1.1.7",
|
||||||
|
"@types/react-dom": "^16.9.16",
|
||||||
"@types/react-redux": "^7.1.24",
|
"@types/react-redux": "^7.1.24",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-transition-group": "^4.4.5",
|
"@types/react-transition-group": "^4.4.5",
|
||||||
@@ -38,44 +40,49 @@
|
|||||||
"axios": "^0.21.2",
|
"axios": "^0.21.2",
|
||||||
"basscss": "^8.0.2",
|
"basscss": "^8.0.2",
|
||||||
"camelcase": "^5.3.1",
|
"camelcase": "^5.3.1",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"deep-map-keys": "^2.0.1",
|
|
||||||
"deepdash": "^5.3.9",
|
"deepdash": "^5.3.9",
|
||||||
"dependency-graph": "^0.11.0",
|
"dependency-graph": "^0.11.0",
|
||||||
"dotenv-webpack": "^8.0.1",
|
"dotenv-webpack": "^8.0.1",
|
||||||
|
"eslint": "^8.33.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"flat": "^5.0.2",
|
"flat": "^5.0.2",
|
||||||
"formik": "^2.2.5",
|
"formik": "^2.2.5",
|
||||||
|
"history": "4.10.1",
|
||||||
"http-proxy-middleware": "^1.0.0",
|
"http-proxy-middleware": "^1.0.0",
|
||||||
"jest": "24.9.0",
|
"jest": "24.9.0",
|
||||||
"jest-environment-jsdom-fourteen": "1.0.1",
|
"jest-environment-jsdom-fourteen": "1.0.1",
|
||||||
"jest-resolve": "24.9.0",
|
"jest-resolve": "24.9.0",
|
||||||
"jest-watch-typeahead": "0.4.2",
|
"jest-watch-typeahead": "0.4.2",
|
||||||
|
"js-cookie": "2.2.1",
|
||||||
"js-money": "^0.6.3",
|
"js-money": "^0.6.3",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"moment-timezone": "^0.5.33",
|
"moment-timezone": "^0.5.33",
|
||||||
"node-sass": "^4.14.1",
|
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
|
"prop-types": "15.8.1",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"ramda": "^0.27.1",
|
"ramda": "^0.27.1",
|
||||||
"react": "^16.14.0",
|
"react": "^18.2.0",
|
||||||
"react-app-polyfill": "^1.0.6",
|
"react-app-polyfill": "^1.0.6",
|
||||||
"react-body-classname": "^1.3.1",
|
"react-body-classname": "^1.3.1",
|
||||||
"react-content-loader": "^6.0.1",
|
"react-content-loader": "^6.0.1",
|
||||||
"react-dev-utils": "^11.0.4",
|
"react-dev-utils": "^11.0.4",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropzone": "^11.0.1",
|
"react-dropzone": "^11.0.1",
|
||||||
"react-error-boundary": "^3.0.2",
|
"react-error-boundary": "^3.0.2",
|
||||||
|
"react-error-overlay": "^6.0.9",
|
||||||
"react-hotkeys-hook": "^3.0.3",
|
"react-hotkeys-hook": "^3.0.3",
|
||||||
"react-intl-universal": "^2.4.7",
|
"react-intl-universal": "^2.4.7",
|
||||||
"react-loadable": "^5.5.0",
|
"react-loadable": "^5.5.0",
|
||||||
"react-query": "^3.6.0",
|
"react-query": "^3.6.0",
|
||||||
"react-query-devtools": "^2.1.1",
|
"react-query-devtools": "^2.1.1",
|
||||||
"react-redux": "^7.1.3",
|
"react-redux": "^7.2.9",
|
||||||
|
"react-router": "5.3.4",
|
||||||
"react-router-breadcrumbs-hoc": "^3.2.10",
|
"react-router-breadcrumbs-hoc": "^3.2.10",
|
||||||
"react-router-dom": "^5.3.3",
|
"react-router-dom": "^5.3.3",
|
||||||
"react-scripts": "^3.4.4",
|
"react-scripts": "5.0.1",
|
||||||
"react-scroll-sync": "^0.7.1",
|
"react-scroll-sync": "^0.7.1",
|
||||||
"react-scrollbars-custom": "^4.0.21",
|
"react-scrollbars-custom": "^4.0.21",
|
||||||
"react-sortablejs": "^2.0.11",
|
"react-sortablejs": "^2.0.11",
|
||||||
@@ -86,11 +93,13 @@
|
|||||||
"react-use": "^13.26.1",
|
"react-use": "^13.26.1",
|
||||||
"react-use-context-menu": "^0.1.4",
|
"react-use-context-menu": "^0.1.4",
|
||||||
"react-virtualized": "^9.22.3",
|
"react-virtualized": "^9.22.3",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.2.1",
|
||||||
"redux-devtools": "^3.5.0",
|
"redux-devtools": "^3.5.0",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.4.2",
|
||||||
|
"reselect": "4.1.7",
|
||||||
"rtl-detect": "^1.0.3",
|
"rtl-detect": "^1.0.3",
|
||||||
|
"sass": "^1.68.0",
|
||||||
"semver": "6.3.0",
|
"semver": "6.3.0",
|
||||||
"style-loader": "0.23.1",
|
"style-loader": "0.23.1",
|
||||||
"styled-components": "^5.3.1",
|
"styled-components": "^5.3.1",
|
||||||
@@ -105,13 +114,15 @@
|
|||||||
"storybook": "start-storybook -p 6006"
|
"storybook": "start-storybook -p 6006"
|
||||||
},
|
},
|
||||||
"proxy": "http://localhost:3000/",
|
"proxy": "http://localhost:3000/",
|
||||||
"devDependencies": {
|
|
||||||
"@types/react-dom": "^16.9.16",
|
|
||||||
"react-error-overlay": "^6.0.9"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"react-error-overlay": "6.0.9"
|
"react-error-overlay": "6.0.9"
|
||||||
},
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"react-app/jest"
|
||||||
|
]
|
||||||
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
">0.2%",
|
">0.2%",
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import { FSelect } from '@/components/Forms';
|
import { FSelect } from '@/components/Forms';
|
||||||
|
|
||||||
export function AccountsTypesSelect({ ...props }) {
|
export function AccountsTypesSelect({ ...props }) {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
// Filters accounts items.
|
// Filters accounts items.
|
||||||
export const accountPredicate = (query, account, _index, exactMatch) => {
|
export const accountPredicate = (query, account, _index, exactMatch) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Formik, FastField, FieldArray, useFormikContext } from 'formik';
|
import { Formik, FastField, FieldArray } from 'formik';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import { Router, Switch, Route } from 'react-router';
|
import { Router, Switch, Route } from 'react-router';
|
||||||
import { createBrowserHistory } from 'history';
|
import { createBrowserHistory } from 'history';
|
||||||
import { QueryClientProvider, QueryClient } from 'react-query';
|
import { QueryClientProvider, QueryClient } from 'react-query';
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ export const CardFooterActions = styled.div`
|
|||||||
border-top: 1px solid #e0e7ea;
|
border-top: 1px solid #e0e7ea;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
|
|
||||||
.bp3-button {
|
.bp4-button {
|
||||||
min-width: 70px;
|
min-width: 70px;
|
||||||
|
|
||||||
+ .bp3-button {
|
+ .bp4-button {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
.menu{
|
.menu{
|
||||||
:global .bp3-heading{
|
:global .bp4-heading{
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import BigcapitalLoading from './BigcapitalLoading';
|
import BigcapitalLoading from './BigcapitalLoading';
|
||||||
import withDashboard from '@/containers/Dashboard/withDashboard';
|
import withDashboard from '@/containers/Dashboard/withDashboard';
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function DataTableEditable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DatatableEditableRoot = styled.div`
|
const DatatableEditableRoot = styled.div`
|
||||||
.bp3-form-group {
|
.bp4-form-group {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.table {
|
.table {
|
||||||
@@ -69,17 +69,17 @@ const DatatableEditableRoot = styled.div`
|
|||||||
}
|
}
|
||||||
.tr {
|
.tr {
|
||||||
&:hover .td,
|
&:hover .td,
|
||||||
.bp3-input {
|
.bp4-input {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
.bp3-form-group:not(.bp3-intent-danger) .bp3-input,
|
.bp4-form-group:not(.bp4-intent-danger) .bp4-input,
|
||||||
.form-group--select-list .bp3-button {
|
.form-group--select-list .bp4-button {
|
||||||
border-color: #ffffff;
|
border-color: #ffffff;
|
||||||
color: #222;
|
color: #222;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
text-align: inherit;
|
text-align: inherit;
|
||||||
}
|
}
|
||||||
.bp3-form-group:not(.bp3-intent-danger) .bp3-input {
|
.bp4-form-group:not(.bp4-intent-danger) .bp4-input {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding-left: 14px;
|
padding-left: 14px;
|
||||||
padding-right: 14px;
|
padding-right: 14px;
|
||||||
@@ -88,7 +88,7 @@ const DatatableEditableRoot = styled.div`
|
|||||||
box-shadow: 0 0 0 2px #116cd0;
|
box-shadow: 0 0 0 2px #116cd0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.form-group--select-list .bp3-button {
|
.form-group--select-list .bp4-button {
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
|
|
||||||
@@ -97,16 +97,16 @@ const DatatableEditableRoot = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.form-group--select-list,
|
.form-group--select-list,
|
||||||
.bp3-form-group {
|
.bp4-form-group {
|
||||||
&.bp3-intent-danger {
|
&.bp4-intent-danger {
|
||||||
.bp3-button:not(.bp3-minimal),
|
.bp4-button:not(.bp4-minimal),
|
||||||
.bp3-input {
|
.bp4-input {
|
||||||
border-color: #f7b6b6;
|
border-color: #f7b6b6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.td.actions {
|
.td.actions {
|
||||||
.bp3-button {
|
.bp4-button {
|
||||||
color: #80858f;
|
color: #80858f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const DialogFooterActionsRoot = styled.div`
|
|||||||
${(props) =>
|
${(props) =>
|
||||||
props.alignment === 'right' ? 'margin-left: auto;' : 'margin-right: auto;'};
|
props.alignment === 'right' ? 'margin-left: auto;' : 'margin-right: auto;'};
|
||||||
|
|
||||||
.bp3-button {
|
.bp4-button {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import AccountDialog from '@/containers/Dialogs/AccountDialog';
|
import AccountDialog from '@/containers/Dialogs/AccountDialog';
|
||||||
import InviteUserDialog from '@/containers/Dialogs/InviteUserDialog';
|
import InviteUserDialog from '@/containers/Dialogs/InviteUserDialog';
|
||||||
import UserFormDialog from '@/containers/Dialogs/UserFormDialog';
|
import UserFormDialog from '@/containers/Dialogs/UserFormDialog';
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export function DrawerMainTabs({ children, ...restProps }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DrawerMainTabsRoot = styled.div`
|
const DrawerMainTabsRoot = styled.div`
|
||||||
.bp3-tabs {
|
.bp4-tabs {
|
||||||
.bp3-tab-list {
|
.bp4-tab-list {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
@@ -28,7 +28,7 @@ const DrawerMainTabsRoot = styled.div`
|
|||||||
margin-right: 25px;
|
margin-right: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bp3-large > .bp3-tab {
|
&.bp4-large > .bp4-tab {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #7f8596;
|
color: #7f8596;
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
@@ -38,13 +38,13 @@ const DrawerMainTabsRoot = styled.div`
|
|||||||
color: #0052cc;
|
color: #0052cc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.bp3-tab-indicator-wrapper .bp3-tab-indicator {
|
.bp4-tab-indicator-wrapper .bp4-tab-indicator {
|
||||||
height: 2px;
|
height: 2px;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-tab-panel {
|
.bp4-tab-panel {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import AccountDrawer from '@/containers/Drawers/AccountDrawer';
|
import AccountDrawer from '@/containers/Drawers/AccountDrawer';
|
||||||
import ManualJournalDrawer from '@/containers/Drawers/ManualJournalDrawer';
|
import ManualJournalDrawer from '@/containers/Drawers/ManualJournalDrawer';
|
||||||
import ExpenseDrawer from '@/containers/Drawers/ExpenseDrawer';
|
import ExpenseDrawer from '@/containers/Drawers/ExpenseDrawer';
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ export function ExchangeRateMutedField({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ExchangeRateFormGroup = styled(FormGroup)`
|
const ExchangeRateFormGroup = styled(FormGroup)`
|
||||||
&.bp3-form-group {
|
&.bp4-form-group {
|
||||||
label.bp3-label {
|
label.bp4-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -79,7 +79,7 @@ const ExchangeRateButton = styled.div`
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
|
|
||||||
.bp3-button {
|
.bp4-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ const ExchangeRateButton = styled.div`
|
|||||||
const ExchangeRateFormGroupContent = styled.div`
|
const ExchangeRateFormGroupContent = styled.div`
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
|
|
||||||
.bp3-form-group {
|
.bp4-form-group {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
margin: 2px 4px !important;
|
margin: 2px 4px !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ const SelectButton = styled(Button)`
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding-right: 30px;
|
padding-right: 30px;
|
||||||
|
|
||||||
&:not(.is-selected):not([class*='bp3-intent-']):not(.bp3-minimal) {
|
&.bp4-small{
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.is-selected):not([class*='bp4-intent-']):not(.bp4-minimal) {
|
||||||
color: #5c7080;
|
color: #5c7080;
|
||||||
}
|
}
|
||||||
&:after {
|
&:after {
|
||||||
@@ -46,13 +50,13 @@ const SelectButton = styled(Button)`
|
|||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
}
|
}
|
||||||
&:not([class*='bp3-intent-']):not(.bp3-disabled) {
|
&:not([class*='bp4-intent-']):not(.bp4-disabled) {
|
||||||
&,
|
&,
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.bp3-intent-danger & {
|
.bp4-intent-danger & {
|
||||||
border-color: #db3737;
|
border-color: #db3737;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export function MenuItemLabel({ text }) {
|
export function MenuItemLabel({ text }) {
|
||||||
return <span class="bp3-menu-item-labeler">{text}</span>;
|
return <span class="bp4-menu-item-labeler">{text}</span>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ const FormTopBarRoot = styled(Navbar)`
|
|||||||
height: 35px;
|
height: 35px;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
|
|
||||||
.bp3-navbar-group {
|
.bp4-navbar-group {
|
||||||
height: 35px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
.bp3-navbar-divider {
|
.bp4-navbar-divider {
|
||||||
border-left-color: #d2dce2;
|
border-left-color: #d2dce2;
|
||||||
}
|
}
|
||||||
.bp3-skeleton {
|
.bp4-skeleton {
|
||||||
max-height: 10px;
|
max-height: 10px;
|
||||||
}
|
}
|
||||||
.bp3-button {
|
.bp4-button {
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(167, 182, 194, 0.12);
|
background: rgba(167, 182, 194, 0.12);
|
||||||
color: #32304a;
|
color: #32304a;
|
||||||
|
|||||||
62
packages/webapp/src/components/TaxRates/TaxRatesSelect.tsx
Normal file
62
packages/webapp/src/components/TaxRates/TaxRatesSelect.tsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { FSelect } from '@/components';
|
||||||
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
|
import { MenuItem } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
// Create new account renderer.
|
||||||
|
const createNewItemRenderer = (query, active, handleClick) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
icon="add"
|
||||||
|
text={intl.get('list.create', { value: `"${query}"` })}
|
||||||
|
active={active}
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create new item from the given query string.
|
||||||
|
const createNewItemFromQuery = (name) => ({ name });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax rates select field binded with Formik form.
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
function TaxRatesSelectRoot({
|
||||||
|
// #withDialogActions
|
||||||
|
openDialog,
|
||||||
|
|
||||||
|
// #ownProps
|
||||||
|
allowCreate,
|
||||||
|
|
||||||
|
...restProps
|
||||||
|
}) {
|
||||||
|
// Maybe inject new item props to select component.
|
||||||
|
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
|
||||||
|
const maybeCreateNewItemFromQuery = allowCreate
|
||||||
|
? createNewItemFromQuery
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Handles the create item click.
|
||||||
|
const handleCreateItemClick = () => {
|
||||||
|
openDialog(DialogsName.TaxRateForm);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FSelect
|
||||||
|
valueAccessor={'id'}
|
||||||
|
labelAccessor={'code'}
|
||||||
|
textAccessor={'name_formatted'}
|
||||||
|
popoverProps={{ minimal: true, usePortal: true, inline: false }}
|
||||||
|
createNewItemRenderer={maybeCreateNewItemRenderer}
|
||||||
|
createNewItemFromQuery={maybeCreateNewItemFromQuery}
|
||||||
|
onCreateItemSelect={handleCreateItemClick}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TaxRatesSelect = R.compose(withDialogActions)(TaxRatesSelectRoot);
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export const For = ({ render, of }) =>
|
export const For = ({ render, of }) =>
|
||||||
|
|||||||
7
packages/webapp/src/constants/InclusiveTaxOptions.ts
Normal file
7
packages/webapp/src/constants/InclusiveTaxOptions.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
import { TaxType } from '@/interfaces/TaxRates';
|
||||||
|
|
||||||
|
export const InclusiveTaxOptions = [
|
||||||
|
{ key: TaxType.Inclusive, label: 'Inclusive of Tax' },
|
||||||
|
{ key: TaxType.Exclusive, label: 'Exclusive of Tax' },
|
||||||
|
];
|
||||||
@@ -22,12 +22,12 @@ export function MakeJournalFormFooterLeft() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DescriptionFormGroup = styled(FFormGroup)`
|
const DescriptionFormGroup = styled(FFormGroup)`
|
||||||
&.bp3-form-group {
|
&.bp4-form-group {
|
||||||
.bp3-label {
|
.bp4-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.bp3-form-content {
|
.bp4-form-content {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Spinner } from '@blueprintjs/core';
|
import { Spinner } from '@blueprintjs/core';
|
||||||
@@ -39,7 +40,7 @@ export const AuthInsiderCopyright = styled.div`
|
|||||||
color: #666;
|
color: #666;
|
||||||
margin-top: 1.2rem;
|
margin-top: 1.2rem;
|
||||||
|
|
||||||
.bp3-icon-bigcapital {
|
.bp4-icon-bigcapital {
|
||||||
svg {
|
svg {
|
||||||
path {
|
path {
|
||||||
fill: #a3a3a3;
|
fill: #a3a3a3;
|
||||||
@@ -65,11 +66,11 @@ export const AuthFooterLink = styled.p`
|
|||||||
export const AuthSubmitButton = styled(Button)`
|
export const AuthSubmitButton = styled(Button)`
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
&.bp3-intent-primary {
|
&.bp4-intent-primary {
|
||||||
background-color: #0052cc;
|
background-color: #0052cc;
|
||||||
|
|
||||||
&:disabled,
|
&:disabled,
|
||||||
&.bp3-disabled {
|
&.bp4-disabled {
|
||||||
background-color: rgba(0, 82, 204, 0.4);
|
background-color: rgba(0, 82, 204, 0.4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ const AccountSwitchItemUpdatedAt = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const AccountSwitchButtonBase = styled(Button)`
|
const AccountSwitchButtonBase = styled(Button)`
|
||||||
.bp3-button-text {
|
.bp4-button-text {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ export function Sidebar() {
|
|||||||
* @returns {React.JSX}
|
* @returns {React.JSX}
|
||||||
*/
|
*/
|
||||||
function SidebarFooterVersion() {
|
function SidebarFooterVersion() {
|
||||||
const { MONOREPO_VERSION } = process.env;
|
const { REACT_APP_VERSION } = process.env;
|
||||||
|
|
||||||
if (!MONOREPO_VERSION) {
|
if (!REACT_APP_VERSION) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return <div class="sidebar__version">v{MONOREPO_VERSION}</div>;
|
return <div class="sidebar__version">v{REACT_APP_VERSION}</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import { Button, Popover, Menu, Position } from '@blueprintjs/core';
|
import { Button, Popover, Menu, Position } from '@blueprintjs/core';
|
||||||
|
|
||||||
import { Icon } from '@/components';
|
import { Icon } from '@/components';
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default function BillDetailHeader() {
|
|||||||
<CommercialDocTopHeader>
|
<CommercialDocTopHeader>
|
||||||
<DetailsMenu>
|
<DetailsMenu>
|
||||||
<AmountDetailItem label={intl.get('amount')}>
|
<AmountDetailItem label={intl.get('amount')}>
|
||||||
<h3 class="big-number">{bill.formatted_amount}</h3>
|
<h3 class="big-number">{bill.total_formatted}</h3>
|
||||||
</AmountDetailItem>
|
</AmountDetailItem>
|
||||||
<StatusDetailItem>
|
<StatusDetailItem>
|
||||||
<BillDetailsStatus bill={bill} />
|
<BillDetailsStatus bill={bill} />
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TotalLineBorderStyle,
|
TotalLineBorderStyle,
|
||||||
TotalLineTextStyle,
|
TotalLineTextStyle,
|
||||||
FormatNumber,
|
|
||||||
T,
|
T,
|
||||||
TotalLines,
|
TotalLines,
|
||||||
TotalLine,
|
TotalLine,
|
||||||
@@ -23,12 +20,20 @@ export function BillDetailTableFooter() {
|
|||||||
<BillTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
<BillTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={<T id={'bill.details.subtotal'} />}
|
title={<T id={'bill.details.subtotal'} />}
|
||||||
value={<FormatNumber value={bill.amount} />}
|
value={bill.subtotal_formatted}
|
||||||
borderStyle={TotalLineBorderStyle.SingleDark}
|
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||||
/>
|
/>
|
||||||
|
{bill.taxes.map((taxRate) => (
|
||||||
|
<TotalLine
|
||||||
|
key={taxRate.id}
|
||||||
|
title={`${taxRate.name} [${taxRate.tax_rate}%]`}
|
||||||
|
value={taxRate.tax_rate_amount_formatted}
|
||||||
|
textStyle={TotalLineTextStyle.Regular}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={<T id={'bill.details.total'} />}
|
title={<T id={'bill.details.total'} />}
|
||||||
value={bill.formatted_amount}
|
value={bill.total_formatted}
|
||||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||||
textStyle={TotalLineTextStyle.Bold}
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
/>
|
/>
|
||||||
@@ -39,6 +44,7 @@ export function BillDetailTableFooter() {
|
|||||||
<TotalLine
|
<TotalLine
|
||||||
title={<T id={'bill.details.due_amount'} />}
|
title={<T id={'bill.details.due_amount'} />}
|
||||||
value={bill.formatted_due_amount}
|
value={bill.formatted_due_amount}
|
||||||
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
/>
|
/>
|
||||||
</BillTotalLines>
|
</BillTotalLines>
|
||||||
</BillDetailsFooterRoot>
|
</BillDetailsFooterRoot>
|
||||||
|
|||||||
@@ -67,6 +67,14 @@ export default function ItemDetailHeader() {
|
|||||||
label={intl.get('cost_account_id')}
|
label={intl.get('cost_account_id')}
|
||||||
children={defaultTo(item.cost_account?.name, '-')}
|
children={defaultTo(item.cost_account?.name, '-')}
|
||||||
/>
|
/>
|
||||||
|
<DetailItem
|
||||||
|
label={intl.get('item.details.sell_tax_rate')}
|
||||||
|
children={item?.sell_tax_rate?.name}
|
||||||
|
/>
|
||||||
|
<DetailItem
|
||||||
|
label={intl.get('item.details.purchase_tax_rate')}
|
||||||
|
children={item?.purchase_tax_rate?.name}
|
||||||
|
/>
|
||||||
<If condition={item.type === 'inventory'}>
|
<If condition={item.type === 'inventory'}>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('inventory_account')}
|
label={intl.get('inventory_account')}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const ItemManuTransaction = ({ onChange }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ItemSwitchButton = styled(Button)`
|
const ItemSwitchButton = styled(Button)`
|
||||||
.bp3-button-text {
|
.bp4-button-text {
|
||||||
display: flex;
|
display: flex;
|
||||||
color: #727983;
|
color: #727983;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { defaultTo } from 'lodash';
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { CommercialDocBox } from '@/components';
|
import { CommercialDocBox } from '@/components';
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { Card } from '@/components';
|
import { Card } from '@/components';
|
||||||
|
|||||||
16
packages/webapp/src/containers/Entries/EntriesActionBar.tsx
Normal file
16
packages/webapp/src/containers/Entries/EntriesActionBar.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Box } from '@/components';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export const EntriesActionsBar = styled(Box)`
|
||||||
|
padding-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.bp4-form-group {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
label.bp4-label {
|
||||||
|
opacity: 0.6;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -8,20 +8,30 @@ import { DataTableEditable } from '@/components';
|
|||||||
import { useEditableItemsEntriesColumns } from './components';
|
import { useEditableItemsEntriesColumns } from './components';
|
||||||
import {
|
import {
|
||||||
useFetchItemRow,
|
useFetchItemRow,
|
||||||
composeRowsOnNewRow,
|
|
||||||
useComposeRowsOnEditTableCell,
|
useComposeRowsOnEditTableCell,
|
||||||
useComposeRowsOnRemoveTableRow,
|
useComposeRowsOnRemoveTableRow,
|
||||||
|
useComposeRowsOnNewRow,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import {
|
import {
|
||||||
ItemEntriesTableProvider,
|
ItemEntriesTableProvider,
|
||||||
useItemEntriesTableContext,
|
useItemEntriesTableContext,
|
||||||
} from './ItemEntriesTableProvider';
|
} from './ItemEntriesTableProvider';
|
||||||
import { useUncontrolled } from '@/hooks/useUncontrolled';
|
import { useUncontrolled } from '@/hooks/useUncontrolled';
|
||||||
|
import { ItemEntry } from '@/interfaces/ItemEntries';
|
||||||
|
|
||||||
|
interface ItemsEntriesTableProps {
|
||||||
|
initialValue?: ItemEntry;
|
||||||
|
value?: ItemEntry[];
|
||||||
|
onChange?: (entries: ItemEntry[]) => void;
|
||||||
|
taxRates?: any[];
|
||||||
|
minLinesNumber?: number;
|
||||||
|
enableTaxRates?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Items entries table.
|
* Items entries table.
|
||||||
*/
|
*/
|
||||||
function ItemsEntriesTable(props) {
|
function ItemsEntriesTable(props: ItemsEntriesTableProps) {
|
||||||
const { value, initialValue, onChange } = props;
|
const { value, initialValue, onChange } = props;
|
||||||
|
|
||||||
const [localValue, handleChange] = useUncontrolled({
|
const [localValue, handleChange] = useUncontrolled({
|
||||||
@@ -51,6 +61,7 @@ function ItemEntriesTableRoot() {
|
|||||||
currencyCode,
|
currencyCode,
|
||||||
landedCost,
|
landedCost,
|
||||||
taxRates,
|
taxRates,
|
||||||
|
itemType,
|
||||||
} = useItemEntriesTableContext();
|
} = useItemEntriesTableContext();
|
||||||
|
|
||||||
// Editiable items entries columns.
|
// Editiable items entries columns.
|
||||||
@@ -58,11 +69,12 @@ function ItemEntriesTableRoot() {
|
|||||||
|
|
||||||
const composeRowsOnEditCell = useComposeRowsOnEditTableCell();
|
const composeRowsOnEditCell = useComposeRowsOnEditTableCell();
|
||||||
const composeRowsOnDeleteRow = useComposeRowsOnRemoveTableRow();
|
const composeRowsOnDeleteRow = useComposeRowsOnRemoveTableRow();
|
||||||
|
const composeRowsOnNewRow = useComposeRowsOnNewRow();
|
||||||
|
|
||||||
// Handle the fetch item row details.
|
// Handle the fetch item row details.
|
||||||
const { setItemRow, cellsLoading, isItemFetching } = useFetchItemRow({
|
const { setItemRow, cellsLoading, isItemFetching } = useFetchItemRow({
|
||||||
landedCost,
|
landedCost,
|
||||||
itemType: null,
|
itemType,
|
||||||
notifyNewRow: (newRow, rowIndex) => {
|
notifyNewRow: (newRow, rowIndex) => {
|
||||||
// Update the rate, description and quantity data of the row.
|
// Update the rate, description and quantity data of the row.
|
||||||
const newRows = composeRowsOnNewRow(rowIndex, newRow, localValue);
|
const newRows = composeRowsOnNewRow(rowIndex, newRow, localValue);
|
||||||
@@ -119,8 +131,11 @@ ItemsEntriesTable.defaultProps = {
|
|||||||
discount: '',
|
discount: '',
|
||||||
},
|
},
|
||||||
initialEntries: [],
|
initialEntries: [],
|
||||||
|
taxRates: [],
|
||||||
|
items: [],
|
||||||
linesNumber: 1,
|
linesNumber: 1,
|
||||||
minLinesNumber: 1,
|
minLinesNumber: 1,
|
||||||
|
enableTaxRates: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ItemsEntriesTable;
|
export default ItemsEntriesTable;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ const LandedCostHeaderCell = () => {
|
|||||||
*/
|
*/
|
||||||
export function useEditableItemsEntriesColumns() {
|
export function useEditableItemsEntriesColumns() {
|
||||||
const { featureCan } = useFeatureCan();
|
const { featureCan } = useFeatureCan();
|
||||||
const { landedCost } = useItemEntriesTableContext();
|
const { landedCost, enableTaxRates } = useItemEntriesTableContext();
|
||||||
|
|
||||||
const isProjectsFeatureEnabled = featureCan(Features.Projects);
|
const isProjectsFeatureEnabled = featureCan(Features.Projects);
|
||||||
|
|
||||||
@@ -132,13 +132,17 @@ export function useEditableItemsEntriesColumns() {
|
|||||||
width: 70,
|
width: 70,
|
||||||
align: Align.Right,
|
align: Align.Right,
|
||||||
},
|
},
|
||||||
{
|
...(enableTaxRates
|
||||||
Header: 'Tax rate',
|
? [
|
||||||
accessor: 'tax_rate_id',
|
{
|
||||||
Cell: TaxRatesSuggestInputCell,
|
Header: 'Tax rate',
|
||||||
disableSortBy: true,
|
accessor: 'tax_rate_id',
|
||||||
width: 110,
|
Cell: TaxRatesSuggestInputCell,
|
||||||
},
|
disableSortBy: true,
|
||||||
|
width: 110,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
Header: intl.get('discount'),
|
Header: intl.get('discount'),
|
||||||
accessor: 'discount',
|
accessor: 'discount',
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { sumBy, isEmpty, last, keyBy } from 'lodash';
|
import { sumBy, isEmpty, last, keyBy, groupBy } from 'lodash';
|
||||||
|
|
||||||
import { useItem } from '@/hooks/query';
|
import { useItem } from '@/hooks/query';
|
||||||
import {
|
import {
|
||||||
toSafeNumber,
|
toSafeNumber,
|
||||||
@@ -12,6 +11,7 @@ import {
|
|||||||
updateAutoAddNewLine,
|
updateAutoAddNewLine,
|
||||||
orderingLinesIndexes,
|
orderingLinesIndexes,
|
||||||
updateTableRow,
|
updateTableRow,
|
||||||
|
formattedAmount,
|
||||||
} from '@/utils';
|
} from '@/utils';
|
||||||
import { useItemEntriesTableContext } from './ItemEntriesTableProvider';
|
import { useItemEntriesTableContext } from './ItemEntriesTableProvider';
|
||||||
|
|
||||||
@@ -119,17 +119,24 @@ export function useFetchItemRow({ landedCost, itemType, notifyNewRow }) {
|
|||||||
// Detarmines whether the landed cost checkbox should be disabled.
|
// Detarmines whether the landed cost checkbox should be disabled.
|
||||||
const landedCostDisabled = isLandedCostDisabled(item);
|
const landedCostDisabled = isLandedCostDisabled(item);
|
||||||
|
|
||||||
|
const taxRateId =
|
||||||
|
itemType === ITEM_TYPE.PURCHASABLE
|
||||||
|
? item.purchase_tax_rate_id
|
||||||
|
: item.sell_tax_rate_id;
|
||||||
|
|
||||||
// The new row.
|
// The new row.
|
||||||
const newRow = {
|
const newRow = {
|
||||||
rate: price,
|
rate: price,
|
||||||
description,
|
description,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
|
tax_rate_id: taxRateId,
|
||||||
...(landedCost
|
...(landedCost
|
||||||
? {
|
? {
|
||||||
landed_cost: false,
|
landed_cost: false,
|
||||||
landed_cost_disabled: landedCostDisabled,
|
landed_cost_disabled: landedCostDisabled,
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
taxRateId,
|
||||||
};
|
};
|
||||||
setItemRow(null);
|
setItemRow(null);
|
||||||
saveInvoke(notifyNewRow, newRow, rowIndex);
|
saveInvoke(notifyNewRow, newRow, rowIndex);
|
||||||
@@ -158,13 +165,21 @@ export const composeRowsOnEditCell = R.curry(
|
|||||||
/**
|
/**
|
||||||
* Compose table rows when insert a new row to table rows.
|
* Compose table rows when insert a new row to table rows.
|
||||||
*/
|
*/
|
||||||
export const composeRowsOnNewRow = R.curry((rowIndex, newRow, rows) => {
|
export const useComposeRowsOnNewRow = () => {
|
||||||
return compose(
|
const { taxRates, isInclusiveTax } = useItemEntriesTableContext();
|
||||||
orderingLinesIndexes,
|
|
||||||
updateItemsEntriesTotal,
|
return React.useMemo(() => {
|
||||||
updateTableRow(rowIndex, newRow),
|
return R.curry((rowIndex, newRow, rows) => {
|
||||||
)(rows);
|
return compose(
|
||||||
});
|
assignEntriesTaxAmount(isInclusiveTax),
|
||||||
|
assignEntriesTaxRate(taxRates),
|
||||||
|
orderingLinesIndexes,
|
||||||
|
updateItemsEntriesTotal,
|
||||||
|
updateTableRow(rowIndex, newRow),
|
||||||
|
)(rows);
|
||||||
|
});
|
||||||
|
}, [isInclusiveTax, taxRates]);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate tax rate to entries.
|
* Associate tax rate to entries.
|
||||||
@@ -266,3 +281,29 @@ export const useComposeRowsOnRemoveTableRow = () => {
|
|||||||
[minLinesNumber, defaultEntry, localValue],
|
[minLinesNumber, defaultEntry, localValue],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the aggregate tax rates from the given item entries.
|
||||||
|
*/
|
||||||
|
export const aggregateItemEntriesTaxRates = R.curry((taxRates, entries) => {
|
||||||
|
const taxRatesById = keyBy(taxRates, 'id');
|
||||||
|
|
||||||
|
// Calculate the total tax amount of invoice entries.
|
||||||
|
const filteredEntries = entries.filter((e) => e.tax_rate_id);
|
||||||
|
const groupedTaxRates = groupBy(filteredEntries, 'tax_rate_id');
|
||||||
|
|
||||||
|
return Object.keys(groupedTaxRates).map((taxRateId) => {
|
||||||
|
const taxRate = taxRatesById[taxRateId];
|
||||||
|
const taxRates = groupedTaxRates[taxRateId];
|
||||||
|
const totalTaxAmount = sumBy(taxRates, 'tax_amount');
|
||||||
|
const taxAmountFormatted = formattedAmount(totalTaxAmount, 'USD');
|
||||||
|
|
||||||
|
return {
|
||||||
|
taxRateId,
|
||||||
|
taxRate: taxRate.rate,
|
||||||
|
label: `${taxRate.name} [${taxRate.rate}%]`,
|
||||||
|
taxAmount: totalTaxAmount,
|
||||||
|
taxAmountFormatted,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ export function ExpenseFormFooterLeft() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const DescriptionFormGroup = styled(FFormGroup)`
|
const DescriptionFormGroup = styled(FFormGroup)`
|
||||||
&.bp3-form-group {
|
&.bp4-form-group {
|
||||||
.bp3-label {
|
.bp4-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.bp3-form-content {
|
.bp4-form-content {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export default compose(
|
|||||||
)(APAgingSummaryHeader);
|
)(APAgingSummaryHeader);
|
||||||
|
|
||||||
const APAgingDrawerHeader = styled(FinancialStatementHeader)`
|
const APAgingDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -14,12 +14,11 @@ import classNames from 'classnames';
|
|||||||
|
|
||||||
import NumberFormatDropdown from '@/components/NumberFormatDropdown';
|
import NumberFormatDropdown from '@/components/NumberFormatDropdown';
|
||||||
|
|
||||||
import { safeInvoke } from '@blueprintjs/core/lib/esm/common/utils';
|
|
||||||
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
||||||
import withARAgingSummaryActions from './withARAgingSummaryActions';
|
import withARAgingSummaryActions from './withARAgingSummaryActions';
|
||||||
import withARAgingSummary from './withARAgingSummary';
|
import withARAgingSummary from './withARAgingSummary';
|
||||||
|
|
||||||
import { compose } from '@/utils';
|
import { compose, safeInvoke } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A/R Aging summary sheet - Actions bar.
|
* A/R Aging summary sheet - Actions bar.
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export default compose(
|
|||||||
)(ARAgingSummaryHeader);
|
)(ARAgingSummaryHeader);
|
||||||
|
|
||||||
const ARAgingDrawerHeader = styled(FinancialStatementHeader)`
|
const ARAgingDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export default compose(
|
|||||||
)(BalanceSheetHeader);
|
)(BalanceSheetHeader);
|
||||||
|
|
||||||
const BalanceSheetFinancialHeader = styled(FinancialStatementHeader)`
|
const BalanceSheetFinancialHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export default function BalanceSheetHeaderComparisonPanal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BalanceSheetComparisonWrap = styled.div`
|
const BalanceSheetComparisonWrap = styled.div`
|
||||||
.bp3-form-group {
|
.bp4-form-group {
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ const BalanceSheetDataTable = styled(ReportDataTable)`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding-top: 0.32rem;
|
padding-top: 0.32rem;
|
||||||
padding-bottom: 0.32rem;
|
padding-bottom: 0.32rem;
|
||||||
|
color: #252A31;
|
||||||
}
|
}
|
||||||
&.is-expanded {
|
&.is-expanded {
|
||||||
.td:not(.name) .cell-inner {
|
.td:not(.name) .cell-inner {
|
||||||
@@ -72,6 +73,7 @@ const BalanceSheetDataTable = styled(ReportDataTable)`
|
|||||||
.td {
|
.td {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { Row, Col } from '@/components';
|
import { Row, Col } from '@/components';
|
||||||
import FinancialStatementDateRange from '../FinancialStatementDateRange';
|
import FinancialStatementDateRange from '../FinancialStatementDateRange';
|
||||||
import FinancialStatementsFilter from '../FinancialStatementsFilter';
|
import FinancialStatementsFilter from '../FinancialStatementsFilter';
|
||||||
|
|||||||
@@ -60,9 +60,8 @@ const CashflowStatementDataTable = styled(DataTable)`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding-top: 0.32rem;
|
padding-top: 0.32rem;
|
||||||
padding-bottom: 0.32rem;
|
padding-bottom: 0.32rem;
|
||||||
|
color: #252a31;
|
||||||
}
|
}
|
||||||
|
|
||||||
// &.row-type--AGGREGATE,
|
|
||||||
&.row_type--ACCOUNTS {
|
&.row_type--ACCOUNTS {
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
}
|
}
|
||||||
@@ -72,6 +71,9 @@ const CashflowStatementDataTable = styled(DataTable)`
|
|||||||
&.row_type--TOTAL {
|
&.row_type--TOTAL {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
|
.td {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
&:not(:first-child) .td {
|
&:not(:first-child) .td {
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import {
|
import {
|
||||||
NavbarGroup,
|
NavbarGroup,
|
||||||
Button,
|
Button,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import { FastField } from 'formik';
|
import { FastField } from 'formik';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
import { FormGroup, Position, Checkbox } from '@blueprintjs/core';
|
import { FormGroup, Position, Checkbox } from '@blueprintjs/core';
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export default compose(
|
|||||||
)(CustomersBalanceSummaryHeader);
|
)(CustomersBalanceSummaryHeader);
|
||||||
|
|
||||||
const CustomerBalanceDrawerHeader = styled(FinancialStatementHeader)`
|
const CustomerBalanceDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export default compose(
|
|||||||
)(CustomersTransactionsHeader);
|
)(CustomersTransactionsHeader);
|
||||||
|
|
||||||
const CustomerTransactionsDrawerHeader = styled(FinancialStatementHeader)`
|
const CustomerTransactionsDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default function FinancialStatementsFilter({
|
|||||||
{({ form: { setFieldValue }, field: { value } }) => (
|
{({ form: { setFieldValue }, field: { value } }) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={label}
|
label={label}
|
||||||
className="form-group--select-list bp3-fill"
|
className="form-group--select-list bp4-fill"
|
||||||
inline={false}
|
inline={false}
|
||||||
>
|
>
|
||||||
<ListSelect
|
<ListSelect
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ export default compose(
|
|||||||
)(GeneralLedgerHeader);
|
)(GeneralLedgerHeader);
|
||||||
|
|
||||||
const GeneralLedgerDrawerHeader = styled(FinancialStatementHeader)`
|
const GeneralLedgerDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export default compose(
|
|||||||
)(InventoryItemDetailsHeader);
|
)(InventoryItemDetailsHeader);
|
||||||
|
|
||||||
const InventoryItemDetailsDrawerHeader = styled(FinancialStatementHeader)`
|
const InventoryItemDetailsDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export default compose(
|
|||||||
)(InventoryValuationHeader);
|
)(InventoryValuationHeader);
|
||||||
|
|
||||||
const InventoryValuationDrawerHeader = styled(FinancialStatementHeader)`
|
const InventoryValuationDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export default compose(
|
|||||||
)(JournalHeader);
|
)(JournalHeader);
|
||||||
|
|
||||||
const JournalDrawerHeader = styled(FinancialStatementHeader)`
|
const JournalDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 350px;
|
max-height: 350px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default R.compose(
|
|||||||
)(ProfitLossHeader);
|
)(ProfitLossHeader);
|
||||||
|
|
||||||
const ProfitLossSheetHeader = styled(FinancialStatementHeader)`
|
const ProfitLossSheetHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ export default function ProfitLossSheetHeaderComparisonPanel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ProfitLossSheetComparisonWrap = styled.div`
|
const ProfitLossSheetComparisonWrap = styled.div`
|
||||||
.bp3-form-group {
|
.bp4-form-group {
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const ProfitLossDataTable = styled(ReportDataTable)`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding-top: 0.32rem;
|
padding-top: 0.32rem;
|
||||||
padding-bottom: 0.32rem;
|
padding-bottom: 0.32rem;
|
||||||
|
color: #252A31;
|
||||||
}
|
}
|
||||||
&.is-expanded {
|
&.is-expanded {
|
||||||
.td:not(.name) .cell-inner {
|
.td:not(.name) .cell-inner {
|
||||||
@@ -71,6 +72,7 @@ const ProfitLossDataTable = styled(ReportDataTable)`
|
|||||||
.td {
|
.td {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:last-of-type .td {
|
&:last-of-type .td {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export default compose(
|
|||||||
)(ProjectProfitabilitySummaryHeader);
|
)(ProjectProfitabilitySummaryHeader);
|
||||||
|
|
||||||
const ProjectProfitabilityDrawerHeader = styled(FinancialStatementHeader)`
|
const ProjectProfitabilityDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export default compose(
|
|||||||
)(PurchasesByItemsHeader);
|
)(PurchasesByItemsHeader);
|
||||||
|
|
||||||
const PurchasesByItemsDrawerHeader = styled(FinancialStatementHeader)`
|
const PurchasesByItemsDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
.bp3-drawer {
|
.bp4-drawer {
|
||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user