mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
fix: improvements to bank matching transactions
This commit is contained in:
@@ -110,6 +110,7 @@ import { ValidateMatchingOnPaymentMadeDelete } from '@/services/Banking/Matching
|
|||||||
import { ValidateMatchingOnCashflowDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnCashflowDelete';
|
import { ValidateMatchingOnCashflowDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnCashflowDelete';
|
||||||
import { RecognizeSyncedBankTranasctions } from '@/services/Banking/Plaid/subscribers/RecognizeSyncedBankTransactions';
|
import { RecognizeSyncedBankTranasctions } from '@/services/Banking/Plaid/subscribers/RecognizeSyncedBankTransactions';
|
||||||
import { UnlinkBankRuleOnDeleteBankRule } from '@/services/Banking/Rules/events/UnlinkBankRuleOnDeleteBankRule';
|
import { UnlinkBankRuleOnDeleteBankRule } from '@/services/Banking/Rules/events/UnlinkBankRuleOnDeleteBankRule';
|
||||||
|
import { DecrementUncategorizedTransactionOnMatching } from '@/services/Banking/Matching/events/DecrementUncategorizedTransactionsOnMatch';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -258,6 +259,7 @@ export const susbcribers = () => {
|
|||||||
// Bank Rules
|
// Bank Rules
|
||||||
TriggerRecognizedTransactions,
|
TriggerRecognizedTransactions,
|
||||||
UnlinkBankRuleOnDeleteBankRule,
|
UnlinkBankRuleOnDeleteBankRule,
|
||||||
|
DecrementUncategorizedTransactionOnMatching,
|
||||||
|
|
||||||
// Validate matching
|
// Validate matching
|
||||||
ValidateMatchingOnCashflowDelete,
|
ValidateMatchingOnCashflowDelete,
|
||||||
|
|||||||
@@ -105,8 +105,34 @@ export default class UncategorizedCashflowTransaction extends mixin(
|
|||||||
* Filters the excluded transactions.
|
* Filters the excluded transactions.
|
||||||
*/
|
*/
|
||||||
excluded(query) {
|
excluded(query) {
|
||||||
query.whereNotNull('excluded_at')
|
query.whereNotNull('excluded_at');
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter out the recognized transactions.
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
recognized(query) {
|
||||||
|
query.whereNotNull('recognizedTransactionId');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter out the not recognized transactions.
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
notRecognized(query) {
|
||||||
|
query.whereNull('recognizedTransactionId');
|
||||||
|
},
|
||||||
|
|
||||||
|
categorized(query) {
|
||||||
|
query.whereNotNull('categorizeRefType');
|
||||||
|
query.whereNotNull('categorizeRefId');
|
||||||
|
},
|
||||||
|
|
||||||
|
notCategorized(query) {
|
||||||
|
query.whereNull('categorizeRefType');
|
||||||
|
query.whereNull('categorizeRefId');
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
|
||||||
import { Server } from 'socket.io';
|
|
||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { initialize } from 'objection';
|
||||||
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class GetBankAccountSummary {
|
export class GetBankAccountSummary {
|
||||||
@@ -14,22 +14,41 @@ export class GetBankAccountSummary {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async getBankAccountSummary(tenantId: number, bankAccountId: number) {
|
public async getBankAccountSummary(tenantId: number, bankAccountId: number) {
|
||||||
|
const knex = this.tenancy.knex(tenantId);
|
||||||
const {
|
const {
|
||||||
Account,
|
Account,
|
||||||
UncategorizedCashflowTransaction,
|
UncategorizedCashflowTransaction,
|
||||||
RecognizedBankTransaction,
|
RecognizedBankTransaction,
|
||||||
} = this.tenancy.models(tenantId);
|
} = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
await initialize(knex, [
|
||||||
|
UncategorizedCashflowTransaction,
|
||||||
|
RecognizedBankTransaction,
|
||||||
|
]);
|
||||||
const bankAccount = await Account.query()
|
const bankAccount = await Account.query()
|
||||||
.findById(bankAccountId)
|
.findById(bankAccountId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
// Retrieves the uncategorized transactions count of the given bank account.
|
// Retrieves the uncategorized transactions count of the given bank account.
|
||||||
const uncategorizedTranasctionsCount =
|
const uncategorizedTranasctionsCount =
|
||||||
await UncategorizedCashflowTransaction.query()
|
await UncategorizedCashflowTransaction.query().onBuild((q) => {
|
||||||
.where('accountId', bankAccountId)
|
// Include just the given account.
|
||||||
.count('id as total')
|
q.where('accountId', bankAccountId);
|
||||||
.first();
|
|
||||||
|
// Only the not excluded.
|
||||||
|
q.modify('notExcluded');
|
||||||
|
|
||||||
|
// Only the not categorized.
|
||||||
|
q.modify('notCategorized');
|
||||||
|
|
||||||
|
// Only the not matched bank transactions.
|
||||||
|
q.withGraphJoined('matchedBankTransactions');
|
||||||
|
q.whereNull('matchedBankTransactions.id');
|
||||||
|
|
||||||
|
// Count the results.
|
||||||
|
q.count('uncategorized_cashflow_transactions.id as total');
|
||||||
|
q.first();
|
||||||
|
});
|
||||||
|
|
||||||
// Retrieves the recognized transactions count of the given bank account.
|
// Retrieves the recognized transactions count of the given bank account.
|
||||||
const recognizedTransactionsCount = await RecognizedBankTransaction.query()
|
const recognizedTransactionsCount = await RecognizedBankTransaction.query()
|
||||||
@@ -43,8 +62,8 @@ export class GetBankAccountSummary {
|
|||||||
.first();
|
.first();
|
||||||
|
|
||||||
const totalUncategorizedTransactions =
|
const totalUncategorizedTransactions =
|
||||||
uncategorizedTranasctionsCount?.total;
|
uncategorizedTranasctionsCount?.total || 0;
|
||||||
const totalRecognizedTransactions = recognizedTransactionsCount?.total;
|
const totalRecognizedTransactions = recognizedTransactionsCount?.total || 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: bankAccount.name,
|
name: bankAccount.name,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export class UnmatchMatchedBankTransaction {
|
|||||||
return this.uow.withTransaction(tenantId, async (trx) => {
|
return this.uow.withTransaction(tenantId, async (trx) => {
|
||||||
await this.eventPublisher.emitAsync(events.bankMatch.onUnmatching, {
|
await this.eventPublisher.emitAsync(events.bankMatch.onUnmatching, {
|
||||||
tenantId,
|
tenantId,
|
||||||
|
uncategorizedTransactionId,
|
||||||
trx,
|
trx,
|
||||||
} as IBankTransactionUnmatchingEventPayload);
|
} as IBankTransactionUnmatchingEventPayload);
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ export class UnmatchMatchedBankTransaction {
|
|||||||
|
|
||||||
await this.eventPublisher.emitAsync(events.bankMatch.onUnmatched, {
|
await this.eventPublisher.emitAsync(events.bankMatch.onUnmatched, {
|
||||||
tenantId,
|
tenantId,
|
||||||
|
uncategorizedTransactionId,
|
||||||
trx,
|
trx,
|
||||||
} as IBankTransactionUnmatchingEventPayload);
|
} as IBankTransactionUnmatchingEventPayload);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { ERRORS } from './types';
|
import { ERRORS } from './types';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -18,12 +19,13 @@ export class ValidateTransactionMatched {
|
|||||||
public async validateTransactionNoMatchLinking(
|
public async validateTransactionNoMatchLinking(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
referenceType: string,
|
referenceType: string,
|
||||||
referenceId: number
|
referenceId: number,
|
||||||
|
trx?: Knex.Transaction
|
||||||
) {
|
) {
|
||||||
const { MatchedBankTransaction } = this.tenancy.models(tenantId);
|
const { MatchedBankTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const foundMatchedTransaction =
|
const foundMatchedTransaction =
|
||||||
await MatchedBankTransaction.query().findOne({
|
await MatchedBankTransaction.query(trx).findOne({
|
||||||
referenceType,
|
referenceType,
|
||||||
referenceId,
|
referenceId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
IBankTransactionMatchedEventPayload,
|
||||||
|
IBankTransactionUnmatchedEventPayload,
|
||||||
|
} from '../types';
|
||||||
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class DecrementUncategorizedTransactionOnMatching {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankMatch.onMatched,
|
||||||
|
this.decrementUnCategorizedTransactionsOnMatching.bind(this)
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankMatch.onUnmatched,
|
||||||
|
this.incrementUnCategorizedTransactionsOnUnmatching.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the cashflow transaction whether matched with bank transaction on deleting.
|
||||||
|
* @param {IManualJournalDeletingPayload}
|
||||||
|
*/
|
||||||
|
public async decrementUnCategorizedTransactionsOnMatching({
|
||||||
|
tenantId,
|
||||||
|
uncategorizedTransactionId,
|
||||||
|
matchTransactionsDTO,
|
||||||
|
trx,
|
||||||
|
}: IBankTransactionMatchedEventPayload) {
|
||||||
|
const { UncategorizedCashflowTransaction, Account } =
|
||||||
|
this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const transaction = await UncategorizedCashflowTransaction.query().findById(
|
||||||
|
uncategorizedTransactionId
|
||||||
|
);
|
||||||
|
//
|
||||||
|
await Account.query(trx)
|
||||||
|
.findById(transaction.accountId)
|
||||||
|
.decrement('uncategorizedTransactions', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the cashflow transaction whether matched with bank transaction on deleting.
|
||||||
|
* @param {IManualJournalDeletingPayload}
|
||||||
|
*/
|
||||||
|
public async incrementUnCategorizedTransactionsOnUnmatching({
|
||||||
|
tenantId,
|
||||||
|
uncategorizedTransactionId,
|
||||||
|
trx,
|
||||||
|
}: IBankTransactionUnmatchedEventPayload) {
|
||||||
|
const { UncategorizedCashflowTransaction, Account } =
|
||||||
|
this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const transaction = await UncategorizedCashflowTransaction.query().findById(
|
||||||
|
uncategorizedTransactionId
|
||||||
|
);
|
||||||
|
//
|
||||||
|
await Account.query(trx)
|
||||||
|
.findById(transaction.accountId)
|
||||||
|
.decrement('uncategorizedTransactions', 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { IManualJournalDeletingPayload } from '@/interfaces';
|
import { ICommandCashflowDeletingPayload, IManualJournalDeletingPayload } from '@/interfaces';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
||||||
|
|
||||||
@@ -24,13 +24,14 @@ export class ValidateMatchingOnCashflowDelete {
|
|||||||
*/
|
*/
|
||||||
public async validateMatchingOnCashflowDeleting({
|
public async validateMatchingOnCashflowDeleting({
|
||||||
tenantId,
|
tenantId,
|
||||||
oldManualJournal,
|
oldCashflowTransaction,
|
||||||
trx,
|
trx,
|
||||||
}: IManualJournalDeletingPayload) {
|
}: ICommandCashflowDeletingPayload) {
|
||||||
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
tenantId,
|
tenantId,
|
||||||
'ManualJournal',
|
'CashflowTransaction',
|
||||||
oldManualJournal.id
|
oldCashflowTransaction.id,
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export class ValidateMatchingOnExpenseDelete {
|
|||||||
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
tenantId,
|
tenantId,
|
||||||
'Expense',
|
'Expense',
|
||||||
oldExpense.id
|
oldExpense.id,
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export class ValidateMatchingOnManualJournalDelete {
|
|||||||
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
tenantId,
|
tenantId,
|
||||||
'ManualJournal',
|
'ManualJournal',
|
||||||
oldManualJournal.id
|
oldManualJournal.id,
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ export class ValidateMatchingOnPaymentMadeDelete {
|
|||||||
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
tenantId,
|
tenantId,
|
||||||
'PaymentMade',
|
'PaymentMade',
|
||||||
oldBillPayment.id
|
oldBillPayment.id,
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export class ValidateMatchingOnPaymentReceivedDelete {
|
|||||||
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
tenantId,
|
tenantId,
|
||||||
'PaymentReceive',
|
'PaymentReceive',
|
||||||
oldPaymentReceive.id
|
oldPaymentReceive.id,
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,14 @@ export interface IBankTransactionMatchedEventPayload {
|
|||||||
|
|
||||||
export interface IBankTransactionUnmatchingEventPayload {
|
export interface IBankTransactionUnmatchingEventPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
|
uncategorizedTransactionId: number;
|
||||||
|
trx?: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBankTransactionUnmatchedEventPayload {
|
export interface IBankTransactionUnmatchedEventPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
|
uncategorizedTransactionId: number;
|
||||||
|
trx?: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMatchTransactionDTO {
|
export interface IMatchTransactionDTO {
|
||||||
|
|||||||
@@ -69,6 +69,14 @@ function AccountDeleteTransactionAlert({
|
|||||||
'Cannot delete transaction converted from uncategorized transaction but you uncategorize it.',
|
'Cannot delete transaction converted from uncategorized transaction but you uncategorize it.',
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
});
|
});
|
||||||
|
} else if (
|
||||||
|
errors.find((e) => e.type === 'CANNOT_DELETE_TRANSACTION_MATCHED')
|
||||||
|
) {
|
||||||
|
AppToaster.show({
|
||||||
|
message:
|
||||||
|
'Cannot delete a transaction matched to the bank transaction',
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
color: rgb(21, 82, 200),
|
color: rgb(21, 82, 200),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(.active){
|
&:hover:not(.active){
|
||||||
border-color: #c0c0c0;
|
border-color: #c0c0c0;
|
||||||
}
|
}
|
||||||
@@ -25,7 +24,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator{
|
.checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator{
|
||||||
border-color: #CBCBCB;
|
box-shadow: 0 0 0 1px #CBCBCB;
|
||||||
}
|
}
|
||||||
.checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator{
|
.checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator{
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
@@ -34,10 +33,18 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox:global(.bp4-control.bp4-checkbox) :global input:checked ~ .bp4-control-indicator{
|
||||||
|
box-shadow: 0 0 0 1px #0069ff;
|
||||||
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
color: #10161A;
|
color: #252A33;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
.label :global strong {
|
||||||
|
font-weight: 500;
|
||||||
|
font-variant-numeric:tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export interface MatchTransactionCheckboxProps {
|
|||||||
active?: boolean;
|
active?: boolean;
|
||||||
initialActive?: boolean;
|
initialActive?: boolean;
|
||||||
onChange?: (state: boolean) => void;
|
onChange?: (state: boolean) => void;
|
||||||
label: string;
|
label: string | React.ReactNode;
|
||||||
date: string;
|
date: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ export function MatchTransactionCheckbox({
|
|||||||
position="apart"
|
position="apart"
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<Stack spacing={3}>
|
<Stack spacing={2}>
|
||||||
<span className={styles.label}>{label}</span>
|
<span className={styles.label}>{label}</span>
|
||||||
<Text className={styles.date}>Date: {date}</Text>
|
<Text className={styles.date}>Date: {date}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -237,9 +237,6 @@ function PossibleMatchingTransactions() {
|
|||||||
<Box className={styles.matchBar}>
|
<Box className={styles.matchBar}>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
<h2 className={styles.matchBarTitle}>Possible Matches</h2>
|
<h2 className={styles.matchBarTitle}>Possible Matches</h2>
|
||||||
<Text style={{ fontSize: 12, color: '#5C7080' }}>
|
|
||||||
Transactions up to 20 Aug 2019
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -247,7 +244,12 @@ function PossibleMatchingTransactions() {
|
|||||||
{possibleMatches.map((match, index) => (
|
{possibleMatches.map((match, index) => (
|
||||||
<MatchTransactionField
|
<MatchTransactionField
|
||||||
key={index}
|
key={index}
|
||||||
label={`${match.transsactionTypeFormatted} for ${match.amountFormatted}`}
|
label={
|
||||||
|
<>
|
||||||
|
{`${match.transsactionTypeFormatted} for `}
|
||||||
|
<strong>{match.amountFormatted}</strong>
|
||||||
|
</>
|
||||||
|
}
|
||||||
date={match.dateFormatted}
|
date={match.dateFormatted}
|
||||||
transactionId={match.referenceId}
|
transactionId={match.referenceId}
|
||||||
transactionType={match.referenceType}
|
transactionType={match.referenceType}
|
||||||
@@ -329,7 +331,7 @@ const MatchTransactionFooter = R.compose(withBankingActions)(
|
|||||||
</AnchorButton>
|
</AnchorButton>
|
||||||
)}
|
)}
|
||||||
<Text
|
<Text
|
||||||
style={{ fontSize: 14, marginLeft: 'auto', color: '#5F6B7C' }}
|
style={{ fontSize: 14, marginLeft: 'auto', color: '#404854' }}
|
||||||
tagName="span"
|
tagName="span"
|
||||||
>
|
>
|
||||||
Pending <FormatNumber value={totalPending} currency={'USD'} />
|
Pending <FormatNumber value={totalPending} currency={'USD'} />
|
||||||
@@ -343,8 +345,8 @@ const MatchTransactionFooter = R.compose(withBankingActions)(
|
|||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
style={{ minWidth: 85 }}
|
style={{ minWidth: 85 }}
|
||||||
onClick={handleSubmitBtnClick}
|
onClick={handleSubmitBtnClick}
|
||||||
// loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
// disabled={submitDisabled}
|
disabled={submitDisabled}
|
||||||
>
|
>
|
||||||
Match
|
Match
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -50,3 +50,9 @@ $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='ht
|
|||||||
// z-indexs
|
// z-indexs
|
||||||
$zindex-dashboard-splash-screen: 39;
|
$zindex-dashboard-splash-screen: 39;
|
||||||
$zindex-toast: 40;
|
$zindex-toast: 40;
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
$control-checked-background-color: #0069ff !default;
|
||||||
|
$control-checked-background-color-hover: #0069ff !default;
|
||||||
|
$control-checked-background-color-active: #0069ff !default;
|
||||||
|
$control-box-shadow: inset 0 0 0 1px #666 !default;
|
||||||
@@ -271,203 +271,6 @@ label.bp4-label {
|
|||||||
.select-list--tooltip-items .bp4-popover-target {
|
.select-list--tooltip-items .bp4-popover-target {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin control-checked-colors($selector: ':checked') {
|
|
||||||
input#{$selector}~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: $control-checked-background-color;
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover input#{$selector}~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: $control-checked-background-color-hover;
|
|
||||||
border-color: $control-checked-background-color-active;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:not(:disabled):active#{$selector}~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: $control-checked-background-color-active;
|
|
||||||
border-color: $control-checked-background-color-active;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:disabled#{$selector}~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background: rgba($control-checked-background-color, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///@extend
|
|
||||||
.#{$ns}-control {
|
|
||||||
input:checked~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: transparent;
|
|
||||||
background-image: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover input:checked~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:not(:disabled):active:checked~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:disabled:checked~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.#{$ns}-disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
color: $pt-text-color-disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.#{$ns}-inline {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: $pt-grid-size * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.#{$ns}-control-indicator {
|
|
||||||
box-shadow: 0 0 0 transparent;
|
|
||||||
background-clip: padding-box;
|
|
||||||
background-color: transparent;
|
|
||||||
background-image: none;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.bp4-large .#{$ns}-control-indicator {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .#{$ns}-control-indicator {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:not(:disabled):active~.#{$ns}-control-indicator {
|
|
||||||
box-shadow: 0 0 0 transparent;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Checkbox
|
|
||||||
|
|
||||||
Markup:
|
|
||||||
<label class="#{$ns}-control #{$ns}-checkbox {{.modifier}}">
|
|
||||||
<input type="checkbox" {{:modifier}} />
|
|
||||||
<span class="#{$ns}-control-indicator"></span>
|
|
||||||
Checkbox
|
|
||||||
</label>
|
|
||||||
|
|
||||||
:checked - Checked
|
|
||||||
:disabled - Disabled. Also add <code>.#{$ns}-disabled</code> to <code>.#{$ns}-control</code> to change text color (not shown below).
|
|
||||||
:indeterminate - Indeterminate. Note that this style can only be achieved via JavaScript
|
|
||||||
<code>input.indeterminate = true</code>.
|
|
||||||
.#{$ns}-align-right - Right-aligned indicator
|
|
||||||
.#{$ns}-large - Large
|
|
||||||
|
|
||||||
Styleguide checkbox
|
|
||||||
*/
|
|
||||||
&.#{$ns}-checkbox {
|
|
||||||
&:hover input:indeterminate~.#{$ns}-control-indicator {
|
|
||||||
// box-shadow: 0 0 0 transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin indicator-inline-icon($icon) {
|
|
||||||
&::before {
|
|
||||||
// embed SVG icon image as backgroud-image above gradient.
|
|
||||||
// the SVG image content is inlined into the CSS, so use this sparingly.
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include control-checked-colors(':checked');
|
|
||||||
|
|
||||||
// make :indeterminate look like :checked _for Checkbox only_
|
|
||||||
@include control-checked-colors(':indeterminate');
|
|
||||||
|
|
||||||
.#{$ns}-control-indicator {
|
|
||||||
border: 1px solid #c6c6c6;
|
|
||||||
border-radius: $pt-border-radius;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:checked~.#{$ns}-control-indicator {
|
|
||||||
background-image: escape-svg($form-check-input-checked-bg-image);
|
|
||||||
border-color: $form-check-input-checked-bg-color;
|
|
||||||
background-color: $form-check-input-checked-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:indeterminate~.#{$ns}-control-indicator {
|
|
||||||
// background-image: escape-svg($form-check-input-indeterminate-bg-image);
|
|
||||||
border-color: $form-check-input-checked-bg-color;
|
|
||||||
background-color: $form-check-input-checked-bg-color;
|
|
||||||
box-shadow: 0 0 0 0 transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Radio
|
|
||||||
|
|
||||||
Markup:
|
|
||||||
<label class="#{$ns}-control #{$ns}-radio {{.modifier}}">
|
|
||||||
<input type="radio" name="docs-radio-regular" {{:modifier}} />
|
|
||||||
<span class="#{$ns}-control-indicator"></span>
|
|
||||||
Radio
|
|
||||||
</label>
|
|
||||||
|
|
||||||
:checked - Selected
|
|
||||||
:disabled - Disabled. Also add <code>.#{$ns}-disabled</code> to <code>.#{$ns}-control</code> to change text color (not shown below).
|
|
||||||
.#{$ns}-align-right - Right-aligned indicator
|
|
||||||
.#{$ns}-large - Large
|
|
||||||
|
|
||||||
Styleguide radio
|
|
||||||
*/
|
|
||||||
&.#{$ns}-radio {
|
|
||||||
.#{$ns}-control-indicator {
|
|
||||||
border: 2px solid #cecece;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
height: 14px;
|
|
||||||
width: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input:checked~.#{$ns}-control-indicator {
|
|
||||||
border-color: $form-check-input-checked-bg-color;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
background-image: radial-gradient($form-check-input-checked-bg-color 40%,
|
|
||||||
transparent 40%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input:checked:disabled~.#{$ns}-control-indicator::before {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus~.#{$ns}-control-indicator {
|
|
||||||
-moz-outline-radius: $control-indicator-size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bp4-menu-item::before,
|
.bp4-menu-item::before,
|
||||||
.bp4-menu-item>.bp4-icon {
|
.bp4-menu-item>.bp4-icon {
|
||||||
color: #4b5d6b;
|
color: #4b5d6b;
|
||||||
|
|||||||
Reference in New Issue
Block a user