mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
wip
This commit is contained in:
@@ -9,6 +9,8 @@ import { GetCreditNotesService } from './queries/GetCreditNotes.service';
|
||||
import { CreateCreditNoteDto, EditCreditNoteDto } from './dtos/CreditNote.dto';
|
||||
import { GetCreditNoteState } from './queries/GetCreditNoteState.service';
|
||||
import { GetCreditNoteService } from './queries/GetCreditNote.service';
|
||||
import { BulkDeleteCreditNotesService } from './BulkDeleteCreditNotes.service';
|
||||
import { ValidateBulkDeleteCreditNotesService } from './ValidateBulkDeleteCreditNotes.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreditNoteApplication {
|
||||
@@ -20,8 +22,10 @@ export class CreditNoteApplication {
|
||||
private readonly getCreditNotePdfService: GetCreditNotePdf,
|
||||
private readonly getCreditNotesService: GetCreditNotesService,
|
||||
private readonly getCreditNoteStateService: GetCreditNoteState,
|
||||
private readonly getCreditNoteService: GetCreditNoteService
|
||||
) {}
|
||||
private readonly getCreditNoteService: GetCreditNoteService,
|
||||
private readonly bulkDeleteCreditNotesService: BulkDeleteCreditNotesService,
|
||||
private readonly validateBulkDeleteCreditNotesService: ValidateBulkDeleteCreditNotesService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Creates a new credit note.
|
||||
@@ -97,4 +101,26 @@ export class CreditNoteApplication {
|
||||
getCreditNote(creditNoteId: number) {
|
||||
return this.getCreditNoteService.getCreditNote(creditNoteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes multiple credit notes.
|
||||
* @param {number[]} creditNoteIds
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
bulkDeleteCreditNotes(creditNoteIds: number[]) {
|
||||
return this.bulkDeleteCreditNotesService.bulkDeleteCreditNotes(
|
||||
creditNoteIds,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates which credit notes can be deleted.
|
||||
* @param {number[]} creditNoteIds
|
||||
* @returns {Promise<{deletableCount: number, nonDeletableCount: number, deletableIds: number[], nonDeletableIds: number[]}>}
|
||||
*/
|
||||
validateBulkDeleteCreditNotes(creditNoteIds: number[]) {
|
||||
return this.validateBulkDeleteCreditNotesService.validateBulkDeleteCreditNotes(
|
||||
creditNoteIds,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,16 @@ import { CreateCreditNoteDto, EditCreditNoteDto } from './dtos/CreditNote.dto';
|
||||
import { CreditNoteResponseDto } from './dtos/CreditNoteResponse.dto';
|
||||
import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto';
|
||||
import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders';
|
||||
import {
|
||||
BulkDeleteDto,
|
||||
ValidateBulkDeleteResponseDto,
|
||||
} from '@/common/dtos/BulkDelete.dto';
|
||||
|
||||
@Controller('credit-notes')
|
||||
@ApiTags('Credit Notes')
|
||||
@ApiExtraModels(CreditNoteResponseDto)
|
||||
@ApiExtraModels(PaginatedResponseDto)
|
||||
@ApiExtraModels(ValidateBulkDeleteResponseDto)
|
||||
@ApiCommonHeaders()
|
||||
export class CreditNotesController {
|
||||
/**
|
||||
@@ -112,6 +117,39 @@ export class CreditNotesController {
|
||||
return this.creditNoteApplication.openCreditNote(creditNoteId);
|
||||
}
|
||||
|
||||
@Post('validate-bulk-delete')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Validates which credit notes can be deleted and returns the results.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description:
|
||||
'Validation completed with counts and IDs of deletable and non-deletable credit notes.',
|
||||
schema: {
|
||||
$ref: getSchemaPath(ValidateBulkDeleteResponseDto),
|
||||
},
|
||||
})
|
||||
validateBulkDeleteCreditNotes(
|
||||
@Body() bulkDeleteDto: BulkDeleteDto,
|
||||
): Promise<ValidateBulkDeleteResponseDto> {
|
||||
return this.creditNoteApplication.validateBulkDeleteCreditNotes(
|
||||
bulkDeleteDto.ids,
|
||||
);
|
||||
}
|
||||
|
||||
@Post('bulk-delete')
|
||||
@ApiOperation({ summary: 'Deletes multiple credit notes.' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Credit notes deleted successfully',
|
||||
})
|
||||
bulkDeleteCreditNotes(@Body() bulkDeleteDto: BulkDeleteDto): Promise<void> {
|
||||
return this.creditNoteApplication.bulkDeleteCreditNotes(
|
||||
bulkDeleteDto.ids,
|
||||
);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete a credit note' })
|
||||
@ApiParam({ name: 'id', description: 'Credit note ID', type: 'number' })
|
||||
|
||||
@@ -34,6 +34,8 @@ import { CreditNoteInventoryTransactions } from './commands/CreditNotesInventory
|
||||
import { InventoryCostModule } from '../InventoryCost/InventoryCost.module';
|
||||
import { CreditNoteRefundsModule } from '../CreditNoteRefunds/CreditNoteRefunds.module';
|
||||
import { CreditNotesApplyInvoiceModule } from '../CreditNotesApplyInvoice/CreditNotesApplyInvoice.module';
|
||||
import { BulkDeleteCreditNotesService } from './BulkDeleteCreditNotes.service';
|
||||
import { ValidateBulkDeleteCreditNotesService } from './ValidateBulkDeleteCreditNotes.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -73,6 +75,8 @@ import { CreditNotesApplyInvoiceModule } from '../CreditNotesApplyInvoice/Credit
|
||||
RefundSyncCreditNoteBalanceSubscriber,
|
||||
DeleteCustomerLinkedCreditSubscriber,
|
||||
CreditNoteAutoSerialSubscriber,
|
||||
BulkDeleteCreditNotesService,
|
||||
ValidateBulkDeleteCreditNotesService,
|
||||
],
|
||||
exports: [
|
||||
CreateCreditNoteService,
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from '@/components';
|
||||
|
||||
import { useBulkDeleteReceipts } from '@/hooks/query/receipts';
|
||||
import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Receipt bulk delete alert.
|
||||
*/
|
||||
function ReceiptBulkDeleteAlert({
|
||||
name,
|
||||
isOpen,
|
||||
payload: { receiptsIds },
|
||||
closeAlert,
|
||||
}) {
|
||||
const { mutateAsync: bulkDeleteReceipts, isLoading } = useBulkDeleteReceipts();
|
||||
|
||||
const handleCancel = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
const handleConfirmBulkDelete = () => {
|
||||
bulkDeleteReceipts(receiptsIds)
|
||||
.then(() => {
|
||||
AppToaster.show({
|
||||
message: intl.get('the_receipts_has_been_deleted_successfully'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('sale-receipts-table');
|
||||
closeAlert(name);
|
||||
})
|
||||
.catch((errors) => {
|
||||
// Handle errors
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={
|
||||
<T id={'delete_count'} values={{ count: receiptsIds?.length || 0 }} />
|
||||
}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirmBulkDelete}
|
||||
loading={isLoading}
|
||||
>
|
||||
<p>
|
||||
<T id={'once_delete_these_receipts_you_will_not_able_restore_them'} />
|
||||
</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
)(ReceiptBulkDeleteAlert);
|
||||
|
||||
@@ -29,6 +29,7 @@ import withBillsActions from './withBillsActions';
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import withSettingsActions from '@/containers/Settings/withSettingsActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
|
||||
import { useBillsListContext } from './BillsListProvider';
|
||||
import { useRefreshBills } from '@/hooks/query/bills';
|
||||
@@ -57,6 +58,9 @@ function BillActionsBar({
|
||||
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withAlertActions
|
||||
openAlert,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
@@ -210,4 +214,5 @@ export default compose(
|
||||
billsTableSize: billsettings?.tableSize,
|
||||
})),
|
||||
withDialogActions,
|
||||
withAlertActions,
|
||||
)(BillActionsBar);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
NavbarDivider,
|
||||
NavbarGroup,
|
||||
Alignment,
|
||||
Intent,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Popover,
|
||||
@@ -13,6 +14,7 @@ import {
|
||||
Position,
|
||||
} from '@blueprintjs/core';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
Icon,
|
||||
Can,
|
||||
@@ -34,6 +36,7 @@ import withSettings from '@/containers/Settings/withSettings';
|
||||
import withSettingsActions from '@/containers/Settings/withSettingsActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
|
||||
import { DialogsName } from '@/constants/dialogs';
|
||||
import { compose } from '@/utils';
|
||||
@@ -45,6 +48,7 @@ import { DRAWERS } from '@/constants/drawers';
|
||||
function CreditNotesActionsBar({
|
||||
// #withCreditNotes
|
||||
creditNoteFilterRoles,
|
||||
creditNotesSelectedRows,
|
||||
|
||||
// #withCreditNotesActions
|
||||
setCreditNotesTableState,
|
||||
@@ -59,7 +63,10 @@ function CreditNotesActionsBar({
|
||||
openDialog,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer
|
||||
openDrawer,
|
||||
|
||||
// #withAlertActions
|
||||
openAlert,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
@@ -104,6 +111,26 @@ function CreditNotesActionsBar({
|
||||
openDrawer(DRAWERS.BRANDING_TEMPLATES, { resource: 'CreditNote' });
|
||||
}
|
||||
|
||||
// Show bulk delete button when rows are selected.
|
||||
if (!isEmpty(creditNotesSelectedRows)) {
|
||||
const handleBulkDelete = () => {
|
||||
openAlert('credit-notes-bulk-delete', { creditNotesIds: creditNotesSelectedRows });
|
||||
};
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleBulkDelete}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
@@ -195,12 +222,14 @@ function CreditNotesActionsBar({
|
||||
export default compose(
|
||||
withCreditNotesActions,
|
||||
withSettingsActions,
|
||||
withCreditNotes(({ creditNoteTableState }) => ({
|
||||
withCreditNotes(({ creditNoteTableState, creditNotesSelectedRows }) => ({
|
||||
creditNoteFilterRoles: creditNoteTableState.filterRoles,
|
||||
creditNotesSelectedRows,
|
||||
})),
|
||||
withSettings(({ creditNoteSettings }) => ({
|
||||
creditNoteTableSize: creditNoteSettings?.tableSize,
|
||||
})),
|
||||
withDialogActions,
|
||||
withDrawerActions
|
||||
withDrawerActions,
|
||||
withAlertActions,
|
||||
)(CreditNotesActionsBar);
|
||||
|
||||
@@ -7,6 +7,9 @@ const ReceiptDeleteAlert = React.lazy(
|
||||
const ReceiptCloseAlert = React.lazy(
|
||||
() => import('@/containers/Alerts/Receipts/ReceiptCloseAlert'),
|
||||
);
|
||||
const ReceiptBulkDeleteAlert = React.lazy(
|
||||
() => import('@/containers/Alerts/Receipts/ReceiptBulkDeleteAlert'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Receipts alerts.
|
||||
@@ -14,4 +17,5 @@ const ReceiptCloseAlert = React.lazy(
|
||||
export default [
|
||||
{ name: 'receipt-delete', component: ReceiptDeleteAlert },
|
||||
{ name: 'receipt-close', component: ReceiptCloseAlert },
|
||||
{ name: 'receipts-bulk-delete', component: ReceiptBulkDeleteAlert },
|
||||
];
|
||||
|
||||
@@ -35,6 +35,7 @@ import withReceiptsActions from './withReceiptsActions';
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import withSettingsActions from '@/containers/Settings/withSettingsActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
|
||||
import { useReceiptsListContext } from './ReceiptsListProvider';
|
||||
import { useRefreshReceipts } from '@/hooks/query/receipts';
|
||||
@@ -70,6 +71,9 @@ function ReceiptActionsBar({
|
||||
|
||||
// #withSettingsActions
|
||||
addSetting,
|
||||
|
||||
// #withAlertActions
|
||||
openAlert,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
@@ -250,4 +254,5 @@ export default compose(
|
||||
})),
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
withAlertActions,
|
||||
)(ReceiptActionsBar);
|
||||
|
||||
@@ -104,6 +104,25 @@ export function useDeleteReceipt(props) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes multiple receipts in bulk.
|
||||
*/
|
||||
export function useBulkDeleteReceipts(props) {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
(ids: number[]) => apiRequest.post('sale-receipts/bulk-delete', { ids }),
|
||||
{
|
||||
onSuccess: () => {
|
||||
// Common invalidate queries.
|
||||
commonInvalidateQueries(queryClient);
|
||||
},
|
||||
...props,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given sale invoice.
|
||||
*/
|
||||
|
||||
@@ -544,9 +544,11 @@
|
||||
"send_to_email": "Send to email",
|
||||
"select_deposit_account": "Select Deposit Account...",
|
||||
"once_delete_this_receipt_you_will_able_to_restore_it": "Once you delete this receipt, you won't be able to restore it later. Are you sure you want to delete it?",
|
||||
"once_delete_these_receipts_you_will_not_able_restore_them": "Once you delete these receipts, you won't be able to retrieve them later. Are you sure you want to delete them?",
|
||||
"the_receipt_has_been_created_successfully": "The receipt #{number} has been created successfully.",
|
||||
"the_receipt_has_been_edited_successfully": "The receipt #{number} has been edited successfully.",
|
||||
"the_receipt_has_been_deleted_successfully": "The receipt has been deleted successfully.",
|
||||
"the_receipts_has_been_deleted_successfully": "The receipts have been deleted successfully.",
|
||||
"bills_list": "Bills List",
|
||||
"bills": "Bills",
|
||||
"accept": "Accept",
|
||||
|
||||
@@ -14,6 +14,7 @@ export const defaultTableQuery = {
|
||||
|
||||
const initialState = {
|
||||
tableState: defaultTableQuery,
|
||||
selectedRows: [],
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:receipts';
|
||||
@@ -27,6 +28,10 @@ const CONFIG = {
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('RECEIPTS', defaultTableQuery),
|
||||
|
||||
[t.RECEIPTS_SELECTED_ROWS_SET]: (state, action) => {
|
||||
state.selectedRows = action.payload;
|
||||
},
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user