Compare commits
85 Commits
v0.9.6
...
api-rate-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b0feb9022 | ||
|
|
92f929152f | ||
|
|
da514403a1 | ||
|
|
d57f9e5171 | ||
|
|
0a1299b8a6 | ||
|
|
326a2038e7 | ||
|
|
94bb153120 | ||
|
|
223756b7ae | ||
|
|
a773ee9966 | ||
|
|
47790fba84 | ||
|
|
b122fdc43a | ||
|
|
cb93f313ec | ||
|
|
74c31c5f20 | ||
|
|
d411ae3e68 | ||
|
|
aecef878ba | ||
|
|
ec90056f7b | ||
|
|
30f2f1fb4c | ||
|
|
c72f5374f3 | ||
|
|
66de03b143 | ||
|
|
2b33583a03 | ||
|
|
e5611b4446 | ||
|
|
d12157a8d4 | ||
|
|
b24badfa52 | ||
|
|
c992562760 | ||
|
|
485138344c | ||
|
|
8d990ae85d | ||
|
|
7fbe51ddf2 | ||
|
|
215eb97762 | ||
|
|
3d4fd0b904 | ||
|
|
e552ff6449 | ||
|
|
268942af42 | ||
|
|
02489a907a | ||
|
|
4e0037d1c0 | ||
|
|
39786e5b1f | ||
|
|
6373862044 | ||
|
|
b46154ba59 | ||
|
|
59e3a4016b | ||
|
|
b6a1c9ab4b | ||
|
|
7171fb2a69 | ||
|
|
c64a14aef3 | ||
|
|
ac539aed34 | ||
|
|
c7b4846cb0 | ||
|
|
d54aac9b32 | ||
|
|
fe87713df0 | ||
|
|
4770fdf709 | ||
|
|
1b3c525ba5 | ||
|
|
b35d22d3b3 | ||
|
|
44fce6f33e | ||
|
|
e58a1d6ad1 | ||
|
|
5f191cf335 | ||
|
|
46bf1cc39a | ||
|
|
c98fe00f88 | ||
|
|
4b95c19d3e | ||
|
|
eadaac30d6 | ||
|
|
ca4d543482 | ||
|
|
1f3adf4879 | ||
|
|
532ad61500 | ||
|
|
a44d779670 | ||
|
|
ab5f9f50d0 | ||
|
|
f3f10db6db | ||
|
|
de5694681b | ||
|
|
b1a997c287 | ||
|
|
3e36146bce | ||
|
|
db833888c8 | ||
|
|
c415e3d693 | ||
|
|
e145eabf02 | ||
|
|
caab21647d | ||
|
|
98528e9e5b | ||
|
|
b993fad37f | ||
|
|
94ea44b58e | ||
|
|
877a57043a | ||
|
|
70415d1d63 | ||
|
|
ef2d1977d6 | ||
|
|
46ea26891d | ||
|
|
f750cede89 | ||
|
|
e5d0f16096 | ||
|
|
706694c768 | ||
|
|
d1a09e3b15 | ||
|
|
01c27b56ef | ||
|
|
0d8fb8cf25 | ||
|
|
6562e3ab8c | ||
|
|
c93650ffd3 | ||
|
|
e6a2825065 | ||
|
|
0c2a0b0010 | ||
|
|
a332c51249 |
53
.all-contributorsrc
Normal file
53
.all-contributorsrc
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"files": [
|
||||
"README.md"
|
||||
],
|
||||
"imageSize": 100,
|
||||
"commit": false,
|
||||
"commitType": "docs",
|
||||
"commitConvention": "angular",
|
||||
"contributors": [
|
||||
{
|
||||
"login": "abouolia",
|
||||
"name": "Ahmed Bouhuolia",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2197422?v=4",
|
||||
"profile": "https://github.com/abouolia",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ameir",
|
||||
"name": "Ameir Abdeldayem",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/374330?v=4",
|
||||
"profile": "http://ameir.net",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "elforjani13",
|
||||
"name": "ElforJani13",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/39470382?v=4",
|
||||
"profile": "https://github.com/elforjani13",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "scheibling",
|
||||
"name": "Lars Scheibling",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/24367830?v=4",
|
||||
"profile": "https://scheibling.se",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
"skipCi": true,
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"projectName": "bigcapital",
|
||||
"projectOwner": "bigcapitalhq"
|
||||
}
|
||||
@@ -29,7 +29,7 @@ TENANT_DB_NAME_PERFIX=bigcapital_tenant_
|
||||
# TENANT_DB_CHARSET=
|
||||
|
||||
# Application
|
||||
BASE_URL=https://bigcapital.ly
|
||||
BASE_URL=http://example.com
|
||||
JWT_SECRET=b0JDZW56RnV6aEthb0RGPXVEcUI
|
||||
|
||||
# Jobs MongoDB
|
||||
@@ -44,6 +44,9 @@ AGENDASH_AUTH_USER=agendash
|
||||
AGENDASH_AUTH_PASSWORD=123123
|
||||
|
||||
# Sign-up restrictions
|
||||
SIGNUP_DISABLED=true
|
||||
SIGNUP_DISABLED=false
|
||||
SIGNUP_ALLOWED_DOMAINS=
|
||||
SIGNUP_ALLOWED_EMAILS=
|
||||
|
||||
# API rate limit (points,duration,block duration).
|
||||
API_RATE_LIMIT=120,60,600
|
||||
76
CHANGELOG.md
76
CHANGELOG.md
@@ -2,6 +2,82 @@
|
||||
|
||||
All notable changes to Bigcapital server-side will be in this file.
|
||||
|
||||
# [0.9.9] - 28-06-2023
|
||||
|
||||
* refactor: Customer and vendor select component by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/171
|
||||
* chore: Move auto-increment components in separate files by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/170
|
||||
* fix: Style of quick item drawer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/173
|
||||
* fix: Should not show the form before loading account by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/172
|
||||
* fix: Payment made form does not handle not unique number an e… by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/177
|
||||
* fix: Internal note of invoice/bill payment does not saving by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/181
|
||||
* fix: Storing cash flow transaction description by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/180
|
||||
* fix: No currency in amount field on money in/out dialogs by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/179
|
||||
* fix: No default branch for customer/vendor opening balance branch by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/182
|
||||
|
||||
# [0.9.8] - 19-06-2023
|
||||
|
||||
`bigcapitalhq/webapp`
|
||||
|
||||
* add: Inventory Adjustment option to the item drawer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/158
|
||||
* fix: use all drawers names from common enum object by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/157
|
||||
* fix: adjustment type options do not show up by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/159
|
||||
* fix: change the remove line text to be red to intent as a danger action by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/162
|
||||
* fix: rename sidebar localization keys names to be keyword path by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/161
|
||||
* fix: manual journal placeholder text by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/160
|
||||
* fix: warehouses select component by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/168
|
||||
|
||||
`bigcapitalhq/server`
|
||||
|
||||
* fix: sending emails on reset password and registration by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/167
|
||||
|
||||
## [0.9.7] - 14-06-2023
|
||||
|
||||
`@bigcapital/webapp`
|
||||
* fix: change the footer links of onboarding pages by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/139
|
||||
|
||||
`@bigcapital/server`
|
||||
* fix: expense transaction journal entries by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/155
|
||||
|
||||
## [0.9.6] - 12-06-2023
|
||||
|
||||
`@bigcapital/webapp`
|
||||
|
||||
* fix: remove duplicated form submitting by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/138
|
||||
* feat: add monorepo version on the application sidebar by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/136
|
||||
|
||||
## [0.9.5] - 11-06-2023
|
||||
|
||||
`@bigcapital/server`
|
||||
|
||||
* fix: filter ledger entries that effect contact balance to AR/AP accounts only by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/132
|
||||
|
||||
`@bigcapital/webapp`
|
||||
|
||||
* fix: catch journal error when create a journal with accounts have different currency by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/135
|
||||
* fix: add duplicate icon to context menu of customers and vendors table by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/133
|
||||
* fix: customer/vendor opening balance with exchange rate by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/134
|
||||
|
||||
## [0.9.4] - 08-06-2023
|
||||
|
||||
`@bigcapital/monorepo`
|
||||
- fixed: docker-compose line-ending issue on Windows by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/130
|
||||
|
||||
`@bigcapital/server`
|
||||
- fixed: Disable Webpack minification for JS class name reading.
|
||||
|
||||
## [0.9.3] -04-06-2023
|
||||
|
||||
`@bigcapital/monorepo`
|
||||
* Added: Add env variable to customize the proxy public ports by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/125
|
||||
* Added: Migrate the server database to MariaDB by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/128
|
||||
|
||||
## [0.9.2] - 31-05-2023
|
||||
|
||||
`@bigcapital/webapp`
|
||||
|
||||
- fixed: move `packaeg-lock.json` inside docker container.
|
||||
- fixed: remove Sentry from the web client.
|
||||
|
||||
## [0.9.1] - 28-05-2023
|
||||
|
||||
`@bigcapital/server`
|
||||
|
||||
55
README.md
55
README.md
@@ -7,6 +7,24 @@
|
||||
<p align="center">
|
||||
Simple, smart online accounting software for small and medium businesses.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/bigcapitalhq/bigcapital/commits/develop">
|
||||
<img src="https://img.shields.io/github/commit-activity/m/bigcapitalhq/bigcapital/develop" />
|
||||
</a>
|
||||
<a href="https://discord.com/invite/c8nPBJafeb">
|
||||
<img src="https://img.shields.io/discord/1066514716752625725?label=Discord" alt="" />
|
||||
</a>
|
||||
<a href="https://github.com/bigcapitalhq/bigcapital/graphs/contributors">
|
||||
<img src="https://img.shields.io/github/contributors/bigcapitalhq/bigcapital" alt="" />
|
||||
</a>
|
||||
<a href="https://github.com/bigcapitalhq/bigcapital/blob/develop/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/bigcapitalhq/bigcapital" alt="" />
|
||||
</a>
|
||||
<a href="https://twitter.com/bigcapitalhq">
|
||||
<img src="https://img.shields.io/twitter/follow/bigcapitalhq?style=social" alt="twitter" />
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
# What's Bigcapital?
|
||||
@@ -22,10 +40,45 @@ Bigcapital is a smart and open-source accounting and inventory software, Bigcapi
|
||||
# Resources
|
||||
|
||||
- [Documentation](https://docs.bigcapital.ly/) - Learn how to use.
|
||||
- [Contribution](https://github.com/bigcapitalhq/bigcapital/blob/develop/CONTRIBUTING.md) - Welcome to any contributions.
|
||||
- [Discord](https://discord.com/invite/c8nPBJafeb) - Ask for help.
|
||||
- [Bug Tracker](https://github.com/bigcapitalhq/bigcapital/issues) - Notify us new bugs.
|
||||
- [Source Code](https://github.com/bigcapitalhq/bigcapital) - Github repo.
|
||||
|
||||
# Changelog
|
||||
|
||||
Please see [Releases](https://github.com/bigcapitalhq/bigcapital/releases) for more information what has changed recently.
|
||||
|
||||
# Recognition
|
||||
|
||||
<a href="https://news.ycombinator.com/item?id=36118990">
|
||||
<img
|
||||
style="width: 250px; height: 54px;" width="250" height="54"
|
||||
alt="Featured on Hacker News"
|
||||
src="https://hackernews-badge.vercel.app/api?id=36118990"
|
||||
/>
|
||||
</a>
|
||||
|
||||
# Contributors
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/abouolia"><img src="https://avatars.githubusercontent.com/u/2197422?v=4?s=100" width="100px;" alt="Ahmed Bouhuolia"/><br /><sub><b>Ahmed Bouhuolia</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=abouolia" title="Code">💻</a></td>
|
||||
<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="http://ameir.net"><img src="https://avatars.githubusercontent.com/u/374330?v=4?s=100" width="100px;" alt="Ameir Abdeldayem"/><br /><sub><b>Ameir Abdeldayem</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aameir" title="Bug reports">🐛</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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
13
e2e/_utils.ts
Normal file
13
e2e/_utils.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
export const clearLocalStorage = (page: Page) => {
|
||||
return page.evaluate(`window.localStorage.clear()`);
|
||||
};
|
||||
|
||||
export const defaultPageConfig = () => {
|
||||
return {
|
||||
extraHTTPHeaders: {
|
||||
'ngrok-skip-browser-warning': 'any-value',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,14 +1,23 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { clearLocalStorage, defaultPageConfig } from './_utils';
|
||||
|
||||
let authPage: Page;
|
||||
|
||||
test.describe('authentication', () => {
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
authPage = await browser.newPage();
|
||||
authPage = await browser.newPage({ ...defaultPageConfig() });
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await authPage.close();
|
||||
});
|
||||
test.afterEach(async ({ context }) => {
|
||||
context.clearCookies();
|
||||
await clearLocalStorage(authPage);
|
||||
});
|
||||
|
||||
test.describe('login', () => {
|
||||
test.beforeAll(async () => {
|
||||
test.beforeEach(async () => {
|
||||
await authPage.goto('/auth/login');
|
||||
});
|
||||
test('should show the login page.', async () => {
|
||||
@@ -30,10 +39,23 @@ test.describe('authentication', () => {
|
||||
await authPage.getByRole('link', { name: 'Sign up' }).click();
|
||||
await expect(authPage.url()).toContain('/auth/register');
|
||||
});
|
||||
test('should the email or password is not correct.', async () => {
|
||||
await authPage.getByLabel('Email Address').click();
|
||||
await authPage.getByLabel('Email Address').fill(faker.internet.email());
|
||||
|
||||
await authPage.getByLabel('Password').click();
|
||||
await authPage.getByLabel('Password').fill(faker.internet.password());
|
||||
|
||||
await authPage.getByRole('button', { name: 'Log in' }).click();
|
||||
|
||||
await expect(authPage.locator('body')).toContainText(
|
||||
'The email and password you entered did not match our records.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('register', () => {
|
||||
test.beforeAll(async () => {
|
||||
test.beforeEach(async () => {
|
||||
await authPage.goto('/auth/register');
|
||||
});
|
||||
test('should first name, last name, email and password be required.', async () => {
|
||||
@@ -52,10 +74,36 @@ test.describe('authentication', () => {
|
||||
'Password is a required field'
|
||||
);
|
||||
});
|
||||
test('should signup successfully.', async () => {
|
||||
const form = authPage.locator('form');
|
||||
await form.getByLabel('First Name').click();
|
||||
await form.getByLabel('First Name').fill(faker.person.firstName());
|
||||
|
||||
await form.getByLabel('Email').click();
|
||||
await form.getByLabel('Email').fill(faker.internet.email());
|
||||
|
||||
await form.getByLabel('Last Name').click();
|
||||
await form.getByLabel('Last Name').fill(faker.person.lastName());
|
||||
|
||||
await form.getByLabel('Password').click();
|
||||
await form.getByLabel('Password').fill(faker.internet.password());
|
||||
|
||||
await authPage.getByRole('button', { name: 'Register' }).click();
|
||||
|
||||
await expect(authPage.locator('h1')).toContainText(
|
||||
'Register a New Organization now!'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('reset password', () => {
|
||||
test.beforeAll(async () => {
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
authPage = await browser.newPage({ ...defaultPageConfig() });
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await authPage.close();
|
||||
});
|
||||
test.beforeEach(async () => {
|
||||
await authPage.goto('/auth/send_reset_password');
|
||||
});
|
||||
test('should email be required.', async () => {
|
||||
|
||||
86
e2e/onboarding.spec.ts
Normal file
86
e2e/onboarding.spec.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { defaultPageConfig } from './_utils';
|
||||
|
||||
let authPage: Page;
|
||||
let businessLegalName: string = faker.company.name();
|
||||
|
||||
test.describe('onboarding', () => {
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
authPage = await browser.newPage({ ...defaultPageConfig() });
|
||||
await authPage.goto('/auth/register');
|
||||
|
||||
const form = authPage.locator('form');
|
||||
|
||||
await form.getByLabel('First Name').fill(faker.person.firstName());
|
||||
await form.getByLabel('Email').fill(faker.internet.email());
|
||||
await form.getByLabel('Last Name').fill(faker.person.lastName());
|
||||
await form.getByLabel('Password').fill(faker.internet.password());
|
||||
|
||||
await authPage.getByRole('button', { name: 'Register' }).click();
|
||||
});
|
||||
test('should validation catch all required fields', async () => {
|
||||
const form = authPage.locator('form');
|
||||
|
||||
await authPage.getByRole('button', { name: 'Save & Continue' }).click();
|
||||
|
||||
await expect(form).toContainText('Organization name is a required field');
|
||||
await expect(form).toContainText('Location is a required field');
|
||||
await expect(form).toContainText('Base currency is a required field');
|
||||
await expect(form).toContainText('Fiscal year is a required field');
|
||||
await expect(form).toContainText('Time zone is a required field');
|
||||
});
|
||||
test.describe('after onboarding', () => {
|
||||
test.beforeAll(async () => {
|
||||
await authPage.getByLabel('Legal Organization Name').click();
|
||||
await authPage
|
||||
.getByLabel('Legal Organization Name')
|
||||
.fill(businessLegalName);
|
||||
|
||||
// Fill Business Location.
|
||||
await authPage
|
||||
.getByRole('button', { name: 'Select Business Location...' })
|
||||
.click();
|
||||
await authPage.locator('a').filter({ hasText: 'Albania' }).click();
|
||||
|
||||
// Fill Base Currency.
|
||||
await authPage
|
||||
.getByRole('button', { name: 'Select Base Currency...' })
|
||||
.click();
|
||||
await authPage
|
||||
.locator('a')
|
||||
.filter({ hasText: 'AED - United Arab Emirates Dirham' })
|
||||
.click();
|
||||
|
||||
// Fill Fasical Year.
|
||||
await authPage
|
||||
.getByRole('button', { name: 'Select Fiscal Year...' })
|
||||
.click();
|
||||
await authPage.locator('a').filter({ hasText: 'June - May' }).click();
|
||||
|
||||
// Fill Timezone.
|
||||
await authPage
|
||||
.getByRole('button', { name: 'Select Time Zone...' })
|
||||
.click();
|
||||
await authPage.getByText('Pacific/Marquesas-09:30').click();
|
||||
|
||||
// Click on Submit button
|
||||
await authPage.getByRole('button', { name: 'Save & Continue' }).click();
|
||||
});
|
||||
test('should onboarding process success', async () => {
|
||||
await expect(authPage.locator('body')).toContainText(
|
||||
'Congrats! You are ready to go',
|
||||
{
|
||||
timeout: 30000,
|
||||
}
|
||||
);
|
||||
});
|
||||
test('should go to the dashboard after clicking on "Go to dashboard" button.', async () => {
|
||||
await authPage.getByRole('button', { name: 'Go to dashboard' }).click();
|
||||
|
||||
await expect(
|
||||
authPage.locator('[data-testId="dashboard-topbar"] h1')
|
||||
).toContainText(businessLegalName);
|
||||
});
|
||||
});
|
||||
});
|
||||
14
package-lock.json
generated
14
package-lock.json
generated
@@ -333,6 +333,12 @@
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
}
|
||||
},
|
||||
"@faker-js/faker": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.0.2.tgz",
|
||||
"integrity": "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==",
|
||||
"dev": true
|
||||
},
|
||||
"@gar/promisify": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
|
||||
@@ -945,6 +951,7 @@
|
||||
"version": "1.32.3",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.3.tgz",
|
||||
"integrity": "sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"fsevents": "2.3.2",
|
||||
@@ -954,7 +961,8 @@
|
||||
"playwright-core": {
|
||||
"version": "1.32.3",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.3.tgz",
|
||||
"integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg=="
|
||||
"integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1003,7 +1011,8 @@
|
||||
"@types/node": {
|
||||
"version": "18.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
|
||||
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA=="
|
||||
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.1",
|
||||
@@ -2324,6 +2333,7 @@
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
"shared/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.4.2",
|
||||
"@commitlint/config-conventional": "^17.4.2",
|
||||
"@commitlint/config-lerna-scopes": "^17.4.2",
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"husky": "^8.0.3",
|
||||
"lerna": "^6.4.1",
|
||||
"@commitlint/cli": "^17.4.2",
|
||||
"@playwright/test": "^1.32.3"
|
||||
"lerna": "^6.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "14.x"
|
||||
|
||||
@@ -92,6 +92,7 @@ export default class AuthenticationController extends BaseController {
|
||||
check('password')
|
||||
.exists()
|
||||
.isString()
|
||||
.isLength({ min: 6 })
|
||||
.trim()
|
||||
.escape()
|
||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||
@@ -106,7 +107,7 @@ export default class AuthenticationController extends BaseController {
|
||||
return [
|
||||
check('password')
|
||||
.exists()
|
||||
.isLength({ min: 5 })
|
||||
.isLength({ min: 6 })
|
||||
.custom((value, { req }) => {
|
||||
if (value !== req.body.confirm_password) {
|
||||
throw new Error("Passwords don't match");
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import { toInteger } from 'lodash';
|
||||
import { castCommaListEnvVarToArray, parseBoolean } from '@/utils';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const API_RATE_LIMIT = process.env.API_RATE_LIMIT?.split(',') || [];
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Your favorite port
|
||||
@@ -95,16 +98,15 @@ module.exports = {
|
||||
* JWT secret.
|
||||
*/
|
||||
jwtSecret: process.env.JWT_SECRET,
|
||||
resetPasswordSeconds: 600,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
customerSuccess: {
|
||||
email: 'success@bigcapital.ly',
|
||||
phoneNumber: '(218) 92 791 8381',
|
||||
},
|
||||
resetPasswordSeconds: 600,
|
||||
|
||||
/**
|
||||
* Application base URL.
|
||||
*/
|
||||
baseURL: process.env.BASE_URL,
|
||||
|
||||
/**
|
||||
@@ -131,19 +133,9 @@ module.exports = {
|
||||
blockDuration: 60 * 15,
|
||||
},
|
||||
requests: {
|
||||
points: 60,
|
||||
duration: 60,
|
||||
blockDuration: 60 * 10,
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Users registeration configuration.
|
||||
*/
|
||||
registration: {
|
||||
countries: {
|
||||
whitelist: ['LY'],
|
||||
blacklist: [],
|
||||
points: API_RATE_LIMIT[0] ? toInteger(API_RATE_LIMIT[0]) : 120,
|
||||
duration: API_RATE_LIMIT[1] ? toInteger(API_RATE_LIMIT[1]) : 60,
|
||||
blockDuration: API_RATE_LIMIT[2] ? toInteger(API_RATE_LIMIT[2]) : 60 * 10,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -167,8 +159,6 @@ module.exports = {
|
||||
browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT,
|
||||
},
|
||||
|
||||
protocol: '',
|
||||
hostname: '',
|
||||
scheduleComputeItemCost: 'in 5 seconds',
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,6 +41,8 @@ export interface ILedgerEntry {
|
||||
index: number;
|
||||
indexGroup?: number;
|
||||
|
||||
note?: string;
|
||||
|
||||
userId?: number;
|
||||
itemId?: number;
|
||||
branchId?: number;
|
||||
|
||||
@@ -1,38 +1,34 @@
|
||||
import { Container, Inject } from 'typedi';
|
||||
import AuthenticationService from '@/services/Authentication/AuthApplication';
|
||||
import { Container } from 'typedi';
|
||||
import AuthenticationMailMesssages from '@/services/Authentication/AuthenticationMailMessages';
|
||||
|
||||
export default class WelcomeEmailJob {
|
||||
export default class ResetPasswordEmailJob {
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {Agenda} agenda
|
||||
* @param {Agenda} agenda
|
||||
*/
|
||||
constructor(agenda) {
|
||||
agenda.define(
|
||||
'reset-password-mail',
|
||||
{ priority: 'high' },
|
||||
this.handler.bind(this),
|
||||
this.handler.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle send welcome mail job.
|
||||
* @param {Job} job
|
||||
* @param {Function} done
|
||||
* @param {Job} job
|
||||
* @param {Function} done
|
||||
*/
|
||||
public async handler(job, done: Function): Promise<void> {
|
||||
const { data } = job.attrs;
|
||||
const { user, token } = data;
|
||||
const Logger = Container.get('logger');
|
||||
const authService = Container.get(AuthenticationService);
|
||||
const authService = Container.get(AuthenticationMailMesssages);
|
||||
|
||||
Logger.info(`[send_reset_password] started.`, { data });
|
||||
|
||||
try {
|
||||
await authService.mailMessages.sendResetPasswordMessage(user, token);
|
||||
Logger.info(`[send_reset_password] finished.`, { data });
|
||||
done()
|
||||
await authService.sendResetPasswordMessage(user, token);
|
||||
done();
|
||||
} catch (error) {
|
||||
Logger.error(`[send_reset_password] error.`, { data, error });
|
||||
console.log(error);
|
||||
done(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Container } from 'typedi';
|
||||
|
||||
export default class SmsNotification {
|
||||
constructor(agenda) {
|
||||
agenda.define('sms-notification', { priority: 'high' }, this.handler);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Job}job
|
||||
*/
|
||||
async handler(job) {
|
||||
const { message, to } = job.attrs.data;
|
||||
const smsClient = Container.get('SMSClient');
|
||||
|
||||
try {
|
||||
await smsClient.sendMessage(to, message);
|
||||
} catch (error) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Container, Inject } from 'typedi';
|
||||
import AuthenticationService from '@/services/Authentication/AuthApplication';
|
||||
|
||||
export default class WelcomeSMSJob {
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {Agenda} agenda
|
||||
*/
|
||||
constructor(agenda) {
|
||||
agenda.define('welcome-sms', { priority: 'high' }, this.handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle send welcome mail job.
|
||||
* @param {Job} job
|
||||
* @param {Function} done
|
||||
*/
|
||||
public async handler(job, done: Function): Promise<void> {
|
||||
const { tenant, user } = job.attrs.data;
|
||||
|
||||
const Logger = Container.get('logger');
|
||||
const authService = Container.get(AuthenticationService);
|
||||
|
||||
Logger.info(`[welcome_sms] started: ${job.attrs.data}`);
|
||||
|
||||
try {
|
||||
await authService.smsMessages.sendWelcomeMessage(tenant, user);
|
||||
Logger.info(`[welcome_sms] finished`, { tenant, user });
|
||||
done();
|
||||
} catch (error) {
|
||||
Logger.info(`[welcome_sms] error`, { error, tenant, user });
|
||||
done(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Container } from 'typedi';
|
||||
import AuthenticationService from '@/services/Authentication/AuthApplication';
|
||||
|
||||
export default class WelcomeEmailJob {
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {Agenda} agenda -
|
||||
*/
|
||||
constructor(agenda) {
|
||||
// Welcome mail and SMS message.
|
||||
agenda.define(
|
||||
'welcome-email',
|
||||
{ priority: 'high' },
|
||||
this.handler.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle send welcome mail job.
|
||||
* @param {Job} job
|
||||
* @param {Function} done
|
||||
*/
|
||||
public async handler(job, done: Function): Promise<void> {
|
||||
const { organizationId, user } = job.attrs.data;
|
||||
const Logger: any = Container.get('logger');
|
||||
const authService = Container.get(AuthenticationService);
|
||||
|
||||
Logger.info(`[welcome_mail] started: ${job.attrs.data}`);
|
||||
|
||||
try {
|
||||
await authService.mailMessages.sendWelcomeMessage(user, organizationId);
|
||||
Logger.info(`[welcome_mail] finished: ${job.attrs.data}`);
|
||||
done();
|
||||
} catch (error) {
|
||||
Logger.error(`[welcome_mail] error: ${job.attrs.data}, error: ${error}`);
|
||||
done(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ import OrgBuildSmsNotificationSubscriber from '@/subscribers/Organization/BuildS
|
||||
import PurgeUserAbilityCache from '@/services/Users/PurgeUserAbilityCache';
|
||||
import ResetLoginThrottleSubscriber from '@/subscribers/Authentication/ResetLoginThrottle';
|
||||
import AuthenticationSubscriber from '@/subscribers/Authentication/SendResetPasswordMail';
|
||||
import AuthSendWelcomeMailSubscriber from '@/subscribers/Authentication/SendWelcomeMail';
|
||||
import PurgeAuthorizedUserOnceRoleMutate from '@/services/Roles/PurgeAuthorizedUser';
|
||||
import SendSmsNotificationToCustomer from '@/subscribers/SaleInvoices/SendSmsNotificationToCustomer';
|
||||
import SendSmsNotificationSaleReceipt from '@/subscribers/SaleReceipt/SendSmsNotificationToCustomer';
|
||||
@@ -120,7 +119,6 @@ export const susbcribers = () => {
|
||||
PurgeUserAbilityCache,
|
||||
ResetLoginThrottleSubscriber,
|
||||
AuthenticationSubscriber,
|
||||
AuthSendWelcomeMailSubscriber,
|
||||
PurgeAuthorizedUserOnceRoleMutate,
|
||||
SendSmsNotificationToCustomer,
|
||||
SendSmsNotificationSaleReceipt,
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import Agenda from 'agenda';
|
||||
import WelcomeEmailJob from 'jobs/welcomeEmail';
|
||||
import WelcomeSMSJob from 'jobs/WelcomeSMS';
|
||||
import ResetPasswordMailJob from 'jobs/ResetPasswordMail';
|
||||
import ComputeItemCost from 'jobs/ComputeItemCost';
|
||||
import RewriteInvoicesJournalEntries from 'jobs/writeInvoicesJEntries';
|
||||
import RewriteInvoicesJournalEntries from 'jobs/WriteInvoicesJEntries';
|
||||
import UserInviteMailJob from 'jobs/UserInviteMail';
|
||||
import OrganizationSetupJob from 'jobs/OrganizationSetup';
|
||||
import OrganizationUpgrade from 'jobs/OrganizationUpgrade';
|
||||
import SmsNotification from 'jobs/SmsNotification';
|
||||
|
||||
export default ({ agenda }: { agenda: Agenda }) => {
|
||||
new WelcomeEmailJob(agenda);
|
||||
new ResetPasswordMailJob(agenda);
|
||||
new WelcomeSMSJob(agenda);
|
||||
new UserInviteMailJob(agenda);
|
||||
new ComputeItemCost(agenda);
|
||||
new RewriteInvoicesJournalEntries(agenda);
|
||||
new OrganizationSetupJob(agenda);
|
||||
new OrganizationUpgrade(agenda);
|
||||
new SmsNotification(agenda);
|
||||
|
||||
agenda.start();
|
||||
};
|
||||
|
||||
@@ -21,6 +21,8 @@ export const transformLedgerEntryToTransaction = (
|
||||
transactionNumber: entry.transactionNumber,
|
||||
referenceNumber: entry.referenceNumber,
|
||||
|
||||
note: entry.note,
|
||||
|
||||
index: entry.index,
|
||||
indexGroup: entry.indexGroup,
|
||||
|
||||
|
||||
@@ -5,59 +5,24 @@ import Mail from '@/lib/Mail';
|
||||
|
||||
@Service()
|
||||
export default class AuthenticationMailMesssages {
|
||||
/**
|
||||
* Sends welcome message.
|
||||
* @param {ISystemUser} user - The system user.
|
||||
* @param {string} organizationName -
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async sendWelcomeMessage(
|
||||
user: ISystemUser,
|
||||
organizationId: string
|
||||
): Promise<void> {
|
||||
const root = __dirname + '/../../../views/images/bigcapital.png';
|
||||
|
||||
const mail = new Mail()
|
||||
.setView('mail/Welcome.html')
|
||||
.setSubject('Welcome to Bigcapital')
|
||||
.setTo(user.email)
|
||||
.setAttachments([
|
||||
{
|
||||
filename: 'bigcapital.png',
|
||||
path: root,
|
||||
cid: 'bigcapital_logo',
|
||||
},
|
||||
])
|
||||
.setData({
|
||||
firstName: user.firstName,
|
||||
organizationId,
|
||||
successPhoneNumber: config.customerSuccess.phoneNumber,
|
||||
successEmail: config.customerSuccess.email,
|
||||
});
|
||||
|
||||
await mail.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends reset password message.
|
||||
* @param {ISystemUser} user - The system user.
|
||||
* @param {string} token - Reset password token.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async sendResetPasswordMessage(
|
||||
public async sendResetPasswordMessage(
|
||||
user: ISystemUser,
|
||||
token: string
|
||||
): Promise<void> {
|
||||
const root = __dirname + '/../../../views/images/bigcapital.png';
|
||||
|
||||
const mail = new Mail()
|
||||
await new Mail()
|
||||
.setSubject('Bigcapital - Password Reset')
|
||||
.setView('mail/ResetPassword.html')
|
||||
.setTo(user.email)
|
||||
.setAttachments([
|
||||
{
|
||||
filename: 'bigcapital.png',
|
||||
path: root,
|
||||
path: `${global.__views_dir}/images/bigcapital.png`,
|
||||
cid: 'bigcapital_logo',
|
||||
},
|
||||
])
|
||||
@@ -65,9 +30,7 @@ export default class AuthenticationMailMesssages {
|
||||
resetPasswordUrl: `${config.baseURL}/auth/reset_password/${token}`,
|
||||
first_name: user.firstName,
|
||||
last_name: user.lastName,
|
||||
contact_us_email: config.contactUsMail,
|
||||
});
|
||||
|
||||
await mail.send();
|
||||
})
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { ISystemUser, ITenant } from '@/interfaces';
|
||||
|
||||
@Service()
|
||||
export default class AuthenticationSMSMessages {
|
||||
@Inject('SMSClient')
|
||||
smsClient: any;
|
||||
|
||||
/**
|
||||
* Sends welcome sms message.
|
||||
* @param {ITenant} tenant
|
||||
* @param {ISystemUser} user
|
||||
*/
|
||||
sendWelcomeMessage(tenant: ITenant, user: ISystemUser) {
|
||||
const message: string = `Hi ${user.firstName}, Welcome to Bigcapital, You've joined the new workspace, if you need any help please don't hesitate to contact us.`;
|
||||
|
||||
return this.smsClient.sendMessage(user.phoneNumber, message);
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,8 @@ export default class CashflowTransactionJournalEntries {
|
||||
|
||||
/**
|
||||
* Retrieves the common entry of cashflow transaction.
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @returns {}
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @returns {Partial<ILedgerEntry>}
|
||||
*/
|
||||
private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => {
|
||||
const { entries, ...transaction } = cashflowTransaction;
|
||||
@@ -41,7 +41,9 @@ export default class CashflowTransactionJournalEntries {
|
||||
),
|
||||
transactionId: transaction.id,
|
||||
transactionNumber: transaction.transactionNumber,
|
||||
referenceNo: transaction.referenceNo,
|
||||
referenceNumber: transaction.referenceNo,
|
||||
|
||||
note: transaction.description,
|
||||
|
||||
branchId: cashflowTransaction.branchId,
|
||||
userId: cashflowTransaction.userId,
|
||||
@@ -76,9 +78,9 @@ export default class CashflowTransactionJournalEntries {
|
||||
|
||||
/**
|
||||
* Retrieves the cashflow credit GL entry.
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @param {ICashflowTransactionLine} entry
|
||||
* @param {number} index
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @param {ICashflowTransactionLine} entry
|
||||
* @param {number} index
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
private getCashflowCreditGLEntry = (
|
||||
@@ -102,10 +104,10 @@ export default class CashflowTransactionJournalEntries {
|
||||
|
||||
/**
|
||||
* Retrieves the cashflow transaction GL entry.
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @param {ICashflowTransactionLine} entry
|
||||
* @param {number} index
|
||||
* @returns
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @param {ICashflowTransactionLine} entry
|
||||
* @param {number} index
|
||||
* @returns {ILedgerEntry[]}
|
||||
*/
|
||||
private getJournalEntries = (
|
||||
cashflowTransaction: ICashflowTransaction
|
||||
@@ -118,7 +120,7 @@ export default class CashflowTransactionJournalEntries {
|
||||
|
||||
/**
|
||||
* Retrieves the cashflow GL ledger.
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @returns {Ledger}
|
||||
*/
|
||||
private getCashflowLedger = (cashflowTransaction: ICashflowTransaction) => {
|
||||
@@ -130,6 +132,7 @@ export default class CashflowTransactionJournalEntries {
|
||||
* Write the journal entries of the given cashflow transaction.
|
||||
* @param {number} tenantId
|
||||
* @param {ICashflowTransaction} cashflowTransaction
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public writeJournalEntries = async (
|
||||
tenantId: number,
|
||||
@@ -153,6 +156,7 @@ export default class CashflowTransactionJournalEntries {
|
||||
* Delete the journal entries.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} cashflowTransactionId - Cashflow transaction id.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public revertJournalEntries = async (
|
||||
tenantId: number,
|
||||
|
||||
@@ -9,7 +9,6 @@ import events from '@/subscribers/events';
|
||||
import UnitOfWork from '@/services/UnitOfWork';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import { CommandExpenseValidator } from './CommandExpenseValidator';
|
||||
import { ExpenseCategory } from 'models';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
@Service()
|
||||
@@ -37,7 +36,7 @@ export class DeleteExpense {
|
||||
expenseId: number,
|
||||
authorizedUser: ISystemUser
|
||||
): Promise<void> => {
|
||||
const { Expense } = this.tenancy.models(tenantId);
|
||||
const { Expense, ExpenseCategory } = this.tenancy.models(tenantId);
|
||||
|
||||
// Retrieves the expense transaction with associated entries or
|
||||
// throw not found error.
|
||||
@@ -60,7 +59,7 @@ export class DeleteExpense {
|
||||
} as IExpenseDeletingPayload);
|
||||
|
||||
// Deletes expense associated entries.
|
||||
await ExpenseCategory.query(trx).findById(expenseId).delete();
|
||||
await ExpenseCategory.query(trx).where('expenseId', expenseId).delete();
|
||||
|
||||
// Deletes expense transactions.
|
||||
await Expense.query(trx).findById(expenseId).delete();
|
||||
|
||||
@@ -46,7 +46,7 @@ export class ExpenseGLEntries {
|
||||
...commonEntry,
|
||||
credit: expense.localAmount,
|
||||
accountId: expense.paymentAccountId,
|
||||
accountNormal: AccountNormal.CREDIT,
|
||||
accountNormal: AccountNormal.DEBIT,
|
||||
index: 1,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import events from '@/subscribers/events';
|
||||
@Service()
|
||||
export default class AuthenticationSubscriber {
|
||||
@Inject('agenda')
|
||||
agenda: any;
|
||||
private agenda: any;
|
||||
|
||||
/**
|
||||
* Attaches events with handlers.
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import events from '@/subscribers/events';
|
||||
|
||||
@Service()
|
||||
export default class AuthSendWelcomeMailSubscriber {
|
||||
@Inject('agenda')
|
||||
agenda: any;
|
||||
|
||||
/**
|
||||
* Attaches events with handlers.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(events.auth.signUp, this.sendWelcomeEmailOnceUserRegister);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends welcome email once the user register.
|
||||
*/
|
||||
private sendWelcomeEmailOnceUserRegister = async (payload) => {
|
||||
const { tenant, user } = payload;
|
||||
|
||||
// Send welcome mail to the user.
|
||||
await this.agenda.now('welcome-email', {
|
||||
organizationId: tenant.organizationId,
|
||||
user,
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,411 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Bigcapital | Reset your password</title>
|
||||
<style>
|
||||
/* -------------------------------------
|
||||
GLOBAL RESETS
|
||||
------------------------------------- */
|
||||
|
||||
/*All the styling goes here*/
|
||||
|
||||
img {
|
||||
border: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
font-family: sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
width: 100%; }
|
||||
table td {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BODY & CONTAINER
|
||||
------------------------------------- */
|
||||
|
||||
.body {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
|
||||
.container {
|
||||
display: block;
|
||||
margin: 0 auto !important;
|
||||
/* makes it centered */
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
width: 580px;
|
||||
}
|
||||
|
||||
/* This should also be a block element, so that it will fill 100% of the .container */
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
HEADER, FOOTER, MAIN
|
||||
------------------------------------- */
|
||||
.main {
|
||||
background: #ffffff;
|
||||
border-radius: 3px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
clear: both;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.footer td,
|
||||
.footer p,
|
||||
.footer span,
|
||||
.footer a {
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
TYPOGRAPHY
|
||||
------------------------------------- */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
color: #000000;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p li,
|
||||
ul li,
|
||||
ol li {
|
||||
list-style-position: inside;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BUTTONS
|
||||
------------------------------------- */
|
||||
.btn {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
.btn > tbody > tr > td {
|
||||
padding-bottom: 15px; }
|
||||
.btn table {
|
||||
width: auto;
|
||||
}
|
||||
.btn table td {
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.btn a {
|
||||
background-color: #ffffff;
|
||||
border: solid 1px #3498db;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
color: #3498db;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 12px 25px;
|
||||
text-decoration: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.btn-primary table td {
|
||||
background-color: #2d95fd;
|
||||
}
|
||||
|
||||
.btn-primary a {
|
||||
background-color: #2d95fd;
|
||||
border-color: #2d95fd;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
OTHER STYLES THAT MIGHT BE USEFUL
|
||||
------------------------------------- */
|
||||
.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.mt0 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mb4{
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.preheader {
|
||||
color: transparent;
|
||||
display: none;
|
||||
height: 0;
|
||||
max-height: 0;
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
mso-hide: all;
|
||||
visibility: hidden;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.powered-by a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||
------------------------------------- */
|
||||
@media only screen and (max-width: 620px) {
|
||||
table[class=body] h1 {
|
||||
font-size: 28px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
table[class=body] p,
|
||||
table[class=body] ul,
|
||||
table[class=body] ol,
|
||||
table[class=body] td,
|
||||
table[class=body] span,
|
||||
table[class=body] a {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
table[class=body] .wrapper,
|
||||
table[class=body] .article {
|
||||
padding: 10px !important;
|
||||
}
|
||||
table[class=body] .content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
table[class=body] .container {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .main {
|
||||
border-left-width: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
}
|
||||
table[class=body] .btn table {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .btn a {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .img-responsive {
|
||||
height: auto !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------
|
||||
PRESERVE THESE STYLES IN THE HEAD
|
||||
------------------------------------- */
|
||||
@media all {
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
.ExternalClass,
|
||||
.ExternalClass p,
|
||||
.ExternalClass span,
|
||||
.ExternalClass font,
|
||||
.ExternalClass td,
|
||||
.ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
.apple-link a {
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
#MessageViewBody a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
.btn-primary table td:hover {
|
||||
background-color: #004dd0 !important;
|
||||
}
|
||||
.btn-primary a:hover {
|
||||
background-color: #004dd0 !important;
|
||||
border-color: #004dd0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[data-icon="bigcapital"] path {
|
||||
fill: #004dd0;
|
||||
}
|
||||
|
||||
[data-icon='bigcapital'] .path-1,
|
||||
[data-icon='bigcapital'] .path-13 {
|
||||
fill: #2d95fd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="">
|
||||
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td class="container">
|
||||
<div class="content">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<table role="presentation" class="main">
|
||||
<!-- START MAIN CONTENT AREA -->
|
||||
<tr>
|
||||
<td class="wrapper">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<p class="align-center">
|
||||
<svg data-icon="bigcapital" class="bigcapital" width="190" height="37" viewBox="0 0 309.09 42.89"><desc>bigcapital</desc><path d="M56,3.16,61.33,8.5,31.94,37.9l-5.35-5.35Z" class="path-1" fill-rule="evenodd"></path><path d="M29.53,6.94l5.35,5.34L5.49,41.67.14,36.33l15.8-15.8Z" class="path-2" fill-rule="evenodd"></path><path d="M94.36,38.87H79.62v-31H94c6.33,0,10.22,3.15,10.22,8V16a7.22,7.22,0,0,1-4.07,6.69c3.58,1.37,5.8,3.45,5.8,7.61v.09C106,36,101.35,38.87,94.36,38.87Zm3.1-21.81c0-2-1.59-3.19-4.47-3.19H86.26v6.55h6.29c3,0,4.91-1,4.91-3.28Zm1.72,12.39c0-2.08-1.54-3.37-5-3.37H86.26V32.9h8.1c3,0,4.82-1.06,4.82-3.36Z" class="path-3" fill-rule="evenodd"></path><path d="M110.56,12.54v-6h7.08v6Zm.18,26.33V15.15h6.72V38.87Z" class="path-4" fill-rule="evenodd"></path><path d="M134,46a22.55,22.55,0,0,1-10.49-2.47l2.3-5a15.52,15.52,0,0,0,8,2.17c4.61,0,6.78-2.21,6.78-6.46V33.08c-2,2.39-4.16,3.85-7.75,3.85-5.53,0-10.53-4-10.53-11.07v-.09c0-7.08,5.09-11.06,10.53-11.06a9.63,9.63,0,0,1,7.66,3.54v-3.1h6.72V33.52C147.2,42.46,142.78,46,134,46Zm6.6-20.27a5.79,5.79,0,0,0-11.56,0v.09a5.42,5.42,0,0,0,5.76,5.49,5.49,5.49,0,0,0,5.8-5.49Z" class="path-5" fill-rule="evenodd"></path><path d="M164,39.41a12.11,12.11,0,0,1-12.35-12.26v-.09a12.18,12.18,0,0,1,12.44-12.35c4.47,0,7.25,1.5,9.47,4l-4.12,4.43a6.93,6.93,0,0,0-5.4-2.61c-3.36,0-5.75,3-5.75,6.46v.09c0,3.63,2.34,6.55,6,6.55,2.26,0,3.8-1,5.44-2.53l3.94,4A12,12,0,0,1,164,39.41Z" class="path-6" fill-rule="evenodd"></path><path d="M191.51,38.87V36.31a9.15,9.15,0,0,1-7.17,3c-4.47,0-8.15-2.57-8.15-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.72-4.34-5.09-4.34a17.57,17.57,0,0,0-6.55,1.28l-1.68-5.13a21,21,0,0,1,9.21-1.9c7.34,0,10.57,3.8,10.57,10.22V38.87Zm.13-9.55a10.3,10.3,0,0,0-4.29-.89c-2.88,0-4.65,1.15-4.65,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.15,0,5.27-1.73,5.27-4.16Z" class="path-7" fill-rule="evenodd"></path><path d="M217.49,39.32a9.1,9.1,0,0,1-7.39-3.54V46h-6.73V15.15h6.73v3.41a8.7,8.7,0,0,1,7.39-3.85c5.53,0,10.8,4.34,10.8,12.26v.09C228.29,35,223.11,39.32,217.49,39.32ZM221.56,27c0-3.94-2.66-6.55-5.8-6.55S210,23,210,27v.09c0,3.94,2.61,6.55,5.75,6.55s5.8-2.57,5.8-6.55Z" class="path-8" fill-rule="evenodd"></path><path d="M232.93,12.54v-6H240v6Zm.18,26.33V15.15h6.73V38.87Z" class="path-9" fill-rule="evenodd"></path><path d="M253.73,39.27c-4.11,0-6.9-1.63-6.9-7.12V20.91H244V15.15h2.83V9.09h6.73v6.06h5.57v5.76h-5.57V31c0,1.55.66,2.3,2.16,2.3A6.84,6.84,0,0,0,259,32.5v5.4A9.9,9.9,0,0,1,253.73,39.27Z" class="path-10" fill-rule="evenodd"></path><path d="M277.55,38.87V36.31a9.15,9.15,0,0,1-7.18,3c-4.46,0-8.14-2.57-8.14-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.73-4.34-5.09-4.34A17.57,17.57,0,0,0,266,21.92l-1.68-5.13a20.94,20.94,0,0,1,9.2-1.9c7.35,0,10.58,3.8,10.58,10.22V38.87Zm.13-9.55a10.31,10.31,0,0,0-4.3-.89c-2.87,0-4.64,1.15-4.64,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.14,0,5.27-1.73,5.27-4.16Z" class="path-11" fill-rule="evenodd"></path><path d="M289.72,38.87V6.57h6.72v32.3Z" class="path-12" fill-rule="evenodd"></path><path d="M302.06,38.87V31.79h7.17v7.08Z" class="path-13" fill-rule="evenodd"></path></svg>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p class="align-center">
|
||||
<h3>License Code</h3>
|
||||
</p>
|
||||
<p class="mgb-1x">
|
||||
<h1>{{ licenseCode }}</h1>
|
||||
</p>
|
||||
<p class="email-note">
|
||||
This is an automatically generated email please do not reply to
|
||||
this email. If you face any issues, please contact us at <a href="mailto:{{ successEmail }}">{{ successEmail }}</a> or call <u>{{ successPhoneNumber }}</u></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- END MAIN CONTENT AREA -->
|
||||
</table>
|
||||
<!-- END CENTERED WHITE CONTAINER -->
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<div class="footer">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block powered-by">
|
||||
Powered by <a href="http://htmlemail.io">Bigcapital.com</a>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- END FOOTER -->
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -391,10 +391,8 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>If you did not make this request, please contact us or ignore this message.</p>
|
||||
<p class="email-note">
|
||||
This is an automatically generated email please do not reply to
|
||||
this email. If you face any issues, please contact us at {{ contact_us_email }}</p>
|
||||
<p>If this was a mistake, just ignore this email and nothing will happen.</p>
|
||||
<p class="email-note">This is an automatically generated email please do not reply to this email.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1,407 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Bigcapital | Reset your password</title>
|
||||
<style>
|
||||
/* -------------------------------------
|
||||
GLOBAL RESETS
|
||||
------------------------------------- */
|
||||
|
||||
img {
|
||||
border: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
font-family: sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
width: 100%; }
|
||||
table td {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BODY & CONTAINER
|
||||
------------------------------------- */
|
||||
|
||||
.body {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
|
||||
.container {
|
||||
display: block;
|
||||
margin: 0 auto !important;
|
||||
/* makes it centered */
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
width: 580px;
|
||||
}
|
||||
|
||||
/* This should also be a block element, so that it will fill 100% of the .container */
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
HEADER, FOOTER, MAIN
|
||||
------------------------------------- */
|
||||
.main {
|
||||
background: #ffffff;
|
||||
border-radius: 3px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
clear: both;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.footer td,
|
||||
.footer p,
|
||||
.footer span,
|
||||
.footer a {
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
TYPOGRAPHY
|
||||
------------------------------------- */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
color: #000000;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p li,
|
||||
ul li,
|
||||
ol li {
|
||||
list-style-position: inside;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BUTTONS
|
||||
------------------------------------- */
|
||||
.btn {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
.btn > tbody > tr > td {
|
||||
padding-bottom: 15px; }
|
||||
.btn table {
|
||||
width: auto;
|
||||
}
|
||||
.btn table td {
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.btn a {
|
||||
background-color: #ffffff;
|
||||
border: solid 1px #3498db;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
color: #3498db;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 12px 25px;
|
||||
text-decoration: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.btn-primary table td {
|
||||
background-color: #2d95fd;
|
||||
}
|
||||
|
||||
.btn-primary a {
|
||||
background-color: #2d95fd;
|
||||
border-color: #2d95fd;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
OTHER STYLES THAT MIGHT BE USEFUL
|
||||
------------------------------------- */
|
||||
.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.mt0 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mb4{
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.preheader {
|
||||
color: transparent;
|
||||
display: none;
|
||||
height: 0;
|
||||
max-height: 0;
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
mso-hide: all;
|
||||
visibility: hidden;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.powered-by a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||
------------------------------------- */
|
||||
@media only screen and (max-width: 620px) {
|
||||
table[class=body] h1 {
|
||||
font-size: 28px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
table[class=body] p,
|
||||
table[class=body] ul,
|
||||
table[class=body] ol,
|
||||
table[class=body] td,
|
||||
table[class=body] span,
|
||||
table[class=body] a {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
table[class=body] .wrapper,
|
||||
table[class=body] .article {
|
||||
padding: 10px !important;
|
||||
}
|
||||
table[class=body] .content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
table[class=body] .container {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .main {
|
||||
border-left-width: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
}
|
||||
table[class=body] .btn table {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .btn a {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .img-responsive {
|
||||
height: auto !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------
|
||||
PRESERVE THESE STYLES IN THE HEAD
|
||||
------------------------------------- */
|
||||
@media all {
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
.ExternalClass,
|
||||
.ExternalClass p,
|
||||
.ExternalClass span,
|
||||
.ExternalClass font,
|
||||
.ExternalClass td,
|
||||
.ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
.apple-link a {
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
#MessageViewBody a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
.btn-primary table td:hover {
|
||||
background-color: #004dd0 !important;
|
||||
}
|
||||
.btn-primary a:hover {
|
||||
background-color: #004dd0 !important;
|
||||
border-color: #004dd0 !important;
|
||||
}
|
||||
}
|
||||
[data-icon="bigcapital"] path {
|
||||
fill: #004dd0;
|
||||
}
|
||||
|
||||
[data-icon='bigcapital'] .path-1,
|
||||
[data-icon='bigcapital'] .path-13 {
|
||||
fill: #2d95fd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="">
|
||||
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td class="container">
|
||||
<div class="content">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<table role="presentation" class="main">
|
||||
<!-- START MAIN CONTENT AREA -->
|
||||
<tr>
|
||||
<td class="wrapper">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<p class="align-center">
|
||||
<img src="cid:bigcapital_logo" />
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<p class="align-center">
|
||||
<h3>Hi {{ firstName }}, Welcome to Bigcapital, </h3>
|
||||
</p>
|
||||
|
||||
<p class="mgb-1x">
|
||||
Your organization Id: <strong>{{ organizationId }}</strong>
|
||||
</p>
|
||||
<p class="mgb-1x">We are available to help you get started and answer any questions you may have. You can also email <a href="mailto:{{ successEmail }}">{{ successEmail }}</a> or call <u>{{ successPhoneNumber }}</u> about your set-up questions.</p>
|
||||
|
||||
<p class="mgb-2-5x">Thank you for trusting Bigcapital Software for your business needs. We look forward to serving you!</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- END MAIN CONTENT AREA -->
|
||||
</table>
|
||||
<!-- END CENTERED WHITE CONTAINER -->
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<div class="footer">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block powered-by">
|
||||
Made by Bigcapital Technologies, Inc
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- END FOOTER -->
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
16
packages/webapp/package-lock.json
generated
16
packages/webapp/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bigcapital/webapp",
|
||||
"version": "1.7.1",
|
||||
"version": "0.9.6",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1205,9 +1205,9 @@
|
||||
}
|
||||
},
|
||||
"@blueprintjs-formik/core": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/core/-/core-0.3.3.tgz",
|
||||
"integrity": "sha512-ko7g54YSEcSq2K/GEpmiTG0foGLqe7DwgXGhkGxYEiHhLAUv8WvQmrFsm8e/KOW7n8mLGq0uaZVe2l8m3JTGGQ==",
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/core/-/core-0.3.4.tgz",
|
||||
"integrity": "sha512-gksuBYXXvX7IhZXbPEFEAHgmJWp1vt/GTMW0GYBkCoGBAvXy08hIHjMc85M0WNyen+tic3NRas6I2wsjgokgqw==",
|
||||
"requires": {
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.keyby": "^4.6.0",
|
||||
@@ -1227,9 +1227,9 @@
|
||||
}
|
||||
},
|
||||
"@blueprintjs-formik/select": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.3.tgz",
|
||||
"integrity": "sha512-j/zkX0B9wgtoHgK6Z/rlowB7F7zemrAajBU+d3caCoEYMMqwAI0XA++GytqrIhv5fEGjkZ1hkxS9j8eqX8vtjA==",
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.5.tgz",
|
||||
"integrity": "sha512-Sztf5dOemedUBfEjnDWD8ryfMU/x95hyhIgJT5/ywC/jQfX+d/K2OhujklTrCDzQilUeAJLoVkSdV+w77n8ckQ==",
|
||||
"requires": {
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.keyby": "^4.6.0",
|
||||
@@ -17751,4 +17751,4 @@
|
||||
"integrity": "sha512-7UlRWU4Q3uCMCeDVMOm7eBrIu145OqsIJ3p6zq58l8UsSYwKWxc6zEapC5YA9tIeh0oheb4cT9Kk2Wq353loFg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "0.9.6",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@blueprintjs-formik/core": "^0.3.3",
|
||||
"@blueprintjs-formik/core": "^0.3.4",
|
||||
"@blueprintjs-formik/datetime": "^0.3.4",
|
||||
"@blueprintjs-formik/select": "^0.2.3",
|
||||
"@blueprintjs-formik/select": "^0.2.5",
|
||||
"@blueprintjs/core": "^3.50.2",
|
||||
"@blueprintjs/datetime": "^3.23.12",
|
||||
"@blueprintjs/popover2": "^0.11.1",
|
||||
|
||||
@@ -5,59 +5,20 @@ import { MenuItem, Button } from '@blueprintjs/core';
|
||||
import { FSelect } from '../Forms';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} query
|
||||
* @param {*} branch
|
||||
* @param {*} _index
|
||||
* @param {*} exactMatch
|
||||
* @returns
|
||||
*/
|
||||
const branchItemPredicate = (query, branch, _index, exactMatch) => {
|
||||
const normalizedTitle = branch.name.toLowerCase();
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
|
||||
if (exactMatch) {
|
||||
return normalizedTitle === normalizedQuery;
|
||||
} else {
|
||||
return `${branch.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} film
|
||||
* @param {*} param1
|
||||
* @returns
|
||||
*/
|
||||
const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
|
||||
const text = `${branch.name}`;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
disabled={modifiers.disabled}
|
||||
label={branch.code}
|
||||
key={branch.id}
|
||||
onClick={handleClick}
|
||||
text={text}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const branchSelectProps = {
|
||||
itemPredicate: branchItemPredicate,
|
||||
itemRenderer: branchItemRenderer,
|
||||
valueAccessor: 'id',
|
||||
labelAccessor: 'name',
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Branch select field.
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export function BranchSelect({ branches, ...rest }) {
|
||||
return <FSelect {...branchSelectProps} {...rest} items={branches} />;
|
||||
return (
|
||||
<FSelect
|
||||
valueAccessor={'id'}
|
||||
textAccessor={'name'}
|
||||
labelAccessor={'code'}
|
||||
{...rest}
|
||||
items={branches}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as R from 'ramda';
|
||||
|
||||
import { ButtonLink } from '../Button';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
function CustomerDrawerLinkComponent({
|
||||
// #ownProps
|
||||
@@ -16,7 +17,7 @@ function CustomerDrawerLinkComponent({
|
||||
}) {
|
||||
// Handle view customer drawer.
|
||||
const handleCustomerDrawer = (event) => {
|
||||
openDrawer('customer-detail-drawer', { customerId });
|
||||
openDrawer(DRAWERS.CUSTOMER_DETAILS, { customerId });
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import React, { useCallback, useState, useEffect, useMemo } from 'react';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import intl from 'react-intl-universal';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import { MenuItem, Button } from '@blueprintjs/core';
|
||||
import { Select } from '@blueprintjs/select';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
|
||||
import {
|
||||
itemPredicate,
|
||||
handleContactRenderer,
|
||||
createNewItemRenderer,
|
||||
createNewItemFromQuery,
|
||||
} from './utils';
|
||||
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
function CustomerSelectFieldRoot({
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
|
||||
// #ownProps
|
||||
contacts,
|
||||
initialContactId,
|
||||
selectedContactId,
|
||||
defaultSelectText = <T id={'select_contact'} />,
|
||||
onContactSelected,
|
||||
popoverFill = false,
|
||||
disabled = false,
|
||||
allowCreate,
|
||||
buttonProps,
|
||||
|
||||
...restProps
|
||||
}) {
|
||||
const localContacts = useMemo(
|
||||
() =>
|
||||
contacts.map((contact) => ({
|
||||
...contact,
|
||||
_id: `${contact.id}_${contact.contact_type}`,
|
||||
})),
|
||||
[contacts],
|
||||
);
|
||||
|
||||
const initialContact = useMemo(
|
||||
() => contacts.find((a) => a.id === initialContactId),
|
||||
[initialContactId, contacts],
|
||||
);
|
||||
|
||||
const [selecetedContact, setSelectedContact] = useState(
|
||||
initialContact || null,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof selectedContactId !== 'undefined') {
|
||||
const account = selectedContactId
|
||||
? contacts.find((a) => a.id === selectedContactId)
|
||||
: null;
|
||||
setSelectedContact(account);
|
||||
}
|
||||
}, [selectedContactId, contacts, setSelectedContact]);
|
||||
|
||||
const handleContactSelect = useCallback(
|
||||
(contact) => {
|
||||
if (contact.id) {
|
||||
setSelectedContact({ ...contact });
|
||||
onContactSelected && onContactSelected(contact);
|
||||
} else {
|
||||
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
|
||||
}
|
||||
},
|
||||
[setSelectedContact, onContactSelected, openDrawer],
|
||||
);
|
||||
|
||||
// Maybe inject create new item props to suggest component.
|
||||
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
|
||||
const maybeCreateNewItemFromQuery = allowCreate
|
||||
? createNewItemFromQuery
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Select
|
||||
items={localContacts}
|
||||
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
|
||||
itemRenderer={handleContactRenderer}
|
||||
itemPredicate={itemPredicate}
|
||||
filterable={true}
|
||||
disabled={disabled}
|
||||
onItemSelect={handleContactSelect}
|
||||
popoverProps={{ minimal: true, usePortal: !popoverFill }}
|
||||
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
|
||||
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
|
||||
})}
|
||||
inputProps={{
|
||||
placeholder: intl.get('filter_'),
|
||||
}}
|
||||
createNewItemRenderer={maybeCreateNewItemRenderer}
|
||||
createNewItemFromQuery={maybeCreateNewItemFromQuery}
|
||||
createNewItemPosition={'top'}
|
||||
{...restProps}
|
||||
>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
text={
|
||||
selecetedContact ? selecetedContact.display_name : defaultSelectText
|
||||
}
|
||||
{...buttonProps}
|
||||
/>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
export const CustomerSelectField = R.compose(withDrawerActions)(
|
||||
CustomerSelectFieldRoot,
|
||||
);
|
||||
48
packages/webapp/src/components/Customers/CustomersSelect.tsx
Normal file
48
packages/webapp/src/components/Customers/CustomersSelect.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
|
||||
import { FSelect } from '../Forms';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Customer select field.
|
||||
* @returns {React.ReactNode}
|
||||
*/
|
||||
function CustomerSelectRoot({
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
|
||||
// #ownProps
|
||||
items,
|
||||
allowCreate,
|
||||
...props
|
||||
}) {
|
||||
// Maybe inject create new item props to suggest component.
|
||||
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
|
||||
const maybeCreateNewItemFromQuery = allowCreate
|
||||
? createNewItemFromQuery
|
||||
: null;
|
||||
|
||||
// Handles the create item click.
|
||||
const handleCreateItemClick = () => {
|
||||
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
|
||||
};
|
||||
|
||||
return (
|
||||
<FSelect
|
||||
items={items}
|
||||
textAccessor={'display_name'}
|
||||
labelAccessor={'code'}
|
||||
valueAccessor={'id'}
|
||||
popoverProps={{ minimal: true, usePortal: true, inline: false }}
|
||||
createNewItemRenderer={maybeCreateNewItemRenderer}
|
||||
createNewItemFromQuery={maybeCreateNewItemFromQuery}
|
||||
onCreateItemSelect={handleCreateItemClick}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const CustomersSelect = R.compose(withDrawerActions)(CustomerSelectRoot);
|
||||
@@ -1,3 +1,3 @@
|
||||
// @ts-nocheck
|
||||
export * from './CustomerSelectField';
|
||||
export * from './CustomerDrawerLink';
|
||||
export * from './CustomersSelect';
|
||||
|
||||
@@ -53,7 +53,7 @@ function DashboardTopbar({
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="dashboard__topbar">
|
||||
<div class="dashboard__topbar" data-testId={'dashboard-topbar'}>
|
||||
<div class="dashboard__topbar-left">
|
||||
<div class="dashboard__topbar-sidebar-toggle">
|
||||
<Tooltip
|
||||
|
||||
@@ -31,28 +31,28 @@ import { DRAWERS } from '@/constants/drawers';
|
||||
export default function DrawersContainer() {
|
||||
return (
|
||||
<div>
|
||||
<AccountDrawer name={DRAWERS.ACCOUNT} />
|
||||
<ManualJournalDrawer name={DRAWERS.JOURNAL} />
|
||||
<ExpenseDrawer name={DRAWERS.EXPENSE} />
|
||||
<BillDrawer name={DRAWERS.BILL} />
|
||||
<InvoiceDetailDrawer name={DRAWERS.INVOICE} />
|
||||
<EstimateDetailDrawer name={DRAWERS.ESTIMATE} />
|
||||
<ReceiptDetailDrawer name={DRAWERS.RECEIPT} />
|
||||
<PaymentReceiveDetailDrawer name={DRAWERS.PAYMENT_RECEIVE} />
|
||||
<PaymentMadeDetailDrawer name={DRAWERS.PAYMENT_MADE} />
|
||||
<ItemDetailDrawer name={DRAWERS.ITEM} />
|
||||
<CustomerDetailsDrawer name={DRAWERS.CUSTOMER} />
|
||||
<VendorDetailsDrawer name={DRAWERS.VENDOR} />
|
||||
<InventoryAdjustmentDetailDrawer name={DRAWERS.INVENTORY_ADJUSTMENT} />
|
||||
<CashflowTransactionDetailDrawer name={DRAWERS.CASHFLOW_TRNASACTION} />
|
||||
<AccountDrawer name={DRAWERS.ACCOUNT_DETAILS} />
|
||||
<ManualJournalDrawer name={DRAWERS.JOURNAL_DETAILS} />
|
||||
<ExpenseDrawer name={DRAWERS.EXPENSE_DETAILS} />
|
||||
<BillDrawer name={DRAWERS.BILL_DETAILS} />
|
||||
<InvoiceDetailDrawer name={DRAWERS.INVOICE_DETAILS} />
|
||||
<EstimateDetailDrawer name={DRAWERS.ESTIMATE_DETAILS} />
|
||||
<ReceiptDetailDrawer name={DRAWERS.RECEIPT_DETAILS} />
|
||||
<PaymentReceiveDetailDrawer name={DRAWERS.PAYMENT_RECEIVE_DETAILS} />
|
||||
<PaymentMadeDetailDrawer name={DRAWERS.PAYMENT_MADE_DETAILS} />
|
||||
<ItemDetailDrawer name={DRAWERS.ITEM_DETAILS} />
|
||||
<CustomerDetailsDrawer name={DRAWERS.CUSTOMER_DETAILS} />
|
||||
<VendorDetailsDrawer name={DRAWERS.VENDOR_DETAILS} />
|
||||
<InventoryAdjustmentDetailDrawer name={DRAWERS.INVENTORY_ADJUSTMENT_DETAILS} />
|
||||
<CashflowTransactionDetailDrawer name={DRAWERS.CASHFLOW_TRNASACTION_DETAILS} />
|
||||
<QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} />
|
||||
<QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} />
|
||||
<QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} />
|
||||
<CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE} />
|
||||
<VendorCreditDetailDrawer name={DRAWERS.VENDOR_CREDIT} />
|
||||
<RefundCreditNoteDetailDrawer name={DRAWERS.REFUND_CREDIT_NOTE} />
|
||||
<RefundVendorCreditDetailDrawer name={DRAWERS.REFUND_VENDOR_CREDIT} />
|
||||
<WarehouseTransferDetailDrawer name={DRAWERS.WAREHOUSE_TRANSFER} />
|
||||
<CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE_DETAILS} />
|
||||
<VendorCreditDetailDrawer name={DRAWERS.VENDOR_CREDIT_DETAILS} />
|
||||
<RefundCreditNoteDetailDrawer name={DRAWERS.REFUND_CREDIT_NOTE_DETAILS} />
|
||||
<RefundVendorCreditDetailDrawer name={DRAWERS.REFUND_VENDOR_CREDIT_DETAILS} />
|
||||
<WarehouseTransferDetailDrawer name={DRAWERS.WAREHOUSE_TRANSFER_DETAILS} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function FSelect({ ...props }) {
|
||||
/>
|
||||
);
|
||||
};
|
||||
return <Select input={input} {...props} fill={true} />;
|
||||
return <Select input={input} fill={true} {...props} />;
|
||||
}
|
||||
|
||||
const SelectButton = styled(Button)`
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Button } from '@blueprintjs/core';
|
||||
import { Icon } from '@/components';
|
||||
|
||||
export function FormWarehouseSelectButton({ text }) {
|
||||
return (
|
||||
<Button
|
||||
text={intl.get('page_form.warehouse_button.label', { text })}
|
||||
minimal={true}
|
||||
small={true}
|
||||
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function FormBranchSelectButton({ text }) {
|
||||
return (
|
||||
<Button
|
||||
text={intl.get('page_form.branch_button.label', { text })}
|
||||
minimal={true}
|
||||
small={true}
|
||||
icon={<Icon icon={'branch-16'} iconSize={16} />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
export * from './FormTopbar';
|
||||
export * from './FormTopbarSelectInputs';
|
||||
export * from './PageFormBigNumber';
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as R from 'ramda';
|
||||
|
||||
import { ButtonLink } from '../Button';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
function VendorDrawerLinkComponent({
|
||||
// #ownProps
|
||||
@@ -16,7 +17,7 @@ function VendorDrawerLinkComponent({
|
||||
}) {
|
||||
// Handle view customer drawer.
|
||||
const handleVendorDrawer = (event) => {
|
||||
openDrawer('vendor-detail-drawer', { vendorId });
|
||||
openDrawer(DRAWERS.VENDOR_DETAILS, { vendorId });
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import React, { useCallback, useState, useEffect, useMemo } from 'react';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import intl from 'react-intl-universal';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import { MenuItem, Button } from '@blueprintjs/core';
|
||||
import { Select } from '@blueprintjs/select';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
|
||||
import {
|
||||
itemPredicate,
|
||||
handleContactRenderer,
|
||||
createNewItemFromQuery,
|
||||
createNewItemRenderer,
|
||||
} from './utils';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
function VendorSelectFieldRoot({
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
|
||||
// #ownProps
|
||||
contacts,
|
||||
initialContactId,
|
||||
selectedContactId,
|
||||
defaultSelectText = <T id={'select_contact'} />,
|
||||
onContactSelected,
|
||||
popoverFill = false,
|
||||
disabled = false,
|
||||
allowCreate,
|
||||
buttonProps,
|
||||
|
||||
...restProps
|
||||
}) {
|
||||
const localContacts = useMemo(
|
||||
() =>
|
||||
contacts.map((contact) => ({
|
||||
...contact,
|
||||
_id: `${contact.id}_${contact.contact_type}`,
|
||||
})),
|
||||
[contacts],
|
||||
);
|
||||
|
||||
const initialContact = useMemo(
|
||||
() => contacts.find((a) => a.id === initialContactId),
|
||||
[initialContactId, contacts],
|
||||
);
|
||||
|
||||
const [selecetedContact, setSelectedContact] = useState(
|
||||
initialContact || null,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof selectedContactId !== 'undefined') {
|
||||
const account = selectedContactId
|
||||
? contacts.find((a) => a.id === selectedContactId)
|
||||
: null;
|
||||
setSelectedContact(account);
|
||||
}
|
||||
}, [selectedContactId, contacts, setSelectedContact]);
|
||||
|
||||
const handleContactSelect = useCallback(
|
||||
(contact) => {
|
||||
if (contact.id) {
|
||||
setSelectedContact({ ...contact });
|
||||
onContactSelected && onContactSelected(contact);
|
||||
} else {
|
||||
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
|
||||
}
|
||||
},
|
||||
[setSelectedContact, onContactSelected, openDrawer],
|
||||
);
|
||||
|
||||
// Maybe inject create new item props to suggest component.
|
||||
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
|
||||
const maybeCreateNewItemFromQuery = allowCreate
|
||||
? createNewItemFromQuery
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Select
|
||||
items={localContacts}
|
||||
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
|
||||
itemRenderer={handleContactRenderer}
|
||||
itemPredicate={itemPredicate}
|
||||
filterable={true}
|
||||
disabled={disabled}
|
||||
onItemSelect={handleContactSelect}
|
||||
popoverProps={{ minimal: true, usePortal: !popoverFill }}
|
||||
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
|
||||
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
|
||||
})}
|
||||
inputProps={{
|
||||
placeholder: intl.get('filter_'),
|
||||
}}
|
||||
createNewItemRenderer={maybeCreateNewItemRenderer}
|
||||
createNewItemFromQuery={maybeCreateNewItemFromQuery}
|
||||
createNewItemPosition={'top'}
|
||||
{...restProps}
|
||||
>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
text={
|
||||
selecetedContact ? selecetedContact.display_name : defaultSelectText
|
||||
}
|
||||
{...buttonProps}
|
||||
/>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
export const VendorSelectField = R.compose(withDrawerActions)(
|
||||
VendorSelectFieldRoot,
|
||||
);
|
||||
49
packages/webapp/src/components/Vendors/VendorsSelect.tsx
Normal file
49
packages/webapp/src/components/Vendors/VendorsSelect.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
|
||||
import { FSelect } from '../Forms';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Vendor select.
|
||||
* @returns {React.ReactNode}
|
||||
*/
|
||||
function VendorsSelectRoot({
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
|
||||
// #ownProps
|
||||
items,
|
||||
allowCreate,
|
||||
|
||||
...restProps
|
||||
}) {
|
||||
// Maybe inject create new item props to suggest component.
|
||||
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
|
||||
const maybeCreateNewItemFromQuery = allowCreate
|
||||
? createNewItemFromQuery
|
||||
: null;
|
||||
|
||||
// Handles the create item click.
|
||||
const handleCreateItemClick = () => {
|
||||
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
|
||||
};
|
||||
|
||||
return (
|
||||
<FSelect
|
||||
items={items}
|
||||
textAccessor={'display_name'}
|
||||
labelAccessor={'code'}
|
||||
valueAccessor={'id'}
|
||||
popoverProps={{ minimal: true, usePortal: true, inline: false }}
|
||||
createNewItemRenderer={maybeCreateNewItemRenderer}
|
||||
createNewItemFromQuery={maybeCreateNewItemFromQuery}
|
||||
onCreateItemSelect={handleCreateItemClick}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const VendorsSelect = R.compose(withDrawerActions)(VendorsSelectRoot);
|
||||
@@ -1,3 +1,3 @@
|
||||
// @ts-nocheck
|
||||
export * from './VendorDrawerLink'
|
||||
export * from './VendorSelectField'
|
||||
export * from './VendorsSelect';
|
||||
@@ -1,75 +1,21 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
import { MenuItem, Button } from '@blueprintjs/core';
|
||||
import { FSelect } from '../Forms';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} query
|
||||
* @param {*} warehouse
|
||||
* @param {*} _index
|
||||
* @param {*} exactMatch
|
||||
* @returns
|
||||
*/
|
||||
const warehouseItemPredicate = (query, warehouse, _index, exactMatch) => {
|
||||
const normalizedTitle = warehouse.name.toLowerCase();
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
|
||||
if (exactMatch) {
|
||||
return normalizedTitle === normalizedQuery;
|
||||
} else {
|
||||
return (
|
||||
`${warehouse.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} film
|
||||
* @param {*} param1
|
||||
* @returns
|
||||
*/
|
||||
const warehouseItemRenderer = (
|
||||
warehouse,
|
||||
{ handleClick, modifiers, query },
|
||||
) => {
|
||||
const text = `${warehouse.name}`;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
disabled={modifiers.disabled}
|
||||
label={warehouse.code}
|
||||
key={warehouse.id}
|
||||
onClick={handleClick}
|
||||
text={text}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const warehouseSelectProps = {
|
||||
itemPredicate: warehouseItemPredicate,
|
||||
itemRenderer: warehouseItemRenderer,
|
||||
valueAccessor: 'id',
|
||||
labelAccessor: 'name',
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Warehouse select field.
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export function WarehouseSelect({ warehouses, ...rest }) {
|
||||
return <FSelect {...warehouseSelectProps} {...rest} items={warehouses} />;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export function WarehouseSelectButton({ label, ...rest }) {
|
||||
return <Button text={label} />;
|
||||
return (
|
||||
<FSelect
|
||||
valueAccessor={'id'}
|
||||
labelAccessor={'code'}
|
||||
textAccessor={'name'}
|
||||
popoverProps={{ minimal: true, usePortal: true, inline: false }}
|
||||
{...rest}
|
||||
items={warehouses}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
export default [
|
||||
{ name: intl.get('decrement'), value: 'decrement' },
|
||||
{ name: intl.get('increment'), value: 'increment' },
|
||||
]
|
||||
@@ -1,25 +1,25 @@
|
||||
// @ts-nocheck
|
||||
export enum DRAWERS {
|
||||
ACCOUNT = 'account-drawer',
|
||||
JOURNAL = 'journal-drawer',
|
||||
EXPENSE = 'expense-drawer',
|
||||
BILL = 'bill-drawer',
|
||||
INVOICE = 'invoice-detail-drawer',
|
||||
RECEIPT = 'receipt-detail-drawer',
|
||||
PAYMENT_RECEIVE = 'payment-receive-detail-drawer',
|
||||
PAYMENT_MADE = 'payment-made-drawer',
|
||||
ESTIMATE = 'estimate-detail-drawer',
|
||||
ITEM = 'item-detail-drawer',
|
||||
CUSTOMER = 'customer-detail-drawer',
|
||||
VENDOR = 'vendor-detail-drawer',
|
||||
INVENTORY_ADJUSTMENT = 'inventory-adjustment-drawer',
|
||||
CASHFLOW_TRNASACTION = 'cashflow-transaction-drawer',
|
||||
ACCOUNT_DETAILS = 'account-drawer',
|
||||
JOURNAL_DETAILS = 'journal-drawer',
|
||||
EXPENSE_DETAILS = 'expense-drawer',
|
||||
BILL_DETAILS = 'bill-drawer',
|
||||
INVOICE_DETAILS = 'invoice-detail-drawer',
|
||||
RECEIPT_DETAILS = 'receipt-detail-drawer',
|
||||
PAYMENT_RECEIVE_DETAILS = 'payment-receive-detail-drawer',
|
||||
PAYMENT_MADE_DETAILS = 'payment-made-drawer',
|
||||
ESTIMATE_DETAILS = 'estimate-detail-drawer',
|
||||
ITEM_DETAILS = 'item-detail-drawer',
|
||||
CUSTOMER_DETAILS = 'customer-detail-drawer',
|
||||
VENDOR_DETAILS = 'vendor-detail-drawer',
|
||||
INVENTORY_ADJUSTMENT_DETAILS = 'inventory-adjustment-drawer',
|
||||
CASHFLOW_TRNASACTION_DETAILS = 'cashflow-transaction-drawer',
|
||||
QUICK_CREATE_CUSTOMER = 'quick-create-customer',
|
||||
QUICK_CREATE_ITEM = 'quick-create-item',
|
||||
QUICK_WRITE_VENDOR = 'quick-write-vendor',
|
||||
CREDIT_NOTE = 'credit-note-detail-drawer',
|
||||
VENDOR_CREDIT = 'vendor-credit-detail-drawer',
|
||||
REFUND_CREDIT_NOTE = 'refund-credit-detail-drawer',
|
||||
REFUND_VENDOR_CREDIT = 'refund-vendor-detail-drawer',
|
||||
WAREHOUSE_TRANSFER = 'warehouse-transfer-detail-drawer',
|
||||
CREDIT_NOTE_DETAILS = 'credit-note-detail-drawer',
|
||||
VENDOR_CREDIT_DETAILS = 'vendor-credit-detail-drawer',
|
||||
REFUND_CREDIT_NOTE_DETAILS = 'refund-credit-detail-drawer',
|
||||
REFUND_VENDOR_CREDIT_DETAILS = 'refund-vendor-detail-drawer',
|
||||
WAREHOUSE_TRANSFER_DETAILS = 'warehouse-transfer-detail-drawer',
|
||||
}
|
||||
|
||||
@@ -4,30 +4,22 @@ import intl from 'react-intl-universal';
|
||||
export const getFooterLinks = () => [
|
||||
{
|
||||
title: intl.get('blog'),
|
||||
link: '#',
|
||||
link: 'https://docs.bigcapital.ly/blog',
|
||||
},
|
||||
{
|
||||
title: intl.get('community'),
|
||||
link: 'https://discord.com/invite/c8nPBJafeb',
|
||||
},
|
||||
{
|
||||
title: intl.get('support'),
|
||||
link: '#',
|
||||
},
|
||||
{
|
||||
title: intl.get('service_status'),
|
||||
link: '#',
|
||||
},
|
||||
{
|
||||
title: intl.get('pricing'),
|
||||
link: '#',
|
||||
},
|
||||
{
|
||||
title: intl.get('reseller_partner'),
|
||||
link: '#',
|
||||
link: 'https://discord.com/invite/c8nPBJafeb',
|
||||
},
|
||||
{
|
||||
title: intl.get('docs'),
|
||||
link: '#',
|
||||
link: 'https://docs.bigcapital.ly',
|
||||
},
|
||||
{
|
||||
title: 'Bigcapital',
|
||||
link: 'http://bigcapital.ly',
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@@ -4,7 +4,6 @@ export * from './tableStyle';
|
||||
export * from './features';
|
||||
export * from './cellTypes';
|
||||
export * from './classes';
|
||||
export * from './adjustmentType';
|
||||
export * from './cashflowOptions';
|
||||
|
||||
export const Align = { Left: 'left', Right: 'right', Center: 'center' };
|
||||
|
||||
@@ -25,13 +25,14 @@ import {
|
||||
CashflowAction,
|
||||
PreferencesAbility,
|
||||
} from '@/constants/abilityOption';
|
||||
import { DialogsName } from './dialogs';
|
||||
|
||||
export const SidebarMenu = [
|
||||
// ---------------
|
||||
// # Homepage
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'homepage'} />,
|
||||
text: <T id={'sidebar.homepage'} />,
|
||||
type: ISidebarMenuItemType.Link,
|
||||
disabled: false,
|
||||
href: '/',
|
||||
@@ -41,20 +42,20 @@ export const SidebarMenu = [
|
||||
// # Sales & Inventory
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'sales_inventory'} />,
|
||||
text: <T id={'sidebar.sales_inventory'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'items'} />,
|
||||
text: <T id={'sidebar.items'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Items,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'items'} />,
|
||||
text: <T id={'sidebar.items'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'items'} />,
|
||||
text: <T id={'sidebar.items'} />,
|
||||
href: '/items',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -63,7 +64,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'inventory_adjustments'} />,
|
||||
text: <T id={'sidebar.inventory_adjustments'} />,
|
||||
href: '/inventory-adjustments',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -71,12 +72,6 @@ export const SidebarMenu = [
|
||||
ability: InventoryAdjustmentAction.View,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'sidebar_warehouse_transfer'} />,
|
||||
href: '/warehouses-transfers',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
feature: Features.Warehouses,
|
||||
},
|
||||
{
|
||||
text: <T id={'category_list'} />,
|
||||
href: '/items/categories',
|
||||
@@ -86,31 +81,20 @@ export const SidebarMenu = [
|
||||
ability: ItemAction.View,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'New inventory item'} />,
|
||||
href: '/items/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
subject: AbilitySubject.Item,
|
||||
ability: ItemAction.Create,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: (
|
||||
<T id={'warehouse_transfer.label.new_warehouse_transfer'} />
|
||||
),
|
||||
href: '/warehouses-transfers/new',
|
||||
text: <T id={'sidebar.warehouse_transfer'} />,
|
||||
href: '/warehouses-transfers',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
feature: Features.Warehouses,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'New service'} />,
|
||||
text: <T id={'sidebar.new_inventory_item'} />,
|
||||
href: '/items/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -119,15 +103,30 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'New item category'} />,
|
||||
href: '/items/categories/new',
|
||||
type: ISidebarMenuItemType.Dialog,
|
||||
dialogName: 'item-category-form',
|
||||
text: <T id={'sidebar.new_service'} />,
|
||||
href: '/items/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
subject: AbilitySubject.Item,
|
||||
ability: ItemAction.Create,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'sidebar.new_item_category'} />,
|
||||
href: '/items/categories/new',
|
||||
type: ISidebarMenuItemType.Dialog,
|
||||
dialogName: DialogsName.ItemCategoryForm,
|
||||
permission: {
|
||||
subject: AbilitySubject.Item,
|
||||
ability: ItemAction.Create,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'sidebar.new_warehouse_transfer'} />,
|
||||
href: '/warehouses-transfers/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
feature: Features.Warehouses,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -138,16 +137,16 @@ export const SidebarMenu = [
|
||||
// # Sales
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'sales'} />,
|
||||
text: <T id={'sidebar.sales'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Sales,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'sales'} />,
|
||||
text: <T id={'sidebar.sales'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'estimates'} />,
|
||||
text: <T id={'sidebar.estimates'} />,
|
||||
href: '/estimates',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -156,7 +155,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'invoices'} />,
|
||||
text: <T id={'sidebar.invoices'} />,
|
||||
href: '/invoices',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -165,7 +164,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'receipts'} />,
|
||||
text: <T id={'sidebar.receipts'} />,
|
||||
href: '/receipts',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -174,12 +173,12 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'sidebar_credit_note'} />,
|
||||
text: <T id={'sidebar.credit_notes'} />,
|
||||
href: '/credit-notes',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
},
|
||||
{
|
||||
text: <T id={'payment_receives'} />,
|
||||
text: <T id={'sidebar.payment_receives'} />,
|
||||
href: '/payment-receives',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -190,11 +189,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'new_estimate'} />,
|
||||
text: <T id={'sidebar.new_estimate'} />,
|
||||
href: '/estimates/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -203,7 +202,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'new_invoice'} />,
|
||||
text: <T id={'sidebar.new_invoice'} />,
|
||||
href: '/invoices/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -212,7 +211,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'new_receipt'} />,
|
||||
text: <T id={'sidebar.new_receipt'} />,
|
||||
href: '/receipts/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -221,12 +220,12 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'credit_note.label.new_credit_note'} />,
|
||||
text: <T id={'sidebar.new_credit_note'} />,
|
||||
href: '/credit-notes/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
},
|
||||
{
|
||||
text: <T id={'new_payment_receive'} />,
|
||||
text: <T id={'sidebar.new_payment_receive'} />,
|
||||
href: '/payment-receives/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -242,12 +241,12 @@ export const SidebarMenu = [
|
||||
// # Purchases
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'purchases'} />,
|
||||
text: <T id={'sidebar.purchases'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Purchases,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'purchases'} />,
|
||||
text: <T id={'sidebar.purchases'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
@@ -276,11 +275,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'New purchase invoice'} />,
|
||||
text: <T id={'sidebar.new_purchase_invoice'} />,
|
||||
href: '/bills/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -289,7 +288,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'vendor_credits.label.new_vendor_credit'} />,
|
||||
text: <T id={'sidebar.new_vendor_credit'} />,
|
||||
href: '/vendor-credits/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -298,7 +297,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'new_payment_made'} />,
|
||||
text: <T id={'sidebar.new_payment_made'} />,
|
||||
href: '/payment-mades/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -314,16 +313,16 @@ export const SidebarMenu = [
|
||||
// # Contacts
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'contacts'} />,
|
||||
text: <T id={'sidebar.contacts'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Contacts,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'contacts'} />,
|
||||
text: <T id={'sidebar.contacts'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'customers'} />,
|
||||
text: <T id={'sidebar.customers'} />,
|
||||
href: '/customers',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -332,7 +331,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'vendors'} />,
|
||||
text: <T id={'sidebar.vendors'} />,
|
||||
href: '/vendors',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -343,11 +342,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'new_customer'} />,
|
||||
text: <T id={'sidebar.new_customer'} />,
|
||||
href: '/customers/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -356,7 +355,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'new_vendor'} />,
|
||||
text: <T id={'sidebar.new_vendor'} />,
|
||||
href: '/vendors/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -372,20 +371,20 @@ export const SidebarMenu = [
|
||||
// # Accounting
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'accounting'} />,
|
||||
text: <T id={'sidebar.accounting'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'financial'} />,
|
||||
text: <T id={'sidebar.financial'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Financial,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'financial'} />,
|
||||
text: <T id={'sidebar.financial'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'accounts_chart'} />,
|
||||
text: <T id={'sidebar.accounts_chart'} />,
|
||||
href: '/accounts',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -394,7 +393,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'manual_journals'} />,
|
||||
text: <T id={'sidebar.manual_journals'} />,
|
||||
href: '/manual-journals',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -410,11 +409,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'make_journal_entry'} />,
|
||||
text: <T id={'sidebar.make_journal_entry'} />,
|
||||
href: '/make-journal-entry',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -441,7 +440,7 @@ export const SidebarMenu = [
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'siebar.cashflow.label_cash_and_bank_accounts'} />,
|
||||
text: <T id={'sidebar.cash_bank_accounts'} />,
|
||||
href: '/cashflow-accounts',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -452,42 +451,45 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
divider: true,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'cash_flow.label.add_money_in'} />,
|
||||
text: <T id={'sidebar.add_money_in'} />,
|
||||
href: '/cashflow-accounts',
|
||||
type: ISidebarMenuItemType.Dialog,
|
||||
dialogName: 'money-in',
|
||||
dialogName: DialogsName.MoneyInForm,
|
||||
permission: {
|
||||
subject: AbilitySubject.Cashflow,
|
||||
ability: CashflowAction.Create,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'cash_flow.label.add_money_out'} />,
|
||||
text: <T id={'sidebar.add_money_out'} />,
|
||||
href: '/cashflow-accounts',
|
||||
type: ISidebarMenuItemType.Dialog,
|
||||
dialogName: DialogsName.MoneyOutForm,
|
||||
permission: {
|
||||
subject: AbilitySubject.Cashflow,
|
||||
ability: CashflowAction.Create,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'cash_flow.label.add_cash_account'} />,
|
||||
text: <T id={'sidebar.add_cash_account'} />,
|
||||
href: '/cashflow-accounts',
|
||||
type: ISidebarMenuItemType.Dialog,
|
||||
dialogName: DialogsName.AccountForm,
|
||||
permission: {
|
||||
subject: AbilitySubject.Cashflow,
|
||||
ability: CashflowAction.Create,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'cash_flow.label.add_bank_account'} />,
|
||||
text: <T id={'sidebar.add_bank_account'} />,
|
||||
href: '/cashflow-accounts',
|
||||
type: ISidebarMenuItemType.Dialog,
|
||||
dialogName: DialogsName.AccountForm,
|
||||
permission: {
|
||||
subject: AbilitySubject.Cashflow,
|
||||
ability: CashflowAction.Create,
|
||||
@@ -501,16 +503,16 @@ export const SidebarMenu = [
|
||||
// # Expenses
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'expenses'} />,
|
||||
text: <T id={'sidebar.expenses'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Expenses,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'expenses'} />,
|
||||
text: <T id={'sidebar.expenses'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'expenses'} />,
|
||||
text: <T id={'sidebar.expenses'} />,
|
||||
href: '/expenses',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -521,11 +523,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'New tasks'} />,
|
||||
text: <T id={'sidebar.new_tasks'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'new_expense'} />,
|
||||
text: <T id={'sidebar.new_expense'} />,
|
||||
href: '/expenses/new',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -541,16 +543,16 @@ export const SidebarMenu = [
|
||||
// # Projects Management
|
||||
// ---------------------
|
||||
// {
|
||||
// text: 'Projects',
|
||||
// text: <T id={'sidebar.projects'} />,
|
||||
// type: ISidebarMenuItemType.Overlay,
|
||||
// overlayId: ISidebarMenuOverlayIds.Projects,
|
||||
// children: [
|
||||
// {
|
||||
// text: 'Projects',
|
||||
// text: <T id={'sidebar.projects'} />,
|
||||
// type: ISidebarMenuItemType.Group,
|
||||
// children: [
|
||||
// {
|
||||
// text: 'Projects',
|
||||
// text: <T id={'sidebar.projects'} />,
|
||||
// href: '/projects',
|
||||
// type: ISidebarMenuItemType.Link,
|
||||
// permission: {
|
||||
@@ -561,11 +563,11 @@ export const SidebarMenu = [
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// text: <T id={'New tasks'} />,
|
||||
// text: <T id={'sidebar.new_tasks'} />,
|
||||
// type: ISidebarMenuItemType.Group,
|
||||
// children: [
|
||||
// {
|
||||
// text: <T id={'projects.label.new_project'} />,
|
||||
// text: <T id={'sidebar.new_project'} />,
|
||||
// type: ISidebarMenuItemType.Dialog,
|
||||
// dialogName: 'project-form',
|
||||
// permission: {
|
||||
@@ -574,18 +576,18 @@ export const SidebarMenu = [
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// text: <T id={'projects.label.new_time_entry'} />,
|
||||
// text: <T id={'sidebar.new_time_entry'} />,
|
||||
// type: ISidebarMenuItemType.Dialog,
|
||||
// dialogName: 'project-time-entry-form',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// text: <T id={'Reports'} />,
|
||||
// text: <T id={'sidebar.reports'} />,
|
||||
// type: ISidebarMenuItemType.Group,
|
||||
// children: [
|
||||
// {
|
||||
// text: <T id={'project_profitability_summary'} />,
|
||||
// text: <T id={'sidebar.project_profitability_summary'} />,
|
||||
// href: '/financial-reports/project-profitability-summary',
|
||||
// type: ISidebarMenuItemType.Link,
|
||||
// },
|
||||
@@ -597,16 +599,16 @@ export const SidebarMenu = [
|
||||
// # Reports
|
||||
// ---------------
|
||||
{
|
||||
text: <T id={'Reports'} />,
|
||||
text: <T id={'sidebar.reports'} />,
|
||||
type: ISidebarMenuItemType.Overlay,
|
||||
overlayId: ISidebarMenuOverlayIds.Reports,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'Reports'} />,
|
||||
text: <T id={'sidebar.reports'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'balance_sheet'} />,
|
||||
text: <T id={'sidebar.balance_sheet'} />,
|
||||
href: '/financial-reports/balance-sheet',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -615,7 +617,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'trial_balance_sheet'} />,
|
||||
text: <T id={'sidebar.trial_balance_sheet'} />,
|
||||
href: '/financial-reports/trial-balance-sheet',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -624,7 +626,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'journal'} />,
|
||||
text: <T id={'sidebar.journal'} />,
|
||||
href: '/financial-reports/journal-sheet',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -633,7 +635,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'general_ledger'} />,
|
||||
text: <T id={'sidebar.general_ledger'} />,
|
||||
href: '/financial-reports/general-ledger',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -642,7 +644,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'profit_loss_sheet'} />,
|
||||
text: <T id={'sidebar.profit_loss_sheet'} />,
|
||||
href: '/financial-reports/profit-loss-sheet',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -651,7 +653,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'cash_flow_statement'} />,
|
||||
text: <T id={'sidebar.cash_flow_statement'} />,
|
||||
href: '/financial-reports/cash-flow',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -660,7 +662,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'AR_Aging_Summary'} />,
|
||||
text: <T id={'sidebar.ar_aging_Summary'} />,
|
||||
href: '/financial-reports/receivable-aging-summary',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -669,7 +671,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'AP_Aging_Summary'} />,
|
||||
text: <T id={'sidebar.ap_aging_summary'} />,
|
||||
href: '/financial-reports/payable-aging-summary',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -680,11 +682,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'Sales/Purchases'} />,
|
||||
text: <T id={'sidebar.sales_purchases'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'purchases_by_items'} />,
|
||||
text: <T id={'sidebar.purchases_by_items'} />,
|
||||
type: ISidebarMenuItemType.Link,
|
||||
href: '/financial-reports/purchases-by-items',
|
||||
permission: {
|
||||
@@ -693,7 +695,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'sales_by_items'} />,
|
||||
text: <T id={'sidebar.sales_by_items'} />,
|
||||
href: '/financial-reports/sales-by-items',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -702,7 +704,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'customers_transactions'} />,
|
||||
text: <T id={'sidebar.customers_transactions'} />,
|
||||
href: '/financial-reports/transactions-by-customers',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -711,7 +713,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'vendors_transactions'} />,
|
||||
text: <T id={'sidebar.vendors_transactions'} />,
|
||||
href: '/financial-reports/transactions-by-vendors',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -720,7 +722,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'customers_balance_summary'} />,
|
||||
text: <T id={'sidebar.customers_balance_summary'} />,
|
||||
href: '/financial-reports/customers-balance-summary',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -729,7 +731,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'vendors_balance_summary'} />,
|
||||
text: <T id={'sidebar.vendors_balance_summary'} />,
|
||||
href: '/financial-reports/vendors-balance-summary',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -740,11 +742,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'inventory'} />,
|
||||
text: <T id={'sidebar.inventory'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'inventory_item_details'} />,
|
||||
text: <T id={'sidebar.inventory_item_details'} />,
|
||||
href: '/financial-reports/inventory-item-details',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -753,7 +755,7 @@ export const SidebarMenu = [
|
||||
},
|
||||
},
|
||||
{
|
||||
text: <T id={'inventory_valuation'} />,
|
||||
text: <T id={'sidebar.inventory_valuation'} />,
|
||||
href: '/financial-reports/inventory-valuation',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
@@ -766,11 +768,11 @@ export const SidebarMenu = [
|
||||
],
|
||||
},
|
||||
{
|
||||
text: <T id={'system'} />,
|
||||
text: <T id={'sidebar.system'} />,
|
||||
type: ISidebarMenuItemType.Group,
|
||||
children: [
|
||||
{
|
||||
text: <T id={'preferences'} />,
|
||||
text: <T id={'sidebar.preferences'} />,
|
||||
href: '/preferences',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
permission: {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { useMemorizedColumnsWidths } from '@/hooks';
|
||||
import { useManualJournalsColumns } from './utils';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Manual journals data-table.
|
||||
@@ -79,14 +80,16 @@ function ManualJournalsDataTable({
|
||||
|
||||
// Handle view detail journal.
|
||||
const handleViewDetailJournal = ({ id }) => {
|
||||
openDrawer('journal-drawer', {
|
||||
openDrawer(DRAWERS.JOURNAL_DETAILS, {
|
||||
manualJournalId: id,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle cell click.
|
||||
const handleCellClick = (cell, event) => {
|
||||
openDrawer('journal-drawer', { manualJournalId: cell.row.original.id });
|
||||
openDrawer(DRAWERS.JOURNAL_DETAILS, {
|
||||
manualJournalId: cell.row.original.id,
|
||||
});
|
||||
};
|
||||
|
||||
// Local storage memorizing columns widths.
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import {
|
||||
InputGroup,
|
||||
FormGroup,
|
||||
Position,
|
||||
ControlGroup,
|
||||
} from '@blueprintjs/core';
|
||||
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
import { InputGroup, FormGroup, Position } from '@blueprintjs/core';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import * as R from 'ramda';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
@@ -20,99 +14,15 @@ import {
|
||||
} from '@/utils';
|
||||
import {
|
||||
Hint,
|
||||
FieldHint,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
InputPrependButton,
|
||||
CurrencySelectList,
|
||||
FormattedMessage as T,
|
||||
FInputGroup,
|
||||
FFormGroup,
|
||||
} from '@/components';
|
||||
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||
import { JournalExchangeRateInputField } from './components';
|
||||
import { currenciesFieldShouldUpdate } from './utils';
|
||||
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
|
||||
/**
|
||||
* Journal number field of make journal form.
|
||||
*/
|
||||
const MakeJournalTransactionNoField = R.compose(
|
||||
withDialogActions,
|
||||
withSettings(({ manualJournalsSettings }) => ({
|
||||
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
||||
})),
|
||||
)(
|
||||
({
|
||||
// #withDialog
|
||||
openDialog,
|
||||
|
||||
// #withSettings
|
||||
journalAutoIncrement,
|
||||
}) => {
|
||||
const { setFieldValue, values } = useFormikContext();
|
||||
|
||||
const handleJournalNumberChange = () => {
|
||||
openDialog('journal-number-form');
|
||||
};
|
||||
const handleJournalNoBlur = (event) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
if (values.journal_number !== newValue && journalAutoIncrement) {
|
||||
openDialog('journal-number-form', {
|
||||
initialFormValues: {
|
||||
onceManualNumber: newValue,
|
||||
incrementMode: 'manual-transaction',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!journalAutoIncrement) {
|
||||
setFieldValue('journal_number', newValue);
|
||||
setFieldValue('journal_number_manually', newValue);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FFormGroup
|
||||
name={'journal_number'}
|
||||
label={<T id={'journal_no'} />}
|
||||
labelInfo={
|
||||
<>
|
||||
<FieldRequiredHint />
|
||||
<FieldHint />
|
||||
</>
|
||||
}
|
||||
fill={true}
|
||||
inline={true}
|
||||
fastField={true}
|
||||
>
|
||||
<ControlGroup fill={true}>
|
||||
<FInputGroup
|
||||
name={'journal_number'}
|
||||
fill={true}
|
||||
asyncControl={true}
|
||||
onBlur={handleJournalNoBlur}
|
||||
fastField={true}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<InputPrependButton
|
||||
buttonProps={{
|
||||
onClick: handleJournalNumberChange,
|
||||
icon: <Icon icon={'settings-18'} />,
|
||||
}}
|
||||
tooltip={true}
|
||||
tooltipProps={{
|
||||
content: <T id={'setting_your_auto_generated_journal_number'} />,
|
||||
position: Position.BOTTOM_LEFT,
|
||||
}}
|
||||
/>
|
||||
</ControlGroup>
|
||||
</FFormGroup>
|
||||
);
|
||||
},
|
||||
);
|
||||
import { MakeJournalTransactionNoField } from './MakeJournalTransactionNoField';
|
||||
|
||||
/**
|
||||
* Make journal entries header.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import intl from 'react-intl-universal';
|
||||
import { FFormGroup, FEditableText, FormattedMessage as T } from '@/components';
|
||||
|
||||
export function MakeJournalFormFooterLeft() {
|
||||
@@ -13,7 +14,7 @@ export function MakeJournalFormFooterLeft() {
|
||||
>
|
||||
<FEditableText
|
||||
name={'description'}
|
||||
placeholder={<T id={'make_jorunal.decscrption.placeholder'} />}
|
||||
placeholder={intl.get('make_jorunal.decscrption.placeholder')}
|
||||
/>
|
||||
</DescriptionFormGroup>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
FeatureCan,
|
||||
FormTopbar,
|
||||
DetailsBarSkeletonBase,
|
||||
FormBranchSelectButton,
|
||||
} from '@/components';
|
||||
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||
|
||||
@@ -51,18 +52,9 @@ function MakeJournalFormSelectBranch() {
|
||||
<BranchSelect
|
||||
name={'branch_id'}
|
||||
branches={branches}
|
||||
input={MakeJournalBranchSelectButton}
|
||||
input={FormBranchSelectButton}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
function MakeJournalBranchSelectButton({ label }) {
|
||||
return (
|
||||
<Button
|
||||
text={intl.get('make_journal.branch_button.label', { label })}
|
||||
minimal={true}
|
||||
small={true}
|
||||
icon={<Icon icon={'branch-16'} iconSize={16} />}
|
||||
fill={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Position, ControlGroup } from '@blueprintjs/core';
|
||||
import { useFormikContext } from 'formik';
|
||||
import * as R from 'ramda';
|
||||
import {
|
||||
FieldHint,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
InputPrependButton,
|
||||
FormattedMessage as T,
|
||||
FInputGroup,
|
||||
FFormGroup,
|
||||
} from '@/components';
|
||||
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
|
||||
/**
|
||||
* Journal number field of make journal form.
|
||||
*/
|
||||
export const MakeJournalTransactionNoField = R.compose(
|
||||
withDialogActions,
|
||||
withSettings(({ manualJournalsSettings }) => ({
|
||||
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
||||
})),
|
||||
)(
|
||||
({
|
||||
// #withDialog
|
||||
openDialog,
|
||||
|
||||
// #withSettings
|
||||
journalAutoIncrement,
|
||||
}) => {
|
||||
const { setFieldValue, values } = useFormikContext();
|
||||
|
||||
const handleJournalNumberChange = () => {
|
||||
openDialog('journal-number-form');
|
||||
};
|
||||
const handleJournalNoBlur = (event) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
if (values.journal_number !== newValue && journalAutoIncrement) {
|
||||
openDialog('journal-number-form', {
|
||||
initialFormValues: {
|
||||
onceManualNumber: newValue,
|
||||
incrementMode: 'manual-transaction',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!journalAutoIncrement) {
|
||||
setFieldValue('journal_number', newValue);
|
||||
setFieldValue('journal_number_manually', newValue);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FFormGroup
|
||||
name={'journal_number'}
|
||||
label={<T id={'journal_no'} />}
|
||||
labelInfo={
|
||||
<>
|
||||
<FieldRequiredHint />
|
||||
<FieldHint />
|
||||
</>
|
||||
}
|
||||
fill={true}
|
||||
inline={true}
|
||||
fastField={true}
|
||||
>
|
||||
<ControlGroup fill={true}>
|
||||
<FInputGroup
|
||||
name={'journal_number'}
|
||||
fill={true}
|
||||
asyncControl={true}
|
||||
onBlur={handleJournalNoBlur}
|
||||
fastField={true}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<InputPrependButton
|
||||
buttonProps={{
|
||||
onClick: handleJournalNumberChange,
|
||||
icon: <Icon icon={'settings-18'} />,
|
||||
}}
|
||||
tooltip={true}
|
||||
tooltipProps={{
|
||||
content: <T id={'setting_your_auto_generated_journal_number'} />,
|
||||
position: Position.BOTTOM_LEFT,
|
||||
}}
|
||||
/>
|
||||
</ControlGroup>
|
||||
</FFormGroup>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
MakeJournalTransactionNoField.displayName = 'MakeJournalTransactionNoField';
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import React, { useEffect } from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Menu, MenuItem, Position, Button } from '@blueprintjs/core';
|
||||
import { Menu, MenuItem, Position, Button, Intent } from '@blueprintjs/core';
|
||||
import { Popover2 } from '@blueprintjs/popover2';
|
||||
import { useFormikContext } from 'formik';
|
||||
import * as R from 'ramda';
|
||||
@@ -74,6 +74,7 @@ export const ActionsCellRenderer = ({
|
||||
const exampleMenu = (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleClickRemoveRole}
|
||||
text={intl.get('make_journal.entries.remove_row')}
|
||||
/>
|
||||
|
||||
@@ -3,6 +3,7 @@ import intl from 'react-intl-universal';
|
||||
import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
|
||||
import { AbilitySubject, ManualJournalAction } from '@/constants/abilityOption';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Universal search manual journal item select action.
|
||||
@@ -17,7 +18,7 @@ function JournalUniversalSearchSelectComponent({
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) {
|
||||
openDrawer('journal-drawer', { manualJournalId: resourceId });
|
||||
openDrawer(DRAWERS.JOURNAL_DETAILS, { manualJournalId: resourceId });
|
||||
onAction && onAction();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -5,6 +5,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { AbilitySubject, AccountAction } from '@/constants/abilityOption';
|
||||
import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
function AccountUniversalSearchItemSelectComponent({
|
||||
// #ownProps
|
||||
@@ -16,7 +17,7 @@ function AccountUniversalSearchItemSelectComponent({
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.ACCOUNT) {
|
||||
openDrawer('account-drawer', { accountId: resourceId });
|
||||
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: resourceId });
|
||||
onAction && onAction();
|
||||
}
|
||||
return null;
|
||||
@@ -28,8 +29,8 @@ export const AccountUniversalSearchItemSelect = withDrawerActions(
|
||||
|
||||
/**
|
||||
* Transformes account item to search item.
|
||||
* @param {*} account
|
||||
* @returns
|
||||
* @param {*} account
|
||||
* @returns
|
||||
*/
|
||||
const accountToSearch = (account) => ({
|
||||
id: account.id,
|
||||
|
||||
@@ -23,6 +23,7 @@ import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Accounts data-table.
|
||||
@@ -71,7 +72,7 @@ function AccountsDataTable({
|
||||
|
||||
// Handle view detail account.
|
||||
const handleViewDetailAccount = ({ id }) => {
|
||||
openDrawer('account-drawer', { accountId: id });
|
||||
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: id });
|
||||
};
|
||||
|
||||
// Handle new child button click.
|
||||
@@ -84,7 +85,7 @@ function AccountsDataTable({
|
||||
};
|
||||
// Handle cell click.
|
||||
const handleCellClick = (cell, event) => {
|
||||
openDrawer('account-drawer', { accountId: cell.row.original.id });
|
||||
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: cell.row.original.id });
|
||||
};
|
||||
// Local storage memorizing columns widths.
|
||||
const [initialColumnsWidths, , handleColumnResizing] =
|
||||
|
||||
@@ -16,6 +16,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { useDeleteAccount } from '@/hooks/query';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Account delete alerts.
|
||||
@@ -48,7 +49,7 @@ function AccountDeleteAlert({
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeAlert(name);
|
||||
closeDrawer('account-drawer');
|
||||
closeDrawer(DRAWERS.ACCOUNT_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -11,6 +11,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { handleDeleteErrors } from '@/containers/Purchases/Bills/BillForm/utils';
|
||||
import { useDeleteBill } from '@/hooks/query';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Bill delete alert.
|
||||
@@ -43,8 +44,7 @@ function BillDeleteAlert({
|
||||
message: intl.get('the_bill_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
|
||||
closeDrawer('bill-drawer');
|
||||
closeDrawer(DRAWERS.BILL_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Account delete transaction alert.
|
||||
@@ -48,7 +49,7 @@ function AccountDeleteTransactionAlert({
|
||||
message: intl.get('cash_flow_transaction.delete.alert_message'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('cashflow-transaction-drawer');
|
||||
closeDrawer(DRAWERS.CASHFLOW_TRNASACTION_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -15,6 +15,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { useDeleteCreditNote } from '@/hooks/query';
|
||||
import { handleDeleteErrors } from '@/containers/Sales/CreditNotes/CreditNotesLanding/utils';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Credit note delete alert.
|
||||
@@ -46,7 +47,7 @@ function CreditNoteDeleteAlert({
|
||||
message: intl.get('credit_note.alert.delete_message'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('credit-note-detail-drawer');
|
||||
closeDrawer(DRAWERS.CREDIT_NOTE_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -11,6 +11,7 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Refund credit transactions delete alert
|
||||
@@ -42,7 +43,7 @@ function RefundCreditNoteDeleteAlert({
|
||||
message: intl.get('refund_credit_transactions.alert.delete_message'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('refund-credit-detail-drawer');
|
||||
closeDrawer(DRAWERS.REFUND_CREDIT_NOTE_DETAILS);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { useDeleteCustomer } from '@/hooks/query';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Customer delete alert.
|
||||
@@ -47,7 +48,7 @@ function CustomerDeleteAlert({
|
||||
message: intl.get('the_customer_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('customer-detail-drawer');
|
||||
closeDrawer(DRAWERS.CUSTOMER_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Estimate delete alert.
|
||||
@@ -47,7 +48,7 @@ function EstimateDeleteAlert({
|
||||
message: intl.get('the_estimate_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('estimate-detail-drawer');
|
||||
closeDrawer(DRAWERS.ESTIMATE_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -10,6 +10,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { useDeleteExpense } from '@/hooks/query';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Expense delete alert.
|
||||
@@ -42,7 +43,7 @@ function ExpenseDeleteAlert({
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('expense-drawer');
|
||||
closeDrawer(DRAWERS.EXPENSE_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -16,6 +16,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Invoice delete alert.
|
||||
@@ -48,7 +49,7 @@ function InvoiceDeleteAlert({
|
||||
message: intl.get('the_invoice_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('invoice-detail-drawer');
|
||||
closeDrawer(DRAWERS.INVOICE_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -14,6 +14,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { useDeleteInventoryAdjustment } from '@/hooks/query';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Inventory Adjustment delete alerts.
|
||||
@@ -49,7 +50,7 @@ function InventoryAdjustmentDeleteAlert({
|
||||
),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('inventory-adjustment-drawer');
|
||||
closeDrawer(DRAWERS.INVENTORY_ADJUSTMENT_DETAILS);
|
||||
})
|
||||
.catch((errors) => {})
|
||||
.finally(() => {
|
||||
|
||||
@@ -17,6 +17,7 @@ import withItemsActions from '@/containers/Items/withItemsActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Item delete alerts.
|
||||
@@ -54,7 +55,7 @@ function ItemDeleteAlert({
|
||||
});
|
||||
// Reset to page number one.
|
||||
setItemsTableState({ page: 1 });
|
||||
closeDrawer('item-detail-drawer');
|
||||
closeDrawer(DRAWERS.ITEM_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -10,6 +10,7 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Journal delete alert.
|
||||
@@ -45,7 +46,7 @@ function JournalDeleteAlert({
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeAlert(name);
|
||||
closeDrawer('journal-drawer');
|
||||
closeDrawer(DRAWERS.JOURNAL_DETAILS);
|
||||
})
|
||||
.catch(() => {
|
||||
closeAlert(name);
|
||||
|
||||
@@ -11,6 +11,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { useDeletePaymentMade } from '@/hooks/query';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Payment made delete alert.
|
||||
@@ -44,7 +45,7 @@ function PaymentMadeDeleteAlert({
|
||||
message: intl.get('the_payment_made_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('payment-made-detail-drawer');
|
||||
closeDrawer(DRAWERS.PAYMENT_MADE_DETAILS);
|
||||
})
|
||||
.finally(() => {
|
||||
closeAlert(name);
|
||||
|
||||
@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Payment receive delete alert.
|
||||
@@ -50,7 +51,7 @@ function PaymentReceiveDeleteAlert({
|
||||
),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('payment-receive-detail-drawer');
|
||||
closeDrawer(DRAWERS.PAYMENT_RECEIVE_DETAILS);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Invoice alert.
|
||||
@@ -47,7 +48,7 @@ function NameDeleteAlert({
|
||||
message: intl.get('the_receipt_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('receipt-detail-drawer');
|
||||
closeDrawer(DRAWERS.RECEIPT_DETAILS);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
|
||||
@@ -10,6 +10,7 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Refund Vendor transactions delete alert.
|
||||
@@ -43,7 +44,7 @@ function RefundVendorCreditDeleteAlert({
|
||||
),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('refund-vendor-detail-drawer');
|
||||
closeDrawer(DRAWERS.REFUND_VENDOR_CREDIT_DETAILS);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
|
||||
@@ -14,6 +14,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { handleDeleteErrors } from '@/containers/Purchases/CreditNotes/CreditNotesLanding/utils';
|
||||
import { useDeleteVendorCredit } from '@/hooks/query';
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Vendor Credit delete alert.
|
||||
@@ -45,7 +46,7 @@ function VendorCreditDeleteAlert({
|
||||
message: intl.get('vendor_credits.alert.delete_message'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('vendor-credit-detail-drawer');
|
||||
closeDrawer(DRAWERS.VENDOR_CREDIT_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -16,6 +16,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Vendor delete alert.
|
||||
@@ -48,7 +49,7 @@ function VendorDeleteAlert({
|
||||
message: intl.get('the_vendor_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('vendor-detail-drawer');
|
||||
closeDrawer(DRAWERS.VENDOR_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -14,6 +14,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Warehouse transfer delete alert
|
||||
@@ -48,7 +49,7 @@ function WarehouseTransferDeleteAlert({
|
||||
message: intl.get('warehouse_transfer.alert.delete_message'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeDrawer('warehouse-transfer-detail-drawer');
|
||||
closeDrawer(DRAWERS.WAREHOUSE_TRANSFER_DETAILS);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
|
||||
@@ -23,11 +23,11 @@ export const RegisterSchema = Yup.object().shape({
|
||||
first_name: Yup.string().required().label(intl.get('first_name_')),
|
||||
last_name: Yup.string().required().label(intl.get('last_name_')),
|
||||
email: Yup.string().email().required().label(intl.get('email')),
|
||||
password: Yup.string().min(4).required().label(intl.get('password')),
|
||||
password: Yup.string().min(6).required().label(intl.get('password')),
|
||||
});
|
||||
|
||||
export const ResetPasswordSchema = Yup.object().shape({
|
||||
password: Yup.string().min(4).required().label(intl.get('password')),
|
||||
password: Yup.string().min(6).required().label(intl.get('password')),
|
||||
confirm_password: Yup.string()
|
||||
.oneOf([Yup.ref('password'), null])
|
||||
.required()
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
|
||||
import { Select } from '@blueprintjs/select';
|
||||
import { Icon } from '@/components';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
export const CashFlowMenuItems = ({
|
||||
text,
|
||||
@@ -53,40 +54,40 @@ export const CashFlowMenuItems = ({
|
||||
export const handleCashFlowTransactionType = (reference, openDrawer) => {
|
||||
switch (reference.reference_type) {
|
||||
case 'SaleReceipt':
|
||||
return openDrawer('receipt-detail-drawer', {
|
||||
return openDrawer(DRAWERS.RECEIPT_DETAILS, {
|
||||
receiptId: reference.reference_id,
|
||||
});
|
||||
case 'Journal':
|
||||
return openDrawer('journal-drawer', {
|
||||
return openDrawer(DRAWERS.JOURNAL_DETAILS, {
|
||||
manualJournalId: reference.reference_id,
|
||||
});
|
||||
case 'Expense':
|
||||
return openDrawer('expense-drawer', {
|
||||
return openDrawer(DRAWERS.EXPENSE_DETAILS, {
|
||||
expenseId: reference.reference_id,
|
||||
});
|
||||
case 'PaymentReceive':
|
||||
return openDrawer('payment-receive-detail-drawer', {
|
||||
return openDrawer(DRAWERS.PAYMENT_RECEIVE_DETAILS, {
|
||||
paymentReceiveId: reference.reference_id,
|
||||
});
|
||||
case 'BillPayment':
|
||||
return openDrawer('payment-made-detail-drawer', {
|
||||
return openDrawer(DRAWERS.PAYMENT_MADE_DETAILS, {
|
||||
paymentMadeId: reference.reference_id,
|
||||
});
|
||||
case 'RefundCreditNote':
|
||||
return openDrawer('refund-credit-detail-drawer', {
|
||||
return openDrawer(DRAWERS.REFUND_CREDIT_NOTE_DETAILS, {
|
||||
refundTransactionId: reference.reference_id,
|
||||
});
|
||||
case 'RefundVendorCredit':
|
||||
return openDrawer('refund-vendor-detail-drawer', {
|
||||
return openDrawer(DRAWERS.REFUND_VENDOR_CREDIT_DETAILS, {
|
||||
refundTransactionId: reference.reference_id,
|
||||
});
|
||||
case 'InventoryAdjustment':
|
||||
return openDrawer('inventory-adjustment-drawer', {
|
||||
return openDrawer(DRAWERS.INVENTORY_ADJUSTMENT_DETAILS, {
|
||||
inventoryId: reference.reference_id,
|
||||
});
|
||||
|
||||
default:
|
||||
return openDrawer('cashflow-transaction-drawer', {
|
||||
return openDrawer(DRAWERS.CASHFLOW_TRNASACTION_DETAILS, {
|
||||
referenceId: reference.reference_id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
|
||||
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
|
||||
import { safeCallback } from '@/utils';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
const CASHFLOW_SKELETON_N = 4;
|
||||
|
||||
@@ -63,7 +64,7 @@ function CashflowBankAccount({
|
||||
}) {
|
||||
// Handle view detail account.
|
||||
const handleViewClick = () => {
|
||||
openDrawer('account-drawer', { accountId: account.id });
|
||||
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: account.id });
|
||||
};
|
||||
// Handle delete action account.
|
||||
const handleDeleteClick = () => {
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
|
||||
import OwnerContributionFormFields from './OwnerContribution/OwnerContributionFormFields';
|
||||
import OtherIncomeFormFields from './OtherIncome/OtherIncomeFormFields';
|
||||
import TransferFromAccountFormFields from './TransferFromAccount/TransferFromAccountFormFields';
|
||||
import { MoneyInFieldsProvider } from './MoneyInFieldsProvider';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param param0
|
||||
* @returns
|
||||
* Money-in dialog content.
|
||||
* Switches between fields based on the given transaction type.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export default function MoneyInContentFields({ accountType }) {
|
||||
const handleTransactionType = () => {
|
||||
switch (accountType) {
|
||||
export default function MoneyInContentFields() {
|
||||
const { values } = useFormikContext();
|
||||
|
||||
const transactionFields = useMemo(() => {
|
||||
switch (values.transaction_type) {
|
||||
case 'owner_contribution':
|
||||
return <OwnerContributionFormFields />;
|
||||
|
||||
@@ -24,6 +28,10 @@ export default function MoneyInContentFields({ accountType }) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
return <React.Fragment>{handleTransactionType()}</React.Fragment>;
|
||||
}, [values.transaction_type]);
|
||||
|
||||
// Cannot continue if transaction type or account is not selected.
|
||||
if (!values.transaction_type || !values.cashflow_account_id) return null;
|
||||
|
||||
return <MoneyInFieldsProvider>{transactionFields}</MoneyInFieldsProvider>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
import { MoneyInDialogProvider } from './MoneyInDialogProvider';
|
||||
import MoneyInForm from './MoneyInForm';
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { DialogContent } from '@/components';
|
||||
import { Features } from '@/constants';
|
||||
import { useFeatureCan } from '@/hooks/state';
|
||||
import {
|
||||
useCreateCashflowTransaction,
|
||||
useAccount,
|
||||
useAccounts,
|
||||
useBranches,
|
||||
useCashflowAccounts,
|
||||
@@ -18,21 +17,20 @@ const MoneyInDialogContent = React.createContext();
|
||||
* Money in dialog provider.
|
||||
*/
|
||||
function MoneyInDialogProvider({
|
||||
accountId,
|
||||
accountId: defaultAccountId,
|
||||
accountType,
|
||||
dialogName,
|
||||
...props
|
||||
}) {
|
||||
// Holds the selected account id of the dialog.
|
||||
const [accountId, setAccountId] = useState<number | null>(defaultAccountId);
|
||||
|
||||
// Detarmines whether the feature is enabled.
|
||||
const { featureCan } = useFeatureCan();
|
||||
const isBranchFeatureCan = featureCan(Features.Branches);
|
||||
|
||||
// Fetches accounts list.
|
||||
const { isFetching: isAccountsLoading, data: accounts } = useAccounts();
|
||||
|
||||
// Fetches the specific account details.
|
||||
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
|
||||
enabled: !!accountId,
|
||||
});
|
||||
const { isLoading: isAccountsLoading, data: accounts } = useAccounts();
|
||||
|
||||
// Fetches the branches list.
|
||||
const {
|
||||
@@ -41,10 +39,11 @@ function MoneyInDialogProvider({
|
||||
isSuccess: isBranchesSuccess,
|
||||
} = useBranches({}, { enabled: isBranchFeatureCan });
|
||||
|
||||
// Fetch cash flow list .
|
||||
// Fetch cash flow list.
|
||||
const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } =
|
||||
useCashflowAccounts({}, { keepPreviousData: true });
|
||||
|
||||
// Mutation create cashflow transaction.
|
||||
const { mutateAsync: createCashflowTransactionMutate } =
|
||||
useCreateCashflowTransaction();
|
||||
|
||||
@@ -54,12 +53,15 @@ function MoneyInDialogProvider({
|
||||
// Submit payload.
|
||||
const [submitPayload, setSubmitPayload] = React.useState({});
|
||||
|
||||
// provider.
|
||||
// Provider data.
|
||||
const provider = {
|
||||
accounts,
|
||||
account,
|
||||
branches,
|
||||
|
||||
accountId,
|
||||
defaultAccountId,
|
||||
setAccountId,
|
||||
|
||||
accountType,
|
||||
isAccountsLoading,
|
||||
isBranchesSuccess,
|
||||
@@ -73,15 +75,14 @@ function MoneyInDialogProvider({
|
||||
setSubmitPayload,
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
isAccountsLoading ||
|
||||
isCashFlowAccountsLoading ||
|
||||
isBranchesLoading ||
|
||||
isSettingsLoading;
|
||||
|
||||
return (
|
||||
<DialogContent
|
||||
isLoading={
|
||||
isAccountsLoading ||
|
||||
isCashFlowAccountsLoading ||
|
||||
isBranchesLoading ||
|
||||
isSettingsLoading
|
||||
}
|
||||
>
|
||||
<DialogContent isLoading={isLoading}>
|
||||
<MoneyInDialogContent.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { ExchangeRateMutedField } from '@/components';
|
||||
import { useForeignAccount } from './utils';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useMoneyInFieldsContext } from './MoneyInFieldsProvider';
|
||||
|
||||
export function MoneyInExchangeRateField() {
|
||||
const { account } = useMoneyInFieldsContext();
|
||||
const { values } = useFormikContext();
|
||||
|
||||
const isForeigAccount = useForeignAccount();
|
||||
|
||||
if (!isForeigAccount) return null;
|
||||
|
||||
return (
|
||||
<ExchangeRateMutedField
|
||||
name={'exchange_rate'}
|
||||
fromCurrency={values.currency_code}
|
||||
toCurrency={account.currency_code}
|
||||
formGroupProps={{ label: '', inline: false }}
|
||||
date={values.date}
|
||||
exchangeRate={values.exchange_rate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { DialogContent } from '@/components';
|
||||
import { useAccount } from '@/hooks/query';
|
||||
import { useMoneyInDailogContext } from './MoneyInDialogProvider';
|
||||
|
||||
const MoneyInFieldsContext = React.createContext();
|
||||
|
||||
/**
|
||||
* Money in dialog provider.
|
||||
*/
|
||||
function MoneyInFieldsProvider({ ...props }) {
|
||||
const { accountId } = useMoneyInDailogContext();
|
||||
|
||||
// Fetches the specific account details.
|
||||
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
|
||||
enabled: !!accountId,
|
||||
});
|
||||
// Provider data.
|
||||
const provider = {
|
||||
account,
|
||||
};
|
||||
const isLoading = isAccountLoading;
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={isLoading}>
|
||||
<MoneyInFieldsContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useMoneyInFieldsContext = () => React.useContext(MoneyInFieldsContext);
|
||||
|
||||
export { MoneyInFieldsProvider, useMoneyInFieldsContext };
|
||||
@@ -53,7 +53,6 @@ function MoneyInForm({
|
||||
accountId,
|
||||
accountType,
|
||||
createCashflowTransactionMutate,
|
||||
submitPayload,
|
||||
} = useMoneyInDailogContext();
|
||||
|
||||
// transaction number.
|
||||
@@ -61,7 +60,6 @@ function MoneyInForm({
|
||||
transactionNumberPrefix,
|
||||
transactionNextNumber,
|
||||
);
|
||||
|
||||
// Initial form values.
|
||||
const initialValues = {
|
||||
...defaultInitialValues,
|
||||
@@ -95,15 +93,13 @@ function MoneyInForm({
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Formik
|
||||
validationSchema={CreateMoneyInFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<MoneyInFormContent />
|
||||
</Formik>
|
||||
</div>
|
||||
<Formik
|
||||
validationSchema={CreateMoneyInFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<MoneyInFormContent />
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,17 +12,13 @@ import { useMoneyInDailogContext } from './MoneyInDialogProvider';
|
||||
* Money in form fields.
|
||||
*/
|
||||
function MoneyInFormFields() {
|
||||
const { values } = useFormikContext();
|
||||
|
||||
// Money in dialog context.
|
||||
const { accountId } = useMoneyInDailogContext();
|
||||
const { defaultAccountId } = useMoneyInDailogContext();
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<If condition={!accountId}>
|
||||
<TransactionTypeFields />
|
||||
</If>
|
||||
<MoneyInContentFields accountType={values.transaction_type} />
|
||||
{!defaultAccountId && <TransactionTypeFields />}
|
||||
<MoneyInContentFields />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import {
|
||||
Classes,
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
TextArea,
|
||||
Position,
|
||||
ControlGroup,
|
||||
@@ -18,14 +17,15 @@ import {
|
||||
FieldRequiredHint,
|
||||
Col,
|
||||
Row,
|
||||
If,
|
||||
FeatureCan,
|
||||
BranchSelect,
|
||||
BranchSelectButton,
|
||||
ExchangeRateMutedField,
|
||||
FInputGroup,
|
||||
FFormGroup,
|
||||
FTextArea,
|
||||
FMoneyInputGroup,
|
||||
} from '@/components';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { useAutofocus } from '@/hooks';
|
||||
import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants';
|
||||
|
||||
import {
|
||||
@@ -36,22 +36,18 @@ import {
|
||||
} from '@/utils';
|
||||
|
||||
import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
|
||||
import {
|
||||
useSetPrimaryBranchToForm,
|
||||
useForeignAccount,
|
||||
BranchRowDivider,
|
||||
} from '../utils';
|
||||
import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils';
|
||||
import { MoneyInOutTransactionNoField } from '../../_components';
|
||||
import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider';
|
||||
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
|
||||
|
||||
/**
|
||||
* Other income form fields.
|
||||
*/
|
||||
export default function OtherIncomeFormFields() {
|
||||
// Money in dialog context.
|
||||
const { accounts, account, branches } = useMoneyInDailogContext();
|
||||
const { values } = useFormikContext();
|
||||
const amountFieldRef = useAutofocus();
|
||||
const isForeigAccount = useForeignAccount();
|
||||
const { accounts, branches } = useMoneyInDailogContext();
|
||||
const { account } = useMoneyInFieldsContext();
|
||||
|
||||
// Sets the primary branch to form.
|
||||
useSetPrimaryBranchToForm();
|
||||
@@ -61,17 +57,14 @@ export default function OtherIncomeFormFields() {
|
||||
<FeatureCan feature={Features.Branches}>
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
<FormGroup
|
||||
label={<T id={'branch'} />}
|
||||
className={classNames('form-group--select-list', Classes.FILL)}
|
||||
>
|
||||
<FFormGroup name={'amount'} label={<T id={'branch'} />}>
|
||||
<BranchSelect
|
||||
name={'branch_id'}
|
||||
branches={branches}
|
||||
input={BranchSelectButton}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
<BranchRowDivider />
|
||||
@@ -106,53 +99,32 @@ export default function OtherIncomeFormFields() {
|
||||
)}
|
||||
</FastField>
|
||||
</Col>
|
||||
|
||||
<Col xs={5}>
|
||||
{/*------------ Transaction number -----------*/}
|
||||
<MoneyInOutTransactionNoField />
|
||||
</Col>
|
||||
</Row>
|
||||
{/*------------ amount -----------*/}
|
||||
<FastField name={'amount'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
|
||||
{/*------------ Amount -----------*/}
|
||||
<Row>
|
||||
<Col xs={10}>
|
||||
<FFormGroup
|
||||
name={'amount'}
|
||||
label={<T id={'amount'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="amount" />}
|
||||
className={'form-group--amount'}
|
||||
>
|
||||
<ControlGroup>
|
||||
<InputPrependText text={account.currency_code} />
|
||||
|
||||
<MoneyInputGroup
|
||||
value={value}
|
||||
minimal={true}
|
||||
onChange={(amount) => {
|
||||
setFieldValue('amount', amount);
|
||||
}}
|
||||
inputRef={(ref) => (amountFieldRef.current = ref)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
/>
|
||||
<FMoneyInputGroup name={'amount'} minimal={true} />
|
||||
</ControlGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/*------------ Exchange rate -----------*/}
|
||||
<MoneyInExchangeRateField />
|
||||
|
||||
<If condition={isForeigAccount}>
|
||||
{/*------------ exchange rate -----------*/}
|
||||
<ExchangeRateMutedField
|
||||
name={'exchange_rate'}
|
||||
fromCurrency={values.currency_code}
|
||||
toCurrency={account.currency_code}
|
||||
formGroupProps={{ label: '', inline: false }}
|
||||
date={values.date}
|
||||
exchangeRate={values.exchange_rate}
|
||||
/>
|
||||
</If>
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
{/*------------ other income account -----------*/}
|
||||
@@ -182,43 +154,24 @@ export default function OtherIncomeFormFields() {
|
||||
)}
|
||||
</FastField>
|
||||
</Col>
|
||||
|
||||
<Col xs={5}>
|
||||
{/*------------ Reference -----------*/}
|
||||
<FastField name={'reference_no'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'reference_no'} />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="reference_no" />}
|
||||
className={'form-group--reference-no'}
|
||||
>
|
||||
<InputGroup
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<FFormGroup label={<T id={'reference_no'} />} name={'reference_no'}>
|
||||
<FInputGroup name={'reference_no'} />
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
{/*------------ description -----------*/}
|
||||
<FastField name={'description'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
className={'form-group--description'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'description'} />}
|
||||
>
|
||||
<TextArea
|
||||
growVertically={true}
|
||||
large={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/*------------ Description -----------*/}
|
||||
<FFormGroup name={'description'} label={<T id={'description'} />}>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
|
||||
import {
|
||||
Classes,
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
TextArea,
|
||||
Position,
|
||||
ControlGroup,
|
||||
} from '@blueprintjs/core';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
AccountsSuggestField,
|
||||
InputPrependText,
|
||||
MoneyInputGroup,
|
||||
FieldRequiredHint,
|
||||
Col,
|
||||
Row,
|
||||
If,
|
||||
ExchangeRateMutedField,
|
||||
BranchSelect,
|
||||
BranchSelectButton,
|
||||
FeatureCan,
|
||||
FFormGroup,
|
||||
FMoneyInputGroup,
|
||||
FTextArea,
|
||||
FInputGroup,
|
||||
} from '@/components';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { useAutofocus } from '@/hooks';
|
||||
import { ACCOUNT_TYPE, CLASSES, Features } from '@/constants';
|
||||
import {
|
||||
inputIntent,
|
||||
@@ -37,10 +29,11 @@ import {
|
||||
import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
|
||||
import {
|
||||
useSetPrimaryBranchToForm,
|
||||
useForeignAccount,
|
||||
BranchRowDivider,
|
||||
} from '../../MoneyInDialog/utils';
|
||||
import { MoneyInOutTransactionNoField } from '../../_components';
|
||||
import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider';
|
||||
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
|
||||
|
||||
/**
|
||||
/**
|
||||
@@ -48,13 +41,8 @@ import { MoneyInOutTransactionNoField } from '../../_components';
|
||||
*/
|
||||
export default function OwnerContributionFormFields() {
|
||||
// Money in dialog context.
|
||||
const { accounts, account, branches } = useMoneyInDailogContext();
|
||||
|
||||
const { values } = useFormikContext();
|
||||
|
||||
const amountFieldRef = useAutofocus();
|
||||
|
||||
const isForeigAccount = useForeignAccount();
|
||||
const { accounts, branches } = useMoneyInDailogContext();
|
||||
const { account } = useMoneyInFieldsContext();
|
||||
|
||||
// Sets the primary branch to form.
|
||||
useSetPrimaryBranchToForm();
|
||||
@@ -64,21 +52,19 @@ export default function OwnerContributionFormFields() {
|
||||
<FeatureCan feature={Features.Branches}>
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
<FormGroup
|
||||
label={<T id={'branch'} />}
|
||||
className={classNames('form-group--select-list', Classes.FILL)}
|
||||
>
|
||||
<FFormGroup name={'branch_id'} label={<T id={'branch'} />}>
|
||||
<BranchSelect
|
||||
name={'branch_id'}
|
||||
branches={branches}
|
||||
input={BranchSelectButton}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
<BranchRowDivider />
|
||||
</FeatureCan>
|
||||
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
{/*------------ Date -----------*/}
|
||||
@@ -113,47 +99,26 @@ export default function OwnerContributionFormFields() {
|
||||
<MoneyInOutTransactionNoField />
|
||||
</Col>
|
||||
</Row>
|
||||
{/*------------ amount -----------*/}
|
||||
<Field name={'amount'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
|
||||
{/*------------ Amount -----------*/}
|
||||
<Row>
|
||||
<Col xs={10}>
|
||||
<FFormGroup
|
||||
name={'amount'}
|
||||
label={<T id={'amount'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="amount" />}
|
||||
className={'form-group--amount'}
|
||||
>
|
||||
<ControlGroup>
|
||||
<InputPrependText text={account?.currency_code} />
|
||||
|
||||
<MoneyInputGroup
|
||||
value={value}
|
||||
minimal={true}
|
||||
onChange={(amount) => {
|
||||
setFieldValue('amount', amount);
|
||||
}}
|
||||
inputRef={(ref) => (amountFieldRef.current = ref)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
/>
|
||||
<InputPrependText text={account?.currency_code || '--'} />
|
||||
<FMoneyInputGroup name={'amount'} minimal={true} />
|
||||
</ControlGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
</Field>
|
||||
<If condition={isForeigAccount}>
|
||||
{/*------------ exchange rate -----------*/}
|
||||
<ExchangeRateMutedField
|
||||
name={'exchange_rate'}
|
||||
fromCurrency={values.currency_code}
|
||||
toCurrency={account.currency_code}
|
||||
formGroupProps={{ label: '', inline: false }}
|
||||
date={values.date}
|
||||
exchangeRate={values.exchange_rate}
|
||||
/>
|
||||
</If>
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/*------------ Exchange rate -----------*/}
|
||||
<MoneyInExchangeRateField />
|
||||
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
{/*------------ equity account -----------*/}
|
||||
@@ -181,43 +146,24 @@ export default function OwnerContributionFormFields() {
|
||||
)}
|
||||
</FastField>
|
||||
</Col>
|
||||
|
||||
<Col xs={5}>
|
||||
{/*------------ Reference -----------*/}
|
||||
<FastField name={'reference_no'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'reference_no'} />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="reference_no" />}
|
||||
className={'form-group--reference-no'}
|
||||
>
|
||||
<InputGroup
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
|
||||
<FInputGroup name={'reference_no'} />
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
{/*------------ description -----------*/}
|
||||
<FastField name={'description'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
className={'form-group--description'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'description'} />}
|
||||
>
|
||||
<TextArea
|
||||
growVertically={true}
|
||||
large={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/*------------ Description -----------*/}
|
||||
<FFormGroup name={'description'} label={<T id={'description'} />}>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
ListSelect,
|
||||
Col,
|
||||
Row,
|
||||
FFormGroup,
|
||||
FSelect,
|
||||
} from '@/components';
|
||||
import { inputIntent } from '@/utils';
|
||||
import { CLASSES, getAddMoneyInOptions } from '@/constants';
|
||||
@@ -21,7 +23,7 @@ import { useMoneyInDailogContext } from './MoneyInDialogProvider';
|
||||
*/
|
||||
export default function TransactionTypeFields() {
|
||||
// Money in dialog context.
|
||||
const { cashflowAccounts } = useMoneyInDailogContext();
|
||||
const { cashflowAccounts, setAccountId } = useMoneyInDailogContext();
|
||||
|
||||
// Retrieves the add money in button options.
|
||||
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
|
||||
@@ -29,6 +31,23 @@ export default function TransactionTypeFields() {
|
||||
return (
|
||||
<div className="trasnaction-type-fileds">
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
{/*------------ Transaction type -----------*/}
|
||||
<FFormGroup
|
||||
name={'transaction_type'}
|
||||
label={<T id={'transaction_type'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
>
|
||||
<FSelect
|
||||
name={'transaction_type'}
|
||||
items={addMoneyInOptions}
|
||||
popoverProps={{ minimal: true }}
|
||||
valueAccessor={'value'}
|
||||
textAccessor={'name'}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
|
||||
<Col xs={5}>
|
||||
{/*------------ Current account -----------*/}
|
||||
<FastField name={'cashflow_account_id'}>
|
||||
@@ -46,9 +65,10 @@ export default function TransactionTypeFields() {
|
||||
>
|
||||
<AccountsSuggestField
|
||||
accounts={cashflowAccounts}
|
||||
onAccountSelected={({ id }) =>
|
||||
form.setFieldValue('cashflow_account_id', id)
|
||||
}
|
||||
onAccountSelected={({ id }) => {
|
||||
form.setFieldValue('cashflow_account_id', id);
|
||||
setAccountId(id);
|
||||
}}
|
||||
inputProps={{
|
||||
intent: inputIntent({ error, touched }),
|
||||
}}
|
||||
@@ -56,39 +76,6 @@ export default function TransactionTypeFields() {
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
{/*------------ Transaction type -----------*/}
|
||||
</Col>
|
||||
<Col xs={5}>
|
||||
<Field name={'transaction_type'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
label={<T id={'transaction_type'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
helperText={<ErrorMessage name="transaction_type" />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
className={classNames(
|
||||
CLASSES.FILL,
|
||||
'form-group--transaction_type',
|
||||
)}
|
||||
>
|
||||
<ListSelect
|
||||
items={addMoneyInOptions}
|
||||
onItemSelect={(type) => {
|
||||
setFieldValue('transaction_type', type.value);
|
||||
}}
|
||||
filterable={false}
|
||||
selectedItem={value}
|
||||
selectedItemProp={'value'}
|
||||
textProp={'name'}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</Field>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
@@ -1,33 +1,27 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import {
|
||||
Classes,
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
TextArea,
|
||||
Position,
|
||||
ControlGroup,
|
||||
} from '@blueprintjs/core';
|
||||
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
AccountsSuggestField,
|
||||
InputPrependText,
|
||||
MoneyInputGroup,
|
||||
FieldRequiredHint,
|
||||
Col,
|
||||
Row,
|
||||
If,
|
||||
ExchangeRateMutedField,
|
||||
FeatureCan,
|
||||
BranchSelect,
|
||||
BranchSelectButton,
|
||||
FMoneyInputGroup,
|
||||
FInputGroup,
|
||||
FFormGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useAutofocus } from '@/hooks';
|
||||
import { MoneyInOutTransactionNoField } from '../../_components';
|
||||
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
|
||||
import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants';
|
||||
|
||||
import {
|
||||
inputIntent,
|
||||
momentFormatter,
|
||||
@@ -35,25 +29,19 @@ import {
|
||||
handleDateChange,
|
||||
} from '@/utils';
|
||||
import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
|
||||
import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider';
|
||||
import {
|
||||
useSetPrimaryBranchToForm,
|
||||
useForeignAccount,
|
||||
BranchRowDivider,
|
||||
} from '../../MoneyInDialog/utils';
|
||||
|
||||
import { MoneyInOutTransactionNoField } from '../../_components';
|
||||
|
||||
/**
|
||||
* Transfer from account form fields.
|
||||
*/
|
||||
export default function TransferFromAccountFormFields() {
|
||||
// Money in dialog context.
|
||||
const { accounts, account, branches } = useMoneyInDailogContext();
|
||||
|
||||
const isForeigAccount = useForeignAccount();
|
||||
const amountFieldRef = useAutofocus();
|
||||
|
||||
const { values } = useFormikContext();
|
||||
const { accounts, branches } = useMoneyInDailogContext();
|
||||
const { account } = useMoneyInFieldsContext();
|
||||
|
||||
// Sets the primary branch to form.
|
||||
useSetPrimaryBranchToForm();
|
||||
@@ -63,17 +51,14 @@ export default function TransferFromAccountFormFields() {
|
||||
<FeatureCan feature={Features.Branches}>
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
<FormGroup
|
||||
label={<T id={'branch'} />}
|
||||
className={classNames('form-group--select-list', Classes.FILL)}
|
||||
>
|
||||
<FFormGroup label={<T id={'branch'} />} name={'branch_id'}>
|
||||
<BranchSelect
|
||||
name={'branch_id'}
|
||||
branches={branches}
|
||||
input={BranchSelectButton}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
<BranchRowDivider />
|
||||
@@ -112,50 +97,27 @@ export default function TransferFromAccountFormFields() {
|
||||
<MoneyInOutTransactionNoField />
|
||||
</Col>
|
||||
</Row>
|
||||
{/*------------ amount -----------*/}
|
||||
<FastField name={'amount'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
{/*------------ Amount -----------*/}
|
||||
<Row>
|
||||
<Col xs={10}>
|
||||
<FormGroup
|
||||
label={<T id={'amount'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="amount" />}
|
||||
className={'form-group--amount'}
|
||||
>
|
||||
<ControlGroup>
|
||||
<InputPrependText text={account.currency_code} />
|
||||
|
||||
<MoneyInputGroup
|
||||
value={value}
|
||||
minimal={true}
|
||||
onChange={(amount) => {
|
||||
setFieldValue('amount', amount);
|
||||
}}
|
||||
inputRef={(ref) => (amountFieldRef.current = ref)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
/>
|
||||
<InputPrependText text={account.currency_code || '--'} />
|
||||
<FMoneyInputGroup name={'amount'} minimal={true} />
|
||||
</ControlGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<If condition={isForeigAccount}>
|
||||
{/*------------ exchange rate -----------*/}
|
||||
<ExchangeRateMutedField
|
||||
name={'exchange_rate'}
|
||||
fromCurrency={values.currency_code}
|
||||
toCurrency={account.currency_code}
|
||||
formGroupProps={{ label: '', inline: false }}
|
||||
date={values.date}
|
||||
exchangeRate={values.exchange_rate}
|
||||
/>
|
||||
</If>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/*------------ Exchange rate -----------*/}
|
||||
<MoneyInExchangeRateField />
|
||||
|
||||
<Row>
|
||||
<Col xs={5}>
|
||||
{/*------------ transfer from account -----------*/}
|
||||
{/*------------ Transfer from account -----------*/}
|
||||
<FastField name={'credit_account_id'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
@@ -185,43 +147,24 @@ export default function TransferFromAccountFormFields() {
|
||||
)}
|
||||
</FastField>
|
||||
</Col>
|
||||
|
||||
<Col xs={5}>
|
||||
{/*------------ Reference -----------*/}
|
||||
<FastField name={'reference_no'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'reference_no'} />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="reference_no" />}
|
||||
className={'form-group--reference-no'}
|
||||
>
|
||||
<InputGroup
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
|
||||
<FInputGroup name={'reference_no'} />
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
{/*------------ description -----------*/}
|
||||
<FastField name={'description'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
className={'form-group--description'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'description'} />}
|
||||
>
|
||||
<TextArea
|
||||
growVertically={true}
|
||||
large={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/*------------ Description -----------*/}
|
||||
<FormGroup name={'description'} label={<T id={'description'} />}>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FormGroup>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Dialog, DialogSuspense } from '@/components';
|
||||
import withDialogRedux from '@/components/DialogReduxConnect';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
const MoneyInDialogContent = React.lazy(() => import('./MoneyInDialogContent'));
|
||||
|
||||
@@ -6,6 +6,7 @@ import { transactionNumber } from '@/utils';
|
||||
import { isEqual, isNull, first } from 'lodash';
|
||||
|
||||
import { useMoneyInDailogContext } from './MoneyInDialogProvider';
|
||||
import { useMoneyInFieldsContext } from './MoneyInFieldsProvider';
|
||||
|
||||
export const useObserveTransactionNoSettings = (prefix, nextNumber) => {
|
||||
const { setFieldValue } = useFormikContext();
|
||||
@@ -33,7 +34,7 @@ export const useSetPrimaryBranchToForm = () => {
|
||||
|
||||
export const useForeignAccount = () => {
|
||||
const { values } = useFormikContext();
|
||||
const { account } = useMoneyInDailogContext();
|
||||
const { account } = useMoneyInFieldsContext();
|
||||
|
||||
return (
|
||||
!isEqual(account.currency_code, values.currency_code) &&
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
|
||||
import OtherExpnseFormFields from './OtherExpense/OtherExpnseFormFields';
|
||||
import OwnerDrawingsFormFields from './OwnerDrawings/OwnerDrawingsFormFields';
|
||||
import TransferToAccountFormFields from './TransferToAccount/TransferToAccountFormFields';
|
||||
import { MoneyOutFieldsProvider } from './MoneyOutFieldsProvider';
|
||||
|
||||
function MoneyOutContentFields({ accountType }) {
|
||||
const handleTransactionType = () => {
|
||||
switch (accountType) {
|
||||
/**
|
||||
* Money out content fields.
|
||||
* Switches between form fields based on the given transaction type.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
function MoneyOutContentFields() {
|
||||
const { values } = useFormikContext();
|
||||
|
||||
const transactionType = useMemo(() => {
|
||||
switch (values.transaction_type) {
|
||||
case 'OwnerDrawing':
|
||||
return <OwnerDrawingsFormFields />;
|
||||
|
||||
@@ -19,8 +28,12 @@ function MoneyOutContentFields({ accountType }) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
return <React.Fragment>{handleTransactionType()}</React.Fragment>;
|
||||
}, [values.transaction_type]);
|
||||
|
||||
// Cannot continue if transaction type or account is not selected.
|
||||
if (!values.transaction_type || !values.cashflow_account_id) return null;
|
||||
|
||||
return <MoneyOutFieldsProvider>{transactionType}</MoneyOutFieldsProvider>;
|
||||
}
|
||||
|
||||
export default MoneyOutContentFields;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { DialogContent } from '@/components';
|
||||
import { Features } from '@/constants';
|
||||
import { useFeatureCan } from '@/hooks/state';
|
||||
import {
|
||||
useAccounts,
|
||||
useAccount,
|
||||
useBranches,
|
||||
useCreateCashflowTransaction,
|
||||
useCashflowAccounts,
|
||||
@@ -17,7 +16,15 @@ const MoneyInDialogContent = React.createContext();
|
||||
/**
|
||||
* Money out dialog provider.
|
||||
*/
|
||||
function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
|
||||
function MoneyOutProvider({
|
||||
accountId: defaultAccountId,
|
||||
accountType,
|
||||
dialogName,
|
||||
...props
|
||||
}) {
|
||||
// Holds the selected account id of the dialog.
|
||||
const [accountId, setAccountId] = useState<number | null>(defaultAccountId);
|
||||
|
||||
// Features guard.
|
||||
const { featureCan } = useFeatureCan();
|
||||
const isBranchFeatureCan = featureCan(Features.Branches);
|
||||
@@ -25,11 +32,6 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
|
||||
// Fetches accounts list.
|
||||
const { isLoading: isAccountsLoading, data: accounts } = useAccounts();
|
||||
|
||||
// Fetches the specific account details.
|
||||
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
|
||||
enabled: !!accountId,
|
||||
});
|
||||
|
||||
// Fetches the branches list.
|
||||
const {
|
||||
data: branches,
|
||||
@@ -41,6 +43,7 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
|
||||
const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } =
|
||||
useCashflowAccounts({}, { keepPreviousData: true });
|
||||
|
||||
// Mutation to create a new cashflow account.
|
||||
const { mutateAsync: createCashflowTransactionMutate } =
|
||||
useCreateCashflowTransaction();
|
||||
|
||||
@@ -50,11 +53,13 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
|
||||
// Submit payload.
|
||||
const [submitPayload, setSubmitPayload] = React.useState({});
|
||||
|
||||
// provider.
|
||||
// Provider data.
|
||||
const provider = {
|
||||
accounts,
|
||||
account,
|
||||
accountId,
|
||||
setAccountId,
|
||||
defaultAccountId,
|
||||
|
||||
accounts,
|
||||
accountType,
|
||||
branches,
|
||||
isAccountsLoading,
|
||||
@@ -69,15 +74,14 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
|
||||
setSubmitPayload,
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
isAccountsLoading ||
|
||||
isCashFlowAccountsLoading ||
|
||||
isBranchesLoading ||
|
||||
isSettingsLoading;
|
||||
|
||||
return (
|
||||
<DialogContent
|
||||
isLoading={
|
||||
isAccountsLoading ||
|
||||
isCashFlowAccountsLoading ||
|
||||
isBranchesLoading ||
|
||||
isSettingsLoading
|
||||
}
|
||||
>
|
||||
<DialogContent isLoading={isLoading}>
|
||||
<MoneyInDialogContent.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useForeignAccount } from './utils';
|
||||
import { ExchangeRateMutedField } from '@/components';
|
||||
import { useMoneyOutFieldsContext } from './MoneyOutFieldsProvider';
|
||||
|
||||
/**
|
||||
* Money-out exchange rate field.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export function MoneyOutExchangeRateField() {
|
||||
const { values } = useFormikContext();
|
||||
|
||||
const { account } = useMoneyOutFieldsContext();
|
||||
const isForeigAccount = useForeignAccount();
|
||||
|
||||
// Cannot continue if the account is not foreign account.
|
||||
if (!isForeigAccount) return null;
|
||||
|
||||
return (
|
||||
<ExchangeRateMutedField
|
||||
name={'exchange_rate'}
|
||||
fromCurrency={values?.currency_code}
|
||||
toCurrency={account?.currency_code}
|
||||
formGroupProps={{ label: '', inline: false }}
|
||||
date={values.date}
|
||||
exchangeRate={values.exchange_rate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { DialogContent } from '@/components';
|
||||
import { useAccount } from '@/hooks/query';
|
||||
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
|
||||
|
||||
const MoneyOutFieldsContext = React.createContext();
|
||||
|
||||
/**
|
||||
* Money out fields dialog provider.
|
||||
*/
|
||||
function MoneyOutFieldsProvider({ ...props }) {
|
||||
const { accountId } = useMoneyOutDialogContext();
|
||||
|
||||
// Fetches the specific account details.
|
||||
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
|
||||
enabled: !!accountId,
|
||||
});
|
||||
// Provider data.
|
||||
const provider = {
|
||||
account,
|
||||
};
|
||||
const isLoading = isAccountLoading;
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={isLoading}>
|
||||
<MoneyOutFieldsContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useMoneyOutFieldsContext = () => React.useContext(MoneyOutFieldsContext);
|
||||
|
||||
export { MoneyOutFieldsProvider, useMoneyOutFieldsContext };
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user