mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
feat(invoice): add branch & warehouse.
This commit is contained in:
34
src/containers/Sales/Invoices/InvoiceForm/BaseCurrency.js
Normal file
34
src/containers/Sales/Invoices/InvoiceForm/BaseCurrency.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { CurrencyTag } from 'components';
|
||||
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||
|
||||
/**
|
||||
* base currency sign.
|
||||
*/
|
||||
function BaseCurrency({
|
||||
// #withCurrentOrganization
|
||||
organization: { base_currency = '' },
|
||||
}) {
|
||||
// if (base_currency.length <= 0) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return (
|
||||
<BaseCurrencySign>
|
||||
<CurrencyTag>{base_currency}</CurrencyTag>
|
||||
</BaseCurrencySign>
|
||||
);
|
||||
}
|
||||
|
||||
export default R.compose(withCurrentOrganization())(BaseCurrency);
|
||||
|
||||
const BaseCurrencySign = styled.div`
|
||||
font-size: 10px;
|
||||
margin-left: 5px;
|
||||
span {
|
||||
background: #5c7080;
|
||||
}
|
||||
`;
|
||||
20
src/containers/Sales/Invoices/InvoiceForm/FlagKit.js
Normal file
20
src/containers/Sales/Invoices/InvoiceForm/FlagKit.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export default function FlagKit({ flage }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Img
|
||||
alt="flag"
|
||||
src={`https://cdn.jsdelivr.net/gh/madebybowtie/FlagKit@2.2/Assets/SVG/${flage}.svg`}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
const Img = styled.img`
|
||||
display: inline-block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
margin: 0 5px;
|
||||
`;
|
||||
@@ -16,6 +16,7 @@ import InvoiceItemsEntriesEditorField from './InvoiceItemsEntriesEditorField';
|
||||
import InvoiceFloatingActions from './InvoiceFloatingActions';
|
||||
import InvoiceFormFooter from './InvoiceFormFooter';
|
||||
import InvoiceFormDialogs from './InvoiceFormDialogs';
|
||||
import InvoiceFormTopBar from './InvoiceFormTopBar';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withMediaActions from 'containers/Media/withMediaActions';
|
||||
@@ -166,6 +167,7 @@ function InvoiceForm({
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<Form>
|
||||
<InvoiceFormTopBar />
|
||||
<InvoiceFormHeader />
|
||||
<InvoiceItemsEntriesEditorField />
|
||||
<InvoiceFormFooter />
|
||||
|
||||
@@ -4,12 +4,14 @@ import {
|
||||
InputGroup,
|
||||
Position,
|
||||
ControlGroup,
|
||||
Classes,
|
||||
} from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { FastField, Field, ErrorMessage } from 'formik';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
import { FormattedMessage as T, Col, Row } from 'components';
|
||||
import { momentFormatter, compose, tansformDateValue } from 'utils';
|
||||
import classNames from 'classnames';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
useObserveInvoiceNoSettings,
|
||||
@@ -19,15 +21,26 @@ import { CLASSES } from 'common/classes';
|
||||
import {
|
||||
CustomerSelectField,
|
||||
FieldRequiredHint,
|
||||
ListSelect,
|
||||
Icon,
|
||||
InputPrependButton,
|
||||
MoneyInputGroup,
|
||||
} from 'components';
|
||||
import ItemsSuggestField from 'components/ItemsSuggestField';
|
||||
import { useInvoiceFormContext } from './InvoiceFormProvider';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { inputIntent, handleDateChange } from 'utils';
|
||||
import BaseCurrency from './BaseCurrency';
|
||||
import FlagKit from './FlagKit';
|
||||
|
||||
const Data = [
|
||||
{
|
||||
id: '10',
|
||||
name: 'Due on Receipt',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Invoice form header fields.
|
||||
@@ -69,89 +82,158 @@ function InvoiceFormHeaderFields({
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customerNameFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer_name'} />}
|
||||
inline={true}
|
||||
className={classNames(
|
||||
'form-group--customer-name',
|
||||
'form-group--select-list',
|
||||
CLASSES.FILL,
|
||||
<CustomerName>
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customerNameFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer_name'} />}
|
||||
inline={true}
|
||||
className={classNames(
|
||||
'form-group--customer-name',
|
||||
'form-group--select-list',
|
||||
CLASSES.FILL,
|
||||
)}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'customer_id'} />}
|
||||
>
|
||||
<CustomerSelectField
|
||||
contacts={customers}
|
||||
selectedContactId={value}
|
||||
defaultSelectText={<T id={'select_customer_account'} />}
|
||||
onContactSelected={(customer) => {
|
||||
form.setFieldValue('customer_id', customer.id);
|
||||
}}
|
||||
popoverFill={true}
|
||||
allowCreate={true}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<BaseCurrency />
|
||||
</CustomerName>
|
||||
<ExchangeWrapp>
|
||||
<ExchangeLable>
|
||||
<FlagKit flage={'US'} /> 1 USD =
|
||||
</ExchangeLable>
|
||||
|
||||
{/* ----------- Exchange reate ----------- */}
|
||||
<Field name={'exchange_rate'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field,
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
intent={inputIntent({ error, touched })}
|
||||
inline={true}
|
||||
className={'form-group--exchange_rate'}
|
||||
helperText={<ErrorMessage name="exchange_rate" />}
|
||||
>
|
||||
<MoneyInputGroup
|
||||
value={field.value}
|
||||
allowDecimals={false}
|
||||
allowNegativeValue={true}
|
||||
onChange={(value) => {}}
|
||||
intent={inputIntent({ error, touched })}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</Field>
|
||||
<ExchangeLable>
|
||||
<FlagKit flage={'LY'} /> LYD
|
||||
</ExchangeLable>
|
||||
</ExchangeWrapp>
|
||||
<Row>
|
||||
<Col xs={6}>
|
||||
{/* ----------- Invoice date ----------- */}
|
||||
<FastField name={'invoice_date'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'invoice_date'} />}
|
||||
inline={true}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
className={classNames('form-group--invoice-date', CLASSES.FILL)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="invoice_date" />}
|
||||
>
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={tansformDateValue(value)}
|
||||
onChange={handleDateChange((formattedDate) => {
|
||||
form.setFieldValue('invoice_date', formattedDate);
|
||||
})}
|
||||
popoverProps={{
|
||||
position: Position.BOTTOM_LEFT,
|
||||
minimal: true,
|
||||
}}
|
||||
inputProps={{
|
||||
leftIcon: <Icon icon={'date-range'} />,
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'customer_id'} />}
|
||||
>
|
||||
<CustomerSelectField
|
||||
contacts={customers}
|
||||
selectedContactId={value}
|
||||
defaultSelectText={<T id={'select_customer_account'} />}
|
||||
onContactSelected={(customer) => {
|
||||
form.setFieldValue('customer_id', customer.id);
|
||||
}}
|
||||
popoverFill={true}
|
||||
allowCreate={true}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- Invoice date ----------- */}
|
||||
<FastField name={'invoice_date'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'invoice_date'} />}
|
||||
inline={true}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
className={classNames('form-group--invoice-date', CLASSES.FILL)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="invoice_date" />}
|
||||
>
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={tansformDateValue(value)}
|
||||
onChange={handleDateChange((formattedDate) => {
|
||||
form.setFieldValue('invoice_date', formattedDate);
|
||||
})}
|
||||
popoverProps={{ position: Position.BOTTOM_LEFT, minimal: true }}
|
||||
inputProps={{
|
||||
leftIcon: <Icon icon={'date-range'} />,
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- Due date ----------- */}
|
||||
<FastField name={'due_date'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'due_date'} />}
|
||||
inline={true}
|
||||
className={classNames('form-group--due-date', CLASSES.FILL)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="due_date" />}
|
||||
>
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={tansformDateValue(value)}
|
||||
onChange={handleDateChange((formattedDate) => {
|
||||
form.setFieldValue('due_date', formattedDate);
|
||||
})}
|
||||
popoverProps={{ position: Position.BOTTOM_LEFT, minimal: true }}
|
||||
inputProps={{
|
||||
leftIcon: <Icon icon={'date-range'} />,
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
</FastField>
|
||||
</Col>
|
||||
<Col className={'col--terms'}>
|
||||
{/* ----------- Terms ----------- */}
|
||||
<FastField name={'terms'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={'Terms'}
|
||||
inline={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="terms" />}
|
||||
>
|
||||
<ListSelect
|
||||
items={Data}
|
||||
onItemSelect={({ id }) => {
|
||||
form.setFieldValue('terms', id);
|
||||
}}
|
||||
selectedItem={value}
|
||||
selectedItemProp={'value'}
|
||||
textProp={'name'}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</Col>
|
||||
<Col className={'col--due-date'}>
|
||||
{/* ----------- Due date ----------- */}
|
||||
<FastField name={'due_date'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'due_date'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
inline={true}
|
||||
className={classNames('form-group--due-date', CLASSES.FILL)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="due_date" />}
|
||||
>
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={tansformDateValue(value)}
|
||||
onChange={handleDateChange((formattedDate) => {
|
||||
form.setFieldValue('due_date', formattedDate);
|
||||
})}
|
||||
popoverProps={{
|
||||
position: Position.BOTTOM_LEFT,
|
||||
minimal: true,
|
||||
}}
|
||||
inputProps={{
|
||||
leftIcon: <Icon icon={'date-range'} />,
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</Col>
|
||||
</Row>
|
||||
{/* ----------- Invoice number ----------- */}
|
||||
<Field name={'invoice_no'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
@@ -214,3 +296,28 @@ export default compose(
|
||||
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
|
||||
})),
|
||||
)(InvoiceFormHeaderFields);
|
||||
|
||||
const CustomerName = styled.div`
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
`;
|
||||
|
||||
const ExchangeWrapp = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
max-width: 370px;
|
||||
.bp3-form-group.bp3-inline {
|
||||
width: 88px;
|
||||
}
|
||||
`;
|
||||
|
||||
const ExchangeLable = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
margin-right: 5px;
|
||||
font-size: 10px;
|
||||
line-height: 1.6;
|
||||
padding-bottom: calc(1rem + 1px);
|
||||
`;
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
useInvoice,
|
||||
useItems,
|
||||
useCustomers,
|
||||
useWarehouses,
|
||||
useBranches,
|
||||
useCreateInvoice,
|
||||
useEditInvoice,
|
||||
useSettingsInvoices,
|
||||
@@ -53,6 +55,12 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
|
||||
isLoading: isCustomersLoading,
|
||||
} = useCustomers({ page_size: 10000 });
|
||||
|
||||
// Fetch warehouses list.
|
||||
const { data: warehouses, isLoading: isWarehouesLoading } = useWarehouses();
|
||||
|
||||
// Fetches the branches list.
|
||||
const { data: branches, isLoading: isBranchesLoading } = useBranches();
|
||||
|
||||
// Handle fetching settings.
|
||||
const { isLoading: isSettingsLoading } = useSettingsInvoices();
|
||||
|
||||
@@ -75,6 +83,8 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
|
||||
estimateId,
|
||||
invoiceId,
|
||||
submitPayload,
|
||||
branches,
|
||||
warehouses,
|
||||
|
||||
isInvoiceLoading,
|
||||
isItemsLoading,
|
||||
@@ -94,6 +104,8 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
|
||||
isItemsLoading ||
|
||||
isCustomersLoading ||
|
||||
isEstimateLoading ||
|
||||
isWarehouesLoading ||
|
||||
isBranchesLoading ||
|
||||
isSettingsLoading
|
||||
}
|
||||
name={'invoice-form'}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { FastField } from 'formik';
|
||||
import {
|
||||
Alignment,
|
||||
Navbar,
|
||||
NavbarGroup,
|
||||
NavbarDivider,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
import { Icon, FormattedMessage as T, CustomSelectList } from 'components';
|
||||
|
||||
import { useInvoiceFormContext } from './InvoiceFormProvider';
|
||||
|
||||
export default function InvoiceFormTopBar() {
|
||||
const { warehouses, branches } = useInvoiceFormContext();
|
||||
|
||||
return (
|
||||
<Navbar className={'navbar--dashboard-topbar'}>
|
||||
<NavbarGroup align={Alignment.LEFT}>
|
||||
<FastField name={'branch'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<CustomSelectList
|
||||
items={branches}
|
||||
text={'Branch'}
|
||||
onItemSelected={(item) => {
|
||||
form.setFieldValue('name', item.id);
|
||||
}}
|
||||
selectedItemId={value}
|
||||
buttonProps={{
|
||||
icon: <Icon icon={'domain-16'} iconSize={20} />,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<NavbarDivider />
|
||||
<FastField name={'warehouse'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<CustomSelectList
|
||||
items={warehouses}
|
||||
text={'Warehosue'}
|
||||
onItemSelected={(item) => {
|
||||
form.setFieldValue('warehouse', item.id);
|
||||
}}
|
||||
selectedItemId={value}
|
||||
buttonProps={{
|
||||
icon: <Icon icon={'warehouse-16'} iconSize={20} />,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</FastField>
|
||||
</NavbarGroup>
|
||||
</Navbar>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user