feat(purchases): add purchases.

This commit is contained in:
elforjani13
2022-03-20 17:56:37 +02:00
parent 39a68f5c25
commit e51f203ca8
16 changed files with 214 additions and 64 deletions

View File

@@ -8,6 +8,7 @@ function VendorDrawerLinkComponent({
// #ownProps
children,
vendorId,
className,
// #withDrawerActions
openDrawer,
@@ -18,7 +19,7 @@ function VendorDrawerLinkComponent({
event.preventDefault();
};
return <ButtonLink onClick={handleVendorDrawer}>{children}</ButtonLink>;
return <ButtonLink className={className} onClick={handleVendorDrawer}>{children}</ButtonLink>;
}
export const VendorDrawerLink = R.compose(withDrawerActions)(VendorDrawerLinkComponent);

View File

@@ -13,10 +13,10 @@ import styled from 'styled-components';
import { CLASSES } from 'common/classes';
import {
FFormGroup,
VendorSelectField,
FieldRequiredHint,
Icon,
CustomerDrawerLink,
VendorDrawerLink,
} from 'components';
import { vendorsFieldShouldUpdate } from './utils';
@@ -48,17 +48,16 @@ function BillFormHeader() {
shouldUpdate={vendorsFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
className={classNames(
'form-group--customer-name',
'form-group--vendor-name',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'vendor_id'} />}
>
<ControlVendorGroup>
<VendorSelectField
@@ -75,10 +74,10 @@ function BillFormHeader() {
</ControlVendorGroup>
{value && (
<VendorButtonLink vendorId={value}>
View Vendor Details
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FormGroup>
</FFormGroup>
)}
</FastField>

View File

@@ -7,8 +7,11 @@ import {
TotalLineBorderStyle,
TotalLineTextStyle,
} from 'components';
import { useVendorCrditNoteTotals } from './utils';
export function VendorCreditNoteFormFooterRight() {
const { formattedSubtotal, formattedTotal } = useVendorCrditNoteTotals();
return (
<VendorCreditNoteTotalLines
labelColWidth={'180px'}
@@ -16,12 +19,12 @@ export function VendorCreditNoteFormFooterRight() {
>
<TotalLine
title={<T id={'credit_note.drawer.label_subtotal'} />}
value={'$5000.00'}
value={formattedSubtotal}
borderStyle={TotalLineBorderStyle.None}
/>
<TotalLine
title={<T id={'credit_note.drawer.label_total'} />}
value={'$5000.00'}
value={formattedTotal}
// borderStyle={TotalLineBorderStyle.SingleDark}
textStyle={TotalLineTextStyle.Bold}
/>

View File

@@ -6,19 +6,19 @@ import {
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FastField, Field, ErrorMessage } from 'formik';
import { FastField, ErrorMessage } from 'formik';
import { CLASSES } from 'common/classes';
import classNames from 'classnames';
import styled from 'styled-components';
import {
FFormGroup,
VendorSelectField,
FieldRequiredHint,
InputPrependButton,
ExchangeRateInputGroup,
Icon,
If,
FormattedMessage as T,
VendorDrawerLink,
} from 'components';
import {
vendorsFieldShouldUpdate,
@@ -26,7 +26,7 @@ import {
} from './utils';
import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
import VendorCreditNoteFormCurrencyTag from './VendorCreditNoteFormCurrencyTag';
import { VendorCreditNoteExchangeRateInputField } from './components';
import {
momentFormatter,
compose,
@@ -51,13 +51,7 @@ function VendorCreditNoteFormHeaderFields({
vendorcreditNextNumber,
}) {
// Vendor Credit form context.
const {
vendors,
isForeignVendor,
baseCurrency,
selectVendor,
setSelectVendor,
} = useVendorCreditNoteFormContext();
const { vendors } = useVendorCreditNoteFormContext();
// Handle vendor credit number changing.
const handleVendorCreditNumberChange = () => {
@@ -92,13 +86,12 @@ function VendorCreditNoteFormHeaderFields({
shouldUpdate={vendorsFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
className={classNames(CLASSES.FILL, 'form-group--vendor')}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'vendor_id'} />}
>
<ControlVendorGroup>
<VendorSelectField
@@ -108,25 +101,25 @@ function VendorCreditNoteFormHeaderFields({
onContactSelected={(contact) => {
form.setFieldValue('vendor_id', contact.id);
form.setFieldValue('currency_code', contact?.currency_code);
setSelectVendor(contact);
}}
popoverFill={true}
allowCreate={true}
/>
</ControlVendorGroup>
</FormGroup>
{value && (
<VendorButtonLink vendorId={value}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */}
<If condition={isForeignVendor}>
<ExchangeRateInputGroup
fromCurrency={baseCurrency}
toCurrency={selectVendor?.currency_code}
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
</If>
<VendorCreditNoteExchangeRateInputField
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
{/* ------- Vendor Credit date ------- */}
<FastField name={'vendor_credit_date'}>
@@ -226,3 +219,8 @@ const ControlVendorGroup = styled(ControlGroup)`
align-items: center;
transform: none;
`;
const VendorButtonLink = styled(VendorDrawerLink)`
font-size: 11px;
margin-top: 6px;
`;

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { useFormikContext } from 'formik';
import { ExchangeRateInputGroup } from 'components';
import { useCurrentOrganization } from 'hooks/state';
import { useVendorNoteIsForeignCustomer } from './utils';
/**
* vendor credit note exchange rate input field.
* @returns {JSX.Element}
*/
export function VendorCreditNoteExchangeRateInputField({ ...props }) {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
const isForeignCustomer = useVendorNoteIsForeignCustomer();
// Can't continue if the customer is not foreign.
if (!isForeignCustomer) {
return null;
}
return (
<ExchangeRateInputGroup
fromCurrency={values.currency_code}
toCurrency={currentOrganization.base_currency}
{...props}
/>
);
}

View File

@@ -9,6 +9,7 @@ import {
repeatValue,
transactionNumber,
orderingLinesIndexes,
formattedAmount,
} from 'utils';
import {
updateItemsEntriesTotal,
@@ -16,6 +17,8 @@ import {
} from 'containers/Entries/utils';
import { useFormikContext } from 'formik';
import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
import { useCurrentOrganization } from 'hooks/state';
import { getEntriesTotal } from 'containers/Entries/utils';
export const MIN_LINES_NUMBER = 1;
@@ -166,3 +169,44 @@ export const useSetPrimaryWarehouseToForm = () => {
}
}, [isWarehousesSuccess, setFieldValue, warehouses]);
};
export const useVendorCrditNoteTotals = () => {
const {
values: { entries, currency_code: currencyCode },
} = useFormikContext();
// Retrieves the invoice entries total.
const total = React.useMemo(() => getEntriesTotal(entries), [entries]);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),
[total, currencyCode],
);
// Retrieves the formatted subtotal.
const formattedSubtotal = React.useMemo(
() => formattedAmount(total, currencyCode, { money: false }),
[total, currencyCode],
);
return {
total,
formattedTotal,
formattedSubtotal,
};
};
/**
* Detarmines whether the vendor note has foreign customer.
* @returns {boolean}
*/
export const useVendorNoteIsForeignCustomer = () => {
const { values } = useFormikContext();
const currentOrganization = useCurrentOrganization();
const isForeignCustomer = React.useMemo(
() => values.currency_code !== currentOrganization.base_currency,
[values.currency_code, currentOrganization.base_currency],
);
return isForeignCustomer;
};

View File

@@ -7,18 +7,20 @@ import {
TotalLineBorderStyle,
TotalLineTextStyle,
} from 'components';
import { usePaymentMadeTotals } from './utils';
export function PaymentMadeFormFooterRight() {
const { formattedSubtotal, formattedTotal } = usePaymentMadeTotals();
return (
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
<TotalLine
title={<T id={'estimate.details.subtotal'} />}
value={'$5000.00'}
value={formattedSubtotal}
borderStyle={TotalLineBorderStyle.None}
/>
<TotalLine
title={<T id={'estimate.details.total'} />}
value={'$5000.00'}
value={formattedTotal}
// borderStyle={TotalLineBorderStyle.SingleDark}
textStyle={TotalLineTextStyle.Bold}
/>

View File

@@ -16,21 +16,21 @@ import { CLASSES } from 'common/classes';
import styled from 'styled-components';
import {
FFormGroup,
AccountsSelectList,
VendorSelectField,
FieldRequiredHint,
InputPrependText,
Money,
Hint,
If,
Icon,
VendorDrawerLink,
MoneyInputGroup,
ExchangeRateInputGroup,
} from 'components';
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
import { usePaymentMadeFormContext } from './PaymentMadeFormProvider';
import { ACCOUNT_TYPE } from 'common/accountTypes';
import PaymentMadeFormCurrencyTag from './PaymentMadeFormCurrencyTag';
import { PaymentMadeExchangeRateInputField } from './components';
import {
momentFormatter,
tansformDateValue,
@@ -62,7 +62,6 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
isForeignVendor,
baseCurrency,
selectVendor,
setSelectVendor,
} = usePaymentMadeFormContext();
// Sumation of payable full-amount.
@@ -95,13 +94,12 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
shouldUpdate={vendorsFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
className={classNames('form-group--select-list', Classes.FILL)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'vendor_id'} />}
>
<ControlVendorGroup>
<VendorSelectField
@@ -112,26 +110,26 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
form.setFieldValue('vendor_id', contact.id);
form.setFieldValue('currency_code', contact?.currency_code);
setPaymentVendorId(contact.id);
setSelectVendor(contact);
}}
disabled={!isNewMode}
popoverFill={true}
allowCreate={true}
/>
</ControlVendorGroup>
</FormGroup>
{value && (
<VendorButtonLink vendorId={value}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */}
<If condition={isForeignVendor}>
<ExchangeRateInputGroup
fromCurrency={baseCurrency}
toCurrency={selectVendor?.currency_code}
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
</If>
<PaymentMadeExchangeRateInputField
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
{/* ------------ Payment date ------------ */}
<FastField name={'payment_date'}>
@@ -285,3 +283,8 @@ const ControlVendorGroup = styled(ControlGroup)`
align-items: center;
transform: none;
`;
const VendorButtonLink = styled(VendorDrawerLink)`
font-size: 11px;
margin-top: 6px;
`;

View File

@@ -1,9 +1,12 @@
import React from 'react';
import intl from 'react-intl-universal';
import moment from 'moment';
import { Money } from 'components';
import { Money, ExchangeRateInputGroup } from 'components';
import { safeSumBy, formattedAmount } from 'utils';
import { MoneyFieldCell } from 'components/DataTableCells';
import { useFormikContext } from 'formik';
import { useCurrentOrganization } from 'hooks/state';
import { usePaymentMadeIsForeignCustomer } from './utils';
function BillNumberAccessor(row) {
return row?.bill_no ? row?.bill_no : '-';
@@ -51,8 +54,6 @@ function MoneyTableCell({ row: { original }, value }) {
* Payment made entries table columns
*/
export function usePaymentMadeEntriesTableColumns() {
return React.useMemo(
() => [
{
@@ -107,3 +108,26 @@ export function usePaymentMadeEntriesTableColumns() {
[],
);
}
/**
* payment made exchange rate input field.
* @returns {JSX.Element}
*/
export function PaymentMadeExchangeRateInputField({ ...props }) {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
const isForeignCustomer = usePaymentMadeIsForeignCustomer();
// Can't continue if the customer is not foreign.
if (!isForeignCustomer) {
return null;
}
return (
<ExchangeRateInputGroup
fromCurrency={values.currency_code}
toCurrency={currentOrganization.base_currency}
{...props}
/>
);
}

View File

@@ -11,7 +11,10 @@ import {
safeSumBy,
transformToForm,
orderingLinesIndexes,
formattedAmount,
} from 'utils';
import { getEntriesTotal } from '../../../Entries/utils';
import { useCurrentOrganization } from 'hooks/state';
export const ERRORS = {
PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE',
@@ -126,8 +129,51 @@ export const transformErrors = (errors, { setFieldError }) => {
}
if (getError('WITHDRAWAL_ACCOUNT_CURRENCY_INVALID')) {
AppToaster.show({
message: intl.get('payment_made.error.withdrawal_account_currency_invalid'),
message: intl.get(
'payment_made.error.withdrawal_account_currency_invalid',
),
intent: Intent.DANGER,
});
}
};
export const usePaymentMadeTotals = () => {
const {
values: { entries, currency_code: currencyCode },
} = useFormikContext();
// Retrieves the invoice entries total.
const total = React.useMemo(() => getEntriesTotal(entries), [entries]);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),
[total, currencyCode],
);
// Retrieves the formatted subtotal.
const formattedSubtotal = React.useMemo(
() => formattedAmount(total, currencyCode, { money: false }),
[total, currencyCode],
);
return {
total,
formattedTotal,
formattedSubtotal,
};
};
/**
* Detarmines whether the bill has foreign customer.
* @returns {boolean}
*/
export const usePaymentMadeIsForeignCustomer = () => {
const { values } = useFormikContext();
const currentOrganization = useCurrentOrganization();
const isForeignCustomer = React.useMemo(
() => values.currency_code !== currentOrganization.base_currency,
[values.currency_code, currentOrganization.base_currency],
);
return isForeignCustomer;
};

View File

@@ -108,7 +108,7 @@ function CreditNoteFormHeaderFields({
</ControlCustomerGroup>
{value && (
<CustomerButtonLink customerId={value}>
View Customer Details
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>

View File

@@ -101,7 +101,7 @@ function EstimateFormHeader({
</ControlCustomerGroup>
{value && (
<CustomerButtonLink customerId={value}>
View Customer Details
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>

View File

@@ -107,7 +107,7 @@ function InvoiceFormHeaderFields({
</ControlCustomerGroup>
{value && (
<CustomerButtonLink customerId={value}>
View Customer Details
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>

View File

@@ -158,7 +158,7 @@ function PaymentReceiveHeaderFields({
</ControlCustomerGroup>
{value && (
<CustomerButtonLink customerId={value}>
View Customer Details
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>

View File

@@ -105,7 +105,7 @@ function ReceiptFormHeader({
</ControlCustomerGroup>
{value && (
<CustomerButtonLink customerId={value}>
View Customer Details
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>

View File

@@ -1912,6 +1912,8 @@
"warehouse.error.warehouse_has_associated_transactions": "You could not delete the warehouse that has associated transactions.",
"branche.error.warehouse_code_not_unique": "Branch code not unique",
"branche.error.branch_has_associated_transactions": "You could not delete the branch that has associated transactions.",
"payment_Receive.error.payment_account_currency_invalid":"The deposit account currency should be same customer currency or organization base currency.",
"payment_made.error.withdrawal_account_currency_invalid":"The withdrawal account currency should be same vendor currency or organization base currency."
"payment_Receive.error.payment_account_currency_invalid": "The deposit account currency should be same customer currency or organization base currency.",
"payment_made.error.withdrawal_account_currency_invalid": "The withdrawal account currency should be same vendor currency or organization base currency.",
"view_customer_details": "View Customer Details",
"view_vendor_details":"View Vendor Details"
}