mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
Compare commits
7 Commits
v0.19.5
...
publish-jo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cb9d6da59 | ||
|
|
f46cd28f87 | ||
|
|
dffcfe50aa | ||
|
|
fac55efbc7 | ||
|
|
8b90ce5f6c | ||
|
|
b768f18294 | ||
|
|
25297bc191 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -2,6 +2,27 @@
|
|||||||
|
|
||||||
All notable changes to Bigcapital server-side will be in this file.
|
All notable changes to Bigcapital server-side will be in this file.
|
||||||
|
|
||||||
|
## [0.19.4] - 18-08-2024
|
||||||
|
|
||||||
|
* fix: Allow multi-lines to statements transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/594
|
||||||
|
* feat: Add amount comparators to amount bank rule field by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/595
|
||||||
|
* fix: Transaction type and description do not show in general ledger. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/596
|
||||||
|
* fix: Refresh accounts and account transactions. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/597
|
||||||
|
* fix: Typo payments made by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/598
|
||||||
|
* fix: Typo categories list by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/600
|
||||||
|
* fix: Autofill the quick created customer/vendor by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/601
|
||||||
|
* fix: Remove views tabs from receipts list by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/602
|
||||||
|
* fix: Typo payment receive messages by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/599
|
||||||
|
* fix: Enhance Dropzone visual of accept and reject modes by @Champetaman in https://github.com/bigcapitalhq/bigcapital/pull/603
|
||||||
|
* fix: Matching bank transactions should create associate payment transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/606
|
||||||
|
* fix: Change Dropzone title and subtitle by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/607
|
||||||
|
* fix: Inconsistance page size of paginated data tables by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/604
|
||||||
|
* fix: Database connection lost error by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/611
|
||||||
|
* fix: Language typos by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/613
|
||||||
|
* Fix: Correctly display Date, Published At, and Created At in ExpenseDrawerHeader by @Champetaman in https://github.com/bigcapitalhq/bigcapital/pull/612
|
||||||
|
* fix: Delete bank account with uncategorized transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/614
|
||||||
|
* feat: activate/inactivate account from drawer details by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/615
|
||||||
|
|
||||||
## [v0.18.0] - 10-08-2024
|
## [v0.18.0] - 10-08-2024
|
||||||
|
|
||||||
* feat: Bank rules for automated categorization by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511
|
* feat: Bank rules for automated categorization by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511
|
||||||
|
|||||||
@@ -164,6 +164,10 @@ export class Transformer {
|
|||||||
return date ? moment(date).format(this.dateFormat) : '';
|
return date ? moment(date).format(this.dateFormat) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected formatDateFromNow(date){
|
||||||
|
return date ? moment(date).fromNow(true) : '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param number
|
* @param number
|
||||||
|
|||||||
@@ -257,25 +257,25 @@ export default {
|
|||||||
name: 'item.field.sell_price',
|
name: 'item.field.sell_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
cost_price: {
|
costPrice: {
|
||||||
name: 'item.field.cost_price',
|
name: 'item.field.cost_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
costAccount: {
|
costAccountId: {
|
||||||
name: 'item.field.cost_account',
|
name: 'item.field.cost_account',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'Account',
|
relationModel: 'Account',
|
||||||
relationImportMatch: ['name', 'code'],
|
relationImportMatch: ['name', 'code'],
|
||||||
importHint: 'Matches the account name or code.',
|
importHint: 'Matches the account name or code.',
|
||||||
},
|
},
|
||||||
sellAccount: {
|
sellAccountId: {
|
||||||
name: 'item.field.sell_account',
|
name: 'item.field.sell_account',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'Account',
|
relationModel: 'Account',
|
||||||
relationImportMatch: ['name', 'code'],
|
relationImportMatch: ['name', 'code'],
|
||||||
importHint: 'Matches the account name or code.',
|
importHint: 'Matches the account name or code.',
|
||||||
},
|
},
|
||||||
inventoryAccount: {
|
inventoryAccountId: {
|
||||||
name: 'item.field.inventory_account',
|
name: 'item.field.inventory_account',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'Account',
|
relationModel: 'Account',
|
||||||
|
|||||||
@@ -8,7 +8,12 @@ export class CashflowAccountTransformer extends Transformer {
|
|||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return ['formattedAmount'];
|
return [
|
||||||
|
'formattedAmount',
|
||||||
|
'lastFeedsUpdatedAt',
|
||||||
|
'lastFeedsUpdatedAtFormatted',
|
||||||
|
'lastFeedsUpdatedFromNow',
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,4 +42,22 @@ export class CashflowAccountTransformer extends Transformer {
|
|||||||
currencyCode: account.currencyCode,
|
currencyCode: account.currencyCode,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the last feeds update at formatted date.
|
||||||
|
* @param {IAccount} account
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected lastFeedsUpdatedAtFormatted(account: IAccount): string {
|
||||||
|
return this.formatDate(account.lastFeedsUpdatedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the last feeds updated from now.
|
||||||
|
* @param {IAccount} account
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected lastFeedsUpdatedFromNow(account: IAccount): string {
|
||||||
|
return this.formatDateFromNow(account.lastFeedsUpdatedAt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,12 +43,22 @@ export class CreateItem {
|
|||||||
itemDTO.sellAccountId
|
itemDTO.sellAccountId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Validate the income account id existance if the item is sellable.
|
||||||
|
this.validators.validateIncomeAccountExistance(
|
||||||
|
itemDTO.sellable,
|
||||||
|
itemDTO.sellAccountId
|
||||||
|
);
|
||||||
if (itemDTO.costAccountId) {
|
if (itemDTO.costAccountId) {
|
||||||
await this.validators.validateItemCostAccountExistance(
|
await this.validators.validateItemCostAccountExistance(
|
||||||
tenantId,
|
tenantId,
|
||||||
itemDTO.costAccountId
|
itemDTO.costAccountId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Validate the cost account id existance if the item is purchasable.
|
||||||
|
this.validators.validateCostAccountExistance(
|
||||||
|
itemDTO.purchasable,
|
||||||
|
itemDTO.costAccountId
|
||||||
|
);
|
||||||
if (itemDTO.inventoryAccountId) {
|
if (itemDTO.inventoryAccountId) {
|
||||||
await this.validators.validateItemInventoryAccountExistance(
|
await this.validators.validateItemInventoryAccountExistance(
|
||||||
tenantId,
|
tenantId,
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ export class EditItem {
|
|||||||
itemDTO.categoryId
|
itemDTO.categoryId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Validate the income account id existance if the item is sellable.
|
||||||
|
this.validators.validateIncomeAccountExistance(
|
||||||
|
itemDTO.sellable,
|
||||||
|
itemDTO.sellAccountId
|
||||||
|
);
|
||||||
// Validate the sell account existance on the storage.
|
// Validate the sell account existance on the storage.
|
||||||
if (itemDTO.sellAccountId) {
|
if (itemDTO.sellAccountId) {
|
||||||
await this.validators.validateItemSellAccountExistance(
|
await this.validators.validateItemSellAccountExistance(
|
||||||
@@ -62,6 +67,11 @@ export class EditItem {
|
|||||||
itemDTO.sellAccountId
|
itemDTO.sellAccountId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Validate the cost account id existance if the item is purchasable.
|
||||||
|
this.validators.validateCostAccountExistance(
|
||||||
|
itemDTO.purchasable,
|
||||||
|
itemDTO.costAccountId
|
||||||
|
);
|
||||||
// Validate the cost account existance on the storage.
|
// Validate the cost account existance on the storage.
|
||||||
if (itemDTO.costAccountId) {
|
if (itemDTO.costAccountId) {
|
||||||
await this.validators.validateItemCostAccountExistance(
|
await this.validators.validateItemCostAccountExistance(
|
||||||
|
|||||||
@@ -85,6 +85,42 @@ export class ItemsValidators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates income account existance.
|
||||||
|
* @param {number|null} sellable - Detarmines if the item sellable.
|
||||||
|
* @param {number|null} incomeAccountId - Income account id.
|
||||||
|
* @throws {ServiceError(ERRORS.INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM)}
|
||||||
|
*/
|
||||||
|
public validateIncomeAccountExistance(
|
||||||
|
sellable?: boolean,
|
||||||
|
incomeAccountId?: number
|
||||||
|
) {
|
||||||
|
if (sellable && !incomeAccountId) {
|
||||||
|
throw new ServiceError(
|
||||||
|
ERRORS.INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM,
|
||||||
|
'Income account is require with sellable item.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the cost account existance.
|
||||||
|
* @param {boolean|null} purchasable - Detarmines if the item purchasble.
|
||||||
|
* @param {number|null} costAccountId - Cost account id.
|
||||||
|
* @throws {ServiceError(ERRORS.COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM)}
|
||||||
|
*/
|
||||||
|
public validateCostAccountExistance(
|
||||||
|
purchasable: boolean,
|
||||||
|
costAccountId?: number
|
||||||
|
) {
|
||||||
|
if (purchasable && !costAccountId) {
|
||||||
|
throw new ServiceError(
|
||||||
|
ERRORS.COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM,
|
||||||
|
'The cost account is required with purchasable item.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate item inventory account existance and type.
|
* Validate item inventory account existance and type.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ export const ERRORS = {
|
|||||||
|
|
||||||
PURCHASE_TAX_RATE_NOT_FOUND: 'PURCHASE_TAX_RATE_NOT_FOUND',
|
PURCHASE_TAX_RATE_NOT_FOUND: 'PURCHASE_TAX_RATE_NOT_FOUND',
|
||||||
SELL_TAX_RATE_NOT_FOUND: 'SELL_TAX_RATE_NOT_FOUND',
|
SELL_TAX_RATE_NOT_FOUND: 'SELL_TAX_RATE_NOT_FOUND',
|
||||||
|
|
||||||
|
INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM:
|
||||||
|
'INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM',
|
||||||
|
COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM:
|
||||||
|
'COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_VIEW_COLUMNS = [];
|
export const DEFAULT_VIEW_COLUMNS = [];
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export function BankAccount({
|
|||||||
balance,
|
balance,
|
||||||
loading = false,
|
loading = false,
|
||||||
updatedBeforeText,
|
updatedBeforeText,
|
||||||
|
uncategorizedTransactionsCount,
|
||||||
...restProps
|
...restProps
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
@@ -77,17 +78,19 @@ export function BankAccount({
|
|||||||
</BankAccountHeader>
|
</BankAccountHeader>
|
||||||
|
|
||||||
<BankAccountMeta>
|
<BankAccountMeta>
|
||||||
{false && (
|
{uncategorizedTransactionsCount > 0 && (
|
||||||
<BankAccountMetaLine
|
<BankAccountMetaLine
|
||||||
title={intl.get('cash_flow.transactions_for_review')}
|
title={intl.get('cash_flow.transactions_for_review')}
|
||||||
value={'0'}
|
value={uncategorizedTransactionsCount}
|
||||||
className={clsx({ [Classes.SKELETON]: loading })}
|
className={clsx({ [Classes.SKELETON]: loading })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{updatedBeforeText && (
|
||||||
<BankAccountMetaLine
|
<BankAccountMetaLine
|
||||||
title={updatedBeforeText}
|
title={updatedBeforeText}
|
||||||
className={clsx({ [Classes.SKELETON]: loading })}
|
className={clsx({ [Classes.SKELETON]: loading })}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</BankAccountMeta>
|
</BankAccountMeta>
|
||||||
|
|
||||||
<BankAccountBalance amount={balance} loading={loading} />
|
<BankAccountBalance amount={balance} loading={loading} />
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ export const SubscriptionPlans = [
|
|||||||
},
|
},
|
||||||
{ text: 'Unlimited User Seats' },
|
{ text: 'Unlimited User Seats' },
|
||||||
],
|
],
|
||||||
monthlyPrice: '$10',
|
monthlyPrice: '$20',
|
||||||
monthlyPriceLabel: 'Per month',
|
monthlyPriceLabel: 'Per month',
|
||||||
annuallyPrice: '$7.5',
|
annuallyPrice: '$15',
|
||||||
annuallyPriceLabel: 'Per month',
|
annuallyPriceLabel: 'Per month',
|
||||||
monthlyVariantId: '446152',
|
monthlyVariantId: '446152',
|
||||||
// monthlyVariantId: '450016',
|
// monthlyVariantId: '450016',
|
||||||
@@ -78,9 +78,9 @@ export const SubscriptionPlans = [
|
|||||||
{ text: 'Smart Financial Reports' },
|
{ text: 'Smart Financial Reports' },
|
||||||
{ text: 'Advanced Inventory Reports' },
|
{ text: 'Advanced Inventory Reports' },
|
||||||
],
|
],
|
||||||
monthlyPrice: '$20',
|
monthlyPrice: '$40',
|
||||||
monthlyPriceLabel: 'Per month',
|
monthlyPriceLabel: 'Per month',
|
||||||
annuallyPrice: '$15',
|
annuallyPrice: '$30',
|
||||||
annuallyPriceLabel: 'Per month',
|
annuallyPriceLabel: 'Per month',
|
||||||
// monthlyVariantId: '450028',
|
// monthlyVariantId: '450028',
|
||||||
monthlyVariantId: '446155',
|
monthlyVariantId: '446155',
|
||||||
@@ -101,9 +101,9 @@ export const SubscriptionPlans = [
|
|||||||
},
|
},
|
||||||
{ text: 'Analysis Cost Center' },
|
{ text: 'Analysis Cost Center' },
|
||||||
],
|
],
|
||||||
monthlyPrice: '$25',
|
monthlyPrice: '$55',
|
||||||
monthlyPriceLabel: 'Per month',
|
monthlyPriceLabel: 'Per month',
|
||||||
annuallyPrice: '$19',
|
annuallyPrice: '$40',
|
||||||
annuallyPriceLabel: 'Per month',
|
annuallyPriceLabel: 'Per month',
|
||||||
featured: true,
|
featured: true,
|
||||||
// monthlyVariantId: '450031',
|
// monthlyVariantId: '450031',
|
||||||
@@ -128,9 +128,9 @@ export const SubscriptionPlans = [
|
|||||||
hint: 'Track the organization inventory in multiple warehouses and transfer goods between them.',
|
hint: 'Track the organization inventory in multiple warehouses and transfer goods between them.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
monthlyPrice: '$40',
|
monthlyPrice: '$60',
|
||||||
monthlyPriceLabel: 'Per month',
|
monthlyPriceLabel: 'Per month',
|
||||||
annuallyPrice: '$30',
|
annuallyPrice: '$45',
|
||||||
annuallyPriceLabel: 'Per month',
|
annuallyPriceLabel: 'Per month',
|
||||||
// monthlyVariantId: '450024',
|
// monthlyVariantId: '450024',
|
||||||
monthlyVariantId: '446167',
|
monthlyVariantId: '446167',
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export function useExcludedTransactionsColumns() {
|
|||||||
{
|
{
|
||||||
Header: 'Description',
|
Header: 'Description',
|
||||||
accessor: descriptionAccessor,
|
accessor: descriptionAccessor,
|
||||||
|
textOverview: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Payee',
|
Header: 'Payee',
|
||||||
|
|||||||
@@ -123,7 +123,12 @@ function CashflowBankAccount({
|
|||||||
code={account.code}
|
code={account.code}
|
||||||
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
|
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
|
||||||
type={account.account_type}
|
type={account.account_type}
|
||||||
updatedBeforeText={getUpdatedBeforeText(account.createdAt)}
|
updatedBeforeText={
|
||||||
|
account.last_feeds_updated_from_now
|
||||||
|
? `Updated ${account.last_feeds_updated_from_now} ago`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
uncategorizedTransactionsCount={account.uncategorized_transactions}
|
||||||
/>
|
/>
|
||||||
</CashflowAccountAnchor>
|
</CashflowAccountAnchor>
|
||||||
</ContextMenu2>
|
</ContextMenu2>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
DrawerActionsBar,
|
DrawerActionsBar,
|
||||||
Can,
|
Can,
|
||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
|
If,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
|
|
||||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||||
@@ -35,7 +36,7 @@ function ManualJournalDrawerActionBar({
|
|||||||
closeDrawer,
|
closeDrawer,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { manualJournalId } = useManualJournalDrawerContext();
|
const { manualJournalId, manualJournal } = useManualJournalDrawerContext();
|
||||||
|
|
||||||
// Handle edit manual journal action.
|
// Handle edit manual journal action.
|
||||||
const handleEditManualJournal = () => {
|
const handleEditManualJournal = () => {
|
||||||
@@ -48,6 +49,11 @@ function ManualJournalDrawerActionBar({
|
|||||||
openAlert('journal-delete', { manualJournalId });
|
openAlert('journal-delete', { manualJournalId });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle manual journal publish action.
|
||||||
|
const handlePublishManualJournal = () => {
|
||||||
|
openAlert('journal-publish', { manualJournalId });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerActionsBar>
|
<DrawerActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
@@ -59,6 +65,19 @@ function ManualJournalDrawerActionBar({
|
|||||||
onClick={handleEditManualJournal}
|
onClick={handleEditManualJournal}
|
||||||
/>
|
/>
|
||||||
</Can>
|
</Can>
|
||||||
|
|
||||||
|
<If condition={!manualJournal.is_published}>
|
||||||
|
<Can I={ManualJournalAction.Edit} a={AbilitySubject.ManualJournal}>
|
||||||
|
<NavbarDivider />
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
icon={<Icon icon="arrow-to-top" />}
|
||||||
|
text={'Publish'}
|
||||||
|
intent={Intent.SUCCESS}
|
||||||
|
onClick={handlePublishManualJournal}
|
||||||
|
/>
|
||||||
|
</Can>
|
||||||
|
</If>
|
||||||
<Can I={ManualJournalAction.Delete} a={AbilitySubject.ManualJournal}>
|
<Can I={ManualJournalAction.Delete} a={AbilitySubject.ManualJournal}>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user