Merge pull request #904 from bigcapitalhq/fix-landed-cost-dialog

fix: landed cost dialog
This commit is contained in:
Ahmed Bouhuolia
2026-01-17 21:45:23 +02:00
committed by GitHub
11 changed files with 77 additions and 33 deletions

View File

@@ -22,6 +22,9 @@
"field.status.unpaid": "Unpaid", "field.status.unpaid": "Unpaid",
"field.status.opened": "Opened", "field.status.opened": "Opened",
"field.status.draft": "Draft", "field.status.draft": "Draft",
"field.created_at": "Created At" "field.created_at": "Created At",
"allocation_method": "Allocation Method",
"allocation_method.quantity": "Quantity",
"allocation_method.value": "Valuation"
} }

View File

@@ -77,6 +77,13 @@ export class BillAllocatedLandedCostTransactions {
transaction.fromTransactionType, transaction.fromTransactionType,
transaction, transaction,
); );
const allocationMethodFormattedKey = transaction.allocationMethodFormatted;
const allocationMethodFormatted = allocationMethodFormattedKey
? this.i18nService.t(allocationMethodFormattedKey, {
defaultValue: allocationMethodFormattedKey,
})
: '';
return { return {
formattedAmount: formatNumber(transaction.amount, { formattedAmount: formatNumber(transaction.amount, {
currencyCode: transaction.currencyCode, currencyCode: transaction.currencyCode,
@@ -84,12 +91,14 @@ export class BillAllocatedLandedCostTransactions {
...omit(transaction, [ ...omit(transaction, [
'allocatedFromBillEntry', 'allocatedFromBillEntry',
'allocatedFromExpenseEntry', 'allocatedFromExpenseEntry',
'allocationMethodFormatted',
]), ]),
name, name,
description, description,
formattedLocalAmount: formatNumber(transaction.localAmount, { formattedLocalAmount: formatNumber(transaction.localAmount, {
currencyCode: 'USD', currencyCode: 'USD',
}), }),
allocationMethodFormatted,
}; };
}; };

View File

@@ -45,8 +45,8 @@ export class LandedCostTranasctions {
)(transactionType); )(transactionType);
return pipe( return pipe(
this.transformLandedCostTransactions,
R.map(transformLandedCost), R.map(transformLandedCost),
this.transformLandedCostTransactions,
)(transactions); )(transactions);
}; };
@@ -90,7 +90,7 @@ export class LandedCostTranasctions {
const entries = R.map< const entries = R.map<
ILandedCostTransactionEntry, ILandedCostTransactionEntry,
ILandedCostTransactionEntryDOJO ILandedCostTransactionEntryDOJO
>(transformLandedCostEntry)(transaction.entries); >(transformLandedCostEntry)(transaction.entries ?? []);
return { return {
...transaction, ...transaction,

View File

@@ -4,7 +4,6 @@ import {
IsOptional, IsOptional,
IsArray, IsArray,
ValidateNested, ValidateNested,
IsDecimal,
IsString, IsString,
IsNumber, IsNumber,
} from 'class-validator'; } from 'class-validator';
@@ -17,8 +16,9 @@ export class AllocateBillLandedCostItemDto {
@ToNumber() @ToNumber()
entryId: number; entryId: number;
@IsDecimal() @IsNumber()
cost: string; // Use string for IsDecimal, or use @IsNumber() if you want a number @ToNumber()
cost: number;
} }
export class AllocateBillLandedCostDto { export class AllocateBillLandedCostDto {

View File

@@ -60,8 +60,8 @@ export class BillLandedCost extends BaseModel {
const allocationMethod = lowerCase(this.allocationMethod); const allocationMethod = lowerCase(this.allocationMethod);
const keyLabelsPairs = { const keyLabelsPairs = {
value: 'allocation_method.value.label', value: 'bill.allocation_method.value',
quantity: 'allocation_method.quantity.label', quantity: 'bill.allocation_method.quantity',
}; };
return keyLabelsPairs[allocationMethod] || ''; return keyLabelsPairs[allocationMethod] || '';
} }

View File

@@ -24,7 +24,7 @@ function AllocateLandedCostDialogProvider({
dialogName, dialogName,
...props ...props
}) { }) {
const [transactionsType, setTransactionsType] = React.useState(null); const [transactionsType, setTransactionsType] = React.useState('Bill');
const [transactionId, setTransactionId] = React.useState(null); const [transactionId, setTransactionId] = React.useState(null);
const [transactionEntryId, setTransactionEntryId] = React.useState(null); const [transactionEntryId, setTransactionEntryId] = React.useState(null);
@@ -34,7 +34,8 @@ function AllocateLandedCostDialogProvider({
}); });
// Retrieve the landed cost transactions based on the given transactions type. // Retrieve the landed cost transactions based on the given transactions type.
const { const {
data: { transactions: landedCostTransactions }, data: landedCostTransactions,
isLoading: isLandedCostTransactionsLoading,
} = useLandedCostTransaction(transactionsType, { } = useLandedCostTransaction(transactionsType, {
enabled: !!transactionsType, enabled: !!transactionsType,
}); });
@@ -88,6 +89,7 @@ function AllocateLandedCostDialogProvider({
costTransactionEntries, costTransactionEntries,
transactionsType, transactionsType,
landedCostTransactions, landedCostTransactions,
isLandedCostTransactionsLoading,
setTransactionsType, setTransactionsType,
setTransactionId, setTransactionId,
setTransactionEntryId, setTransactionEntryId,

View File

@@ -68,11 +68,16 @@ const AllocateDialogFooter = styled(DialogFooter)`
`; `;
const UnallocatedAmount = styled.div` const UnallocatedAmount = styled.div`
color: #3f5278; --x-color-text: #3f5278;
.bp4-dark & {
--x-color-text: var(--color-light-gray1);
}
color: var(--x-color-text);
align-self: center; align-self: center;
strong { strong {
color: #353535; color: var(--x-color-text);
padding-left: 4px; padding-left: 4px;
} }
`; `;

View File

@@ -8,8 +8,10 @@ import {
RadioGroup, RadioGroup,
Radio, Radio,
InputGroup, InputGroup,
Spinner,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { x } from '@xstyled/emotion';
import { FormattedMessage as T, If, FFormGroup, FSelect, FRadioGroup, FInputGroup } from '@/components'; import { FormattedMessage as T, If, FFormGroup, FSelect, FRadioGroup, FInputGroup } from '@/components';
import { handleStringChange } from '@/utils'; import { handleStringChange } from '@/utils';
import { FieldRequiredHint } from '@/components'; import { FieldRequiredHint } from '@/components';
@@ -28,7 +30,7 @@ import { useAllocateLandedConstDialogContext } from './AllocateLandedCostDialogP
*/ */
export default function AllocateLandedCostFormFields() { export default function AllocateLandedCostFormFields() {
// Allocated landed cost dialog. // Allocated landed cost dialog.
const { costTransactionEntries, landedCostTransactions } = const { costTransactionEntries, landedCostTransactions, isLandedCostTransactionsLoading } =
useAllocateLandedConstDialogContext(); useAllocateLandedConstDialogContext();
const { values, setFieldValue, form } = useFormikContext(); const { values, setFieldValue, form } = useFormikContext();
@@ -97,9 +99,10 @@ export default function AllocateLandedCostFormFields() {
inline inline
fill fill
> >
<x.div position="relative" w="100%">
<FSelect <FSelect
name={'transaction_id'} name={'transaction_id'}
items={landedCostTransactions} items={landedCostTransactions || []}
onItemChange={handleTransactionChange} onItemChange={handleTransactionChange}
filterable={false} filterable={false}
valueAccessor={'id'} valueAccessor={'id'}
@@ -107,11 +110,24 @@ export default function AllocateLandedCostFormFields() {
labelAccessor={'formatted_unallocated_cost_amount'} labelAccessor={'formatted_unallocated_cost_amount'}
placeholder={intl.get('landed_cost.dialog.label_select_transaction')} placeholder={intl.get('landed_cost.dialog.label_select_transaction')}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
disabled={isLandedCostTransactionsLoading}
/> />
{isLandedCostTransactionsLoading && (
<x.div
position="absolute"
right="35px"
top="50%"
transform="translateY(-50%)"
pointerEvents="none"
>
<Spinner size={16} />
</x.div>
)}
</x.div>
</FFormGroup> </FFormGroup>
{/*------------ Transaction line -----------*/} {/*------------ Transaction line -----------*/}
<If condition={costTransactionEntries.length > 0}> <If condition={costTransactionEntries?.length > 0}>
<FFormGroup <FFormGroup
name={'transaction_entry_id'} name={'transaction_entry_id'}
label={<T id={'transaction_line'} />} label={<T id={'transaction_line'} />}

View File

@@ -67,9 +67,6 @@ export function useLandedCostTransaction(query, props) {
}, },
{ {
select: (res) => res.data, select: (res) => res.data,
defaultData: {
transactions: [],
},
...props, ...props,
}, },
); );

View File

@@ -21,7 +21,7 @@
} }
.bp4-dialog-footer{ .bp4-dialog-footer{
padding-top: 10px; // padding-top: 10px;
} }
.bigcapital-datatable { .bigcapital-datatable {
@@ -30,6 +30,10 @@
border: 1px solid #d1dee2; border: 1px solid #d1dee2;
min-width: auto; min-width: auto;
.bp4-dark & {
border-color: var(--color-dark-gray5);
}
.tbody, .tbody,
.tbody-inner { .tbody-inner {
height: auto; height: auto;
@@ -43,6 +47,10 @@
padding: 0.4rem; padding: 0.4rem;
margin-left: -1px; margin-left: -1px;
border-left: 1px solid #ececec; border-left: 1px solid #ececec;
.bp4-dark & {
border-left-color: var(--color-dark-gray5);
}
} }
.bp4-form-group{ .bp4-form-group{
@@ -51,6 +59,10 @@
&:not(.bp4-intent-danger) .bp4-input{ &:not(.bp4-intent-danger) .bp4-input{
border: 1px solid #d0dfe2; border: 1px solid #d0dfe2;
.bp4-dark & {
border-color: var(--color-dark-gray5);
}
&:focus{ &:focus{
box-shadow: 0 0 0 1px #116cd0; box-shadow: 0 0 0 1px #116cd0;
border-color: #116cd0; border-color: #116cd0;