Merge pull request #881 from bigcapitalhq/bugs-bashing

bugs bashing
This commit is contained in:
Ahmed Bouhuolia
2025-12-29 22:08:56 +02:00
committed by GitHub
39 changed files with 372 additions and 528 deletions

View File

@@ -211,7 +211,7 @@ export class InventoryValuationSheet extends FinancialSheet {
* Detarmines whether the items post filter is active.
*/
private isItemsPostFilter = (): boolean => {
return isEmpty(this.query.itemsIds);
return !isEmpty(this.query.itemsIds);
};
/**

View File

@@ -18,7 +18,7 @@ export class InventoryValuationSheetService {
private readonly inventoryValuationMeta: InventoryValuationMetaInjectable,
private readonly eventPublisher: EventEmitter2,
private readonly inventoryValuationSheetRepository: InventoryValuationSheetRepository,
) {}
) { }
/**
* Inventory valuation sheet.

View File

@@ -172,7 +172,10 @@ export class TrialBalanceSheet extends FinancialSheet {
private filterNoneTransactions = (
accountNode: ITrialBalanceAccount
): boolean => {
return false === this.repository.totalAccountsLedger.isEmpty();
const accountLedger = this.repository.totalAccountsLedger.whereAccountId(
accountNode.id,
);
return !accountLedger.isEmpty();
};
/**

View File

@@ -93,7 +93,7 @@ export class InventoryComputeCostService {
*/
async scheduleComputeItemCost(itemId: number, startingDate: Date | string) {
const debounceKey = `inventory-cost-compute-debounce:${itemId}`;
const debounceTime = 1000 * 60; // 1 minute
const debounceTime = 1000 * 10; // 10 seconds
// Generate a unique job ID or use a custom identifier
const jobId = `task-${Date.now()}-${Math.random().toString(36).substring(2)}`;

View File

@@ -2,7 +2,8 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Scope } from '@nestjs/common';
import { Job } from 'bullmq';
import { ClsService } from 'nestjs-cls';
import { ClsService, UseCls } from 'nestjs-cls';
import * as moment from 'moment';
import { TenantJobPayload } from '@/interfaces/Tenant';
import { InventoryComputeCostService } from '../commands/InventoryComputeCost.service';
import { events } from '@/common/events/events';
@@ -14,7 +15,7 @@ import { Process } from '@nestjs/bull';
interface ComputeItemCostJobPayload extends TenantJobPayload {
itemId: number;
startingDate: Date;
startingDate: Date | string;
}
@Processor({
name: ComputeItemCostQueue,
@@ -39,28 +40,34 @@ export class ComputeItemCostProcessor extends WorkerHost {
* @param {Job<ComputeItemCostJobPayload>} job - The job to process
*/
@Process(ComputeItemCostQueueJob)
@UseCls()
async process(job: Job<ComputeItemCostJobPayload>) {
const { itemId, startingDate, organizationId, userId } = job.data;
console.log(`Compute item cost for item ${itemId} started`);
// Parse startingDate using moment to handle both Date and string formats
const startingDateObj = moment(startingDate).toDate();
console.log(`[info] Compute item cost for item ${itemId} started`, {
payload: job.data,
jobId: job.id
});
this.clsService.set('organizationId', organizationId);
this.clsService.set('userId', userId);
try {
await this.inventoryComputeCostService.computeItemCost(
startingDate,
startingDateObj,
itemId,
);
// Emit job completed event
await this.eventEmitter.emitAsync(
events.inventory.onComputeItemCostJobCompleted,
{ startingDate, itemId, organizationId, userId },
{ startingDate: startingDateObj, itemId, organizationId, userId },
);
console.log(`Compute item cost for item ${itemId} completed`);
console.log(`[info] Compute item cost for item ${itemId} completed successfully`);
} catch (error) {
console.error('Error computing item cost:', error);
console.error(`[error] Error computing item cost for item ${itemId}:`, error);
console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace');
throw error;
}
}

View File

@@ -19,7 +19,7 @@ export class SaleInvoiceCostGLEntries {
private readonly inventoryCostLotTracker: TenantModelProxy<
typeof InventoryCostLotTracker
>,
) {}
) { }
/**
* Writes journal entries from sales invoices.

View File

@@ -10,7 +10,7 @@ import { events } from '@/common/events/events';
@Injectable()
export class InvoiceGLEntriesSubscriber {
constructor(public readonly saleInvoiceGLEntries: SaleInvoiceGLEntries) {}
constructor(public readonly saleInvoiceGLEntries: SaleInvoiceGLEntries) { }
/**
* Records journal entries of the non-inventory invoice.

View File

@@ -26,7 +26,7 @@ export class TransactionsLockingService {
constructor(
private readonly transactionsLockingRepo: TransactionsLockingRepository,
private readonly eventPublisher: EventEmitter2,
) {}
) { }
/**
* Enable/disable all transacations locking.

View File

@@ -20,12 +20,3 @@ export function BranchSelect({ branches, ...rest }) {
/>
);
}
/**
*
* @param {*} param0
* @returns
*/
export function BranchSelectButton({ label, ...rest }) {
return <Button text={label} {...rest} />;
}

View File

@@ -171,6 +171,15 @@ export const financialReportMenus = [
subject: AbilitySubject.Report,
ability: ReportsAction.READ_INVENTORY_ITEM_DETAILS,
},
{
title: <T id={'inventory_valuation'} />,
desc: (
<T id={'summerize_your_transactions_for_each_inventory_item'} />
),
link: '/financial-reports/inventory-valuation',
subject: AbilitySubject.Report,
ability: ReportsAction.READ_INVENTORY_VALUATION_SUMMARY,
},
],
},
{

View File

@@ -1,7 +1,7 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { FastField, Field, ErrorMessage } from 'formik';
import { ErrorMessage, useFormikContext } from 'formik';
import {
Classes,
FormGroup,
@@ -10,15 +10,14 @@ import {
InputGroup,
} from '@blueprintjs/core';
import classNames from 'classnames';
import { FormattedMessage as T, If } from '@/components';
import { inputIntent, handleStringChange } from '@/utils';
import { FieldRequiredHint, ListSelect } from '@/components';
import { FormattedMessage as T, If, FFormGroup, FSelect, FRadioGroup, FInputGroup } from '@/components';
import { handleStringChange } from '@/utils';
import { FieldRequiredHint } from '@/components';
import { CLASSES } from '@/constants/classes';
import allocateLandedCostType from '@/constants/allocateLandedCostType';
import AllocateLandedCostFormBody from './AllocateLandedCostFormBody';
import {
transactionsSelectShouldUpdate,
allocateCostToEntries,
resetAllocatedCostEntries,
} from './utils';
@@ -32,196 +31,157 @@ export default function AllocateLandedCostFormFields() {
const { costTransactionEntries, landedCostTransactions } =
useAllocateLandedConstDialogContext();
const { values, setFieldValue, form } = useFormikContext();
// Handle transaction type select change.
const handleTransactionTypeChange = (type) => {
const { items } = values;
setFieldValue('transaction_type', type.value);
setFieldValue('transaction_id', '');
setFieldValue('transaction_entry_id', '');
setFieldValue('amount', '');
setFieldValue('items', resetAllocatedCostEntries(items));
};
// Handle transaction select change.
const handleTransactionChange = (transaction) => {
const { items } = values;
setFieldValue('transaction_id', transaction.id);
setFieldValue('transaction_entry_id', '');
setFieldValue('amount', '');
setFieldValue('items', resetAllocatedCostEntries(items));
};
// Handle transaction entry select change.
const handleTransactionEntryChange = (entry) => {
const { id, unallocated_cost_amount: unallocatedAmount } = entry;
const { items, allocation_method } = values;
setFieldValue('amount', unallocatedAmount);
setFieldValue('transaction_entry_id', id);
setFieldValue(
'items',
allocateCostToEntries(unallocatedAmount, allocation_method, items),
);
};
return (
<div className={Classes.DIALOG_BODY}>
{/*------------Transaction type -----------*/}
<FastField
<FFormGroup
name={'transaction_type'}
transactions={allocateLandedCostType}
shouldUpdate={transactionsSelectShouldUpdate}
label={<T id={'transaction_type'} />}
labelInfo={<FieldRequiredHint />}
inline
fill
fastField
>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={<T id={'transaction_type'} />}
labelInfo={<FieldRequiredHint />}
helperText={<ErrorMessage name="transaction_type" />}
intent={inputIntent({ error, touched })}
inline={true}
className={classNames(CLASSES.FILL, 'form-group--transaction_type')}
>
<ListSelect
items={allocateLandedCostType}
onItemSelect={(type) => {
const { items } = values;
setFieldValue('transaction_type', type.value);
setFieldValue('transaction_id', '');
setFieldValue('transaction_entry_id', '');
setFieldValue('amount', '');
setFieldValue('items', resetAllocatedCostEntries(items));
}}
filterable={false}
selectedItem={value}
selectedItemProp={'value'}
textProp={'name'}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</FastField>
<FSelect
name={'transaction_type'}
items={allocateLandedCostType}
onItemChange={handleTransactionTypeChange}
filterable={false}
valueAccessor={'value'}
textAccessor={'name'}
popoverProps={{ minimal: true }}
fastField
/>
</FFormGroup>
{/*------------ Transaction -----------*/}
<Field
<FFormGroup
name={'transaction_id'}
transactions={landedCostTransactions}
shouldUpdate={transactionsSelectShouldUpdate}
label={<T id={'transaction_id'} />}
labelInfo={<FieldRequiredHint />}
inline
fill
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'transaction_id'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="transaction_id" />}
className={classNames(CLASSES.FILL, 'form-group--transaction_id')}
inline={true}
>
<ListSelect
items={landedCostTransactions}
onItemSelect={({ id }) => {
const { items } = form.values;
form.setFieldValue('transaction_id', id);
form.setFieldValue('transaction_entry_id', '');
form.setFieldValue('amount', '');
form.setFieldValue('items', resetAllocatedCostEntries(items));
}}
filterable={false}
selectedItem={value}
selectedItemProp={'id'}
textProp={'name'}
labelProp={'formatted_unallocated_cost_amount'}
defaultText={intl.get(
'landed_cost.dialog.label_select_transaction',
)}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</Field>
<FSelect
name={'transaction_id'}
items={landedCostTransactions}
onItemChange={handleTransactionChange}
filterable={false}
valueAccessor={'id'}
textAccessor={'name'}
labelAccessor={'formatted_unallocated_cost_amount'}
placeholder={intl.get('landed_cost.dialog.label_select_transaction')}
popoverProps={{ minimal: true }}
/>
</FFormGroup>
{/*------------ Transaction line -----------*/}
<If condition={costTransactionEntries.length > 0}>
<Field
<FFormGroup
name={'transaction_entry_id'}
transactions={costTransactionEntries}
shouldUpdate={transactionsSelectShouldUpdate}
label={<T id={'transaction_line'} />}
inline
fill
fastField
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'transaction_line'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="transaction_entry_id" />}
className={classNames(
CLASSES.FILL,
'form-group--transaction_entry_id',
)}
inline={true}
>
<ListSelect
items={costTransactionEntries}
onItemSelect={(entry) => {
const { id, unallocated_cost_amount: unallocatedAmount } =
entry;
const { items, allocation_method } = form.values;
form.setFieldValue('amount', unallocatedAmount);
form.setFieldValue('transaction_entry_id', id);
form.setFieldValue(
'items',
allocateCostToEntries(
unallocatedAmount,
allocation_method,
items,
),
);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'id'}
textProp={'name'}
labelProp={'formatted_unallocated_cost_amount'}
defaultText={intl.get(
'landed_cost.dialog.label_select_transaction_entry',
)}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</Field>
<FSelect
name={'transaction_entry_id'}
items={costTransactionEntries}
onItemChange={handleTransactionEntryChange}
filterable={false}
valueAccessor={'id'}
textAccessor={'name'}
labelAccessor={'formatted_unallocated_cost_amount'}
placeholder={intl.get(
'landed_cost.dialog.label_select_transaction_entry',
)}
popoverProps={{ minimal: true }}
fastField
/>
</FFormGroup>
</If>
{/*------------ Amount -----------*/}
<FastField name={'amount'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'amount'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
inline={true}
>
<InputGroup
{...field}
onBlur={(e) => {
const amount = e.target.value;
const { allocation_method, items } = form.values;
<FFormGroup
name={'amount'}
label={<T id={'amount'} />}
inline={true}
fastField
>
<FInputGroup
name={'amount'}
onBlur={(e) => {
const amount = e.target.value;
const { allocation_method, items } = values;
form.setFieldValue(
'items',
allocateCostToEntries(amount, allocation_method, items),
);
}}
/>
</FormGroup>
)}
</FastField>
setFieldValue(
'items',
allocateCostToEntries(amount, allocation_method, items),
);
}}
/>
</FFormGroup>
{/*------------ Allocation method -----------*/}
<Field name={'allocation_method'}>
{({ form, field: { value }, meta: { touched, error } }) => (
<FormGroup
medium={true}
label={<T id={'allocation_method'} />}
labelInfo={<FieldRequiredHint />}
className={'form-group--allocation_method'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="allocation_method" />}
inline={true}
>
<RadioGroup
onChange={handleStringChange((_value) => {
const { amount, items } = form.values;
<FFormGroup
name={'allocation_method'}
label={<T id={'allocation_method'} />}
medium
inline
fastField
>
<FRadioGroup
name={'allocation_method'}
onChange={handleStringChange((_value) => {
const { amount, items } = values;
form.setFieldValue('allocation_method', _value);
form.setFieldValue(
'items',
allocateCostToEntries(amount, _value, items),
);
})}
selectedValue={value}
inline={true}
>
<Radio label={<T id={'quantity'} />} value="quantity" />
<Radio label={<T id={'valuation'} />} value="value" />
</RadioGroup>
</FormGroup>
)}
</Field>
setFieldValue('allocation_method', _value);
setFieldValue(
'items',
allocateCostToEntries(amount, _value, items),
);
})}
inline={true}
>
<Radio label={<T id={'quantity'} />} value="quantity" />
<Radio label={<T id={'valuation'} />} value="value" />
</FRadioGroup>
</FFormGroup>
{/*------------ Allocate Landed cost Table -----------*/}
<AllocateLandedCostFormBody />

View File

@@ -2,10 +2,9 @@
import React from 'react';
import intl from 'react-intl-universal';
import * as Yup from 'yup';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import { inputIntent } from '@/utils';
import { ListSelect, FieldRequiredHint } from '@/components';
import { Button, FormGroup, Intent, Classes } from '@blueprintjs/core';
import { Formik, Form } from 'formik';
import { FFormGroup, FSelect, FieldRequiredHint } from '@/components';
import { Button, Intent, Classes } from '@blueprintjs/core';
import { FormattedMessage as T } from '@/components';
import { useHistory } from 'react-router-dom';
import { useContactDuplicateFromContext } from './ContactDuplicateProvider';
@@ -60,29 +59,22 @@ function ContactDuplicateForm({
</p>
{/*------------ Contact Type -----------*/}
<Field name={'contact_type'}>
{({ form, meta: { error, touched } }) => (
<FormGroup
label={<T id={'contact_type'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
className={'form-group--select-list'}
helperText={<ErrorMessage name="contact_type" />}
>
<ListSelect
items={Contacts}
onItemSelect={({ path }) =>
form.setFieldValue('contact_type', path)
}
defaultText={<T id={'select_contact'} />}
textProp={'name'}
selectedItemProp={'name'}
filterable={false}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</Field>
<FFormGroup
name={'contact_type'}
label={<T id={'contact_type'} />}
labelInfo={<FieldRequiredHint />}
className={'form-group--select-list'}
>
<FSelect
name={'contact_type'}
items={Contacts}
placeholder={<T id={'select_contact'} />}
textAccessor={'name'}
valueAccessor={'path'}
filterable={false}
popoverProps={{ minimal: true }}
/>
</FFormGroup>
</div>
<div className={Classes.DIALOG_FOOTER}>

View File

@@ -3,7 +3,7 @@ import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import classNames from 'classnames';
import { FastField, ErrorMessage, Field } from 'formik';
import { useFormikContext } from 'formik';
import { Classes, FormGroup, Position } from '@blueprintjs/core';
import {
FFormGroup,
@@ -11,20 +11,19 @@ import {
FDateInput,
FInputGroup,
FTextArea,
FSelect,
} from '@/components';
import { useAutofocus } from '@/hooks';
import {
ListSelect,
FieldRequiredHint,
Col,
Row,
FeatureCan,
BranchSelect,
WarehouseSelect,
BranchSelectButton,
FAccountsSuggestField,
} from '@/components';
import { inputIntent, momentFormatter, toSafeNumber } from '@/utils';
import { momentFormatter, toSafeNumber } from '@/utils';
import { Features, CLASSES } from '@/constants';
import { useInventoryAdjContext } from './InventoryAdjustmentFormProvider';
@@ -52,6 +51,7 @@ export default function InventoryAdjustmentFormDialogFields() {
// Inventory adjustment dialog context.
const { accounts, branches, warehouses } = useInventoryAdjContext();
const { values, setFieldValue } = useFormikContext();
// Sets the primary warehouse to form.
useSetPrimaryWarehouseToForm();
@@ -59,6 +59,17 @@ export default function InventoryAdjustmentFormDialogFields() {
// Sets the primary branch to form.
useSetPrimaryBranchToForm();
// Handle adjustment type change.
const handleAdjustmentTypeChange = (type) => {
const result = diffQuantity(
toSafeNumber(values.quantity),
toSafeNumber(values.quantity_on_hand),
type.value,
);
setFieldValue('type', type.value);
setFieldValue('new_quantity', result);
};
return (
<div className={Classes.DIALOG_BODY}>
<Row>
@@ -66,12 +77,11 @@ export default function InventoryAdjustmentFormDialogFields() {
<Col xs={5}>
<FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
fill
>
<BranchSelect
name={'branch_id'}
branches={branches}
input={BranchSelectButton}
popoverProps={{ minimal: true }}
/>
</FormGroup>
@@ -81,7 +91,7 @@ export default function InventoryAdjustmentFormDialogFields() {
<Col xs={5}>
<FormGroup
label={<T id={'warehouse'} />}
className={classNames('form-group--select-list', Classes.FILL)}
fill
>
<WarehouseSelect
name={'warehouse_id'}
@@ -122,39 +132,24 @@ export default function InventoryAdjustmentFormDialogFields() {
<Col xs={5}>
{/*------------ Adjustment type -----------*/}
<Field name={'type'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FFormGroup
name={'type'}
label={<T id={'adjustment_type'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<ListSelect
items={adjustmentTypes}
onItemSelect={(type) => {
const result = diffQuantity(
toSafeNumber(values.quantity),
toSafeNumber(values.quantity_on_hand),
type.value,
);
setFieldValue('type', type.value);
setFieldValue('new_quantity', result);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'value'}
textProp={'name'}
popoverProps={{ minimal: true }}
intent={inputIntent({ error, touched })}
/>
</FFormGroup>
)}
</Field>
<FFormGroup
name={'type'}
label={<T id={'adjustment_type'} />}
labelInfo={<FieldRequiredHint />}
fill
fastField
>
<FSelect
name={'type'}
items={adjustmentTypes}
onItemChange={handleAdjustmentTypeChange}
filterable={false}
valueAccessor={'value'}
textAccessor={'name'}
popoverProps={{ minimal: true }}
fastField
/>
</FFormGroup>
</Col>
</Row>

View File

@@ -73,7 +73,6 @@ function RefundCreditNoteFormFields({
<BranchSelect
name={'branch_id'}
branches={branches}
input={BranchSelectButton}
popoverProps={{ minimal: true }}
/>
</FormGroup>

View File

@@ -1,19 +1,16 @@
// @ts-nocheck
import React from 'react';
import {
FormGroup,
InputGroup,
Intent,
Classes,
Button,
} from '@blueprintjs/core';
import { FastField, Form, useFormikContext, ErrorMessage } from 'formik';
import { Form, useFormikContext } from 'formik';
import classNames from 'classnames';
import { FFormGroup, FInputGroup, FormattedMessage as T } from '@/components';
import { FFormGroup, FInputGroup, FSelect, FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes';
import { inputIntent } from '@/utils';
import { ListSelect, FieldRequiredHint } from '@/components';
import { FieldRequiredHint } from '@/components';
import { useUserFormContext } from './UserFormProvider';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { compose } from '@/utils';
@@ -68,31 +65,21 @@ function UserFormContent({
</FFormGroup>
{/* ----------- Role name ----------- */}
<FastField name={'role_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'roles.label.role_name'} />}
labelInfo={<FieldRequiredHint />}
helperText={<ErrorMessage name="role_id" />}
className={classNames(CLASSES.FILL, 'form-group--role_name')}
intent={inputIntent({ error, touched })}
>
<ListSelect
items={roles}
onItemSelect={({ id }) => {
form.setFieldValue('role_id', id);
}}
selectedItem={value}
selectedItemProp={'id'}
textProp={'name'}
// labelProp={'id '}
popoverProps={{ minimal: true }}
intent={inputIntent({ error, touched })}
disabled={isAuth}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'role_id'}
label={<T id={'roles.label.role_name'} />}
labelInfo={<FieldRequiredHint />}
className={classNames(CLASSES.FILL, 'form-group--role_name')}
>
<FSelect
name={'role_id'}
items={roles}
valueAccessor={'id'}
textAccessor={'name'}
popoverProps={{ minimal: true }}
disabled={isAuth}
/>
</FFormGroup>
</div>
<div className={CLASSES.DIALOG_FOOTER}>

View File

@@ -105,11 +105,6 @@ function APAgingSummaryActionsBar({
/>
</Popover>
<Button
className={Classes.MINIMAL}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
<NavbarDivider />
<Button

View File

@@ -106,11 +106,6 @@ function ARAgingSummaryActionsBar({
/>
</Popover>
<Button
className={Classes.MINIMAL}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
<NavbarDivider />
<Button

View File

@@ -104,18 +104,6 @@ function BalanceSheetActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button
className={Classes.MINIMAL}

View File

@@ -107,18 +107,6 @@ function CashFlowStatementActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button

View File

@@ -104,18 +104,6 @@ function CustomersBalanceSummaryActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button

View File

@@ -106,18 +106,6 @@ function CustomersTransactionsActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button

View File

@@ -77,19 +77,6 @@ function GeneralLedgerActionsBar({
/>
<NavbarDivider />
<Popover
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}

View File

@@ -102,18 +102,6 @@ function InventoryItemDetailsActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button

View File

@@ -103,18 +103,6 @@ function InventoryValuationActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}

View File

@@ -55,17 +55,29 @@ const InventoryValuationSheet = styled(FinancialSheet)`
`;
const InventoryValuationDataTable = styled(ReportDataTable)`
--color-table-text-color: #252a31;
--color-table-total-text-color: #000;
--color-table-total-border: #bbb;
.bp4-dark & {
--color-table-text-color: var(--color-light-gray1);
--color-table-total-text-color: var(--color-light-gray4);
--color-table-total-border: var(--color-dark-gray5);
}
.table {
.tbody {
.tr .td {
border-bottom: 0;
padding-top: 0.4rem;
padding-bottom: 0.4rem;
color: var(--color-table-text-color);
}
.tr.row_type--TOTAL .td {
border-top: 1px solid #bbb;
border-top: 1px solid var(--color-table-total-border);
border-bottom: 3px double var(--color-table-total-border);
font-weight: 500;
border-bottom: 3px double #000;
color: var(--color-table-total-text-color);
}
}
}

View File

@@ -78,19 +78,6 @@ function JournalActionsBar({
/>
<NavbarDivider />
<Popover
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}

View File

@@ -103,18 +103,6 @@ function ProfitLossActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}

View File

@@ -93,17 +93,6 @@ function ProjectProfitabilitySummaryActionsBar({
icon={<Icon icon="numbers" width={23} height={16} />}
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />

View File

@@ -100,17 +100,6 @@ function PurchasesByItemsActionsBar({
icon={<Icon icon="numbers" width={23} height={16} />}
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<Button
className={Classes.MINIMAL}

View File

@@ -91,11 +91,6 @@ function RealizedGainOrLossActionsBar({
/>
</Popover>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
<NavbarDivider />
<Button

View File

@@ -102,18 +102,6 @@ function SalesByItemsActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}

View File

@@ -104,18 +104,6 @@ function SalesTaxLiabilitySummaryActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button

View File

@@ -103,18 +103,6 @@ function TrialBalanceActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}

View File

@@ -52,6 +52,7 @@ function TrialBalanceSheetHeader({
fromDate: moment().toDate(),
toDate: moment().toDate(),
branchesIds: [],
filterByOption: 'with-transactions',
};
// Initial values.

View File

@@ -92,11 +92,6 @@ function UnrealizedGainOrLossActionsBar({
/>
</Popover>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
<NavbarDivider />
<Button

View File

@@ -105,11 +105,6 @@ function VendorsBalanceSummaryActionsBar({
/>
</Popover>
<Button
className={Classes.MINIMAL}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
<NavbarDivider />
<Button

View File

@@ -106,18 +106,6 @@ function VendorsTransactionsActionsBar({
/>
</Popover>
<Popover
// content={}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={<T id={'filter'} />}
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<NavbarDivider />
<Button

View File

@@ -6,7 +6,8 @@ import classNames from 'classnames';
import styled from 'styled-components';
import {
ListSelect,
FFormGroup,
FSelect,
FieldRequiredHint,
FormattedMessage as T,
} from '@/components';
@@ -16,29 +17,23 @@ import { inputIntent } from '@/utils';
export default function NotifyViaSMSFormFields({ notificationTypes }) {
return (
<NotifyViaSMSFormFieldsRoot>
<FastField name={'notification_key'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'notify_via_sms.dialog.notification_type'} />}
className={classNames(CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_name'} />}
>
<ListSelect
items={notificationTypes}
selectedItemProp={'key'}
selectedItem={value}
textProp={'label'}
popoverProps={{ minimal: true }}
filterable={false}
onItemSelect={(notification) => {
form.setFieldValue('notification_key', notification.key);
}}
disabled={notificationTypes.length < 2}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'notification_key'}
label={<T id={'notify_via_sms.dialog.notification_type'} />}
className={classNames(CLASSES.FILL)}
fastField
>
<FSelect
name={'notification_key'}
items={notificationTypes}
valueAccessor={'key'}
textAccessor={'label'}
popoverProps={{ minimal: true }}
filterable={false}
disabled={notificationTypes.length < 2}
fastField
/>
</FFormGroup>
{/* ----------- Send Notification to ----------- */}
<FastField name={'customer_name'}>

View File

@@ -0,0 +1,98 @@
import { ComponentType } from 'react';
import { Dispatch } from 'redux';
import { connect, MapStateToProps } from 'react-redux';
/**
* Creates a simple dispatch HOC that injects action props into a component.
* This is the DRY utility for Pattern 1: Action HOCs.
*
* @example
* ```tsx
* export interface WithAlertActionsProps {
* openAlert: (name: string) => void;
* }
*
* export const mapDispatchToProps = (dispatch: Dispatch): WithAlertActionsProps => ({
* openAlert: (name) => dispatch({ type: 'OPEN_ALERT', name }),
* });
*
* export const withAlertActions = createActionHOC<WithAlertActionsProps>(mapDispatchToProps);
* ```
*/
export function createActionHOC<TInjectedProps extends object>(
mapDispatchToProps: (dispatch: Dispatch) => TInjectedProps,
) {
return function withHOC<P extends TInjectedProps>(
WrappedComponent: ComponentType<P>,
): ComponentType<Omit<P, keyof TInjectedProps>> {
const Connected = connect(null, mapDispatchToProps)(
WrappedComponent as ComponentType<any>,
);
return Connected as unknown as ComponentType<Omit<P, keyof TInjectedProps>>;
};
}
/**
* Creates a state factory HOC that accepts an optional mapState function.
* This is the DRY utility for Pattern 2: State Factory HOCs.
*
* @example
* ```tsx
* export interface WithDrawersProps {
* isOpen: boolean;
* payload: Record<string, unknown>;
* }
*
* export const withDrawers = createStateFactoryHOC<WithDrawersProps>((state, props) => ({
* isOpen: isDrawerOpen(state, props),
* payload: getDrawerPayload(state, props),
* }));
* ```
*/
export function createStateFactoryHOC<TInjectedProps extends object>(
createMapState: () => (state: any, props: any) => TInjectedProps,
) {
type MapStateFn<T> = (mapped: TInjectedProps, state?: unknown, props?: unknown) => T;
return function withHOC<P, T = TInjectedProps>(mapState?: MapStateFn<T>) {
const mapStateToProps = createMapState();
const wrappedMapState = (state: any, props: any) => {
const mapped = mapStateToProps(state, props);
return mapState ? mapState(mapped, state, props) : mapped;
};
return function <C extends ComponentType<P>>(WrappedComponent: C) {
return connect(wrappedMapState)(WrappedComponent as ComponentType<any>) as unknown as ComponentType<
Omit<P, keyof (T extends TInjectedProps ? T : TInjectedProps)>
>;
};
};
}
/**
* Creates a simple state HOC that directly connects state to component props.
* This is for HOCs that don't use the factory pattern.
*
* @example
* ```tsx
* export interface WithCurrencyDetailProps {
* currency: Record<string, unknown> | null;
* }
*
* export const withCurrencyDetail = createStateHOC<WithCurrencyDetailProps>((state, props) => ({
* currency: getCurrencyByCode(state, props),
* }));
* ```
*/
export function createStateHOC<TInjectedProps extends object>(
mapStateToProps: (state: any, props: any) => TInjectedProps,
) {
return function withHOC<P extends TInjectedProps>(
WrappedComponent: ComponentType<P>,
): ComponentType<Omit<P, keyof TInjectedProps>> {
const Connected = connect(mapStateToProps)(
WrappedComponent as ComponentType<any>,
);
return Connected as unknown as ComponentType<Omit<P, keyof TInjectedProps>>;
};
}