Compare commits

..

1 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
27fee87106 dix(webapp): create quick customer/vendor 2023-08-14 16:28:56 +02:00
550 changed files with 26025 additions and 34056 deletions

View File

@@ -51,15 +51,6 @@
"contributions": [
"code"
]
},
{
"login": "KalliopiPliogka",
"name": "Kalliopi Pliogka",
"avatar_url": "https://avatars.githubusercontent.com/u/81677549?v=4",
"profile": "https://github.com/KalliopiPliogka",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,

13
.github/FUNDING.yml vendored
View File

@@ -1,13 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: Bigcapital # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

7
.gitignore vendored
View File

@@ -1,9 +1,4 @@
node_modules/
# Docker volumes data directory
/data
# Production env file
data
.env
test-results/

View File

@@ -2,34 +2,6 @@
All notable changes to Bigcapital server-side will be in this file.
# [0.10.1] - 25-09-2023
* Fix: Running tenants migration on Docker migration container by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/242
# [0.10.0] - 24-09-2023
* Added: Tax rates service by @abouolia @elforjani13 in https://github.com/bigcapitalhq/bigcapital/pull/204
* Added: Sales Tax Liability Summary report by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/204
* Added: Tax rates tracking with sale invoices by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/204
* fix(webapp): Table headers sticky for all reports. by @elforjani13 in https://github.com/bigcapitalhq/bigcapital/pull/240
* chore(deps): bump word-wrap from 1.2.3 to 1.2.4 by @dependabot in https://github.com/bigcapitalhq/bigcapital/pull/200
* chore(deps): bump word-wrap from 1.2.3 to 1.2.4 in /packages/webapp by @dependabot in https://github.com/bigcapitalhq/bigcapital/pull/199
* chore(deps): bump mongoose from 5.13.15 to 5.13.20 by @dependabot in https://github.com/bigcapitalhq/bigcapital/pull/197
# [0.9.12] - 29-08-2023
* Refactor: split the services to multiple service classes. (by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/202)
* Fix: create quick customer/vendor by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/206
* Fix: typo in bill success message without bill number by @KalliopiPliogka in https://github.com/bigcapitalhq/bigcapital/pull/219
* Fix: AP/AR aging summary issue by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/229
* Fix: shouldn't write GL entries when save transaction as draft. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/221
* Fix: Transaction type of credit note and vendor credit are not defined on account transactions by @abouolia in
* Fix: date format of filtering transactions by date range by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/231
* Fix: change the default from/date date value of reports by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/230
* Fix: typos in words start with `A` letter by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/227
* Fix: filter by customers, vendors and items in reports do not work by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/224
https://github.com/bigcapitalhq/bigcapital/pull/225
# [0.9.11] - 23-07-2023
* added: Restart policy to docker compose files. by @suhaibaffan in https://github.com/bigcapitalhq/bigcapital/pull/198
@@ -125,7 +97,7 @@ https://github.com/bigcapitalhq/bigcapital/pull/225
- fix: delete invoice transaction issue.
`@bigcapital/webapp`
- fix: general, accountant and items preferences.
- fix: general, accoutant and items preferences.
- fix: auto-increment sale invoices, estiamtes, credit notes, payments and manual journals.
- refactor: the setup organization form to use binded Formik components.

View File

@@ -7,7 +7,6 @@ Please read through this document before submitting any issues or pull requests
## Sections
- [General Instructions](#general-instructions)
- [Local Setup Prerequisites](#local-setup-prerequisites)
- [Contribute to Backend](#contribute-to-backend)
- [Contribute to Frontend](#contribute-to-frontend)
- [Other Ways to Contribute](#other-ways-to-contribute)
@@ -32,18 +31,9 @@ Contributions via pull requests are much appreciated. Once the approach is agree
---
## Local Setup Prerequisites
- The application currently supports **Node.js v14.x**. Please ensure that you are using this version of Node.js when developing. (use [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) to switch between node versions)
## Contribute to Backend
- Clone the `bigcapital` repository and `cd` into `bigcapital` directory.
- Create `.env` file by copying `.env.example` file to `.env`. (The ``.env.example`` file has all the necessary values of variables to start development directly).
```
cp .env.example .env
```
- Install all npm dependencies of the monorepo, you don't have to change directory to the `backend` package. just hit these command on root directory and it will install dependencies of all packages.
```

View File

@@ -48,12 +48,6 @@ Bigcapital is a smart and open-source accounting and inventory software, Bigcapi
Please see [Releases](https://github.com/bigcapitalhq/bigcapital/releases) for more information what has changed recently.
# Contact us
Meet our sales team for any commercial inquiries.
<a target="_blank" href="https://cal.com/ahmed-bouhuolia-ekk3ph/30min"><img src="https://cal.com/book-with-cal-dark.svg" alt="Book us with Cal.com"></a>
# Recognition
<a href="https://news.ycombinator.com/item?id=36118990">
@@ -79,7 +73,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elforjani13"><img src="https://avatars.githubusercontent.com/u/39470382?v=4?s=100" width="100px;" alt="ElforJani13"/><br /><sub><b>ElforJani13</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=elforjani13" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://scheibling.se"><img src="https://avatars.githubusercontent.com/u/24367830?v=4?s=100" width="100px;" alt="Lars Scheibling"/><br /><sub><b>Lars Scheibling</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Ascheibling" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/suhaibaffan"><img src="https://avatars.githubusercontent.com/u/18115937?v=4?s=100" width="100px;" alt="Suhaib Affan"/><br /><sub><b>Suhaib Affan</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=suhaibaffan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KalliopiPliogka"><img src="https://avatars.githubusercontent.com/u/81677549?v=4?s=100" width="100px;" alt="Kalliopi Pliogka"/><br /><sub><b>Kalliopi Pliogka</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3AKalliopiPliogka" title="Bug reports">🐛</a></td>
</tr>
</tbody>
</table>

View File

@@ -15,8 +15,8 @@ services:
- ./data/logs/nginx/:/var/log/nginx
- ./docker/certbot/certs/:/var/certs
ports:
- '${PUBLIC_PROXY_PORT:-80}:80'
- '${PUBLIC_PROXY_SSL_PORT:-443}:443'
- "${PUBLIC_PROXY_PORT:-80}:80"
- "${PUBLIC_PROXY_SSL_PORT:-443}:443"
tty: true
depends_on:
- server
@@ -71,7 +71,7 @@ services:
# Authentication
- JWT_SECRET=${JWT_SECRET}
# MongoDB
# MongoDB
- MONGODB_DATABASE_URL=mongodb://mongo/bigcapital
# Application
@@ -92,14 +92,11 @@ services:
context: ./
dockerfile: docker/migration/Dockerfile
environment:
# Database
- DB_HOST=mysql
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- DB_CHARSET=${DB_CHARSET}
- SYSTEM_DB_NAME=${SYSTEM_DB_NAME}
# Tenants databases
- TENANT_DB_NAME_PERFIX=${TENANT_DB_NAME_PERFIX}
depends_on:
- mysql
@@ -139,7 +136,7 @@ services:
build:
context: ./docker/redis
expose:
- '6379'
- "6379"
volumes:
- redis:/data

View File

@@ -34,7 +34,5 @@ WORKDIR /app/packages/server
RUN git clone https://github.com/vishnubob/wait-for-it.git
ADD docker/migration/start.sh /
RUN chmod +x /start.sh
CMD ["/start.sh"]
# Once we listen the mysql port run the migration task.
CMD ["./wait-for-it/wait-for-it.sh", "mysql:3306", "--", "node", "./build/commands.js", "system:migrate:latest"]

View File

@@ -1,5 +0,0 @@
# Migrate the master system database.
./wait-for-it/wait-for-it.sh mysql:3306 -- node ./build/commands.js system:migrate:latest
# Migrate all tenants.
./wait-for-it/wait-for-it.sh mysql:3306 -- node ./build/commands.js tenants:migrate:latest

View File

@@ -1,6 +1,6 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "independent",
"npmClient": "pnpm",
"packages": ["packages/*"]
"useWorkspaces": true,
"version": "0.9.6",
"npmClient": "npm"
}

5730
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "bigcapital-monorepo",
"private": true,
"scripts": {
"bootstrap": "lerna exec pnpm install",
"bootstrap": "lerna exec npm install",
"dev": "lerna run dev",
"build": "lerna run build",
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\"",
@@ -13,6 +13,10 @@
"test:e2e": "playwright test",
"prepare": "husky install"
},
"workspaces": [
"packages/*",
"shared/*"
],
"devDependencies": {
"@commitlint/cli": "^17.4.2",
"@commitlint/config-conventional": "^17.4.2",

View File

@@ -1,6 +1,7 @@
/node_modules/
/.env
/storage
package-lock.json
stdout.log
/dist
/build
/build

View File

@@ -1,6 +1,6 @@
{
"name": "@bigcapital/server",
"version": "0.10.1",
"version": "0.9.5",
"description": "",
"main": "src/server.ts",
"scripts": {
@@ -35,7 +35,6 @@
"babel-loader": "^9.1.2",
"bcryptjs": "^2.4.3",
"bluebird": "^3.7.2",
"body-parser": "^1.20.2",
"compression": "^1.7.4",
"country-codes-list": "^1.6.8",
"cpy": "^8.1.2",
@@ -73,8 +72,6 @@
"memory-cache": "^0.2.0",
"moment": "^2.24.0",
"moment-range": "^4.0.2",
"moment-timezone": "^0.5.43",
"mongodb": "^6.1.0",
"mongoose": "^5.10.0",
"mustache": "^3.0.3",
"mysql": "^2.17.1",
@@ -134,7 +131,7 @@
"rimraf": "^3.0.2",
"rtlcss": "^3.3.0",
"run-script-webpack-plugin": "^0.1.1",
"sass": "^1.58.0",
"sass": "^1.37.5",
"sinon": "^7.4.2",
"start-server-webpack-plugin": "^2.2.5",
"ts-loader": "^9.4.2",

View File

@@ -152,7 +152,7 @@
"Opening Balance Liabilities": "رصيد الالتزامات الافتتاحي",
"Loan": "اقراض",
"Owner A Drawings": "مسحوبات المالك",
"An account that holds valuation of products or goods that available for sale.": "حساب يحمل قيم مخزون البضاعة أو السلع المتاحة للبيع.",
"An account that holds valuation of products or goods that availiable for sale.": "حساب يحمل قيم مخزون البضاعة أو السلع المتاحة للبيع.",
"Tracks the gain and losses of the exchange differences.": "يسجل مكاسب وخسائر فروق الصرف.",
"Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.": "يتم تسجيل أي رسوم مصرفية يتم فرضها في حساب الرسوم والمصروفات البنكية. ومن الأمثلة على ذلك رسوم صيانة الحساب المصرفي ورسوم المعاملات ورسوم الدفع المتأخر.",
"The income activities are not associated to the core business.": "لا ترتبط انشطة الدخل إلى الأعمال الأساسية.",

View File

@@ -151,7 +151,7 @@
"Opening Balance Liabilities": "Opening Balance Liabilities",
"Loan": "Loan",
"Owner A Drawings": "Owner A Drawings",
"An account that holds valuation of products or goods that available for sale.": "An account that holds valuation of products or goods that available for sale.",
"An account that holds valuation of products or goods that availiable for sale.": "An account that holds valuation of products or goods that availiable for sale.",
"Tracks the gain and losses of the exchange differences.": "Tracks the gain and losses of the exchange differences.",
"Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.": "Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.",
"The income activities are not associated to the core business.": "The income activities are not associated to the core business.",

View File

@@ -20,7 +20,6 @@ import InventoryDetailsController from './FinancialStatements/InventoryDetails';
import TransactionsByReferenceController from './FinancialStatements/TransactionsByReference';
import CashflowAccountTransactions from './FinancialStatements/CashflowAccountTransactions';
import ProjectProfitabilityController from './FinancialStatements/ProjectProfitabilitySummary';
import SalesTaxLiabilitySummary from './FinancialStatements/SalesTaxLiabilitySummary';
@Service()
export default class FinancialStatementsService {
@@ -69,44 +68,40 @@ export default class FinancialStatementsService {
);
router.use(
'/customer-balance-summary',
Container.get(CustomerBalanceSummaryController).router()
Container.get(CustomerBalanceSummaryController).router(),
);
router.use(
'/vendor-balance-summary',
Container.get(VendorBalanceSummaryController).router()
Container.get(VendorBalanceSummaryController).router(),
);
router.use(
'/transactions-by-customers',
Container.get(TransactionsByCustomers).router()
Container.get(TransactionsByCustomers).router(),
);
router.use(
'/transactions-by-vendors',
Container.get(TransactionsByVendors).router()
Container.get(TransactionsByVendors).router(),
);
router.use(
'/cash-flow',
Container.get(CashFlowStatementController).router()
Container.get(CashFlowStatementController).router(),
);
router.use(
'/inventory-item-details',
Container.get(InventoryDetailsController).router()
Container.get(InventoryDetailsController).router(),
);
router.use(
'/transactions-by-reference',
Container.get(TransactionsByReferenceController).router()
Container.get(TransactionsByReferenceController).router(),
);
router.use(
'/cashflow-account-transactions',
Container.get(CashflowAccountTransactions).router()
Container.get(CashflowAccountTransactions).router(),
);
router.use(
'/project-profitability-summary',
Container.get(ProjectProfitabilityController).router()
);
router.use(
'/sales-tax-liability-summary',
Container.get(SalesTaxLiabilitySummary).router()
);
Container.get(ProjectProfitabilityController).router(),
)
return router;
}
}

View File

@@ -33,13 +33,10 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC
return [
...this.sheetNumberFormatValidationSchema,
query('as_date').optional().isISO8601(),
query('aging_days_before').default(30).isInt({ max: 500 }).toInt(),
query('aging_periods').default(3).isInt({ max: 12 }).toInt(),
query('aging_days_before').optional().isNumeric().toInt(),
query('aging_periods').optional().isNumeric().toInt(),
query('vendors_ids').optional().isArray({ min: 1 }),
query('vendors_ids.*').isInt({ min: 1 }).toInt(),
query('none_zero').default(true).isBoolean().toBoolean(),
// Filtering by branches.
@@ -56,36 +53,15 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC
const filter = this.matchedQueryData(req);
try {
const accept = this.accepts(req);
const acceptType = accept.types(['json', 'application/json+table']);
const { data, columns, query, meta } =
await this.APAgingSummaryService.APAgingSummary(tenantId, filter);
switch (acceptType) {
case 'application/json+table':
const table = await this.APAgingSummaryService.APAgingSummaryTable(
tenantId,
filter
);
return res.status(200).send({
table: {
rows: table.rows,
columns: table.columns,
},
meta: table.meta,
query: table.query,
});
break;
default:
const { data, columns, query, meta } =
await this.APAgingSummaryService.APAgingSummary(tenantId, filter);
return res.status(200).send({
data: this.transfromToResponse(data),
columns: this.transfromToResponse(columns),
query: this.transfromToResponse(query),
meta: this.transfromToResponse(meta),
});
break;
}
return res.status(200).send({
data: this.transfromToResponse(data),
columns: this.transfromToResponse(columns),
query: this.transfromToResponse(query),
meta: this.transfromToResponse(meta),
});
} catch (error) {
next(error);
}

View File

@@ -36,8 +36,8 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC
query('as_date').optional().isISO8601(),
query('aging_days_before').default(30).isInt({ max: 500 }).toInt(),
query('aging_periods').default(3).isInt({ max: 12 }).toInt(),
query('aging_days_before').optional().isInt({ max: 500 }).toInt(),
query('aging_periods').optional().isInt({ max: 12 }).toInt(),
query('customers_ids').optional().isArray({ min: 1 }),
query('customers_ids.*').isInt({ min: 1 }).toInt(),
@@ -58,36 +58,15 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC
const filter = this.matchedQueryData(req);
try {
const accept = this.accepts(req);
const acceptType = accept.types(['json', 'application/json+table']);
const { data, columns, query, meta } =
await this.ARAgingSummaryService.ARAgingSummary(tenantId, filter);
switch (acceptType) {
case 'application/json+table':
const table = await this.ARAgingSummaryService.ARAgingSummaryTable(
tenantId,
filter
);
return res.status(200).send({
table: {
rows: table.rows,
columns: table.columns,
},
meta: table.meta,
query: table.query,
});
break;
default:
const { data, columns, query, meta } =
await this.ARAgingSummaryService.ARAgingSummary(tenantId, filter);
return res.status(200).send({
data: this.transfromToResponse(data),
columns: this.transfromToResponse(columns),
query: this.transfromToResponse(query),
meta: this.transfromToResponse(meta),
});
break;
}
return res.status(200).send({
data: this.transfromToResponse(data),
columns: this.transfromToResponse(columns),
query: this.transfromToResponse(query),
meta: this.transfromToResponse(meta),
});
} catch (error) {
console.log(error);
}

View File

@@ -1,90 +0,0 @@
import { Router, Request, Response, NextFunction } from 'express';
import { query } from 'express-validator';
import { Inject } from 'typedi';
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
import BaseFinancialReportController from '../BaseFinancialReportController';
import { AbilitySubject, ReportsAction } from '@/interfaces';
import CheckPolicies from '@/api/middleware/CheckPolicies';
import { SalesTaxLiabilitySummaryService } from '@/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService';
export default class SalesTaxLiabilitySummary extends BaseFinancialReportController {
@Inject()
private salesTaxLiabilitySummaryService: SalesTaxLiabilitySummaryService;
/**
* Router constructor.
*/
router() {
const router = Router();
router.get(
'/',
CheckPolicies(
ReportsAction.READ_SALES_TAX_LIABILITY_SUMMARY,
AbilitySubject.Report
),
this.validationSchema,
asyncMiddleware(this.salesTaxLiabilitySummary.bind(this))
);
return router;
}
/**
* Validation schema.
*/
get validationSchema() {
return [
query('from_date').optional().isISO8601(),
query('to_date').optional().isISO8601(),
];
}
/*
* Retrieves the sales tax liability summary.
* @param {Request} req -
* @param {Response} res -
* @param {NextFunction} next -
*/
async salesTaxLiabilitySummary(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
const filter = this.matchedQueryData(req);
try {
const accept = this.accepts(req);
const acceptType = accept.types(['json', 'application/json+table']);
switch (acceptType) {
case 'application/json+table':
const salesTaxLiabilityTable =
await this.salesTaxLiabilitySummaryService.salesTaxLiabilitySummaryTable(
tenantId,
filter
);
return res.status(200).send({
table: salesTaxLiabilityTable.table,
query: salesTaxLiabilityTable.query,
meta: salesTaxLiabilityTable.meta,
});
case 'json':
default:
const salesTaxLiability =
await this.salesTaxLiabilitySummaryService.salesTaxLiability(
tenantId,
filter
);
return res.status(200).send({
data: salesTaxLiability.data,
query: salesTaxLiability.query,
meta: salesTaxLiability.meta,
});
}
} catch (error) {
next(error);
}
}
}

View File

@@ -387,7 +387,7 @@ export default class ManualJournalsController extends BaseController {
errors: [{ type: 'CREDIT.DEBIT.NOT.EQUALS', code: 300 }],
});
}
if (error.errorType === 'accounts_ids_not_found') {
if (error.errorType === 'acccounts_ids_not_found') {
return res.boom.badRequest(
'Journal entries some of accounts ids not exists.',
{ errors: [{ type: 'ACCOUNTS.IDS.NOT.FOUND', code: 400 }] }

View File

@@ -372,7 +372,7 @@ export default class PaymentReceivesController extends BaseController {
/**
* Retrieve the given payment receive details.
* @async
* @asycn
* @param {Request} req -
* @param {Response} res -
*/

View File

@@ -169,9 +169,8 @@ export default class SaleInvoicesController extends BaseController {
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
check('project_id').optional({ nullable: true }).isNumeric().toInt(),
check('is_inclusive_tax').optional().isBoolean().toBoolean(),
check('entries').exists().isArray({ min: 1 }),
check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').exists().isNumeric().toInt(),
check('entries.*.rate').exists().isNumeric().toFloat(),
@@ -184,15 +183,6 @@ export default class SaleInvoicesController extends BaseController {
.optional({ nullable: true })
.trim()
.escape(),
check('entries.*.tax_code')
.optional({ nullable: true })
.trim()
.escape()
.isString(),
check('entries.*.tax_rate_id')
.optional({ nullable: true })
.isNumeric()
.toInt(),
check('entries.*.warehouse_id')
.optional({ nullable: true })
.isNumeric()
@@ -766,16 +756,6 @@ export default class SaleInvoicesController 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: 5000 }],
});
}
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: 5100 }],
});
}
}
next(error);
}

View File

@@ -1,278 +0,0 @@
import { Inject, Service } from 'typedi';
import { Router, Request, Response } from 'express';
import { body, param } from 'express-validator';
import BaseController from '@/api/controllers/BaseController';
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
import { TaxRatesApplication } from '@/services/TaxRates/TaxRatesApplication';
import CheckAbilities from '@/api/middleware/CheckPolicies';
import { ServiceError } from '@/exceptions';
import { ERRORS } from '@/services/TaxRates/constants';
import { AbilitySubject, TaxRateAction } from '@/interfaces';
@Service()
export class TaxRatesController extends BaseController {
@Inject()
private taxRatesApplication: TaxRatesApplication;
/**
* Router constructor.
*/
public router() {
const router = Router();
router.post(
'/',
CheckAbilities(TaxRateAction.CREATE, AbilitySubject.TaxRate),
this.taxRateValidationSchema,
this.validationResult,
asyncMiddleware(this.createTaxRate.bind(this)),
this.handleServiceErrors
);
router.post(
'/:id',
CheckAbilities(TaxRateAction.EDIT, AbilitySubject.TaxRate),
[param('id').exists().toInt(), ...this.taxRateValidationSchema],
this.validationResult,
asyncMiddleware(this.editTaxRate.bind(this)),
this.handleServiceErrors
);
router.post(
'/:id/active',
CheckAbilities(TaxRateAction.EDIT, AbilitySubject.TaxRate),
[param('id').exists().toInt()],
this.validationResult,
asyncMiddleware(this.activateTaxRate.bind(this)),
this.handleServiceErrors
);
router.post(
'/:id/inactive',
CheckAbilities(TaxRateAction.EDIT, AbilitySubject.TaxRate),
[param('id').exists().toInt()],
this.validationResult,
asyncMiddleware(this.inactivateTaxRate.bind(this)),
this.handleServiceErrors
);
router.delete(
'/:id',
CheckAbilities(TaxRateAction.DELETE, AbilitySubject.TaxRate),
[param('id').exists().toInt()],
this.validationResult,
asyncMiddleware(this.deleteTaxRate.bind(this)),
this.handleServiceErrors
);
router.get(
'/:id',
CheckAbilities(TaxRateAction.VIEW, AbilitySubject.TaxRate),
[param('id').exists().toInt()],
this.validationResult,
asyncMiddleware(this.getTaxRate.bind(this)),
this.handleServiceErrors
);
router.get(
'/',
CheckAbilities(TaxRateAction.VIEW, AbilitySubject.TaxRate),
this.validationResult,
asyncMiddleware(this.getTaxRates.bind(this)),
this.handleServiceErrors
);
return router;
}
/**
* Tax rate validation schema.
*/
private get taxRateValidationSchema() {
return [
body('name').exists(),
body('code').exists().isString(),
body('rate').exists().isNumeric().toFloat(),
body('description').optional().trim().isString(),
body('is_non_recoverable').optional().isBoolean().default(false),
body('is_compound').optional().isBoolean().default(false),
body('active').optional().isBoolean().default(false),
];
}
/**
* Creates a new tax rate.
* @param {Request} req -
* @param {Response} res -
*/
public async createTaxRate(req: Request, res: Response, next) {
const { tenantId } = req;
const createTaxRateDTO = this.matchedBodyData(req);
try {
const taxRate = await this.taxRatesApplication.createTaxRate(
tenantId,
createTaxRateDTO
);
return res.status(200).send({
data: taxRate,
});
} catch (error) {
next(error);
}
}
/**
* Edits the given tax rate.
* @param {Request} req -
* @param {Response} res -
*/
public async editTaxRate(req: Request, res: Response, next) {
const { tenantId } = req;
const editTaxRateDTO = this.matchedBodyData(req);
const { id: taxRateId } = req.params;
try {
const taxRate = await this.taxRatesApplication.editTaxRate(
tenantId,
taxRateId,
editTaxRateDTO
);
return res.status(200).send({
data: taxRate,
});
} catch (error) {
next(error);
}
}
/**
* Deletes the given tax rate.
* @param {Request} req -
* @param {Response} res -
*/
public async deleteTaxRate(req: Request, res: Response, next) {
const { tenantId } = req;
const { id: taxRateId } = req.params;
try {
await this.taxRatesApplication.deleteTaxRate(tenantId, taxRateId);
return res.status(200).send({
code: 200,
message: 'The tax rate has been deleted successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Retrieves the given tax rate.
* @param {Request} req -
* @param {Response} res -
*/
public async getTaxRate(req: Request, res: Response, next) {
const { tenantId } = req;
const { id: taxRateId } = req.params;
try {
const taxRate = await this.taxRatesApplication.getTaxRate(
tenantId,
taxRateId
);
return res.status(200).send({ data: taxRate });
} catch (error) {
next(error);
}
}
/**
* Retrieves the tax rates list.
* @param {Request} req -
* @param {Response} res -
*/
public async getTaxRates(req: Request, res: Response, next) {
const { tenantId } = req;
try {
const taxRates = await this.taxRatesApplication.getTaxRates(tenantId);
return res.status(200).send({ data: taxRates });
} catch (error) {
next(error);
}
}
/**
* Inactivates the given tax rate.
* @param req
* @param res
* @param next
* @returns
*/
public async inactivateTaxRate(req: Request, res: Response, next) {
const { tenantId } = req;
const { id: taxRateId } = req.params;
try {
await this.taxRatesApplication.inactivateTaxRate(tenantId, taxRateId);
return res.status(200).send({
id: taxRateId,
message: 'The given tax rate has been inactivated successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Inactivates the given tax rate.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns
*/
public async activateTaxRate(req: Request, res: Response, next) {
const { tenantId } = req;
const { id: taxRateId } = req.params;
try {
await this.taxRatesApplication.activateTaxRate(tenantId, taxRateId);
return res.status(200).send({
id: taxRateId,
message: 'The given tax rate has been activated successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Handles service errors.
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
private handleServiceErrors(error: Error, req: Request, res: Response, next) {
if (error instanceof ServiceError) {
if (error.errorType === ERRORS.TAX_CODE_NOT_UNIQUE) {
return res.boom.badRequest(null, {
errors: [{ type: ERRORS.TAX_CODE_NOT_UNIQUE, code: 100 }],
});
}
if (error.errorType === ERRORS.TAX_RATE_NOT_FOUND) {
return res.boom.badRequest(null, {
errors: [{ type: ERRORS.TAX_RATE_NOT_FOUND, code: 200 }],
});
}
if (error.errorType === ERRORS.TAX_RATE_ALREADY_INACTIVE) {
return res.boom.badRequest(null, {
errors: [{ type: ERRORS.TAX_RATE_ALREADY_INACTIVE, code: 300 }],
});
}
if (error.errorType === ERRORS.TAX_RATE_ALREADY_ACTIVE) {
return res.boom.badRequest(null, {
errors: [{ type: ERRORS.TAX_RATE_ALREADY_ACTIVE, code: 400 }],
});
}
}
next(error);
}
}

View File

@@ -55,7 +55,6 @@ import { InventoryItemsCostController } from './controllers/Inventory/Inventorty
import { ProjectsController } from './controllers/Projects/Projects';
import { ProjectTasksController } from './controllers/Projects/Tasks';
import { ProjectTimesController } from './controllers/Projects/Times';
import { TaxRatesController } from './controllers/TaxRates/TaxRates';
export default () => {
const app = Router();
@@ -130,7 +129,6 @@ export default () => {
);
dashboard.use('/warehouses', Container.get(WarehousesController).router());
dashboard.use('/projects', Container.get(ProjectsController).router());
dashboard.use('/tax-rates', Container.get(TaxRatesController).router());
dashboard.use('/', Container.get(ProjectTasksController).router());
dashboard.use('/', Container.get(ProjectTimesController).router());

View File

@@ -1,28 +0,0 @@
export const TransactionTypes = {
SaleInvoice: 'Sale invoice',
SaleReceipt: 'Sale receipt',
PaymentReceive: 'Payment receive',
Bill: 'Bill',
BillPayment: 'Payment made',
VendorOpeningBalance: 'Vendor opening balance',
CustomerOpeningBalance: 'Customer opening balance',
InventoryAdjustment: 'Inventory adjustment',
ManualJournal: 'Manual journal',
Journal: 'Manual journal',
Expense: 'Expense',
OwnerContribution: 'Owner contribution',
TransferToAccount: 'Transfer to account',
TransferFromAccount: 'Transfer from account',
OtherIncome: 'Other income',
OtherExpense: 'Other expense',
OwnerDrawing: 'Owner drawing',
InvoiceWriteOff: 'Invoice write-off',
CreditNote: 'transaction_type.credit_note',
VendorCredit: 'transaction_type.vendor_credit',
RefundCreditNote: 'transaction_type.refund_credit_note',
RefundVendorCredit: 'transaction_type.refund_vendor_credit',
LandedCost: 'transaction_type.landed_cost',
};

View File

@@ -1,52 +0,0 @@
exports.up = (knex) => {
return knex.schema
.createTable('tax_rates', (table) => {
table.increments();
table.string('name');
table.string('code');
table.decimal('rate');
table.string('description');
table.boolean('is_non_recoverable').defaultTo(false);
table.boolean('is_compound').defaultTo(false);
table.boolean('active').defaultTo(false);
table.date('deleted_at');
table.timestamps();
})
.table('items_entries', (table) => {
table.boolean('is_inclusive_tax').defaultTo(false);
table
.integer('tax_rate_id')
.unsigned()
.references('id')
.inTable('tax_rates');
table.decimal('tax_rate').unsigned();
})
.table('sales_invoices', (table) => {
table.boolean('is_inclusive_tax').defaultTo(false);
table.decimal('tax_amount_withheld');
})
.createTable('tax_rate_transactions', (table) => {
table.increments('id');
table
.integer('tax_rate_id')
.unsigned()
.references('id')
.inTable('tax_rates');
table.string('reference_type');
table.integer('reference_id');
table.decimal('rate').unsigned();
table.integer('tax_account_id').unsigned();
})
.table('accounts_transactions', (table) => {
table
.integer('tax_rate_id')
.unsigned()
.references('id')
.inTable('tax_rates');
table.decimal('tax_rate').unsigned();
});
};
exports.down = (knex) => {
return knex.schema.dropTableIfExists('tax_rates');
};

View File

@@ -1,14 +0,0 @@
import { TenantSeeder } from '@/lib/Seeder/TenantSeeder';
import { InitialTaxRates } from '../data/TaxRates';
export default class SeedTaxRates extends TenantSeeder {
/**
* Seeds initial tax rates to the organization.
*/
up(knex) {
return knex('tax_rates').then(async () => {
// Inserts seed entries.
return knex('tax_rates').insert(InitialTaxRates);
});
}
}

View File

@@ -1,16 +0,0 @@
import { TenantSeeder } from '@/lib/Seeder/TenantSeeder';
import { InitialTaxRates } from '../data/TaxRates';
export default class UpdateTaxPayableAccount extends TenantSeeder {
/**
* Seeds initial tax rates to the organization.
*/
up(knex) {
return knex('accounts').then(async () => {
// Inserts seed entries.
return knex('accounts').where('slug', 'tax-payable').update({
account_type: 'tax-payable',
});
});
}
}

View File

@@ -1,30 +0,0 @@
export const InitialTaxRates = [
{
name: 'Tax Exempt',
code: 'TAX-EXEMPT',
description: 'Exempts goods or services from taxes.',
rate: 0,
active: 1,
},
{
name: 'Tax on Purchases',
code: 'TAX-PURCHASES',
description: 'Fee added to the cost when you buy items.',
rate: 0,
active: 1,
},
{
name: 'Tax on Sales',
code: 'TAX-SALES',
description: 'Fee added to the cost when you sell items.',
rate: 0,
active: 1,
},
{
name: 'Sales Tax on Imports',
code: 'TAX-IMPORTS',
description: 'Fee added to the cost when you sale to another country.',
rate: 0,
active: 1,
},
];

View File

@@ -1,17 +1,7 @@
export const TaxPayableAccount = {
name: 'Tax Payable',
slug: 'tax-payable',
account_type: 'tax-payable',
code: '20006',
description: '',
active: 1,
index: 1,
predefined: 1,
};
export default [
{
name: 'Bank Account',
name:'Bank Account',
slug: 'bank-account',
account_type: 'bank',
code: '10001',
@@ -21,7 +11,7 @@ export default [
predefined: 1,
},
{
name: 'Saving Bank Account',
name:'Saving Bank Account',
slug: 'saving-bank-account',
account_type: 'bank',
code: '10002',
@@ -31,7 +21,7 @@ export default [
predefined: 0,
},
{
name: 'Undeposited Funds',
name:'Undeposited Funds',
slug: 'undeposited-funds',
account_type: 'cash',
code: '10003',
@@ -41,7 +31,7 @@ export default [
predefined: 1,
},
{
name: 'Petty Cash',
name:'Petty Cash',
slug: 'petty-cash',
account_type: 'cash',
code: '10004',
@@ -51,7 +41,7 @@ export default [
predefined: 1,
},
{
name: 'Computer Equipment',
name:'Computer Equipment',
slug: 'computer-equipment',
code: '10005',
account_type: 'fixed-asset',
@@ -62,7 +52,7 @@ export default [
description: '',
},
{
name: 'Office Equipment',
name:'Office Equipment',
slug: 'office-equipment',
code: '10006',
account_type: 'fixed-asset',
@@ -73,7 +63,7 @@ export default [
description: '',
},
{
name: 'Accounts Receivable (A/R)',
name:'Accounts Receivable (A/R)',
slug: 'accounts-receivable',
account_type: 'accounts-receivable',
code: '10007',
@@ -83,7 +73,7 @@ export default [
predefined: 1,
},
{
name: 'Inventory Asset',
name:'Inventory Asset',
slug: 'inventory-asset',
code: '10008',
account_type: 'inventory',
@@ -91,13 +81,12 @@ export default [
parent_account_id: null,
index: 1,
active: 1,
description:
'An account that holds valuation of products or goods that available for sale.',
description:'An account that holds valuation of products or goods that availiable for sale.',
},
// Libilities
{
name: 'Accounts Payable (A/P)',
name:'Accounts Payable (A/P)',
slug: 'accounts-payable',
account_type: 'accounts-payable',
parent_account_id: null,
@@ -108,39 +97,38 @@ export default [
predefined: 1,
},
{
name: 'Owner A Drawings',
name:'Owner A Drawings',
slug: 'owner-drawings',
account_type: 'other-current-liability',
parent_account_id: null,
code: '20002',
description: 'Withdrawals by the owners.',
description:'Withdrawals by the owners.',
active: 1,
index: 1,
predefined: 0,
},
{
name: 'Loan',
name:'Loan',
slug: 'owner-drawings',
account_type: 'other-current-liability',
code: '20003',
description: 'Money that has been borrowed from a creditor.',
description:'Money that has been borrowed from a creditor.',
active: 1,
index: 1,
predefined: 0,
},
{
name: 'Opening Balance Liabilities',
name:'Opening Balance Liabilities',
slug: 'opening-balance-liabilities',
account_type: 'other-current-liability',
code: '20004',
description:
'This account will hold the difference in the debits and credits entered during the opening balance..',
description:'This account will hold the difference in the debits and credits entered during the opening balance..',
active: 1,
index: 1,
predefined: 0,
},
{
name: 'Revenue Received in Advance',
name:'Revenue Received in Advance',
slug: 'revenue-received-in-advance',
account_type: 'other-current-liability',
parent_account_id: null,
@@ -150,27 +138,34 @@ export default [
index: 1,
predefined: 0,
},
TaxPayableAccount,
{
name:'Sales Tax Payable',
slug: 'owner-drawings',
account_type: 'other-current-liability',
code: '20006',
description: '',
active: 1,
index: 1,
predefined: 1,
},
// Equity
{
name: 'Retained Earnings',
name:'Retained Earnings',
slug: 'retained-earnings',
account_type: 'equity',
code: '30001',
description:
'Retained earnings tracks net income from previous fiscal years.',
description:'Retained earnings tracks net income from previous fiscal years.',
active: 1,
index: 1,
predefined: 1,
},
{
name: 'Opening Balance Equity',
name:'Opening Balance Equity',
slug: 'opening-balance-equity',
account_type: 'equity',
code: '30002',
description:
'When you enter opening balances to the accounts, the amounts enter in Opening balance equity. This ensures that you have a correct trial balance sheet for your company, without even specific the second credit or debit entry.',
description:'When you enter opening balances to the accounts, the amounts enter in Opening balance equity. This ensures that you have a correct trial balance sheet for your company, without even specific the second credit or debit entry.',
active: 1,
index: 1,
predefined: 1,
@@ -186,12 +181,11 @@ export default [
predefined: 1,
},
{
name: `Drawings`,
name:`Drawings`,
slug: 'drawings',
account_type: 'equity',
code: '30003',
description:
'Goods purchased with the intention of selling these to customers',
description:'Goods purchased with the intention of selling these to customers',
active: 1,
index: 1,
predefined: 1,
@@ -199,7 +193,7 @@ export default [
// Expenses
{
name: 'Other Expenses',
name:'Other Expenses',
slug: 'other-expenses',
account_type: 'other-expense',
parent_account_id: null,
@@ -210,18 +204,18 @@ export default [
predefined: 1,
},
{
name: 'Cost of Goods Sold',
name:'Cost of Goods Sold',
slug: 'cost-of-goods-sold',
account_type: 'cost-of-goods-sold',
parent_account_id: null,
code: '40002',
description: 'Tracks the direct cost of the goods sold.',
description:'Tracks the direct cost of the goods sold.',
active: 1,
index: 1,
predefined: 1,
},
{
name: 'Office expenses',
name:'Office expenses',
slug: 'office-expenses',
account_type: 'expense',
parent_account_id: null,
@@ -232,7 +226,7 @@ export default [
predefined: 0,
},
{
name: 'Rent',
name:'Rent',
slug: 'rent',
account_type: 'expense',
parent_account_id: null,
@@ -243,30 +237,29 @@ export default [
predefined: 0,
},
{
name: 'Exchange Gain or Loss',
name:'Exchange Gain or Loss',
slug: 'exchange-grain-loss',
account_type: 'other-expense',
parent_account_id: null,
code: '40005',
description: 'Tracks the gain and losses of the exchange differences.',
description:'Tracks the gain and losses of the exchange differences.',
active: 1,
index: 1,
predefined: 1,
},
{
name: 'Bank Fees and Charges',
name:'Bank Fees and Charges',
slug: 'bank-fees-and-charges',
account_type: 'expense',
parent_account_id: null,
code: '40006',
description:
'Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.',
description: 'Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.',
active: 1,
index: 1,
predefined: 0,
},
{
name: 'Depreciation Expense',
name:'Depreciation Expense',
slug: 'depreciation-expense',
account_type: 'expense',
parent_account_id: null,
@@ -279,7 +272,7 @@ export default [
// Income
{
name: 'Sales of Product Income',
name:'Sales of Product Income',
slug: 'sales-of-product-income',
account_type: 'income',
predefined: 1,
@@ -290,7 +283,7 @@ export default [
description: '',
},
{
name: 'Sales of Service Income',
name:'Sales of Service Income',
slug: 'sales-of-service-income',
account_type: 'income',
predefined: 0,
@@ -301,7 +294,7 @@ export default [
description: '',
},
{
name: 'Uncategorized Income',
name:'Uncategorized Income',
slug: 'uncategorized-income',
account_type: 'income',
parent_account_id: null,
@@ -312,15 +305,14 @@ export default [
predefined: 1,
},
{
name: 'Other Income',
name:'Other Income',
slug: 'other-income',
account_type: 'other-income',
parent_account_id: null,
code: '50004',
description:
'The income activities are not associated to the core business.',
description:'The income activities are not associated to the core business.',
active: 1,
index: 1,
predefined: 0,
},
];
}
];

View File

@@ -1,36 +1,51 @@
import {
IAgingPeriod,
IAgingPeriodTotal,
IAgingAmount,
IAgingSummaryQuery,
IAgingSummaryTotal,
IAgingSummaryContact,
IAgingSummaryData,
IAgingAmount
} from './AgingReport';
import { INumberFormatQuery } from './FinancialStatements';
import {
INumberFormatQuery
} from './FinancialStatements';
export interface IAPAgingSummaryQuery extends IAgingSummaryQuery {
export interface IAPAgingSummaryQuery {
asDate: Date | string;
agingDaysBefore: number;
agingPeriods: number;
numberFormat: INumberFormatQuery;
vendorsIds: number[];
noneZero: boolean;
branchesIds?: number[]
}
export interface IAPAgingSummaryVendor extends IAgingSummaryContact {
vendorName: string;
}
export interface IAPAgingSummaryVendor {
vendorName: string,
current: IAgingAmount,
aging: IAgingPeriodTotal[],
total: IAgingAmount,
};
export interface IAPAgingSummaryTotal extends IAgingSummaryTotal {}
export interface IAPAgingSummaryTotal {
current: IAgingAmount,
aging: IAgingPeriodTotal[],
total: IAgingAmount,
};
export interface IAPAgingSummaryData extends IAgingSummaryData {
vendors: IAPAgingSummaryVendor[];
}
export interface IAPAgingSummaryData {
vendors: IAPAgingSummaryVendor[],
total: IAPAgingSummaryTotal,
};
export type IAPAgingSummaryColumns = IAgingPeriod[];
export interface IARAgingSummaryMeta {
baseCurrency: string;
organizationName: string;
baseCurrency: string,
organizationName: string,
}
export interface IAPAgingSummaryMeta {
baseCurrency: string;
organizationName: string;
}
baseCurrency: string,
organizationName: string,
}

View File

@@ -1,28 +1,37 @@
import {
IAgingPeriod,
IAgingSummaryQuery,
IAgingSummaryTotal,
IAgingSummaryContact,
IAgingSummaryData,
} from './AgingReport';
import { IAgingPeriod, IAgingPeriodTotal, IAgingAmount } from './AgingReport';
import { INumberFormatQuery } from './FinancialStatements';
export interface IARAgingSummaryQuery extends IAgingSummaryQuery {
export interface IARAgingSummaryQuery {
asDate: Date | string;
agingDaysBefore: number;
agingPeriods: number;
numberFormat: INumberFormatQuery;
customersIds: number[];
branchesIds: number[];
noneZero: boolean;
}
export interface IARAgingSummaryCustomer extends IAgingSummaryContact {
export interface IARAgingSummaryCustomer {
customerName: string;
current: IAgingAmount;
aging: IAgingPeriodTotal[];
total: IAgingAmount;
}
export interface IARAgingSummaryTotal extends IAgingSummaryTotal {}
export interface IARAgingSummaryTotal {
current: IAgingAmount;
aging: IAgingPeriodTotal[];
total: IAgingAmount;
}
export interface IARAgingSummaryData extends IAgingSummaryData {
export interface IARAgingSummaryData {
customers: IARAgingSummaryCustomer[];
total: IARAgingSummaryTotal;
}
export type IARAgingSummaryColumns = IAgingPeriod[];
export interface IARAgingSummaryMeta {
organizationName: string;
baseCurrency: string;
}
organizationName: string,
baseCurrency: string,
}

View File

@@ -58,7 +58,6 @@ export interface IAccountTransaction {
date: string | Date;
referenceType: string;
referenceTypeFormatted: string;
referenceId: number;
referenceNumber?: string;
@@ -77,9 +76,6 @@ export interface IAccountTransaction {
projectId?: number;
account?: IAccount;
taxRateId?: number;
taxRate?: number;
}
export interface IAccountResponse extends IAccount {}
@@ -153,11 +149,3 @@ export enum AccountAction {
VIEW = 'View',
TransactionsLocking = 'TransactionsLocking',
}
export enum TaxRateAction {
CREATE = 'Create',
EDIT = 'Edit',
DELETE = 'Delete',
VIEW = 'View',
}

View File

@@ -1,9 +1,6 @@
import { INumberFormatQuery } from './FinancialStatements';
export interface IAgingPeriodTotal extends IAgingPeriod {
total: IAgingAmount;
}
};
export interface IAgingAmount {
amount: number;
@@ -23,22 +20,3 @@ export interface IAgingSummaryContact {
aging: IAgingPeriodTotal[];
total: IAgingAmount;
}
export interface IAgingSummaryQuery {
asDate: Date | string;
agingDaysBefore: number;
agingPeriods: number;
numberFormat: INumberFormatQuery;
branchesIds: number[];
noneZero: boolean;
}
export interface IAgingSummaryTotal {
current: IAgingAmount;
aging: IAgingPeriodTotal[];
total: IAgingAmount;
}
export interface IAgingSummaryData {
total: IAgingSummaryTotal;
}

View File

@@ -1,7 +1,7 @@
import { Knex } from 'knex';
import { IDynamicListFilterDTO } from './DynamicFilter';
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
import { IBillLandedCost } from './LandedCost';
import { IBillLandedCost } from './LandedCost';
export interface IBillDTO {
vendorId: number;
billNumber: string;
@@ -99,17 +99,17 @@ export interface IBillCreatedPayload {
trx: Knex.Transaction;
}
export interface IBillCreatingPayload {
export interface IBillCreatingPayload{
tenantId: number;
billDTO: IBillDTO;
trx: Knex.Transaction;
trx: Knex.Transaction;
}
export interface IBillEditingPayload {
tenantId: number;
oldBill: IBill;
billDTO: IBillEditDTO;
trx: Knex.Transaction;
trx: Knex.Transaction;
}
export interface IBillEditedPayload {
tenantId: number;
@@ -129,7 +129,7 @@ export interface IBIllEventDeletedPayload {
export interface IBillEventDeletingPayload {
tenantId: number;
oldBill: IBill;
trx: Knex.Transaction;
trx: Knex.Transaction;
}
export enum BillAction {
Create = 'Create',
@@ -138,16 +138,3 @@ export enum BillAction {
View = 'View',
NotifyBySms = 'NotifyBySms',
}
export interface IBillOpeningPayload {
trx: Knex.Transaction;
tenantId: number;
oldBill: IBill;
}
export interface IBillOpenedPayload {
trx: Knex.Transaction;
bill: IBill;
oldBill: IBill;
tenantId: number;
}

View File

@@ -41,7 +41,7 @@ export interface ICashFlowStatementAccountMeta {
code: string;
total: ICashFlowStatementTotal;
accountType: string;
adjustmentType: string;
adjusmentType: string;
sectionType: ICashFlowStatementSectionType.ACCOUNT;
}

View File

@@ -37,7 +37,6 @@ export enum ReportsAction {
READ_INVENTORY_ITEM_DETAILS = 'read-inventory-item-details',
READ_CASHFLOW_ACCOUNT_TRANSACTION = 'read-cashflow-account-transactions',
READ_PROJECT_PROFITABILITY_SUMMARY = 'read-project-profitability-summary',
READ_SALES_TAX_LIABILITY_SUMMARY = 'read-sales-tax-liability-summary',
}
export interface IFinancialSheetBranchesQuery {

View File

@@ -18,11 +18,6 @@ export interface IItemEntry {
rate: number;
amount: number;
total: number;
amountInclusingTax: number;
amountExludingTax: number;
discountAmount: number;
landedCost: number;
allocatedCostAmount: number;
unallocatedCostAmount: number;
@@ -37,10 +32,6 @@ export interface IItemEntry {
projectRefType?: ProjectLinkRefType;
projectRefInvoicedAmount?: number;
taxRateId: number | null;
taxRate: number;
taxAmount: number;
item?: IItem;
allocatedCostEntries?: IBillLandedCostEntry[];
@@ -55,9 +46,6 @@ export interface IItemEntryDTO {
projectRefId?: number;
projectRefType?: ProjectLinkRefType;
projectRefInvoicedAmount?: number;
taxRateId?: number;
taxCode?: string;
}
export enum ProjectLinkRefType {

View File

@@ -48,9 +48,6 @@ export interface ILedgerEntry {
branchId?: number;
projectId?: number;
taxRateId?: number;
taxRate?: number;
entryId?: number;
createdAt?: Date;

View File

@@ -1,5 +1,6 @@
import { Knex } from 'knex';
import { ISystemUser } from '@/interfaces';
import { Knex } from 'knex';
import { pick } from 'lodash';
import { ILedgerEntry } from './Ledger';
import { ISaleInvoice } from './SaleInvoice';

View File

@@ -1,5 +1,5 @@
import { Knex } from 'knex';
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
import { IItemEntry } from './ItemEntry';
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
export interface ISaleEstimate {
@@ -29,7 +29,7 @@ export interface ISaleEstimateDTO {
estimateDate?: Date;
reference?: string;
estimateNumber?: string;
entries: IItemEntryDTO[];
entries: IItemEntry[];
note: string;
termsConditions: string;
sendToEmail: string;

View File

@@ -1,12 +1,11 @@
import { Knex } from 'knex';
import { ISystemUser, IAccount, ITaxTransaction } from '@/interfaces';
import { ISystemUser, IAccount } from '@/interfaces';
import { IDynamicListFilter } from '@/interfaces/DynamicFilter';
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
export interface ISaleInvoice {
id: number;
amount: number;
amountLocal?: number;
balance: number;
paymentAmount: number;
currencyCode: string;
exchangeRate?: number;
@@ -28,21 +27,12 @@ export interface ISaleInvoice {
branchId?: number;
projectId?: number;
writtenoffAmount?: number;
writtenoffAmountLocal?: number;
localAmount?: number;
localWrittenoffAmount?: number;
writtenoffExpenseAccountId?: number;
writtenoffExpenseAccount?: IAccount;
taxAmountWithheld: number;
taxAmountWithheldLocal: number;
taxes: ITaxTransaction[];
total: number;
totalLocal: number;
subtotal: number;
subtotalLocal: number;
subtotalExludingTax: number;
}
export interface ISaleInvoiceDTO {
@@ -54,15 +44,12 @@ export interface ISaleInvoiceDTO {
exchangeRate?: number;
invoiceMessage: string;
termsConditions: string;
isTaxExclusive: boolean;
entries: IItemEntryDTO[];
delivered: boolean;
warehouseId?: number | null;
projectId?: number;
branchId?: number | null;
isInclusiveTax?: boolean;
}
export interface ISaleInvoiceCreateDTO extends ISaleInvoiceDTO {
@@ -169,7 +156,6 @@ export interface ISaleInvoiceEventDeliveredPayload {
tenantId: number;
saleInvoiceId: number;
saleInvoice: ISaleInvoice;
trx: Knex.Transaction;
}
export interface ISaleInvoiceDeliveringPayload {

View File

@@ -1,51 +0,0 @@
export interface SalesTaxLiabilitySummaryQuery {
fromDate: Date;
toDate: Date;
basis: 'cash' | 'accrual';
}
export interface SalesTaxLiabilitySummaryAmount {
amount: number;
formattedAmount: string;
currencyCode: string;
}
export interface SalesTaxLiabilitySummaryTotal {
taxableAmount: SalesTaxLiabilitySummaryAmount;
taxAmount: SalesTaxLiabilitySummaryAmount;
collectedTaxAmount: SalesTaxLiabilitySummaryAmount;
}
export interface SalesTaxLiabilitySummaryRate {
id: number;
taxName: string;
taxableAmount: SalesTaxLiabilitySummaryAmount;
taxAmount: SalesTaxLiabilitySummaryAmount;
taxPercentage: any;
collectedTaxAmount: SalesTaxLiabilitySummaryAmount;
}
export enum SalesTaxLiabilitySummaryTableRowType {
TaxRate = 'TaxRate',
Total = 'Total',
}
export interface SalesTaxLiabilitySummaryReportData {
taxRates: SalesTaxLiabilitySummaryRate[];
total: SalesTaxLiabilitySummaryTotal;
}
export type SalesTaxLiabilitySummaryPayableById = Record<
string,
{ taxRateId: number; credit: number; debit: number }
>;
export type SalesTaxLiabilitySummarySalesById = Record<
string,
{ taxRateId: number; credit: number; debit: number }
>;
export interface SalesTaxLiabilitySummaryMeta {
organizationName: string;
baseCurrency: string;
}

View File

@@ -1,88 +0,0 @@
import { Knex } from 'knex';
export interface ITaxRate {
id?: number;
name: string;
code: string;
rate: number;
description: string;
IsNonRecoverable: boolean;
IsCompound: boolean;
active: boolean;
}
export interface ICommonTaxRateDTO {
name: string;
code: string;
rate: number;
description: string;
IsNonRecoverable: boolean;
IsCompound: boolean;
active: boolean;
}
export interface ICreateTaxRateDTO extends ICommonTaxRateDTO {}
export interface IEditTaxRateDTO extends ICommonTaxRateDTO {}
export interface ITaxRateCreatingPayload {
createTaxRateDTO: ICreateTaxRateDTO;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateCreatedPayload {
createTaxRateDTO: ICreateTaxRateDTO;
taxRate: ITaxRate;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateEditingPayload {
editTaxRateDTO: IEditTaxRateDTO;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateEditedPayload {
editTaxRateDTO: IEditTaxRateDTO;
oldTaxRate: ITaxRate;
taxRate: ITaxRate;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateDeletingPayload {
oldTaxRate: ITaxRate;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateActivatingPayload {
taxRateId: number;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateActivatedPayload {
taxRateId: number;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxRateDeletedPayload {
oldTaxRate: ITaxRate;
tenantId: number;
trx: Knex.Transaction;
}
export interface ITaxTransaction {
id?: number;
taxRateId: number;
referenceType: string;
referenceId: number;
rate: number;
taxAccountId: number;
}
export enum TaxRateAction {
CREATE = 'Create',
EDIT = 'Edit',
DELETE = 'Delete',
VIEW = 'View',
}

View File

@@ -73,7 +73,6 @@ export * from './Project';
export * from './Tasks';
export * from './Times';
export * from './ProjectProfitabilitySummary';
export * from './TaxRate';
export interface I18nService {
__: (input: string) => string;

View File

@@ -1,8 +1,8 @@
import { forEach, uniqBy } from 'lodash';
import DynamicFilterAbstractor from './DynamicFilterAbstractor';
import DynamicFilterAbstructor from './DynamicFilterAbstructor';
import { IDynamicFilter, IFilterRole, IModel } from '@/interfaces';
export default class DynamicFilter extends DynamicFilterAbstractor{
export default class DynamicFilter extends DynamicFilterAbstructor{
private model: IModel;
private tableName: string;
private dynamicFilters: IDynamicFilter[];

View File

@@ -1,5 +1,5 @@
export default class DynamicFilterAbstractor {
export default class DynamicFilterAbstructor {
/**
* Extract relation table name from relation.
* @param {String} column -

View File

@@ -1,7 +1,7 @@
import DynamicFilterRoleAbstractor from './DynamicFilterRoleAbstractor';
import DynamicFilterRoleAbstructor from './DynamicFilterRoleAbstructor';
import { IFilterRole } from '@/interfaces';
export default class FilterRoles extends DynamicFilterRoleAbstractor {
export default class FilterRoles extends DynamicFilterRoleAbstructor {
private filterRoles: IFilterRole[];
/**

View File

@@ -6,7 +6,7 @@ import DynamicFilterQueryParser from './DynamicFilterQueryParser';
import { Lexer } from '../LogicEvaluation/Lexer';
import { COMPARATOR_TYPE, FIELD_TYPE } from './constants';
export default abstract class DynamicFilterAbstractor
export default abstract class DynamicFilterAbstructor
implements IDynamicFilter
{
protected filterRoles: IFilterRole[] = [];

View File

@@ -1,4 +1,4 @@
import DynamicFilterRoleAbstractor from '@/lib/DynamicFilter/DynamicFilterRoleAbstractor';
import DynamicFilterRoleAbstructor from '@/lib/DynamicFilter/DynamicFilterRoleAbstructor';
import { FIELD_TYPE } from './constants';
interface ISortRole {
@@ -6,7 +6,7 @@ interface ISortRole {
order: string;
}
export default class DynamicFilterSortBy extends DynamicFilterRoleAbstractor {
export default class DynamicFilterSortBy extends DynamicFilterRoleAbstructor {
private sortRole: ISortRole = {};
/**

View File

@@ -1,8 +1,8 @@
import { omit } from 'lodash';
import { IView, IViewRole } from '@/interfaces';
import DynamicFilterRoleAbstractor from './DynamicFilterRoleAbstractor';
import DynamicFilterRoleAbstructor from './DynamicFilterRoleAbstructor';
export default class DynamicFilterViews extends DynamicFilterRoleAbstractor {
export default class DynamicFilterViews extends DynamicFilterRoleAbstructor {
private viewSlug: string;
private logicExpression: string;
private filterRoles: IViewRole[];

View File

@@ -1,7 +1,8 @@
import moment from 'moment';
import * as R from 'ramda';
import { includes, isFunction, isObject, isUndefined, omit } from 'lodash';
import { formatNumber, sortObjectKeysAlphabetically } from 'utils';
import { formatNumber } from 'utils';
import { isArrayLikeObject } from 'lodash/fp';
export class Transformer {
public context: any;
@@ -81,7 +82,6 @@ export class Transformer {
const normlizedItem = this.normalizeModelItem(item);
return R.compose(
sortObjectKeysAlphabetically,
this.transform,
R.when(this.hasExcludeAttributes, this.excludeAttributesTransformed),
this.includeAttributesTransformed

View File

@@ -1,10 +1,10 @@
import DynamicFilterRoleAbstractor from '@/lib/DynamicFilter/DynamicFilterRoleAbstractor';
import DynamicFilterRoleAbstructor from '@/lib/DynamicFilter/DynamicFilterRoleAbstructor';
import {
validateViewRoles,
buildFilterQuery,
} from '@/lib/ViewRolesBuilder';
export default class ViewRolesDynamicFilter extends DynamicFilterRoleAbstractor {
export default class ViewRolesDynamicFilter extends DynamicFilterRoleAbstructor {
/**
* Constructor method.
* @param {*} filterRoles -

View File

@@ -1,5 +1,6 @@
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import ItemSubscriber from '@/subscribers/Items/ItemSubscriber';
import InventoryAdjustmentsSubscriber from '@/subscribers/Inventory/InventoryAdjustment';
import BillWriteInventoryTransactionsSubscriber from '@/subscribers/Bills/WriteInventoryTransactions';
import PaymentSyncBillBalance from '@/subscribers/PaymentMades/PaymentSyncBillBalance';
@@ -79,8 +80,6 @@ import { ProjectBillableTasksSubscriber } from '@/services/Projects/Projects/Pro
import { ProjectBillableExpensesSubscriber } from '@/services/Projects/Projects/ProjectBillableExpenseSubscriber';
import { ProjectBillableBillSubscriber } from '@/services/Projects/Projects/ProjectBillableBillSubscriber';
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
import { WriteInvoiceTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteInvoiceTaxTransactionsSubscriber';
export default () => {
return new EventPublisher();
@@ -88,6 +87,7 @@ export default () => {
export const susbcribers = () => {
return [
ItemSubscriber,
InventoryAdjustmentsSubscriber,
BillWriteInventoryTransactionsSubscriber,
PaymentSyncBillBalance,
@@ -187,9 +187,5 @@ export const susbcribers = () => {
ProjectBillableTasksSubscriber,
ProjectBillableExpensesSubscriber,
ProjectBillableBillSubscriber,
// Tax Rates
SaleInvoiceTaxRateValidateSubscriber,
WriteInvoiceTaxTransactionsSubscriber,
];
};

View File

@@ -58,8 +58,6 @@ import ItemWarehouseQuantity from 'models/ItemWarehouseQuantity';
import Project from 'models/Project';
import Time from 'models/Time';
import Task from 'models/Task';
import TaxRate from 'models/TaxRate';
import TaxRateTransaction from 'models/TaxRateTransaction';
export default (knex) => {
const models = {
@@ -121,8 +119,6 @@ export default (knex) => {
Project,
Time,
Task,
TaxRate,
TaxRateTransaction,
};
return mapValues(models, (model) => model.bindKnex(knex));
};

View File

@@ -152,7 +152,7 @@
"Opening Balance Liabilities": "رصيد الالتزامات الافتتاحي",
"Loan": "اقراض",
"Owner A Drawings": "مسحوبات المالك",
"An account that holds valuation of products or goods that available for sale.": "حساب يحمل قيم مخزون البضاعة أو السلع المتاحة للبيع.",
"An account that holds valuation of products or goods that availiable for sale.": "حساب يحمل قيم مخزون البضاعة أو السلع المتاحة للبيع.",
"Tracks the gain and losses of the exchange differences.": "يسجل مكاسب وخسائر فروق الصرف.",
"Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.": "يتم تسجيل أي رسوم مصرفية يتم فرضها في حساب الرسوم والمصروفات البنكية. ومن الأمثلة على ذلك رسوم صيانة الحساب المصرفي ورسوم المعاملات ورسوم الدفع المتأخر.",
"The income activities are not associated to the core business.": "لا ترتبط انشطة الدخل إلى الأعمال الأساسية.",

View File

@@ -151,7 +151,7 @@
"Opening Balance Liabilities": "Opening Balance Liabilities",
"Loan": "Loan",
"Owner A Drawings": "Owner A Drawings",
"An account that holds valuation of products or goods that available for sale.": "An account that holds valuation of products or goods that available for sale.",
"An account that holds valuation of products or goods that availiable for sale.": "An account that holds valuation of products or goods that availiable for sale.",
"Tracks the gain and losses of the exchange differences.": "Tracks the gain and losses of the exchange differences.",
"Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.": "Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.",
"The income activities are not associated to the core business.": "The income activities are not associated to the core business.",

View File

@@ -127,7 +127,7 @@ export default class Account extends mixin(TenantModel, [
},
filterAccountTypes(query, typesIds) {
if (typesIds.length > 0) {
query.whereIn('account_types.account_type_id', typesIds);
query.whereIn('account_types.accoun_type_id', typesIds);
}
},
viewRolesBuilder(query, conditionals, expression) {

View File

@@ -2,15 +2,8 @@ import { Model, raw } from 'objection';
import moment from 'moment';
import { isEmpty, castArray } from 'lodash';
import TenantModel from 'models/TenantModel';
import { getTransactionTypeLabel } from '@/utils/transactions-types';
export default class AccountTransaction extends TenantModel {
referenceType: string;
credit: number;
debit: number;
exchangeRate: number;
taxRate: number;
/**
* Table name
*/
@@ -29,23 +22,7 @@ export default class AccountTransaction extends TenantModel {
* Virtual attributes.
*/
static get virtualAttributes() {
return ['referenceTypeFormatted', 'creditLocal', 'debitLocal'];
}
/**
* Retrieves the credit amount in base currency.
* @return {number}
*/
get creditLocal() {
return this.credit * this.exchangeRate;
}
/**
* Retrieves the debit amount in base currency.
* @return {number}
*/
get debitLocal() {
return this.debit * this.exchangeRate;
return ['referenceTypeFormatted'];
}
/**
@@ -53,7 +30,40 @@ export default class AccountTransaction extends TenantModel {
* @return {string}
*/
get referenceTypeFormatted() {
return getTransactionTypeLabel(this.referenceType);
return AccountTransaction.getReferenceTypeFormatted(this.referenceType);
}
/**
* Reference type formatted.
*/
static getReferenceTypeFormatted(referenceType) {
const mapped = {
SaleInvoice: 'Sale invoice',
SaleReceipt: 'Sale receipt',
PaymentReceive: 'Payment receive',
Bill: 'Bill',
BillPayment: 'Payment made',
VendorOpeningBalance: 'Vendor opening balance',
CustomerOpeningBalance: 'Customer opening balance',
InventoryAdjustment: 'Inventory adjustment',
ManualJournal: 'Manual journal',
Journal: 'Manual journal',
Expense: 'Expense',
OwnerContribution: 'Owner contribution',
TransferToAccount: 'Transfer to account',
TransferFromAccount: 'Transfer from account',
OtherIncome: 'Other income',
OtherExpense: 'Other expense',
OwnerDrawing: 'Owner drawing',
InvoiceWriteOff: 'Invoice write-off',
CreditNote: 'transaction_type.credit_note',
VendorCredit: 'transaction_type.vendor_credit',
RefundCreditNote: 'transaction_type.refund_credit_note',
RefundVendorCredit: 'transaction_type.refund_vendor_credit',
};
return mapped[referenceType] || '';
}
/**
@@ -79,9 +89,15 @@ export default class AccountTransaction extends TenantModel {
}
},
filterDateRange(query, startDate, endDate, type = 'day') {
const dateFormat = 'YYYY-MM-DD';
const fromDate = moment(startDate).startOf(type).format(dateFormat);
const toDate = moment(endDate).endOf(type).format(dateFormat);
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const fromDate = moment(startDate)
.utcOffset(0)
.startOf(type)
.format(dateFormat);
const toDate = moment(endDate)
.utcOffset(0)
.endOf(type)
.format(dateFormat);
if (startDate) {
query.where('date', '>=', fromDate);
@@ -125,6 +141,7 @@ export default class AccountTransaction extends TenantModel {
query.modify('filterDateRange', null, toDate);
query.modify('sumationCreditDebit');
},
contactsOpeningBalance(
query,
openingDate,

View File

@@ -97,7 +97,7 @@ export default class Branch extends TenantModel {
},
/**
* Branch may belongs to associated bills.
* Branch may belongs to assocaited bills.
*/
bills: {
relation: Model.HasManyRelation,

View File

@@ -121,7 +121,7 @@ export default class CashflowTransaction extends TenantModel {
},
/**
* Cashflow transaction may has associated cashflow account.
* Cashflow transaction may has assocaited cashflow account.
*/
cashflowAccount: {
relation: Model.BelongsToOneRelation,

View File

@@ -33,7 +33,7 @@ export default class InventoryCostLotTracker extends TenantModel {
query.groupBy('item_id');
},
filterDateRange(query, startDate, endDate, type = 'day') {
const dateFormat = 'YYYY-MM-DD';
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const fromDate = moment(startDate).startOf(type).format(dateFormat);
const toDate = moment(endDate).endOf(type).format(dateFormat);

View File

@@ -1,13 +1,9 @@
import { Model, raw } from 'objection';
import { castArray } from 'lodash';
import { castArray, isEmpty } from 'lodash';
import moment from 'moment';
import TenantModel from 'models/TenantModel';
import { getTransactionTypeLabel } from '@/utils/transactions-types';
export default class InventoryTransaction extends TenantModel {
transactionId: number;
transactionType: string;
/**
* Table name
*/
@@ -27,7 +23,27 @@ export default class InventoryTransaction extends TenantModel {
* @return {string}
*/
get transcationTypeFormatted() {
return getTransactionTypeLabel(this.transactionType);
return InventoryTransaction.getReferenceTypeFormatted(this.transactionType);
}
/**
* Reference type formatted.
*/
static getReferenceTypeFormatted(referenceType) {
const mapped = {
SaleInvoice: 'Sale invoice',
SaleReceipt: 'Sale receipt',
PaymentReceive: 'Payment receive',
Bill: 'Bill',
BillPayment: 'Payment made',
VendorOpeningBalance: 'Vendor opening balance',
CustomerOpeningBalance: 'Customer opening balance',
InventoryAdjustment: 'Inventory adjustment',
ManualJournal: 'Manual journal',
Journal: 'Manual journal',
LandedCost: 'transaction_type.landed_cost',
};
return mapped[referenceType] || '';
}
/**
@@ -36,7 +52,7 @@ export default class InventoryTransaction extends TenantModel {
static get modifiers() {
return {
filterDateRange(query, startDate, endDate, type = 'day') {
const dateFormat = 'YYYY-MM-DD';
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const fromDate = moment(startDate).startOf(type).format(dateFormat);
const toDate = moment(endDate).endOf(type).format(dateFormat);

View File

@@ -1,17 +1,9 @@
import { Model } from 'objection';
import TenantModel from 'models/TenantModel';
import { getExlusiveTaxAmount, getInclusiveTaxAmount } from '@/utils/taxRate';
export default class ItemEntry extends TenantModel {
public taxRate: number;
public discount: number;
public quantity: number;
public rate: number;
public isInclusiveTax: number;
/**
* Table name.
* @returns {string}
*/
static get tableName() {
return 'items_entries';
@@ -19,89 +11,26 @@ export default class ItemEntry extends TenantModel {
/**
* Timestamps columns.
* @returns {string[]}
*/
get timestamps() {
return ['created_at', 'updated_at'];
}
/**
* Virtual attributes.
* @returns {string[]}
*/
static get virtualAttributes() {
return [
'amount',
'taxAmount',
'amountExludingTax',
'amountInclusingTax',
'total',
];
return ['amount'];
}
/**
* Item entry total.
* Amount of item entry includes tax and subtracted discount amount.
* @returns {number}
*/
get total() {
return this.amountInclusingTax;
}
/**
* Item entry amount.
* Amount of item entry that may include or exclude tax.
* @returns {number}
*/
get amount() {
return this.quantity * this.rate;
return ItemEntry.calcAmount(this);
}
/**
* Item entry amount including tax.
* @returns {number}
*/
get amountInclusingTax() {
return this.isInclusiveTax ? this.amount : this.amount + this.taxAmount;
static calcAmount(itemEntry) {
const { discount, quantity, rate } = itemEntry;
const total = quantity * rate;
return discount ? total - total * discount * 0.01 : total;
}
/**
* Item entry amount excluding tax.
* @returns {number}
*/
get amountExludingTax() {
return this.isInclusiveTax ? this.amount - this.taxAmount : this.amount;
}
/**
* Discount amount.
* @returns {number}
*/
get discountAmount() {
return this.amount * (this.discount / 100);
}
/**
* Tag rate fraction.
* @returns {number}
*/
get tagRateFraction() {
return this.taxRate / 100;
}
/**
* Tax amount withheld.
* @returns {number}
*/
get taxAmount() {
return this.isInclusiveTax
? getInclusiveTaxAmount(this.amount, this.taxRate)
: getExlusiveTaxAmount(this.amount, this.taxRate);
}
/**
* Item entry relations.
*/
static get relationMappings() {
const Item = require('models/Item');
const BillLandedCostEntry = require('models/BillLandedCostEntry');
@@ -111,7 +40,6 @@ export default class ItemEntry extends TenantModel {
const SaleEstimate = require('models/SaleEstimate');
const ProjectTask = require('models/Task');
const Expense = require('models/Expense');
const TaxRate = require('models/TaxRate');
return {
item: {
@@ -158,9 +86,6 @@ export default class ItemEntry extends TenantModel {
},
},
/**
* Sale receipt reference.
*/
receipt: {
relation: Model.BelongsToOneRelation,
modelClass: SaleReceipt.default,
@@ -171,7 +96,7 @@ export default class ItemEntry extends TenantModel {
},
/**
* Project task reference.
*
*/
projectTaskRef: {
relation: Model.HasManyRelation,
@@ -183,7 +108,7 @@ export default class ItemEntry extends TenantModel {
},
/**
* Project expense reference.
*
*/
projectExpenseRef: {
relation: Model.HasManyRelation,
@@ -195,7 +120,7 @@ export default class ItemEntry extends TenantModel {
},
/**
* Project bill reference.
*
*/
projectBillRef: {
relation: Model.HasManyRelation,
@@ -205,18 +130,6 @@ export default class ItemEntry extends TenantModel {
to: 'bills.id',
},
},
/**
* Tax rate reference.
*/
tax: {
relation: Model.HasOneRelation,
modelClass: TaxRate.default,
join: {
from: 'items_entries.taxRateId',
to: 'tax_rates.id',
},
},
};
}
}

View File

@@ -1,5 +1,5 @@
import { mixin, Model, raw } from 'objection';
import { castArray, takeWhile } from 'lodash';
import { castArray } from 'lodash';
import moment from 'moment';
import TenantModel from 'models/TenantModel';
import ModelSetting from './ModelSetting';
@@ -13,17 +13,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
CustomViewBaseModel,
ModelSearchable,
]) {
public taxAmountWithheld: number;
public balance: number;
public paymentAmount: number;
public exchangeRate: number;
public writtenoffAmount: number;
public creditedAmount: number;
public isInclusiveTax: boolean;
public writtenoffAt: Date;
public dueDate: Date;
public deliveredAt: Date;
/**
* Table name
*/
@@ -38,9 +27,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
return ['created_at', 'updated_at'];
}
/**
*
*/
get pluralName() {
return 'asdfsdf';
}
@@ -50,97 +36,35 @@ export default class SaleInvoice extends mixin(TenantModel, [
*/
static get virtualAttributes() {
return [
'localAmount',
'dueAmount',
'balanceAmount',
'isDelivered',
'isOverdue',
'isPartiallyPaid',
'isFullyPaid',
'isWrittenoff',
'isPaid',
'dueAmount',
'balanceAmount',
'isWrittenoff',
'remainingDays',
'overdueDays',
'subtotal',
'subtotalLocal',
'subtotalExludingTax',
'taxAmountWithheldLocal',
'total',
'totalLocal',
'writtenoffAmountLocal',
'filterByBranches',
];
}
/**
* Invoice amount.
* @todo Sugger attribute to balance, we need to rename the balance to amount.
* Invoice amount in local currency.
* @returns {number}
*/
get amount() {
return this.balance;
get localAmount() {
return this.balance * this.exchangeRate;
}
/**
* Invoice amount in base currency.
* Invoice local written-off amount.
* @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 subtotalExludingTax() {
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;
get localWrittenoffAmount() {
return this.writtenoffAmount * this.exchangeRate;
}
/**
@@ -173,7 +97,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
* @return {boolean}
*/
get dueAmount() {
return Math.max(this.total - this.balanceAmount, 0);
return Math.max(this.balance - this.balanceAmount, 0);
}
/**
@@ -181,7 +105,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
* @return {boolean}
*/
get isPartiallyPaid() {
return this.dueAmount !== this.total && this.dueAmount > 0;
return this.dueAmount !== this.balance && this.dueAmount > 0;
}
/**
@@ -252,7 +176,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
* Filters the invoices between the given date range.
*/
filterDateRange(query, startDate, endDate, type = 'day') {
const dateFormat = 'YYYY-MM-DD';
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const fromDate = moment(startDate).startOf(type).format(dateFormat);
const toDate = moment(endDate).endOf(type).format(dateFormat);
@@ -409,7 +333,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
const PaymentReceiveEntry = require('models/PaymentReceiveEntry');
const Branch = require('models/Branch');
const Account = require('models/Account');
const TaxRateTransaction = require('models/TaxRateTransaction');
return {
/**
@@ -459,7 +382,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
},
/**
* Invoice may has associated cost transactions.
*
*/
costTransactions: {
relation: Model.HasManyRelation,
@@ -474,7 +397,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
},
/**
* Invoice may has associated payment entries.
*
*/
paymentEntries: {
relation: Model.HasManyRelation,
@@ -497,9 +420,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
},
},
/**
* Invoice may has associated written-off expense account.
*/
writtenoffExpenseAccount: {
relation: Model.BelongsToOneRelation,
modelClass: Account.default,
@@ -508,21 +428,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
to: 'accounts.id',
},
},
/**
* Invoice may has associated tax rate transactions.
*/
taxes: {
relation: Model.HasManyRelation,
modelClass: TaxRateTransaction.default,
join: {
from: 'sales_invoices.id',
to: 'tax_rate_transactions.referenceId',
},
filter(builder) {
builder.where('reference_type', 'SaleInvoice');
},
},
};
}

View File

@@ -1,48 +0,0 @@
import { mixin, Model, raw } from 'objection';
import TenantModel from 'models/TenantModel';
import ModelSearchable from './ModelSearchable';
import SoftDeleteQueryBuilder from '@/collection/SoftDeleteQueryBuilder';
export default class TaxRate extends mixin(TenantModel, [ModelSearchable]) {
/**
* Table name
*/
static get tableName() {
return 'tax_rates';
}
/**
* Soft delete query builder.
*/
static get QueryBuilder() {
return SoftDeleteQueryBuilder;
}
/**
* Timestamps columns.
*/
get timestamps() {
return ['createdAt', 'updatedAt'];
}
/**
* Virtual attributes.
*/
static get virtualAttributes() {
return [];
}
/**
* Model modifiers.
*/
static get modifiers() {
return {};
}
/**
* Relationship mapping.
*/
static get relationMappings() {
return {};
}
}

View File

@@ -1,56 +0,0 @@
import { mixin, Model, raw } from 'objection';
import TenantModel from 'models/TenantModel';
import ModelSearchable from './ModelSearchable';
export default class TaxRateTransaction extends mixin(TenantModel, [
ModelSearchable,
]) {
/**
* Table name
*/
static get tableName() {
return 'tax_rate_transactions';
}
/**
* Timestamps columns.
*/
get timestamps() {
return [];
}
/**
* Virtual attributes.
*/
static get virtualAttributes() {
return [];
}
/**
* Model modifiers.
*/
static get modifiers() {
return {};
}
/**
* Relationship mapping.
*/
static get relationMappings() {
const TaxRate = require('models/TaxRate');
return {
/**
* Belongs to the tax rate.
*/
taxRate: {
relation: Model.BelongsToOneRelation,
modelClass: TaxRate.default,
join: {
from: 'tax_rate_transactions.taxRateId',
to: 'tax_rates.id',
},
},
};
}
}

View File

@@ -84,7 +84,7 @@ export default class Warehouse extends TenantModel {
},
/**
* Warehouse may belongs to associated bills.
* Warehouse may belongs to assocaited bills.
*/
bills: {
relation: Model.HasManyRelation,

View File

@@ -2,7 +2,6 @@ import { Account } from 'models';
import TenantRepository from '@/repositories/TenantRepository';
import { IAccount } from '@/interfaces';
import { Knex } from 'knex';
import { TaxPayableAccount } from '@/database/seeds/data/accounts';
export default class AccountRepository extends TenantRepository {
/**
@@ -117,7 +116,7 @@ export default class AccountRepository extends TenantRepository {
if (!result) {
result = await this.model.query(trx).insertAndFetch({
name: this.i18n.__('account.accounts_receivable.currency', {
currency: currencyCode,
currency: currencyCode
}),
accountType: 'accounts-receivable',
currencyCode,
@@ -128,29 +127,6 @@ export default class AccountRepository extends TenantRepository {
return result;
};
/**
* Find or create tax payable account.
* @param {Record<string, string>}extraAttrs
* @param {Knex.Transaction} trx
* @returns
*/
async findOrCreateTaxPayable(
extraAttrs: Record<string, string> = {},
trx?: Knex.Transaction
) {
let result = await this.model
.query(trx)
.findOne({ slug: TaxPayableAccount.slug, ...extraAttrs });
if (!result) {
result = await this.model.query(trx).insertAndFetch({
...TaxPayableAccount,
...extraAttrs,
});
}
return result;
}
findOrCreateAccountsPayable = async (
currencyCode: string = '',
extraAttrs = {},

View File

@@ -1,6 +1,6 @@
import { Service, Inject } from 'typedi';
import events from '@/subscribers/events';
import { InventoryTransactionsWarehouses } from './AccountsTransactionsWarehouses';
import { InventoryTransactionsWarehouses } from './AcountsTransactionsWarehouses';
import { IBranchesActivatedPayload } from '@/interfaces';
@Service()

View File

@@ -1,6 +1,10 @@
import { castArray } from 'lodash';
import moment from 'moment';
import { castArray, sumBy, toArray } from 'lodash';
import { IBill, ISystemUser, IAccount } from '@/interfaces';
import JournalPoster from './JournalPoster';
import JournalEntry from './JournalEntry';
import { IExpense, IExpenseCategory } from '@/interfaces';
import { increment } from 'utils';
export default class JournalCommands {
journal: JournalPoster;
models: any;
@@ -12,6 +16,7 @@ export default class JournalCommands {
*/
constructor(journal: JournalPoster) {
this.journal = journal;
this.repositories = this.journal.repositories;
this.models = this.journal.models;
}

View File

@@ -79,7 +79,7 @@ export default class JournalPoster implements IJournalPoster {
}
/**
* Async initialize accounts dependency graph.
* Async initialize acccounts dependency graph.
* @private
* @returns {Promise<void>}
*/

View File

@@ -234,9 +234,6 @@ export default class Ledger implements ILedger {
entryId: entry.id,
branchId: entry.branchId,
projectId: entry.projectId,
taxRateId: entry.taxRateId,
taxRate: entry.taxRate,
};
}

View File

@@ -66,14 +66,14 @@ export class LedgerContactsBalanceStorage {
): Promise<(entry: ILedgerEntry) => boolean> => {
const { Account } = this.tenancy.models(tenantId);
const ARAPAccounts = await Account.query(trx).whereIn('accountType', [
const ARAPAcounts = await Account.query(trx).whereIn('accountType', [
ACCOUNT_TYPE.ACCOUNTS_RECEIVABLE,
ACCOUNT_TYPE.ACCOUNTS_PAYABLE,
]);
const ARAPAccountsIds = ARAPAccounts.map((a) => a.id);
const ARAPAcountsIds = ARAPAcounts.map((a) => a.id);
return (entry: ILedgerEntry) => {
return ARAPAccountsIds.indexOf(entry.accountId) !== -1;
return ARAPAcountsIds.indexOf(entry.accountId) !== -1;
};
};

View File

@@ -35,7 +35,7 @@ export default class LedgerStorageService {
// Saves the ledger entries.
this.ledgerEntriesService.saveEntries(tenantId, ledger, trx),
// Mutates the associated accounts balances.
// Mutates the assocaited accounts balances.
this.ledgerAccountsBalance.saveAccountsBalance(tenantId, ledger, trx),
// Mutates the associated contacts balances.
@@ -60,7 +60,7 @@ export default class LedgerStorageService {
// Deletes the ledger entries.
this.ledgerEntriesService.deleteEntries(tenantId, ledger, trx),
// Mutates the associated accounts balances.
// Mutates the assocaited accounts balances.
this.ledgerAccountsBalance.saveAccountsBalance(tenantId, ledger, trx),
// Mutates the associated contacts balances.

View File

@@ -108,7 +108,7 @@ export class LedegrAccountsStorage {
const { Account } = this.tenancy.models(tenantId);
const account = await Account.query(trx).findById(accountId);
// Filters the ledger entries by the current account.
// Filters the ledger entries by the current acount.
const accountLedger = ledger.whereAccountId(accountId);
// Retrieves the given tenant metadata.

View File

@@ -32,8 +32,5 @@ export const transformLedgerEntryToTransaction = (
projectId: entry.projectId,
costable: entry.costable,
taxRateId: entry.taxRateId,
taxRate: entry.taxRate,
};
};

View File

@@ -46,7 +46,7 @@ export default class AccountTransactionTransformer extends Transformer {
* @returns {string}
*/
public transactionTypeFormatted(transaction: IAccountTransaction) {
return this.context.i18n.__(transaction.referenceTypeFormatted);
return transaction.referenceTypeFormatted;
}
/**

View File

@@ -77,7 +77,7 @@ export class DeleteAccount {
// Authorize before delete account.
await this.authorize(tenantId, accountId, oldAccount);
// Deletes the account and associated transactions under UOW envirement.
// Deletes the account and assocaited transactions under UOW envirement.
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
// Triggers `onAccountDelete` event.
await this.eventPublisher.emitAsync(events.accounts.onDelete, {

View File

@@ -23,6 +23,15 @@ export class GetAccounts {
@Inject()
private transformer: TransformerInjectable;
/**
* Parsees accounts list filter DTO.
* @param filterDTO
* @returns
*/
private parseListFilterDTO(filterDTO) {
return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO);
}
/**
* Retrieve accounts datatable list.
* @param {number} tenantId
@@ -66,13 +75,4 @@ export class GetAccounts {
filterMeta: dynamicList.getResponseMeta(),
};
};
/**
* Parsees accounts list filter DTO.
* @param filterDTO
* @returns
*/
private parseListFilterDTO(filterDTO) {
return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO);
}
}

View File

@@ -0,0 +1,9 @@
export class AccountsReceivableRepository {
findOrCreateAccount = (currencyCode?: string) => {
};
}

View File

@@ -1,4 +1,4 @@
export * from './CashflowBranchesActivateSubscriber';
export * from './CashflowBranchesActviateSubscriber';
export * from './CreditNoteBranchesActivateSubscriber';
export * from './PaymentMadeBranchesActivateSubscriber';
export * from './PaymentReceiveBranchesActivateSubscriber';

View File

@@ -1,12 +1,17 @@
import { Service } from 'typedi';
import { includes, camelCase, upperFirst } from 'lodash';
import { IAccount } from '@/interfaces';
import { Service, Inject } from 'typedi';
import { includes, difference, camelCase, upperFirst } from 'lodash';
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
import { IAccount, ICashflowTransactionLine } from '@/interfaces';
import { getCashflowTransactionType } from './utils';
import { ServiceError } from '@/exceptions';
import { CASHFLOW_TRANSACTION_TYPE, ERRORS } from './constants';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service()
export class CommandCashflowValidator {
@Inject()
private tenancy: HasTenancyService;
/**
* Validates the lines accounts type should be cash or bank account.
* @param {IAccount} accounts -

View File

@@ -0,0 +1,14 @@
import { difference, includes } from 'lodash';
import { ICashflowTransactionLine } from '@/interfaces';
import { ServiceError } from '@/exceptions';
import { Inject, Service } from 'typedi';
import { CASHFLOW_TRANSACTION_TYPE, ERRORS } from './constants';
import { IAccount } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service()
export default class CommandCashflowTransaction {
@Inject()
private tenancy: HasTenancyService;
}

View File

@@ -6,7 +6,7 @@ import {
} from './constants';
/**
* Ensures the given transaction type to transformed to appropriate format.
* Ensures the given transaction type to transformed to properiate format.
* @param {string} type
* @returns {string}
*/

View File

@@ -16,16 +16,16 @@ import BaseCreditNotes from './CreditNotes';
@Service()
export default class CreateCreditNote extends BaseCreditNotes {
@Inject()
private uow: UnitOfWork;
uow: UnitOfWork;
@Inject()
private itemsEntriesService: ItemsEntriesService;
itemsEntriesService: ItemsEntriesService;
@Inject()
private tenancy: HasTenancyService;
tenancy: HasTenancyService;
@Inject()
private eventPublisher: EventPublisher;
eventPublisher: EventPublisher;
/**
* Creates a new credit note.

View File

@@ -1,4 +1,5 @@
import { Service, Inject } from 'typedi';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import events from '@/subscribers/events';
import {
IApplyCreditToInvoicesCreatedPayload,
@@ -9,12 +10,15 @@ import CreditNoteApplySyncInvoicesCreditedAmount from './CreditNoteApplySyncInvo
@Service()
export default class CreditNoteApplySyncInvoicesCreditedAmountSubscriber {
@Inject()
private syncInvoicesWithCreditNote: CreditNoteApplySyncInvoicesCreditedAmount;
tenancy: HasTenancyService;
@Inject()
syncInvoicesWithCreditNote: CreditNoteApplySyncInvoicesCreditedAmount;
/**
* Attaches events with handlers.
*/
public attach(bus) {
attach(bus) {
bus.subscribe(
events.creditNote.onApplyToInvoicesCreated,
this.incrementAppliedInvoicesOnceCreditCreated

View File

@@ -15,7 +15,7 @@ export default class CreditNoteInventoryTransactionsSubscriber {
/**
* Attaches events with publisher.
*/
public attach(bus) {
attach(bus) {
bus.subscribe(
events.creditNote.onCreated,
this.writeInventoryTranscationsOnceCreated
@@ -37,7 +37,6 @@ export default class CreditNoteInventoryTransactionsSubscriber {
/**
* Writes inventory transactions once credit note created.
* @param {ICreditNoteCreatedPayload} payload -
* @returns {Promise<void>}
*/
public writeInventoryTranscationsOnceCreated = async ({
tenantId,
@@ -45,8 +44,9 @@ export default class CreditNoteInventoryTransactionsSubscriber {
trx,
}: ICreditNoteCreatedPayload) => {
// Can't continue if the credit note is open yet.
if (!creditNote.isOpen) return;
if (!creditNote.isOpen) {
return;
}
await this.inventoryTransactions.createInventoryTransactions(
tenantId,
creditNote,
@@ -57,7 +57,6 @@ export default class CreditNoteInventoryTransactionsSubscriber {
/**
* Rewrites inventory transactions once credit note edited.
* @param {ICreditNoteEditedPayload} payload -
* @returns {Promise<void>}
*/
public rewriteInventoryTransactionsOnceEdited = async ({
tenantId,
@@ -66,8 +65,9 @@ export default class CreditNoteInventoryTransactionsSubscriber {
trx,
}: ICreditNoteEditedPayload) => {
// Can't continue if the credit note is open yet.
if (!creditNote.isOpen) return;
if (!creditNote.isOpen) {
return;
}
await this.inventoryTransactions.editInventoryTransactions(
tenantId,
creditNoteId,
@@ -87,8 +87,9 @@ export default class CreditNoteInventoryTransactionsSubscriber {
trx,
}: ICreditNoteDeletedPayload) => {
// Can't continue if the credit note is open yet.
if (!oldCreditNote.isOpen) return;
if (!oldCreditNote.isOpen) {
return;
}
await this.inventoryTransactions.deleteInventoryTransactions(
tenantId,
creditNoteId,

View File

@@ -49,7 +49,7 @@ export default class CreditNoteInventoryTransactions {
};
/**
* Edits vendor credit associated inventory transactions.
* Edits vendor credit assocaited inventory transactions.
* @param {number} tenantId
* @param {number} creditNoteId
* @param {ICreditNote} creditNote

View File

@@ -29,7 +29,7 @@ export default class DeleteCustomerLinkedCreditSubscriber {
};
/**
* Validate vendor has no associated credit transaction once the vendor deleting.
* Validate vendor has no assocaited credit transaction once the vendor deleting.
* @param {IVendorEventDeletingPayload} payload -
*/
public validateCustomerHasNoLinkedCreditsOnDeleting = async ({

View File

@@ -1,6 +0,0 @@
export default class DynamicListAbstract {
}

View File

@@ -0,0 +1,6 @@
export default class DynamicListAbstruct {
}

View File

@@ -1,5 +1,5 @@
import { Inject, Service } from 'typedi';
import DynamicListAbstract from './DynamicListAbstract';
import DynamicListAbstruct from './DynamicListAbstruct';
import DynamicFilterViews from '@/lib/DynamicFilter/DynamicFilterViews';
import { ServiceError } from '@/exceptions';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@@ -7,7 +7,7 @@ import { ERRORS } from './constants';
import { IModel } from '@/interfaces';
@Service()
export default class DynamicListCustomView extends DynamicListAbstract {
export default class DynamicListCustomView extends DynamicListAbstruct {
@Inject()
tenancy: HasTenancyService;

View File

@@ -2,13 +2,13 @@ import { Service } from 'typedi';
import * as R from 'ramda';
import validator from 'is-my-json-valid';
import { IFilterRole, IModel } from '@/interfaces';
import DynamicListAbstract from './DynamicListAbstract';
import DynamicListAbstruct from './DynamicListAbstruct';
import DynamicFilterAdvancedFilter from '@/lib/DynamicFilter/DynamicFilterAdvancedFilter';
import { ERRORS } from './constants';
import { ServiceError } from '@/exceptions';
@Service()
export default class DynamicListFilterRoles extends DynamicListAbstract {
export default class DynamicListFilterRoles extends DynamicListAbstruct {
/**
* Validates filter roles schema.
* @param {IFilterRole[]} filterRoles - Filter roles.

View File

@@ -1,11 +1,11 @@
import { Service } from 'typedi';
import { IFilterRole, IModel } from '@/interfaces';
import DynamicListAbstract from './DynamicListAbstract';
import DynamicListAbstruct from './DynamicListAbstruct';
import DynamicFilterFilterRoles from '@/lib/DynamicFilter/DynamicFilterFilterRoles';
import DynamicFilterSearch from '@/lib/DynamicFilter/DynamicFilterSearch';
@Service()
export default class DynamicListSearch extends DynamicListAbstract {
export default class DynamicListSearch extends DynamicListAbstruct {
/**
* Dynamic list filter roles.
* @param {IModel} model

View File

@@ -1,12 +1,12 @@
import { Service } from 'typedi';
import DynamicListAbstract from './DynamicListAbstract';
import DynamicListAbstruct from './DynamicListAbstruct';
import DynamicFilterSortBy from '@/lib/DynamicFilter/DynamicFilterSortBy';
import { IModel, ISortOrder } from '@/interfaces';
import { ServiceError } from '@/exceptions';
import { ERRORS } from './constants';
@Service()
export default class DynamicListSortBy extends DynamicListAbstract {
export default class DynamicListSortBy extends DynamicListAbstruct {
/**
* Dynamic list sort by.
* @param {IModel} model

View File

@@ -21,7 +21,7 @@ export class ExpensesWriteGLSubscriber {
* Attaches events with handlers.
* @param bus
*/
public attach(bus) {
attach(bus) {
bus.subscribe(
events.expenses.onCreated,
this.handleWriteGLEntriesOnceCreated

Some files were not shown because too many files have changed in this diff Show More