Compare commits

...

22 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
eff8b41720 Merge pull request #519 from bigcapitalhq/change-settings-value-colum-to-text
fix: alter value column of the settings table to text instead of string
2024-07-04 09:05:17 +02:00
Ahmed Bouhuolia
632cc3d72e fix: alter value column of the settings table to text instead of string 2024-07-04 08:58:41 +02:00
Ahmed Bouhuolia
3e437a041c Merge pull request #518 from bigcapitalhq/BIG-213
fix: Tax rate not saving on creating a new invoice
2024-06-24 10:47:21 +02:00
Ahmed Bouhuolia
e783cfeafa fix: Tax rate not saving on creating a new invoice 2024-06-24 10:46:19 +02:00
Ahmed Bouhuolia
5dde7f5584 Merge pull request #516 from bigcapitalhq/BIG-212
fix: Reorder 'debit' and 'credit' columns
2024-06-24 10:44:28 +02:00
Ahmed Bouhuolia
8e0911ec85 fix: Reorder 'debit' and 'credit' columns 2024-06-24 10:43:34 +02:00
Ahmed Bouhuolia
7b4afd3859 Update .env.example 2024-06-17 18:30:13 +02:00
Ahmed Bouhuolia
590715037b chore: dump CHANGELOG.md 2024-06-17 15:33:49 +02:00
Ahmed Bouhuolia
1e53a8e85e Merge pull request #506 from bigcapitalhq/BIG-206
feat: Setting up the date format in the whole system dates
2024-06-17 12:53:31 +02:00
Ahmed Bouhuolia
2ad77103ac feat: cashflow tranasction date format 2024-06-17 12:50:31 +02:00
Ahmed Bouhuolia
c1fc70863b Merge pull request #497 from bigcapitalhq/BIG-195
fix: Disable email confirmation does not work with invited users
2024-06-17 10:34:33 +02:00
Ahmed Bouhuolia
125dff8376 feat: format created at date 2024-06-17 10:27:02 +02:00
Ahmed Bouhuolia
84da7b7df5 Merge pull request #509 from bigcapitalhq/BIG-193
feat: Migrating to Envoy proxy instead of Nginx
2024-06-17 09:22:23 +02:00
Ahmed Bouhuolia
4c82f6f8ad feat: Migrating to Envoy proxy instead of Nginx 2024-06-15 11:54:19 +02:00
Ahmed Bouhuolia
0d7aad5448 Merge pull request #508 from bigcapitalhq/BIG-142
fix: add space between buttons on floating actions bar
2024-06-14 08:29:45 +02:00
Ahmed Bouhuolia
74b74a2722 fix: add space between buttons on floating actions bar 2024-06-14 08:27:30 +02:00
Ahmed Bouhuolia
3a0a0db8a7 feat: setting up the date format in the whole system dates 2024-06-12 19:43:42 +02:00
Ahmed Bouhuolia
265ea9ca48 Merge pull request #501 from bigcapitalhq/BIG-202
fix: Balance sheet and P/L nested accounts
2024-06-12 13:06:37 +02:00
Ahmed Bouhuolia
cfd37f8894 fix: Balance sheet and P/L nested accounts 2024-06-12 13:05:02 +02:00
Ahmed Bouhuolia
d1caa5c5ce fix: Disable email confirmation does not work with invited users 2024-06-10 15:59:33 +02:00
Ahmed Bouhuolia
d998d716b7 Merge pull request #496 from bigcapitalhq/fix-payment-receive-attachments
fix: Edit the payment received transactions with attachments
2024-06-10 13:41:44 +02:00
Ahmed Bouhuolia
031ccc4a0b fix: Edit the payment received transactions with attachments 2024-06-10 13:41:10 +02:00
78 changed files with 564 additions and 291 deletions

View File

@@ -84,8 +84,8 @@ LEMONSQUEEZY_STORE_ID=
LEMONSQUEEZY_WEBHOOK_SECRET=
# S3 documents and attachments
S3_REGION=
S3_REGION=US
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_ENDPOINT=
S3_BUCKET=
S3_BUCKET=

View File

@@ -2,6 +2,14 @@
All notable changes to Bigcapital server-side will be in this file.
## [v0.17.5] - 17-06-2024
* fix: Balance sheet and P/L nested accounts by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/501
* fix: add space between buttons on floating actions bar by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/508
* feat: Migrating to Envoy proxy instead of Nginx by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/509
* fix: Disable email confirmation does not work with invited users by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/497
* feat: Setting up the date format in the whole system dates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/506
## [0.17.0] - 04-06-2024
### New

View File

@@ -3,24 +3,17 @@
version: '3.3'
services:
nginx:
container_name: bigcapital-nginx-gateway
build:
context: ./docker/nginx
args:
- SERVER_PROXY_PORT=3000
- WEB_SSL=false
- SELF_SIGNED=false
volumes:
- ./data/logs/nginx/:/var/log/nginx
- ./docker/certbot/certs/:/var/certs
proxy:
image: envoyproxy/envoy:v1.30-latest
depends_on:
- server
- webapp
ports:
- '${PUBLIC_PROXY_PORT:-80}:80'
- '${PUBLIC_PROXY_SSL_PORT:-443}:443'
tty: true
depends_on:
- server
- webapp
volumes:
- ./docker/envoy/envoy.yaml:/etc/envoy/envoy.yaml
restart: on-failure
networks:
- bigcapital_network
@@ -46,6 +39,8 @@ services:
- mongo
- redis
restart: on-failure
networks:
- bigcapital_network
environment:
# Mail
- MAIL_HOST=${MAIL_HOST}
@@ -127,8 +122,6 @@ services:
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
- S3_ENDPOINT=${S3_ENDPOINT}
- S3_BUCKET=${S3_BUCKET}
networks:
- bigcapital_network
database_migration:
container_name: bigcapital-database-migration

62
docker/envoy/envoy.yaml Normal file
View File

@@ -0,0 +1,62 @@
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ['*']
routes:
- match:
prefix: '/api'
route:
cluster: dynamic_server
- match:
prefix: '/'
route:
cluster: webapp
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: dynamic_server
connect_timeout: 0.25s
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: dynamic_server
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: server
port_value: 3000
- name: webapp
connect_timeout: 0.25s
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: webapp
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: webapp
port_value: 80

View File

@@ -1,21 +0,0 @@
FROM nginx:1.11
RUN mkdir /etc/nginx/sites-available && rm /etc/nginx/conf.d/default.conf
ADD nginx.conf /etc/nginx/
COPY scripts /root/scripts/
COPY certs /etc/ssl/
COPY sites /etc/nginx/templates
ARG SERVER_PROXY_PORT=3000
ARG WEB_SSL=false
ARG SELF_SIGNED=false
ENV SERVER_PROXY_PORT=$SERVER_PROXY_PORT
ENV WEB_SSL=$WEB_SSL
ENV SELF_SIGNED=$SELF_SIGNED
RUN /bin/bash /root/scripts/build-nginx.sh
CMD nginx

View File

@@ -1,33 +0,0 @@
user www-data;
worker_processes auto;
pid /run/nginx.pid;
daemon off;
events {
worker_connections 2048;
use epoll;
}
http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
types_hash_max_size 2048;
client_max_body_size 20M;
open_file_cache max=100;
gzip on;
gzip_disable "msie6";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-available/*;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}

View File

@@ -1,9 +0,0 @@
#!/bin/bash
for conf in /etc/nginx/templates/*.conf; do
mv $conf "/etc/nginx/sites-available/"$(basename $conf) > /dev/null
done
for template in /etc/nginx/templates/*.template; do
envsubst < $template > "/etc/nginx/sites-available/"$(basename $template)".conf"
done

View File

@@ -1,16 +0,0 @@
server {
listen 80 default_server;
location /api {
proxy_pass http://server:${SERVER_PROXY_PORT};
}
location / {
proxy_pass http://webapp;
}
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt/;
log_not_found off;
}
}

View File

@@ -5,7 +5,7 @@ import DashboardService from '@/services/Dashboard/DashboardService';
@Service()
export default class DashboardMetaController {
@Inject()
dashboardService: DashboardService;
private dashboardService: DashboardService;
/**
* Constructor router.

View File

@@ -0,0 +1,11 @@
exports.up = function (knex) {
return knex.schema.table('settings', (table) => {
table.text('value').alter();
});
};
exports.down = (knex) => {
return knex.schema.table('settings', (table) => {
table.string('value').alter();
});
};

View File

@@ -149,13 +149,19 @@ export class Transformer {
return this.excludeAttributes().length > 0;
};
private dateFormat = 'YYYY MMM DD';
setDateFormat(format: string) {
this.dateFormat = format;
}
/**
*
* @param date
* @returns
*/
protected formatDate(date) {
return date ? moment(date).format('YYYY/MM/DD') : '';
return date ? moment(date).format(this.dateFormat) : '';
}
/**
@@ -193,6 +199,7 @@ export class Transformer {
) {
transformer.setOptions(options);
transformer.setContext(this.context);
transformer.setDateFormat(this.dateFormat);
return transformer.work(obj);
}

View File

@@ -24,6 +24,17 @@ export class TransformerInjectable {
};
}
/**
* Retrieves the given tenatn date format.
* @param {number} tenantId
* @returns {string}
*/
async getTenantDateFormat(tenantId: number) {
const metadata = await TenantMetadata.query().findOne('tenantId', tenantId);
return metadata.dateFormat;
}
/**
* Transformes the given transformer after inject the tenant context.
* @param {number} tenantId
@@ -41,7 +52,11 @@ export class TransformerInjectable {
if (!isNull(tenantId)) {
const context = await this.getApplicationContext(tenantId);
transformer.setContext(context);
const dateFormat = await this.getTenantDateFormat(tenantId);
transformer.setDateFormat(dateFormat);
}
transformer.setOptions(options);
return transformer.work(object);

View File

@@ -1,6 +1,6 @@
import { Container, Inject } from 'typedi';
import { cloneDeep } from 'lodash';
import { Tenant } from '@/system/models';
import { SystemUser, Tenant } from '@/system/models';
import {
IAuthSignedInEventPayload,
IAuthSigningInEventPayload,
@@ -64,7 +64,9 @@ export class AuthSigninService {
const { systemUserRepository } = this.sysRepositories;
// Finds the user of the given email address.
const user = await systemUserRepository.findOneByEmail(email);
const user = await SystemUser.query()
.findOne('email', email)
.modify('inviteAccepted');
// Validate the given email and password.
await this.validateSignIn(user, email, password);

View File

@@ -7,7 +7,12 @@ export class CashflowTransactionTransformer extends Transformer {
* @returns {string[]}
*/
public includeAttributes = (): string[] => {
return ['formattedAmount', 'transactionTypeFormatted'];
return [
'formattedAmount',
'transactionTypeFormatted',
'formattedDate',
'formattedCreatedAt',
];
};
/**
@@ -24,10 +29,28 @@ export class CashflowTransactionTransformer extends Transformer {
/**
* Formatted transaction type.
* @param transaction
* @param transaction
* @returns {string}
*/
protected transactionTypeFormatted = (transaction) => {
return this.context.i18n.__(transaction.transactionTypeFormatted);
}
};
/**
* Retrieve the formatted transaction date.
* @param invoice
* @returns {string}
*/
protected formattedDate = (invoice): string => {
return this.formatDate(invoice.date);
};
/**
* Retrieve the formatted created at date.
* @param invoice
* @returns {string}
*/
protected formattedCreatedAt = (invoice): string => {
return this.formatDate(invoice.createdAt);
};
}

View File

@@ -13,6 +13,8 @@ export class CreditNoteTransformer extends Transformer {
return [
'formattedCreditsRemaining',
'formattedCreditNoteDate',
'formattedCreatedAt',
'formattedCreatedAt',
'formattedAmount',
'formattedCreditsUsed',
'formattedSubtotal',
@@ -30,6 +32,15 @@ export class CreditNoteTransformer extends Transformer {
return this.formatDate(credit.creditNoteDate);
};
/**
* Retrieve formatted created at date.
* @param credit
* @returns {string}
*/
protected formattedCreatedAt = (credit): string => {
return this.formatDate(credit.createdAt);
};
/**
* Retrieve formatted invoice amount.
* @param {ICreditNote} credit

View File

@@ -15,6 +15,7 @@ export class ExpenseTransfromer extends Transformer {
'formattedLandedCostAmount',
'formattedAllocatedCostAmount',
'formattedDate',
'formattedCreatedAt',
'categories',
'attachments',
];
@@ -62,6 +63,15 @@ export class ExpenseTransfromer extends Transformer {
return this.formatDate(expense.paymentDate);
};
/**
* Retrieve formatted created at date.
* @param {IExpense} expense
* @returns {string}
*/
protected formattedCreatedAt = (expense: IExpense): string => {
return this.formatDate(expense.createdAt);
}
/**
* Retrieves the transformed expense categories.
* @param {IExpense} expense

View File

@@ -20,6 +20,8 @@ import { BalanceSheetPercentage } from './BalanceSheetPercentage';
import { BalanceSheetSchema } from './BalanceSheetSchema';
import { BalanceSheetBase } from './BalanceSheetBase';
import { BalanceSheetQuery } from './BalanceSheetQuery';
import { flatToNestedArray } from '@/utils';
import BalanceSheetRepository from './BalanceSheetRepository';
export const BalanceSheetAccounts = (Base: any) =>
class extends R.compose(
@@ -56,6 +58,11 @@ export const BalanceSheetAccounts = (Base: any) =>
*/
readonly i18n: any;
/**
* Balance sheet repository.
*/
readonly repository: BalanceSheetRepository;
/**
* Retrieve the accounts node of accounts types.
* @param {string} accountsTypes
@@ -78,8 +85,12 @@ export const BalanceSheetAccounts = (Base: any) =>
private reportSchemaAccountNodeMapper = (
account: IAccount
): IBalanceSheetAccountNode => {
const childrenAccountsIds = this.repository.accountsGraph.dependenciesOf(
account.id
);
const accountIds = R.uniq(R.append(account.id, childrenAccountsIds));
const total = this.repository.totalAccountsLedger
.whereAccountId(account.id)
.whereAccountsIds(accountIds)
.getClosingBalance();
return {
@@ -128,8 +139,19 @@ export const BalanceSheetAccounts = (Base: any) =>
private getAccountsNodesByAccountTypes = (
accountsTypes: string[]
): IBalanceSheetAccountNode[] => {
// Retrieves accounts from the given defined node account types.
const accounts = this.getAccountsByAccountTypes(accountsTypes);
return R.map(this.reportSchemaAccountNodeComposer, accounts);
// Converts the flatten accounts to tree.
const accountsTree = flatToNestedArray(accounts, {
id: 'id',
parentId: 'parentAccountId',
});
// Maps over the accounts tree.
return this.mapNodesDeep(
accountsTree,
this.reportSchemaAccountNodeComposer
);
};
/**

View File

@@ -38,6 +38,11 @@ export default class BalanceSheetRepository extends R.compose(
*/
public accounts: any;
/**
* @param {}
*/
public accountsGraph: any;
/**
*
*/
@@ -161,6 +166,8 @@ export default class BalanceSheetRepository extends R.compose(
*/
public asyncInitialize = async () => {
await this.initAccounts();
await this.initAccountsGraph();
await this.initAccountsTotalLedger();
// Date periods.
@@ -202,6 +209,15 @@ export default class BalanceSheetRepository extends R.compose(
this.accountsByParentType = transformToMapBy(accounts, 'accountParentType');
};
/**
* Initialize accounts graph.
*/
public initAccountsGraph = async () => {
const { Account } = this.models;
this.accountsGraph = Account.toDependencyGraph(this.accounts);
};
// ----------------------------
// # Closing Total
// ----------------------------

View File

@@ -50,8 +50,8 @@ export class JournalSheetTable extends R.compose(
{ key: 'description', accessor: 'entry.note' },
{ key: 'account_code', accessor: 'entry.accountCode' },
{ key: 'account_name', accessor: 'entry.accountName' },
{ key: 'credit', accessor: 'entry.formattedCredit' },
{ key: 'debit', accessor: 'entry.formattedDebit' },
{ key: 'credit', accessor: 'entry.formattedCredit' },
];
};
@@ -67,8 +67,8 @@ export class JournalSheetTable extends R.compose(
{ key: 'description', accessor: 'note' },
{ key: 'account_code', accessor: 'accountCode' },
{ key: 'account_name', accessor: 'accountName' },
{ key: 'credit', accessor: 'formattedCredit' },
{ key: 'debit', accessor: 'formattedDebit' },
{ key: 'credit', accessor: 'formattedCredit' },
];
};
@@ -84,8 +84,8 @@ export class JournalSheetTable extends R.compose(
{ key: 'description', accessor: '_empty_' },
{ key: 'account_code', accessor: '_empty_' },
{ key: 'account_name', accessor: '_empty_' },
{ key: 'credit', accessor: 'formattedCredit' },
{ key: 'debit', accessor: 'formattedDebit' },
{ key: 'credit', accessor: 'formattedCredit' },
];
};
@@ -101,8 +101,8 @@ export class JournalSheetTable extends R.compose(
{ key: 'description', value: '' },
{ key: 'account_code', value: '' },
{ key: 'account_name', value: '' },
{ key: 'credit', value: '' },
{ key: 'debit', value: '' },
{ key: 'credit', value: '' },
];
};
@@ -118,8 +118,8 @@ export class JournalSheetTable extends R.compose(
{ key: 'description', label: 'Description' },
{ key: 'account_code', label: 'Acc. Code' },
{ key: 'account_name', label: 'Account' },
{ key: 'credit', label: 'Credit' },
{ key: 'debit', label: 'Debit' },
{ key: 'credit', label: 'Credit' },
];
}

View File

@@ -24,6 +24,7 @@ import { ProfitLossSheetPreviousYear } from './ProfitLossSheetPreviousYear';
import { ProfitLossSheetPreviousPeriod } from './ProfitLossSheetPreviousPeriod';
import { FinancialDateRanges } from '../FinancialDateRanges';
import { ProfitLossSheetFilter } from './ProfitLossSheetFilter';
import { flatToNestedArray } from '@/utils';
export default class ProfitLossSheet extends R.compose(
ProfitLossSheetPreviousYear,
@@ -82,14 +83,22 @@ export default class ProfitLossSheet extends R.compose(
/**
* Retrieve the sheet account node from the given account.
* @param {IAccount} account
* @param {IAccount} account
* @returns {IProfitLossSheetAccountNode}
*/
private accountNodeMapper = (
account: IAccount
): IProfitLossSheetAccountNode => {
// Retrieves the children account ids of the given account id.
const childrenAccountIds = this.repository.accountsGraph.dependenciesOf(
account.id
);
// Concat the children and the given account id.
const accountIds = R.uniq(R.append(account.id, childrenAccountIds));
// Retrieves the closing balance of the account included children accounts.
const total = this.repository.totalAccountsLedger
.whereAccountId(account.id)
.whereAccountsIds(accountIds)
.getClosingBalance();
return {
@@ -126,18 +135,19 @@ export default class ProfitLossSheet extends R.compose(
};
/**
* Retrieve report accounts nodes by the given accounts types.
* @param {string[]} types
* Retrieves report accounts nodes by the given accounts types.
* @param {string[]} types
* @returns {IBalanceSheetAccountNode}
*/
private getAccountsNodesByTypes = (
types: string[]
): IProfitLossSheetAccountNode[] => {
return R.compose(
R.map(this.accountNodeCompose),
R.flatten,
R.map(this.repository.getAccountsByType)
)(types);
const accounts = this.repository.getAccountsByType(types);
const accountsTree = flatToNestedArray(accounts, {
id: 'id',
parentId: 'parentAccountId',
});
return this.mapNodesDeep(accountsTree, this.accountNodeCompose);
};
/**

View File

@@ -1,4 +1,4 @@
import { defaultTo } from 'lodash';
import { castArray, defaultTo } from 'lodash';
import * as R from 'ramda';
import { Knex } from 'knex';
import { isEmpty } from 'lodash';
@@ -31,6 +31,11 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
*/
public accounts: IAccount[];
/**
*
*/
public accountsGraph: any;
/**
* Transactions group type.
* @param {IAccountTransactionsGroupBy}
@@ -135,6 +140,8 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
*/
public asyncInitialize = async () => {
await this.initAccounts();
await this.initAccountsGraph();
await this.initAccountsTotalLedger();
// Date Periods.
@@ -177,6 +184,15 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
this.accountsByType = transformToMapBy(accounts, 'accountType');
};
/**
* Initialize accounts graph.
*/
private initAccountsGraph = async () => {
const { Account } = this.models;
this.accountsGraph = Account.toDependencyGraph(this.accounts);
};
// ----------------------------
// # Closing Total.
// ----------------------------
@@ -337,7 +353,18 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
return Account.query();
};
public getAccountsByType = (type: string) => {
return defaultTo(this.accountsByType.get(type), []);
/**
*
* @param type
* @returns
*/
public getAccountsByType = (type: string[] | string) => {
return R.compose(
R.flatten,
R.map((accountType) =>
R.defaultTo([], this.accountsByType.get(accountType))
),
castArray
)(type);
};
}

View File

@@ -46,6 +46,9 @@ export default class SyncSystemSendInvite {
email: user.email,
active: user.active,
tenantId,
// Email should be verified since the user got the invite token through email.
verified: true,
});
// Creates a invite user token.
const invite = await Invite.query().insert({

View File

@@ -13,6 +13,7 @@ export class ManualJournalTransfromer extends Transformer {
'formattedAmount',
'formattedDate',
'formattedPublishedAt',
'formattedCreatedAt',
'attachments',
];
};
@@ -37,6 +38,15 @@ export class ManualJournalTransfromer extends Transformer {
return this.formatDate(manualJorunal.date);
};
/**
* Retrieve formatted created at date.
* @param {IManualJournal} manualJournal
* @returns {string}
*/
protected formattedCreatedAt = (manualJorunal: IManualJournal): string => {
return this.formatDate(manualJorunal.createdAt);
};
/**
* Retrieve formatted published at date.
* @param {IManualJournal} manualJournal

View File

@@ -207,7 +207,7 @@ export default class OrganizationService {
): IOrganizationBuildDTO {
return {
...buildDTO,
dateFormat: defaultTo(buildDTO.dateFormat, 'DD/MM/yyyy'),
dateFormat: defaultTo(buildDTO.dateFormat, 'DD MMM yyyy'),
};
}

View File

@@ -1,5 +1,6 @@
import { Transformer } from '@/lib/Transformer/Transformer';
import { formatNumber } from '@/utils';
import { PurchaseInvoiceTransformer } from '../Bills/PurchaseInvoiceTransformer';
export class BillPaymentEntryTransformer extends Transformer {
/**
@@ -7,7 +8,14 @@ export class BillPaymentEntryTransformer extends Transformer {
* @returns {Array}
*/
public includeAttributes = (): string[] => {
return ['paymentAmountFormatted'];
return ['paymentAmountFormatted', 'bill'];
};
/**
* Retreives the
*/
protected bill = (entry) => {
return this.item(entry.bill, new PurchaseInvoiceTransformer());
};
/**

View File

@@ -12,6 +12,7 @@ export class BillPaymentTransformer extends Transformer {
public includeAttributes = (): string[] => {
return [
'formattedPaymentDate',
'formattedCreatedAt',
'formattedAmount',
'entries',
'attachments',
@@ -27,6 +28,15 @@ export class BillPaymentTransformer extends Transformer {
return this.formatDate(billPayment.paymentDate);
};
/**
* Retrieve formatted created at date.
* @param {IBillPayment} billPayment
* @returns {string}
*/
protected formattedCreatedAt = (billPayment: IBillPayment): string => {
return this.formatDate(billPayment.createdAt);
}
/**
* Retrieve formatted bill amount.
* @param {IBill} invoice

View File

@@ -14,6 +14,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
return [
'formattedBillDate',
'formattedDueDate',
'formattedCreatedAt',
'formattedAmount',
'formattedPaymentAmount',
'formattedBalance',
@@ -57,6 +58,15 @@ export class PurchaseInvoiceTransformer extends Transformer {
return this.formatDate(bill.dueDate);
};
/**
* Retrieve the formatted created at date.
* @param {IBill} bill
* @returns {string}
*/
protected formattedCreatedAt = (bill: IBill): string => {
return this.formatDate(bill.createdAt);
};
/**
* Retrieve formatted bill amount.
* @param {IBill} bill

View File

@@ -14,6 +14,7 @@ export class VendorCreditTransformer extends Transformer {
'formattedAmount',
'formattedSubtotal',
'formattedVendorCreditDate',
'formattedCreatedAt',
'formattedCreditsRemaining',
'formattedInvoicedAmount',
'entries',
@@ -30,6 +31,15 @@ export class VendorCreditTransformer extends Transformer {
return this.formatDate(vendorCredit.vendorCreditDate);
};
/**
* Retireve formatted created at date.
* @param vendorCredit
* @returns {string}
*/
protected formattedCreatedAt = (vendorCredit): string => {
return this.formatDate(vendorCredit.createdAt);
};
/**
* Retrieve formatted vendor credit amount.
* @param {IVendorCredit} credit

View File

@@ -18,6 +18,7 @@ export class SaleEstimateTransfromer extends Transformer {
'formattedDeliveredAtDate',
'formattedApprovedAtDate',
'formattedRejectedAtDate',
'formattedCreatedAt',
'entries',
'attachments',
];
@@ -41,6 +42,15 @@ export class SaleEstimateTransfromer extends Transformer {
return this.formatDate(estimate.expirationDate);
};
/**
* Retrieves the formatted estimate created at.
* @param {ISaleEstimate} estimate -
* @returns {string}
*/
protected formattedCreatedAt = (estimate: ISaleEstimate): string => {
return this.formatDate(estimate.createdAt);
};
/**
* Retrieve formatted estimate date.
* @param {ISaleEstimate} invoice

View File

@@ -13,6 +13,7 @@ export class SaleInvoiceTransformer extends Transformer {
return [
'invoiceDateFormatted',
'dueDateFormatted',
'createdAtFormatted',
'dueAmountFormatted',
'paymentAmountFormatted',
'balanceAmountFormatted',
@@ -48,6 +49,15 @@ export class SaleInvoiceTransformer extends Transformer {
return this.formatDate(invoice.dueDate);
};
/**
* Retrieve the formatted created at date.
* @param invoice
* @returns {string}
*/
protected createdAtFormatted = (invoice): string => {
return this.formatDate(invoice.createdAt);
};
/**
* Retrieve formatted invoice due amount.
* @param {ISaleInvoice} invoice

View File

@@ -146,6 +146,7 @@ export class EditPaymentReceive {
paymentReceiveId,
paymentReceive,
oldPaymentReceive,
paymentReceiveDTO,
authorizedUser,
trx,
} as IPaymentReceiveEditedPayload);

View File

@@ -12,6 +12,7 @@ export class PaymentReceiveTransfromer extends Transformer {
return [
'subtotalFormatted',
'formattedPaymentDate',
'formattedCreatedAt',
'formattedAmount',
'formattedExchangeRate',
'entries',
@@ -27,9 +28,18 @@ export class PaymentReceiveTransfromer extends Transformer {
return this.formatDate(payment.paymentDate);
};
/**
* Retrieves the formatted created at date.
* @param {IPaymentReceive} payment
* @returns {string}
*/
protected formattedCreatedAt = (payment: IPaymentReceive): string => {
return this.formatDate(payment.createdAt);
};
/**
* Retrieve the formatted payment subtotal.
* @param {IPaymentReceive} payment
* @param {IPaymentReceive} payment
* @returns {string}
*/
protected subtotalFormatted = (payment: IPaymentReceive): string => {

View File

@@ -17,6 +17,7 @@ export class SaleReceiptTransformer extends Transformer {
'formattedAmount',
'formattedReceiptDate',
'formattedClosedAtDate',
'formattedCreatedAt',
'entries',
'attachments',
];
@@ -40,6 +41,15 @@ export class SaleReceiptTransformer extends Transformer {
return this.formatDate(receipt.closedAt);
};
/**
* Retrieve formatted receipt created at date.
* @param receipt
* @returns {string}
*/
protected formattedCreatedAt = (receipt: ISaleReceipt): string => {
return this.formatDate(receipt.createdAt);
};
/**
* Retrieves the estimate formatted subtotal.
* @param {ISaleReceipt} receipt

View File

@@ -90,6 +90,20 @@ export default class SystemUser extends SystemModel {
};
}
/**
* Model modifiers.
*/
static get modifiers() {
return {
/**
* Filters the invite accepted users.
*/
inviteAccepted(query) {
query.whereNotNull('invite_accepted_at');
},
};
}
/**
* Verify the password of the user.
* @param {String} password - The given password.

View File

@@ -21,9 +21,9 @@ import RefundCreditNoteDetailDrawer from '@/containers/Drawers/RefundCreditNoteD
import RefundVendorCreditDetailDrawer from '@/containers/Drawers/RefundVendorCreditDetailDrawer';
import WarehouseTransferDetailDrawer from '@/containers/Drawers/WarehouseTransferDetailDrawer';
import TaxRateDetailsDrawer from '@/containers/TaxRates/drawers/TaxRateDetailsDrawer/TaxRateDetailsDrawer';
import CategorizeTransactionDrawer from '@/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionDrawer';
import { DRAWERS } from '@/constants/drawers';
import CategorizeTransactionDrawer from '@/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionDrawer';
/**
* Drawers container of the dashboard.

View File

@@ -16,8 +16,7 @@ export const useManualJournalsColumns = () => {
{
id: 'date',
Header: intl.get('date'),
accessor: 'date',
Cell: FormatDateCell,
accessor: 'formatted_date',
width: 115,
className: 'date',
clickable: true,
@@ -66,8 +65,7 @@ export const useManualJournalsColumns = () => {
{
id: 'created_at',
Header: intl.get('created_at'),
accessor: 'created_at',
Cell: FormatDateCell,
accessor: 'formatted_created_at',
width: 125,
clickable: true,
},

View File

@@ -13,7 +13,7 @@ import {
import { useHistory } from 'react-router-dom';
import { useFormikContext } from 'formik';
import classNames from 'classnames';
import { Icon, If, FormattedMessage as T } from '@/components';
import { Group, Icon, If, FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes';
import { useMakeJournalFormContext } from './MakeJournalProvider';
@@ -76,7 +76,10 @@ export default function MakeJournalFloatingAction() {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Publish ----------- */}
<If condition={!manualJournal || !manualJournal?.is_published}>
<ButtonGroup>
@@ -188,6 +191,6 @@ export default function MakeJournalFloatingAction() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -111,16 +111,16 @@ export const useJournalTableEntriesColumns = () => {
fieldProps: { allowCreate: true },
},
{
Header: CreditHeaderCell,
accessor: 'credit',
Header: DebitHeaderCell,
accessor: 'debit',
Cell: MoneyFieldCell,
disableSortBy: true,
width: 100,
align: Align.Right,
},
{
Header: DebitHeaderCell,
accessor: 'debit',
Header: CreditHeaderCell,
accessor: 'credit',
Cell: MoneyFieldCell,
disableSortBy: true,
width: 100,

View File

@@ -13,12 +13,11 @@ import {
} from '@blueprintjs/core';
import classNames from 'classnames';
import { useFormikContext } from 'formik';
import { Icon, FormattedMessage as T } from '@/components';
import { Group, Icon, FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes';
import { useCustomerFormContext } from './CustomerFormProvider';
import { safeInvoke } from '@/utils';
/**
* Customer floating actions bar.
*/
@@ -51,7 +50,10 @@ export default function CustomerFloatingActions({ onCancel }) {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
<ButtonGroup>
{/* ----------- Save and New ----------- */}
<SaveButton
@@ -96,7 +98,7 @@ export default function CustomerFloatingActions({ onCancel }) {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -26,6 +26,14 @@ export const useAccountReadEntriesColumns = () => {
width: 100,
textOverview: true,
},
{
Header: intl.get('debit'),
accessor: isFCYCurrencyType ? 'formatted_fc_debit' : 'formatted_debit',
width: 80,
className: 'debit',
align: 'right',
textOverview: true,
},
{
Header: intl.get('credit'),
accessor: isFCYCurrencyType
@@ -36,14 +44,6 @@ export const useAccountReadEntriesColumns = () => {
align: 'right',
textOverview: true,
},
{
Header: intl.get('debit'),
accessor: isFCYCurrencyType ? 'formatted_fc_debit' : 'formatted_debit',
width: 80,
className: 'debit',
align: 'right',
textOverview: true,
},
],
[isFCYCurrencyType],
);

View File

@@ -41,19 +41,23 @@ export default function BillDetailHeader() {
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem label={intl.get('bill_date')}>
<FormatDate value={bill.bill_date} />
{bill.formatted_bill_date}
</DetailItem>
<DetailItem label={intl.get('due_date')}>
<FormatDate value={bill.due_date} />
{bill.formatted_due_date}
</DetailItem>
<DetailItem label={intl.get('vendor_name')}>
<VendorDrawerLink vendorId={bill.vendor_id}>
{bill.vendor?.display_name}
</VendorDrawerLink>
</DetailItem>
<DetailItem label={intl.get('bill.details.bill_number')}>
{defaultTo(bill.bill_number, '-')}
</DetailItem>
<ExchangeRateDetailItem
exchangeRate={bill?.exchange_rate}
toCurrency={bill?.currency_code}
@@ -75,7 +79,7 @@ export default function BillDetailHeader() {
/>
<DetailItem
label={intl.get('bill.details.created_at')}
children={<FormatDate value={bill.created_at} />}
children={bill.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -46,7 +46,7 @@ export default function CashflowTransactionDrawerHeader() {
</DetailItem>
<DetailItem label={<T id={'date'} />}>
<FormatDate value={cashflowTransaction.date} />
{cashflowTransaction.formatted_date}
</DetailItem>
<DetailItem name={'reference-no'} label={<T id={'reference_no'} />}>

View File

@@ -5,13 +5,11 @@ import styled from 'styled-components';
import { defaultTo } from 'lodash';
import {
FormatDate,
T,
Row,
Col,
DetailsMenu,
DetailItem,
ButtonLink,
CommercialDocHeader,
CommercialDocTopHeader,
CustomerDrawerLink,
@@ -47,7 +45,7 @@ export default function CreditNoteDetailHeader() {
<DetailItem
label={intl.get('credit_note.drawer.label_credit_note_date')}
>
<FormatDate value={creditNote.formatted_credit_note_date} />
{creditNote.formatted_credit_note_date}
</DetailItem>
<DetailItem
@@ -85,7 +83,7 @@ export default function CreditNoteDetailHeader() {
/>
<DetailItem
label={<T id={'credit_note.drawer.label_created_at'} />}
children={<FormatDate value={creditNote.created_at} />}
children={creditNote.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -81,7 +81,7 @@ export default function EstimateDetailHeader() {
/>
<DetailItem
label={<T id={'estimate.details.created_at'} />}
children={<FormatDate value={estimate.created_at} />}
children={estimate.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -1,6 +1,5 @@
// @ts-nocheck
import React from 'react';
import moment from 'moment';
import styled from 'styled-components';
import { defaultTo } from 'lodash';
@@ -42,7 +41,7 @@ export default function ExpenseDrawerHeader() {
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem name={'date'} label={<T id={'date'} />}>
{moment(expense.payment_date).format('YYYY MMM DD')}
{expense.formatted_payment_date}
</DetailItem>
<DetailItem name={'reference'} label={<T id={'reference_no'} />}>
@@ -66,11 +65,11 @@ export default function ExpenseDrawerHeader() {
minLabelSize={'180px'}
>
<DetailItem label={<T id={'published_at'} />}>
<FormatDate value={expense.published_at} />
{expense.formatted_date}
</DetailItem>
<DetailItem label={<T id={'created_at'} />}>
<FormatDate value={expense.created_at} />
{expense.formatted_created_at}
</DetailItem>
</DetailsMenu>
</Col>

View File

@@ -43,11 +43,11 @@ export default function InvoiceDetailHeader() {
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem label={intl.get('invoice_date')}>
<FormatDate value={invoice.invoice_date} />
{invoice.invoice_date_formatted}
</DetailItem>
<DetailItem label={intl.get('due_date')}>
<FormatDate value={invoice.due_date} />
{invoice.due_date_formatted}
</DetailItem>
<DetailItem label={intl.get('customer_name')}>
@@ -86,7 +86,7 @@ export default function InvoiceDetailHeader() {
/>
<DetailItem
label={intl.get('invoice.details.created_at')}
children={<FormatDate value={invoice.created_at} />}
children={invoice.created_at_formatted}
/>
</DetailsMenu>
</Col>

View File

@@ -82,20 +82,6 @@ export const useManualJournalEntriesColumns = () => {
},
]
: []),
{
Header: intl.get('credit'),
accessor: 'credit',
Cell: FormatNumberCell,
width: getColumnWidth(entries, 'credit', {
minWidth: 60,
magicSpacing: 5,
}),
disableResizable: true,
disableSortBy: true,
textOverview: true,
formatNumber: { noZero: true },
align: 'right',
},
{
Header: intl.get('debit'),
accessor: 'debit',
@@ -110,6 +96,20 @@ export const useManualJournalEntriesColumns = () => {
formatNumber: { noZero: true },
align: 'right',
},
{
Header: intl.get('credit'),
accessor: 'credit',
Cell: FormatNumberCell,
width: getColumnWidth(entries, 'credit', {
minWidth: 60,
magicSpacing: 5,
}),
disableResizable: true,
disableSortBy: true,
textOverview: true,
formatNumber: { noZero: true },
align: 'right',
},
],
[],
);

View File

@@ -37,7 +37,7 @@ export default function PaymentMadeDetailHeader() {
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('payment_date')}
children={<FormatDate value={paymentMade.payment_date} />}
children={paymentMade.formatted_payment_date}
/>
<DetailItem
label={intl.get('payment_made.details.payment_number')}
@@ -58,6 +58,7 @@ export default function PaymentMadeDetailHeader() {
/>
</DetailsMenu>
</Col>
<Col xs={6}>
<DetailsMenu
textAlign={'right'}
@@ -70,7 +71,7 @@ export default function PaymentMadeDetailHeader() {
/>
<DetailItem
label={intl.get('created_at')}
children={<FormatDate value={paymentMade.created_at} />}
children={paymentMade.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -1,8 +1,6 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import moment from 'moment';
import { getColumnWidth } from '@/utils';
import { FormatNumberCell } from '@/components';
import { usePaymentMadeDetailContext } from './PaymentMadeDetailProvider';
@@ -17,7 +15,7 @@ export const usePaymentMadeEntriesColumns = () => {
() => [
{
Header: intl.get('date'),
accessor: (row) => moment(row.date).format('YYYY MMM DD'),
accessor: 'bill.formatted_bill_date',
width: 100,
disableSortBy: true,
className: 'date',

View File

@@ -5,7 +5,6 @@ import { defaultTo } from 'lodash';
import {
Row,
Col,
FormatDate,
DetailsMenu,
DetailItem,
CommercialDocHeader,
@@ -36,7 +35,7 @@ export default function PaymentReceiveDetailHeader() {
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('payment_date')}
children={<FormatDate value={paymentReceive.payment_date} />}
children={paymentReceive.formatted_payment_date}
/>
<DetailItem
label={intl.get('payment_receive.details.payment_number')}
@@ -71,7 +70,7 @@ export default function PaymentReceiveDetailHeader() {
/>
<DetailItem
label={intl.get('created_at')}
children={<FormatDate value={paymentReceive.created_at} />}
children={paymentReceive.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -1,7 +1,6 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import moment from 'moment';
import {
Button,
Popover,
@@ -26,7 +25,7 @@ export const usePaymentReceiveEntriesColumns = () => {
() => [
{
Header: intl.get('date'),
accessor: (row) => moment(row.payment_date).format('YYYY MMM DD'),
accessor: 'invoice.invoice_date_formatted',
width: 100,
className: 'date',
disableSortBy: true,

View File

@@ -54,11 +54,11 @@ export default function ReceiptDetailHeader() {
</DetailItem>
<DetailItem
label={intl.get('receipt_date')}
children={<FormatDate value={receipt.receipt_date} />}
children={receipt.formatted_receipt_date}
/>
<DetailItem
label={intl.get('closed_date')}
children={<FormatDate value={receipt.closed_at_date} />}
children={receipt.formatted_closed_at_date}
/>
<ExchangeRateDetailItem
exchangeRate={receipt?.exchange_rate}
@@ -82,7 +82,7 @@ export default function ReceiptDetailHeader() {
/>
<DetailItem
label={intl.get('receipt.details.created_at')}
children={<FormatDate value={receipt.created_at} />}
children={receipt.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -42,7 +42,7 @@ export default function VendorCreditDetailHeader() {
<DetailItem
label={intl.get('vendor_credit.drawer.label_vendor_credit_date')}
>
<FormatDate value={vendorCredit.formatted_vendor_credit_date} />
{vendorCredit.formatted_vendor_credit_date}
</DetailItem>
<DetailItem
label={intl.get('vendor_credit.drawer.label_vendor_credit_no')}
@@ -78,7 +78,7 @@ export default function VendorCreditDetailHeader() {
/>
<DetailItem
label={<T id={'vendor_credit.drawer.label_created_at'} />}
children={<FormatDate value={vendorCredit.created_at} />}
children={vendorCredit.formatted_created_at}
/>
</DetailsMenu>
</Col>

View File

@@ -11,7 +11,7 @@ import {
MenuItem,
} from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import { FormattedMessage as T } from '@/components';
import { Group, FormattedMessage as T } from '@/components';
import { useHistory } from 'react-router-dom';
import { CLASSES } from '@/constants/classes';
@@ -78,7 +78,10 @@ export default function ExpenseFloatingFooter() {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Publish ----------- */}
<If condition={isNewMode}>
<ButtonGroup>
@@ -190,6 +193,6 @@ export default function ExpenseFloatingFooter() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -17,13 +17,7 @@ import clsx from 'classnames';
import { CLASSES } from '@/constants/classes';
import { ExpenseAction, AbilitySubject } from '@/constants/abilityOption';
import {
FormatDateCell,
FormattedMessage as T,
Icon,
If,
Can,
} from '@/components';
import { FormattedMessage as T, Icon, If, Can } from '@/components';
import { safeCallback } from '@/utils';
/**
@@ -137,8 +131,7 @@ export function useExpensesTableColumns() {
{
id: 'payment_date',
Header: intl.get('payment_date'),
accessor: 'payment_date',
Cell: FormatDateCell,
accessor: 'formatted_date',
width: 140,
className: 'payment_date',
clickable: true,

View File

@@ -5,9 +5,8 @@ import classNames from 'classnames';
import { Button, Intent, FormGroup, Checkbox } from '@blueprintjs/core';
import { FastField, useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes';
import { useItemFormContext } from './ItemFormProvider';
import { FormattedMessage as T } from '@/components';
import { Group, FormattedMessage as T } from '@/components';
import { saveInvoke } from '@/utils';
/**
@@ -37,7 +36,10 @@ export default function ItemFormFloatingActions({ onCancel }) {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
<SaveButton
intent={Intent.PRIMARY}
disabled={isSubmitting}
@@ -78,7 +80,7 @@ export default function ItemFormFloatingActions({ onCancel }) {
</FormGroup>
)}
</FastField>
</div>
</Group>
);
}

View File

@@ -3,7 +3,6 @@ import React from 'react';
import { useParams } from 'react-router-dom';
import ItemForm from './ItemForm';
/**
* Item form page.
*/

View File

@@ -1,16 +1,13 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import moment from 'moment';
export const useGLEntriesTableColumns = () => {
return React.useMemo(
() => [
{
Header: intl.get('date'),
accessor: ({ formatted_date }) =>
moment(formatted_date).format('YYYY MMM DD'),
accessor: 'date.formatted_date',
width: 140,
className: 'date',
textOverview: true,
@@ -28,14 +25,6 @@ export const useGLEntriesTableColumns = () => {
width: 140,
textOverview: true,
},
{
Header: intl.get('credit'),
accessor: ({ credit }) => credit.formatted_amount,
width: 100,
className: 'credit',
align: 'right',
textOverview: true,
},
{
Header: intl.get('debit'),
accessor: ({ debit }) => debit.formatted_amount,
@@ -44,6 +33,14 @@ export const useGLEntriesTableColumns = () => {
textOverview: true,
align: 'right',
},
{
Header: intl.get('credit'),
accessor: ({ credit }) => credit.formatted_amount,
width: 100,
className: 'credit',
align: 'right',
textOverview: true,
},
],
[],
);

View File

@@ -10,7 +10,7 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { FormattedMessage as T } from '@/components';
import { Group, FormattedMessage as T } from '@/components';
import { useHistory } from 'react-router-dom';
import { CLASSES } from '@/constants/classes';
import classNames from 'classnames';
@@ -76,7 +76,10 @@ export default function BillFloatingActions() {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Open ----------- */}
<If condition={!bill || !bill?.is_open}>
<ButtonGroup>
@@ -189,6 +192,6 @@ export default function BillFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -161,8 +161,7 @@ export function useBillsTableColumns() {
{
id: 'bill_date',
Header: intl.get('bill_date'),
accessor: 'bill_date',
Cell: FormatDateCell,
accessor: 'formatted_bill_date',
width: 110,
className: 'bill_date',
clickable: true,

View File

@@ -13,7 +13,7 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { If, Icon, FormattedMessage as T } from '@/components';
import { If, Icon, FormattedMessage as T, Group } from '@/components';
import { CLASSES } from '@/constants/classes';
import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
@@ -69,11 +69,15 @@ export default function VendorCreditNoteFloatingActions() {
history.goBack();
};
// Handle the clear button click.
const handleClearBtnClick = (event) => {
resetForm();
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Open ----------- */}
<If condition={!vendorCredit || !vendorCredit?.is_open}>
<ButtonGroup>
@@ -185,6 +189,6 @@ export default function VendorCreditNoteFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -5,14 +5,7 @@ import clsx from 'classnames';
import { Intent, Tag, Menu, MenuItem, MenuDivider } from '@blueprintjs/core';
import { CLASSES } from '@/constants/classes';
import {
FormatDateCell,
FormattedMessage as T,
Choose,
If,
Icon,
Can,
} from '@/components';
import { FormattedMessage as T, Choose, If, Icon, Can } from '@/components';
import { safeCallback } from '@/utils';
import { VendorCreditAction, AbilitySubject } from '@/constants/abilityOption';
@@ -119,7 +112,6 @@ export function useVendorsCreditNoteTableColumns() {
id: 'credit_date',
Header: intl.get('date'),
accessor: 'formatted_vendor_credit_date',
Cell: FormatDateCell,
width: 110,
className: 'credit_date',
clickable: true,

View File

@@ -11,14 +11,12 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { Icon, FormattedMessage as T } from '@/components';
import { Group, Icon, FormattedMessage as T } from '@/components';
import { useHistory } from 'react-router-dom';
import { useFormikContext } from 'formik';
import { usePaymentMadeFormContext } from './PaymentMadeFormProvider';
import { CLASSES } from '@/constants/classes';
/**
* Payment made floating actions bar.
*/
@@ -56,11 +54,14 @@ export default function PaymentMadeFloatingActions() {
// Handle submit & continue editing button click.
const handleSubmitContinueEditingBtnClick = (event) => {
setSubmitPayload({ redirect: false, publish: true });
submitForm()
submitForm();
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save and New ----------- */}
<ButtonGroup>
<Button
@@ -109,6 +110,6 @@ export default function PaymentMadeFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -11,7 +11,7 @@ import {
Position,
} from '@blueprintjs/core';
import { Icon, Money, FormatDateCell, Can } from '@/components';
import { Icon, Money, Can } from '@/components';
import { PaymentMadeAction, AbilitySubject } from '@/constants/abilityOption';
import { safeCallback } from '@/utils';
@@ -29,7 +29,7 @@ export function ActionsMenu({
}) {
return (
<Menu>
<MenuItem
<MenuItem
icon={<Icon icon="reader-18" />}
text={intl.get('view_details')}
onClick={safeCallback(onViewDetails, original)}
@@ -79,8 +79,7 @@ export function usePaymentMadesTableColumns() {
{
id: 'payment_date',
Header: intl.get('payment_date'),
Cell: FormatDateCell,
accessor: 'payment_date',
accessor: 'formatted_payment_date',
width: 140,
className: 'payment_date',
clickable: true,

View File

@@ -12,7 +12,7 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { If, Icon, FormattedMessage as T } from '@/components';
import { If, Icon, FormattedMessage as T, Group } from '@/components';
import { CLASSES } from '@/constants/classes';
import classNames from 'classnames';
import { useCreditNoteFormContext } from './CreditNoteFormProvider';
@@ -69,12 +69,16 @@ export default function CreditNoteFloatingActions() {
history.goBack();
};
// Handle clear button click.
const handleClearBtnClick = (event) => {
resetForm();
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Open ----------- */}
<If condition={!creditNote || !creditNote?.is_open}>
<ButtonGroup>
@@ -186,6 +190,6 @@ export default function CreditNoteFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -5,7 +5,6 @@ import clsx from 'classnames';
import { Intent, Tag, Menu, MenuItem, MenuDivider } from '@blueprintjs/core';
import { CLASSES } from '@/constants/classes';
import {
FormatDateCell,
FormattedMessage as T,
Choose,
If,
@@ -112,7 +111,6 @@ export function useCreditNoteTableColumns() {
id: 'credit_date',
Header: intl.get('credit_note.column.credit_date'),
accessor: 'formatted_credit_note_date',
Cell: FormatDateCell,
width: 110,
className: 'credit_date',
clickable: true,

View File

@@ -11,7 +11,7 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { If, Icon, FormattedMessage as T } from '@/components';
import { If, Icon, FormattedMessage as T, Group } from '@/components';
import { CLASSES } from '@/constants/classes';
import { useHistory } from 'react-router-dom';
import { useFormikContext } from 'formik';
@@ -63,16 +63,21 @@ export default function EstimateFloatingActions() {
submitForm();
};
// Handle the cancel button click.
const handleCancelBtnClick = (event) => {
history.goBack();
};
// Handle the clear button click.
const handleClearBtnClick = (event) => {
resetForm();
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Deliver ----------- */}
<If condition={!estimate || !estimate?.is_delivered}>
<ButtonGroup>
@@ -188,6 +193,6 @@ export default function EstimateFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -164,8 +164,7 @@ export function useEstiamtesTableColumns() {
{
id: 'estimate_date',
Header: intl.get('estimate_date'),
accessor: 'estimate_date',
Cell: FormatDateCell,
accessor: 'formatted_estimate_date',
width: 140,
className: 'estimate_date',
clickable: true,

View File

@@ -13,7 +13,7 @@ import {
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
import { useFormikContext } from 'formik';
import { If, Icon, FormattedMessage as T } from '@/components';
import { If, Icon, FormattedMessage as T, Group } from '@/components';
import { useHistory } from 'react-router-dom';
import { useInvoiceFormContext } from './InvoiceFormProvider';
@@ -76,7 +76,10 @@ export default function InvoiceFloatingActions() {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Deliver ----------- */}
<If condition={!invoice || !invoice?.is_delivered}>
<ButtonGroup>
@@ -189,6 +192,6 @@ export default function InvoiceFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -70,6 +70,17 @@ export const defaultInvoice = {
attachments: [],
};
// Invoice entry request schema.
export const defaultReqInvoiceEntry = {
index: 0,
item_id: '',
rate: '',
discount: '',
quantity: '',
description: '',
tax_rate_id: '',
};
/**
* Transform invoice to initial values in edit mode.
*/
@@ -175,13 +186,27 @@ export const ITEMS_FILTER_ROLES_QUERY = JSON.stringify([
},
]);
/**
* Transformes bill entries to submit request.
*/
const transformEntriesToRequest = (entries) => {
return R.compose(
R.map(R.compose(R.curry(transformToForm)(R.__, defaultReqInvoiceEntry))),
filterNonZeroEntries,
)(entries);
};
/**
* Filters the givne non-zero entries.
*/
const filterNonZeroEntries = (entries) => {
return entries.filter((item) => item.item_id && item.quantity);
};
/**
* Transformes the form values to request body values.
*/
export function transformValueToRequest(values) {
const entries = values.entries.filter(
(item) => item.item_id && item.quantity,
);
return {
...omit(values, [
'invoice_no',
@@ -194,9 +219,7 @@ export function transformValueToRequest(values) {
invoice_no: values.invoice_no,
}),
is_inclusive_tax: values.inclusive_exclusive_tax === TaxType.Inclusive,
entries: entries.map((entry) => ({
...omit(entry, ['amount', 'tax_amount', 'tax_rate']),
})),
entries: transformEntriesToRequest(values.entries),
delivered: false,
attachments: transformAttachmentsToRequest(values),
};

View File

@@ -128,7 +128,7 @@ export function ActionsMenu({
onQuick,
onViewDetails,
onPrint,
onSendMail
onSendMail,
},
row: { original },
}) {
@@ -202,8 +202,7 @@ export function useInvoicesTableColumns() {
{
id: 'invoice_date',
Header: intl.get('invoice_date'),
accessor: 'invoice_date',
Cell: FormatDateCell,
accessor: 'invoice_date_formatted',
width: 110,
className: 'invoice_date',
clickable: true,

View File

@@ -11,12 +11,11 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { Icon, FormattedMessage as T } from '@/components';
import { useHistory } from 'react-router-dom';
import { Group, Icon, FormattedMessage as T } from '@/components';
import { useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes';
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import { CLASSES } from '@/constants/classes';
/**
* Payment receive floating actions bar.
@@ -55,7 +54,10 @@ export default function PaymentReceiveFormFloatingActions() {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save and New ----------- */}
<ButtonGroup>
<Button
@@ -107,6 +109,6 @@ export default function PaymentReceiveFormFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -90,8 +90,7 @@ export function usePaymentReceivesColumns() {
{
id: 'payment_date',
Header: intl.get('payment_date'),
accessor: 'payment_date',
Cell: FormatDateCell,
accessor: 'formatted_payment_date',
width: 140,
className: 'payment_date',
clickable: true,

View File

@@ -11,7 +11,7 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { FormattedMessage as T } from '@/components';
import { Group, FormattedMessage as T } from '@/components';
import { useFormikContext } from 'formik';
import { useHistory } from 'react-router-dom';
import { CLASSES } from '@/constants/classes';
@@ -71,12 +71,16 @@ export default function ReceiptFormFloatingActions() {
history.goBack();
};
// Handle the clear button click.
const handleClearBtnClick = (event) => {
resetForm();
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
{/* ----------- Save And Close ----------- */}
<If condition={!receipt || !receipt?.is_closed}>
<ButtonGroup>
@@ -187,6 +191,6 @@ export default function ReceiptFormFloatingActions() {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -119,8 +119,7 @@ export function useReceiptsTableColumns() {
{
id: 'receipt_date',
Header: intl.get('receipt_date'),
accessor: 'receipt_date',
Cell: FormatDateCell,
accessor: 'formatted_receipt_date',
width: 140,
className: 'receipt_date',
clickable: true,

View File

@@ -14,7 +14,7 @@ import styled from 'styled-components';
import classNames from 'classnames';
import { useFormikContext } from 'formik';
import { Icon, FormattedMessage as T } from '@/components';
import { Group, Icon, FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes';
import { useVendorFormContext } from './VendorFormProvider';
import { safeInvoke } from '@/utils';
@@ -51,7 +51,10 @@ export default function VendorFloatingActions({ onCancel }) {
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<Group
spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
>
<ButtonGroup>
{/* ----------- Save and New ----------- */}
<SaveButton
@@ -96,7 +99,7 @@ export default function VendorFloatingActions({ onCancel }) {
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
</Group>
);
}

View File

@@ -73,13 +73,11 @@
}
#{$self}__floating-actions {
// margin-left: -40px;
// margin-right: -40px;
.form-group--active {
display: inline-block;
margin: 0;
margin-left: 40px;
margin-left: 20px;
}
}