mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
Compare commits
5 Commits
v0.19.6
...
publish-jo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cb9d6da59 | ||
|
|
f46cd28f87 | ||
|
|
dffcfe50aa | ||
|
|
fac55efbc7 | ||
|
|
8b90ce5f6c |
@@ -164,6 +164,10 @@ export class Transformer {
|
||||
return date ? moment(date).format(this.dateFormat) : '';
|
||||
}
|
||||
|
||||
protected formatDateFromNow(date){
|
||||
return date ? moment(date).fromNow(true) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param number
|
||||
|
||||
@@ -257,25 +257,25 @@ export default {
|
||||
name: 'item.field.sell_price',
|
||||
fieldType: 'number',
|
||||
},
|
||||
cost_price: {
|
||||
costPrice: {
|
||||
name: 'item.field.cost_price',
|
||||
fieldType: 'number',
|
||||
},
|
||||
costAccount: {
|
||||
costAccountId: {
|
||||
name: 'item.field.cost_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
importHint: 'Matches the account name or code.',
|
||||
},
|
||||
sellAccount: {
|
||||
sellAccountId: {
|
||||
name: 'item.field.sell_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
importHint: 'Matches the account name or code.',
|
||||
},
|
||||
inventoryAccount: {
|
||||
inventoryAccountId: {
|
||||
name: 'item.field.inventory_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
|
||||
@@ -8,7 +8,12 @@ export class CashflowAccountTransformer extends Transformer {
|
||||
* @returns {string[]}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['formattedAmount'];
|
||||
return [
|
||||
'formattedAmount',
|
||||
'lastFeedsUpdatedAt',
|
||||
'lastFeedsUpdatedAtFormatted',
|
||||
'lastFeedsUpdatedFromNow',
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -29,7 +34,7 @@ export class CashflowAccountTransformer extends Transformer {
|
||||
|
||||
/**
|
||||
* Retrieve formatted account amount.
|
||||
* @param {IAccount} invoice
|
||||
* @param {IAccount} invoice
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedAmount = (account: IAccount): string => {
|
||||
@@ -37,4 +42,22 @@ export class CashflowAccountTransformer extends Transformer {
|
||||
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
|
||||
);
|
||||
}
|
||||
// Validate the income account id existance if the item is sellable.
|
||||
this.validators.validateIncomeAccountExistance(
|
||||
itemDTO.sellable,
|
||||
itemDTO.sellAccountId
|
||||
);
|
||||
if (itemDTO.costAccountId) {
|
||||
await this.validators.validateItemCostAccountExistance(
|
||||
tenantId,
|
||||
itemDTO.costAccountId
|
||||
);
|
||||
}
|
||||
// Validate the cost account id existance if the item is purchasable.
|
||||
this.validators.validateCostAccountExistance(
|
||||
itemDTO.purchasable,
|
||||
itemDTO.costAccountId
|
||||
);
|
||||
if (itemDTO.inventoryAccountId) {
|
||||
await this.validators.validateItemInventoryAccountExistance(
|
||||
tenantId,
|
||||
|
||||
@@ -55,6 +55,11 @@ export class EditItem {
|
||||
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.
|
||||
if (itemDTO.sellAccountId) {
|
||||
await this.validators.validateItemSellAccountExistance(
|
||||
@@ -62,6 +67,11 @@ export class EditItem {
|
||||
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.
|
||||
if (itemDTO.costAccountId) {
|
||||
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.
|
||||
* @param {number} tenantId
|
||||
|
||||
@@ -26,6 +26,11 @@ export const ERRORS = {
|
||||
|
||||
PURCHASE_TAX_RATE_NOT_FOUND: 'PURCHASE_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 = [];
|
||||
|
||||
@@ -62,6 +62,7 @@ export function BankAccount({
|
||||
balance,
|
||||
loading = false,
|
||||
updatedBeforeText,
|
||||
uncategorizedTransactionsCount,
|
||||
...restProps
|
||||
}) {
|
||||
return (
|
||||
@@ -77,17 +78,19 @@ export function BankAccount({
|
||||
</BankAccountHeader>
|
||||
|
||||
<BankAccountMeta>
|
||||
{false && (
|
||||
{uncategorizedTransactionsCount > 0 && (
|
||||
<BankAccountMetaLine
|
||||
title={intl.get('cash_flow.transactions_for_review')}
|
||||
value={'0'}
|
||||
value={uncategorizedTransactionsCount}
|
||||
className={clsx({ [Classes.SKELETON]: loading })}
|
||||
/>
|
||||
)}
|
||||
{updatedBeforeText && (
|
||||
<BankAccountMetaLine
|
||||
title={updatedBeforeText}
|
||||
className={clsx({ [Classes.SKELETON]: loading })}
|
||||
/>
|
||||
)}
|
||||
<BankAccountMetaLine
|
||||
title={updatedBeforeText}
|
||||
className={clsx({ [Classes.SKELETON]: loading })}
|
||||
/>
|
||||
</BankAccountMeta>
|
||||
|
||||
<BankAccountBalance amount={balance} loading={loading} />
|
||||
|
||||
@@ -37,12 +37,13 @@ export function useExcludedTransactionsColumns() {
|
||||
() => [
|
||||
{
|
||||
Header: 'Date',
|
||||
accessor: 'formatted_date',
|
||||
accessor: 'formatted_date',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
Header: 'Description',
|
||||
accessor: descriptionAccessor,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
Header: 'Payee',
|
||||
|
||||
@@ -123,7 +123,12 @@ function CashflowBankAccount({
|
||||
code={account.code}
|
||||
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
|
||||
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>
|
||||
</ContextMenu2>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
DrawerActionsBar,
|
||||
Can,
|
||||
FormattedMessage as T,
|
||||
If,
|
||||
} from '@/components';
|
||||
|
||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||
@@ -35,7 +36,7 @@ function ManualJournalDrawerActionBar({
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { manualJournalId } = useManualJournalDrawerContext();
|
||||
const { manualJournalId, manualJournal } = useManualJournalDrawerContext();
|
||||
|
||||
// Handle edit manual journal action.
|
||||
const handleEditManualJournal = () => {
|
||||
@@ -48,6 +49,11 @@ function ManualJournalDrawerActionBar({
|
||||
openAlert('journal-delete', { manualJournalId });
|
||||
};
|
||||
|
||||
// Handle manual journal publish action.
|
||||
const handlePublishManualJournal = () => {
|
||||
openAlert('journal-publish', { manualJournalId });
|
||||
};
|
||||
|
||||
return (
|
||||
<DrawerActionsBar>
|
||||
<NavbarGroup>
|
||||
@@ -59,6 +65,19 @@ function ManualJournalDrawerActionBar({
|
||||
onClick={handleEditManualJournal}
|
||||
/>
|
||||
</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}>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user