mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
PaymentMadeAction,
|
||||
AbilitySubject,
|
||||
} from '../../../common/abilityOption';
|
||||
import { BillMenuItem } from './utils';
|
||||
|
||||
import { safeCallback, compose } from 'utils';
|
||||
|
||||
@@ -50,6 +51,14 @@ function BillDetailActionsBar({
|
||||
closeDrawer('bill-drawer');
|
||||
};
|
||||
|
||||
// Handle convert to vendor credit.
|
||||
const handleConvertToVendorCredit = () => {
|
||||
history.push(`/vendor-credits/new?from_bill_id=${billId}`, {
|
||||
billId: billId,
|
||||
});
|
||||
closeDrawer('bill-drawer');
|
||||
};
|
||||
|
||||
// Handle delete bill.
|
||||
const onDeleteBill = () => {
|
||||
openAlert('bill-delete', { billId });
|
||||
@@ -92,6 +101,14 @@ function BillDetailActionsBar({
|
||||
onClick={safeCallback(onDeleteBill)}
|
||||
/>
|
||||
</Can>
|
||||
<Can I={BillAction.Edit} a={AbilitySubject.Bill}>
|
||||
<NavbarDivider />
|
||||
<BillMenuItem
|
||||
payload={{
|
||||
onConvert: handleConvertToVendorCredit,
|
||||
}}
|
||||
/>
|
||||
</Can>
|
||||
</NavbarGroup>
|
||||
</DrawerActionsBar>
|
||||
);
|
||||
|
||||
@@ -1,51 +1,27 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
TotalLineBorderStyle,
|
||||
TotalLineTextStyle,
|
||||
FormatNumber,
|
||||
CommercialDocFooter,
|
||||
T,
|
||||
TotalLines,
|
||||
TotalLine,
|
||||
} from '../../../components';
|
||||
If,
|
||||
DetailsMenu,
|
||||
DetailItem,
|
||||
} from 'components';
|
||||
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
|
||||
/**
|
||||
* Bill read-only details footer.
|
||||
* Bill detail footer.
|
||||
* @returns {React.JSX}
|
||||
*/
|
||||
export function BillDetailFooter() {
|
||||
export default function BillDetailFooter() {
|
||||
const { bill } = useBillDrawerContext();
|
||||
|
||||
return (
|
||||
<BillDetailsFooterRoot>
|
||||
<BillTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.subtotal'} />}
|
||||
value={<FormatNumber value={bill.amont} />}
|
||||
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.total'} />}
|
||||
value={bill.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.payment_amount'} />}
|
||||
value={bill.formatted_payment_amount}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.due_amount'} />}
|
||||
value={bill.formatted_due_amount}
|
||||
/>
|
||||
</BillTotalLines>
|
||||
</BillDetailsFooterRoot>
|
||||
<CommercialDocFooter>
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||
<If condition={bill.note}>
|
||||
<DetailItem label={<T id={'note'} />}>{bill.note}</DetailItem>
|
||||
</If>
|
||||
</DetailsMenu>
|
||||
</CommercialDocFooter>
|
||||
);
|
||||
}
|
||||
|
||||
export const BillDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const BillTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
@@ -4,8 +4,8 @@ import { CommercialDocBox } from 'components';
|
||||
|
||||
import BillDetailHeader from './BillDetailHeader';
|
||||
import BillDetailTable from './BillDetailTable';
|
||||
import { BillDetailFooter } from './BillDetailFooter';
|
||||
|
||||
import { BillDetailTableFooter } from './BillDetailTableFooter';
|
||||
import BillDetailFooter from './BillDetailFooter';
|
||||
|
||||
/**
|
||||
* Bill detail panel tab.
|
||||
@@ -15,6 +15,7 @@ export default function BillDetailTab() {
|
||||
<CommercialDocBox>
|
||||
<BillDetailHeader />
|
||||
<BillDetailTable />
|
||||
<BillDetailTableFooter />
|
||||
<BillDetailFooter />
|
||||
</CommercialDocBox>
|
||||
);
|
||||
|
||||
51
src/containers/Drawers/BillDrawer/BillDetailTableFooter.js
Normal file
51
src/containers/Drawers/BillDrawer/BillDetailTableFooter.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
TotalLineBorderStyle,
|
||||
TotalLineTextStyle,
|
||||
FormatNumber,
|
||||
T,
|
||||
TotalLines,
|
||||
TotalLine,
|
||||
} from '../../../components';
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
|
||||
/**
|
||||
* Bill read-only details table footer.
|
||||
*/
|
||||
export function BillDetailTableFooter() {
|
||||
const { bill } = useBillDrawerContext();
|
||||
|
||||
return (
|
||||
<BillDetailsFooterRoot>
|
||||
<BillTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.subtotal'} />}
|
||||
value={<FormatNumber value={bill.amont} />}
|
||||
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.total'} />}
|
||||
value={bill.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.payment_amount'} />}
|
||||
value={bill.formatted_payment_amount}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'bill.details.due_amount'} />}
|
||||
value={bill.formatted_due_amount}
|
||||
/>
|
||||
</BillTotalLines>
|
||||
</BillDetailsFooterRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const BillDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const BillTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
@@ -1,12 +1,21 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import styled from 'styled-components';
|
||||
import { Intent, Tag } from '@blueprintjs/core';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
PopoverInteractionKind,
|
||||
Position,
|
||||
MenuItem,
|
||||
Menu,
|
||||
Intent,
|
||||
Tag,
|
||||
} from '@blueprintjs/core';
|
||||
import {
|
||||
FormatNumberCell,
|
||||
FormattedMessage as T,
|
||||
Choose,
|
||||
Icon,
|
||||
} from '../../../components';
|
||||
|
||||
/**
|
||||
@@ -73,7 +82,7 @@ export function BillDetailsStatus({ bill }) {
|
||||
<Choose>
|
||||
<Choose.When condition={bill.is_overdue}>
|
||||
<StatusTag intent={Intent.WARNING} round={true}>
|
||||
Overdue
|
||||
<T id={'overdue'} />
|
||||
</StatusTag>
|
||||
</Choose.When>
|
||||
<Choose.Otherwise>
|
||||
@@ -92,6 +101,29 @@ export function BillDetailsStatus({ bill }) {
|
||||
);
|
||||
}
|
||||
|
||||
export const BillMenuItem = ({ payload: { onConvert } }) => {
|
||||
return (
|
||||
<Popover
|
||||
minimal={true}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
modifiers={{
|
||||
offset: { offset: '0, 4' },
|
||||
}}
|
||||
content={
|
||||
<Menu>
|
||||
<MenuItem
|
||||
onClick={onConvert}
|
||||
text={<T id={'convert_to_vendor_credit'} />}
|
||||
/>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Button icon={<Icon icon="more-vert" iconSize={16} />} minimal={true} />
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
const StatusTag = styled(Tag)`
|
||||
min-width: 65px;
|
||||
text-align: center;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
CommercialDocFooter,
|
||||
T,
|
||||
If,
|
||||
DetailsMenu,
|
||||
DetailItem,
|
||||
} from 'components';
|
||||
|
||||
import { useCreditNoteDetailDrawerContext } from './CreditNoteDetailDrawerProvider';
|
||||
|
||||
/**
|
||||
* Credit note detail footer
|
||||
* @returns {React.JSX}
|
||||
*/
|
||||
export default function CreditNoteDetailFooter() {
|
||||
const { creditNote } = useCreditNoteDetailDrawerContext();
|
||||
return (
|
||||
<CommercialDocFooter>
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||
<If condition={creditNote.terms_conditions}>
|
||||
<DetailItem label={<T id={'credit_note.drawer.terms_conditions'} />}>
|
||||
{creditNote.terms_conditions}
|
||||
</DetailItem>
|
||||
</If>
|
||||
</DetailsMenu>
|
||||
</CommercialDocFooter>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,8 @@ import { CommercialDocBox } from 'components';
|
||||
|
||||
import CreditNoteDetailHeader from './CreditNoteDetailHeader';
|
||||
import CreditNoteDetailTable from './CreditNoteDetailTable';
|
||||
import CreditNoteDetailDrawerFooter from './CreditNoteDetailDrawerFooter';
|
||||
import CreditNoteDetailTableFooter from './CreditNoteDetailTableFooter';
|
||||
import CreditNoteDetailFooter from './CreditNoteDetailFooter';
|
||||
|
||||
/**
|
||||
* Credit note details panel.
|
||||
@@ -14,7 +15,8 @@ export default function CreditNoteDetailPanel() {
|
||||
<CommercialDocBox>
|
||||
<CreditNoteDetailHeader />
|
||||
<CreditNoteDetailTable />
|
||||
<CreditNoteDetailDrawerFooter />
|
||||
<CreditNoteDetailTableFooter />
|
||||
<CreditNoteDetailFooter />
|
||||
</CommercialDocBox>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useCreditNoteDetailDrawerContext } from './CreditNoteDetailDrawerProvid
|
||||
/**
|
||||
* Credit note details panel footer.
|
||||
*/
|
||||
export default function CreditNoteDetailDrawerFooter() {
|
||||
export default function CreditNoteDetailTableFooter() {
|
||||
const { creditNote } = useCreditNoteDetailDrawerContext();
|
||||
|
||||
return (
|
||||
@@ -1,43 +1,35 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
CommercialDocFooter,
|
||||
T,
|
||||
TotalLines,
|
||||
TotalLine,
|
||||
TotalLineBorderStyle,
|
||||
TotalLineTextStyle,
|
||||
FormatNumber,
|
||||
If,
|
||||
DetailsMenu,
|
||||
DetailItem,
|
||||
} from 'components';
|
||||
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';
|
||||
|
||||
/**
|
||||
* Estimate details panel footer content.
|
||||
* Estimate details footer.
|
||||
* @returns {React.JSX}
|
||||
*/
|
||||
export default function EstimateDetailFooter() {
|
||||
const { estimate } = useEstimateDetailDrawerContext();
|
||||
|
||||
|
||||
return (
|
||||
<EstimateDetailsFooterRoot>
|
||||
<EstimateTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||
<TotalLine
|
||||
title={<T id={'estimate.details.subtotal'} />}
|
||||
value={<FormatNumber value={estimate.amount} />}
|
||||
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'estimate.details.total'} />}
|
||||
value={estimate.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
</EstimateTotalLines>
|
||||
</EstimateDetailsFooterRoot>
|
||||
<CommercialDocFooter>
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||
<If condition={estimate.terms_conditions}>
|
||||
<DetailItem label={<T id={'estimate.details.terms_conditions'} />}>
|
||||
{estimate.terms_conditions}
|
||||
</DetailItem>
|
||||
</If>
|
||||
<If condition={estimate.note}>
|
||||
<DetailItem label={<T id={'estimate.details.note'} />}>
|
||||
{estimate.note}
|
||||
</DetailItem>
|
||||
</If>
|
||||
</DetailsMenu>
|
||||
</CommercialDocFooter>
|
||||
);
|
||||
}
|
||||
|
||||
export const EstimateDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const EstimateTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
@@ -4,13 +4,16 @@ import { CommercialDocBox } from 'components';
|
||||
|
||||
import EstimateDetailHeader from './EstimateDetailHeader';
|
||||
import EstimateDetailTable from './EstimateDetailTable';
|
||||
import EstimateDetailTableFooter from './EstimateDetailTableFooter';
|
||||
import EstimateDetailFooter from './EstimateDetailFooter';
|
||||
|
||||
|
||||
export default function EstimateDetailTab() {
|
||||
return (
|
||||
<CommercialDocBox>
|
||||
<EstimateDetailHeader />
|
||||
<EstimateDetailTable />
|
||||
<EstimateDetailTableFooter />
|
||||
<EstimateDetailFooter />
|
||||
</CommercialDocBox>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
T,
|
||||
TotalLines,
|
||||
TotalLine,
|
||||
TotalLineBorderStyle,
|
||||
TotalLineTextStyle,
|
||||
FormatNumber,
|
||||
} from 'components';
|
||||
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';
|
||||
|
||||
/**
|
||||
* Estimate details panel footer content.
|
||||
*/
|
||||
export default function EstimateDetailTableFooter() {
|
||||
const { estimate } = useEstimateDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<EstimateDetailsFooterRoot>
|
||||
<EstimateTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||
<TotalLine
|
||||
title={<T id={'estimate.details.subtotal'} />}
|
||||
value={<FormatNumber value={estimate.amount} />}
|
||||
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'estimate.details.total'} />}
|
||||
value={estimate.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
</EstimateTotalLines>
|
||||
</EstimateDetailsFooterRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const EstimateDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const EstimateTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
@@ -5,7 +5,7 @@ export const useInventoryAdjustmentEntriesColumns = () =>
|
||||
React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: intl.get('product_and_service'),
|
||||
Header: intl.get('inventory_adjustment.column.product'),
|
||||
accessor: 'item.name',
|
||||
width: 150,
|
||||
className: 'name',
|
||||
|
||||
@@ -14,7 +14,13 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { If, Can, Icon, DrawerActionsBar, FormattedMessage as T } from 'components';
|
||||
import {
|
||||
If,
|
||||
Can,
|
||||
Icon,
|
||||
DrawerActionsBar,
|
||||
FormattedMessage as T,
|
||||
} from 'components';
|
||||
import {
|
||||
SaleInvoiceAction,
|
||||
PaymentReceiveAction,
|
||||
@@ -48,6 +54,14 @@ function InvoiceDetailActionsBar({
|
||||
closeDrawer('invoice-detail-drawer');
|
||||
};
|
||||
|
||||
// Handle convert to invoice.
|
||||
const handleConvertToCreitNote = () => {
|
||||
history.push(`/credit-notes/new?from_invoice_id=${invoiceId}`, {
|
||||
invoiceId: invoiceId,
|
||||
});
|
||||
closeDrawer('invoice-detail-drawer');
|
||||
};
|
||||
|
||||
// Handle delete sale invoice.
|
||||
const handleDeleteInvoice = () => {
|
||||
openAlert('invoice-delete', { invoiceId });
|
||||
@@ -124,6 +138,7 @@ function InvoiceDetailActionsBar({
|
||||
onBadDebt: handleBadDebtInvoice,
|
||||
onCancelBadDebt: handleCancelBadDebtInvoice,
|
||||
onNotifyViaSMS: handleNotifyViaSMS,
|
||||
onConvert: handleConvertToCreitNote,
|
||||
}}
|
||||
/>
|
||||
</Can>
|
||||
|
||||
@@ -76,7 +76,7 @@ export const useInvoiceReadonlyEntriesColumns = () =>
|
||||
* @returns {React.JSX}
|
||||
*/
|
||||
export const BadDebtMenuItem = ({
|
||||
payload: { onCancelBadDebt, onBadDebt, onNotifyViaSMS },
|
||||
payload: { onCancelBadDebt, onBadDebt, onNotifyViaSMS, onConvert },
|
||||
}) => {
|
||||
const { invoice } = useInvoiceDetailDrawerContext();
|
||||
|
||||
@@ -104,6 +104,12 @@ export const BadDebtMenuItem = ({
|
||||
/>
|
||||
</Choose.When>
|
||||
</Choose>
|
||||
<Can I={SaleInvoiceAction.Edit} a={AbilitySubject.Invoice}>
|
||||
<MenuItem
|
||||
onClick={onConvert}
|
||||
text={<T id={'convert_to_credit_note'} />}
|
||||
/>
|
||||
</Can>
|
||||
<Can I={SaleInvoiceAction.NotifyBySms} a={AbilitySubject.Invoice}>
|
||||
<MenuItem
|
||||
onClick={onNotifyViaSMS}
|
||||
@@ -135,12 +141,12 @@ export function InvoiceDetailsStatus({ invoice }) {
|
||||
<Choose>
|
||||
<Choose.When condition={invoice.is_overdue}>
|
||||
<StatusTag intent={Intent.WARNING} round={true}>
|
||||
Overdue
|
||||
<T id={'overdue'} />
|
||||
</StatusTag>
|
||||
</Choose.When>
|
||||
<Choose.Otherwise>
|
||||
<StatusTag intent={Intent.PRIMARY} round={true}>
|
||||
Delivered
|
||||
<T id={'delivered'} />
|
||||
</StatusTag>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
FormatNumber,
|
||||
TotalLineTextStyle,
|
||||
TotalLineBorderStyle,
|
||||
CommercialDocFooter,
|
||||
T,
|
||||
TotalLine,
|
||||
TotalLines,
|
||||
If,
|
||||
DetailsMenu,
|
||||
DetailItem,
|
||||
} from 'components';
|
||||
import { usePaymentReceiveDetailContext } from './PaymentReceiveDetailProvider';
|
||||
|
||||
@@ -17,30 +15,16 @@ import { usePaymentReceiveDetailContext } from './PaymentReceiveDetailProvider';
|
||||
*/
|
||||
export default function PaymentReceiveDetailFooter() {
|
||||
const { paymentReceive } = usePaymentReceiveDetailContext();
|
||||
|
||||
|
||||
return (
|
||||
<PaymentReceiveDetailsFooterRoot>
|
||||
<PaymentReceiveTotalLines
|
||||
labelColWidth={'180px'}
|
||||
amountColWidth={'180px'}
|
||||
>
|
||||
<TotalLine
|
||||
title={<T id={'payment_receive.details.subtotal'} />}
|
||||
value={<FormatNumber value={paymentReceive.amount} />}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'payment_receive.details.total'} />}
|
||||
value={paymentReceive.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
</PaymentReceiveTotalLines>
|
||||
</PaymentReceiveDetailsFooterRoot>
|
||||
<CommercialDocFooter>
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||
<If condition={paymentReceive.statement}>
|
||||
<DetailItem label={<T id={'payment_receive.details.statement'} />}>
|
||||
{paymentReceive.statement}
|
||||
</DetailItem>
|
||||
</If>
|
||||
</DetailsMenu>
|
||||
</CommercialDocFooter>
|
||||
);
|
||||
}
|
||||
|
||||
export const PaymentReceiveDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const PaymentReceiveTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { CommercialDocBox } from 'components';
|
||||
|
||||
import PaymentReceiveDetailHeader from './PaymentReceiveDetailHeader';
|
||||
import PaymentReceiveDetailTable from './PaymentReceiveDetailTable';
|
||||
import PaymentReceiveDetailTableFooter from './PaymentReceiveDetailTableFooter';
|
||||
import PaymentReceiveDetailFooter from './PaymentReceiveDetailFooter';
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,7 @@ export default function PaymentReceiveDetailTab() {
|
||||
<CommercialDocBox>
|
||||
<PaymentReceiveDetailHeader />
|
||||
<PaymentReceiveDetailTable />
|
||||
<PaymentReceiveDetailTableFooter />
|
||||
<PaymentReceiveDetailFooter />
|
||||
</CommercialDocBox>
|
||||
</PaymentReceiveDetailsTabPanelRoot>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
FormatNumber,
|
||||
TotalLineTextStyle,
|
||||
TotalLineBorderStyle,
|
||||
T,
|
||||
TotalLine,
|
||||
TotalLines,
|
||||
} from 'components';
|
||||
import { usePaymentReceiveDetailContext } from './PaymentReceiveDetailProvider';
|
||||
|
||||
/**
|
||||
* Payment receive detail table footer.
|
||||
* @returns {React.JSX}
|
||||
*/
|
||||
export default function PaymentReceiveDetailTableFooter() {
|
||||
const { paymentReceive } = usePaymentReceiveDetailContext();
|
||||
|
||||
return (
|
||||
<PaymentReceiveDetailsFooterRoot>
|
||||
<PaymentReceiveTotalLines
|
||||
labelColWidth={'180px'}
|
||||
amountColWidth={'180px'}
|
||||
>
|
||||
<TotalLine
|
||||
title={<T id={'payment_receive.details.subtotal'} />}
|
||||
value={<FormatNumber value={paymentReceive.amount} />}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'payment_receive.details.total'} />}
|
||||
value={paymentReceive.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
</PaymentReceiveTotalLines>
|
||||
</PaymentReceiveDetailsFooterRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const PaymentReceiveDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const PaymentReceiveTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
@@ -1,51 +1,35 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
CommercialDocFooter,
|
||||
T,
|
||||
TotalLines,
|
||||
TotalLine,
|
||||
TotalLineBorderStyle,
|
||||
TotalLineTextStyle,
|
||||
FormatNumber,
|
||||
If,
|
||||
DetailsMenu,
|
||||
DetailItem,
|
||||
} from 'components';
|
||||
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
|
||||
/**
|
||||
* Receipts read-only details footer.
|
||||
* Receipt details footer
|
||||
* @returns {React.JSX}
|
||||
*/
|
||||
export function ReceiptDetailFooter() {
|
||||
export default function ReceiptDetailFooter() {
|
||||
const { receipt } = useReceiptDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<ReceiptDetailsFooterRoot>
|
||||
<ReceiptTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.subtotal'} />}
|
||||
value={<FormatNumber value={receipt.amount} />}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.total'} />}
|
||||
value={receipt.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.payment_amount'} />}
|
||||
value={receipt.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.due_amount'} />}
|
||||
value={'0'}
|
||||
/>
|
||||
</ReceiptTotalLines>
|
||||
</ReceiptDetailsFooterRoot>
|
||||
<CommercialDocFooter>
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||
<If condition={receipt.statement}>
|
||||
<DetailItem label={<T id={'receipt.details.statement'} />}>
|
||||
{receipt.statement}
|
||||
</DetailItem>
|
||||
</If>
|
||||
<If condition={receipt.receipt_message}>
|
||||
<DetailItem label={<T id={'receipt.details.receipt_message'} />}>
|
||||
{receipt.receipt_message}
|
||||
</DetailItem>
|
||||
</If>
|
||||
</DetailsMenu>
|
||||
</CommercialDocFooter>
|
||||
);
|
||||
}
|
||||
|
||||
export const ReceiptDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const ReceiptTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
@@ -5,7 +5,8 @@ import { CommercialDocBox } from 'components';
|
||||
|
||||
import ReceiptDetailHeader from './ReceiptDetailHeader';
|
||||
import ReceiptDetailTable from './ReceiptDetailTable';
|
||||
import { ReceiptDetailFooter } from './ReceiptDetailFooter';
|
||||
import ReceiptDetailTableFooter from './ReceiptDetailTableFooter';
|
||||
import ReceiptDetailFooter from './ReceiptDetailFooter';
|
||||
|
||||
export default function ReceiptDetailTab() {
|
||||
return (
|
||||
@@ -13,6 +14,7 @@ export default function ReceiptDetailTab() {
|
||||
<CommercialDocBox>
|
||||
<ReceiptDetailHeader />
|
||||
<ReceiptDetailTable />
|
||||
<ReceiptDetailTableFooter />
|
||||
<ReceiptDetailFooter />
|
||||
</CommercialDocBox>
|
||||
</ReceiptDetailsOverviewRoot>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
T,
|
||||
TotalLines,
|
||||
TotalLine,
|
||||
TotalLineBorderStyle,
|
||||
TotalLineTextStyle,
|
||||
FormatNumber,
|
||||
} from 'components';
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
|
||||
/**
|
||||
* Receipts read-only details table footer.
|
||||
*/
|
||||
export default function ReceiptDetailTableFooter() {
|
||||
const { receipt } = useReceiptDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<ReceiptDetailsFooterRoot>
|
||||
<ReceiptTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.subtotal'} />}
|
||||
value={<FormatNumber value={receipt.amount} />}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.total'} />}
|
||||
value={receipt.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
textStyle={TotalLineTextStyle.Bold}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.payment_amount'} />}
|
||||
value={receipt.formatted_amount}
|
||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||
/>
|
||||
<TotalLine
|
||||
title={<T id={'receipt.details.due_amount'} />}
|
||||
value={'0'}
|
||||
/>
|
||||
</ReceiptTotalLines>
|
||||
</ReceiptDetailsFooterRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const ReceiptDetailsFooterRoot = styled.div``;
|
||||
|
||||
export const ReceiptTotalLines = styled(TotalLines)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
@@ -70,6 +70,11 @@ function BillsDataTable({
|
||||
history.push(`/bills/${bill.id}/edit`);
|
||||
};
|
||||
|
||||
// Handle convert to vendor credit.
|
||||
const handleConvertToVendorCredit = ({ id }) => {
|
||||
history.push(`/vendor-credits/new?from_bill_id=${id}`, { billId: id });
|
||||
};
|
||||
|
||||
// Handle bill delete action.
|
||||
const handleDeleteBill = (bill) => {
|
||||
openAlert('bill-delete', { billId: bill.id });
|
||||
@@ -137,6 +142,7 @@ function BillsDataTable({
|
||||
onQuick: handleQuickPaymentMade,
|
||||
onAllocateLandedCost: handleAllocateLandedCost,
|
||||
onViewDetails: handleViewDetailBill,
|
||||
onConvert: handleConvertToVendorCredit,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
|
||||
@@ -34,6 +34,7 @@ export function ActionsMenu({
|
||||
onOpen,
|
||||
onDelete,
|
||||
onQuick,
|
||||
onConvert,
|
||||
onViewDetails,
|
||||
onAllocateLandedCost,
|
||||
},
|
||||
@@ -53,6 +54,11 @@ export function ActionsMenu({
|
||||
text={intl.get('edit_bill')}
|
||||
onClick={safeCallback(onEdit, original)}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={<Icon icon="convert_to" />}
|
||||
text={intl.get('convert_to_vendor_credit')}
|
||||
onClick={safeCallback(onConvert, original)}
|
||||
/>
|
||||
|
||||
<If condition={!original.is_open}>
|
||||
<MenuItem
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { isEmpty, pick } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import {
|
||||
@@ -50,6 +50,7 @@ function VendorCreditNoteForm({
|
||||
isNewMode,
|
||||
submitPayload,
|
||||
vendorCredit,
|
||||
bill,
|
||||
createVendorCreditMutate,
|
||||
editVendorCreditMutate,
|
||||
} = useVendorCreditNoteFormContext();
|
||||
@@ -72,6 +73,9 @@ function VendorCreditNoteForm({
|
||||
...(vendorcreditAutoIncrement && {
|
||||
vendor_credit_number: vendorCreditNumber,
|
||||
}),
|
||||
...transformToEditForm({
|
||||
...pick(bill, ['vendor_id', 'entries']),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
[vendorCredit, base_currency],
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { isEmpty, pick } from 'lodash';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
|
||||
import { transformToEditForm } from './utils';
|
||||
import {
|
||||
useCreateVendorCredit,
|
||||
useEditVendorCredit,
|
||||
@@ -8,6 +10,7 @@ import {
|
||||
useItems,
|
||||
useVendors,
|
||||
useSettingsVendorCredits,
|
||||
useBill,
|
||||
} from 'hooks/query';
|
||||
|
||||
const VendorCreditNoteFormContext = React.createContext();
|
||||
@@ -16,6 +19,10 @@ const VendorCreditNoteFormContext = React.createContext();
|
||||
* Vendor Credit note data provider.
|
||||
*/
|
||||
function VendorCreditNoteFormProvider({ vendorCreditId, ...props }) {
|
||||
const { state } = useLocation();
|
||||
|
||||
const billId = state?.billId;
|
||||
|
||||
// Handle fetching the items table based on the given query.
|
||||
const {
|
||||
data: { items },
|
||||
@@ -39,6 +46,11 @@ function VendorCreditNoteFormProvider({ vendorCreditId, ...props }) {
|
||||
enabled: !!vendorCreditId,
|
||||
});
|
||||
|
||||
// Handle fetch bill details.
|
||||
const { isLoading: isBillLoading, data: bill } = useBill(billId, {
|
||||
enabled: !!billId,
|
||||
});
|
||||
|
||||
// Form submit payload.
|
||||
const [submitPayload, setSubmitPayload] = React.useState();
|
||||
|
||||
@@ -56,6 +68,7 @@ function VendorCreditNoteFormProvider({ vendorCreditId, ...props }) {
|
||||
vendorCredit,
|
||||
submitPayload,
|
||||
isNewMode,
|
||||
bill,
|
||||
|
||||
isVendorCreditLoading,
|
||||
|
||||
@@ -70,7 +83,8 @@ function VendorCreditNoteFormProvider({ vendorCreditId, ...props }) {
|
||||
isVendorCreditLoading ||
|
||||
isItemsLoading ||
|
||||
isVendorsLoading ||
|
||||
isVendorCreditLoading
|
||||
isVendorCreditLoading ||
|
||||
isBillLoading
|
||||
}
|
||||
name={'vendor-credit-form'}
|
||||
>
|
||||
|
||||
@@ -56,6 +56,7 @@ function CreditNoteForm({
|
||||
isNewMode,
|
||||
submitPayload,
|
||||
creditNote,
|
||||
newCreditNote,
|
||||
createCreditNoteMutate,
|
||||
editCreditNoteMutate,
|
||||
} = useCreditNoteFormContext();
|
||||
@@ -74,6 +75,7 @@ function CreditNoteForm({
|
||||
credit_note_number: creditNumber,
|
||||
}),
|
||||
entries: orderingLinesIndexes(defaultCreditNote.entries),
|
||||
...newCreditNote,
|
||||
}),
|
||||
}),
|
||||
[],
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
useItems,
|
||||
useCustomers,
|
||||
useSettingsCreditNotes,
|
||||
useInvoice,
|
||||
} from 'hooks/query';
|
||||
|
||||
const CreditNoteFormContext = React.createContext();
|
||||
@@ -19,6 +20,9 @@ const CreditNoteFormContext = React.createContext();
|
||||
* Credit note data provider.
|
||||
*/
|
||||
function CreditNoteFormProvider({ creditNoteId, ...props }) {
|
||||
const { state } = useLocation();
|
||||
const invoiceId = state?.invoiceId;
|
||||
|
||||
// Handle fetch customers data table or list
|
||||
const {
|
||||
data: { customers },
|
||||
@@ -33,13 +37,17 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
|
||||
page_size: 10000,
|
||||
});
|
||||
|
||||
// Handle fetch vendor credit details.
|
||||
// Handle fetch credit details.
|
||||
const { data: creditNote, isLoading: isCreditNoteLoading } = useCreditNote(
|
||||
creditNoteId,
|
||||
{
|
||||
enabled: !!creditNoteId,
|
||||
},
|
||||
);
|
||||
// Handle fetch invoice detail.
|
||||
const { data: invoice, isLoading: isInvoiceLoading } = useInvoice(invoiceId, {
|
||||
enabled: !!invoiceId,
|
||||
});
|
||||
|
||||
// Handle fetching settings.
|
||||
useSettingsCreditNotes();
|
||||
@@ -54,6 +62,12 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
|
||||
// Determines whether the form in new mode.
|
||||
const isNewMode = !creditNoteId;
|
||||
|
||||
const newCreditNote = !isEmpty(invoice)
|
||||
? transformToEditForm({
|
||||
...pick(invoice, ['customer_id', 'entries']),
|
||||
})
|
||||
: [];
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
items,
|
||||
@@ -61,6 +75,7 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
|
||||
creditNote,
|
||||
submitPayload,
|
||||
isNewMode,
|
||||
newCreditNote,
|
||||
|
||||
isItemsLoading,
|
||||
isCustomersLoading,
|
||||
@@ -70,11 +85,14 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
|
||||
setSubmitPayload,
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
isItemsLoading ||
|
||||
isCustomersLoading ||
|
||||
isCreditNoteLoading ||
|
||||
isInvoiceLoading;
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isItemsLoading || isCustomersLoading || isCreditNoteLoading}
|
||||
name={'credit-note-form'}
|
||||
>
|
||||
<DashboardInsider loading={isLoading} name={'credit-note-form'}>
|
||||
<CreditNoteFormContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
|
||||
@@ -74,6 +74,11 @@ function InvoicesDataTable({
|
||||
history.push(`/invoices/${invoice.id}/edit`);
|
||||
};
|
||||
|
||||
// Handle convert to credit note.
|
||||
const handleConvertToCreitNote = ({ id }) => {
|
||||
history.push(`/credit-notes/new?from_invoice_id=${id}`, { invoiceId: id });
|
||||
};
|
||||
|
||||
// handle quick payment receive.
|
||||
const handleQuickPaymentReceive = ({ id }) => {
|
||||
openDialog('quick-payment-receive', { invoiceId: id });
|
||||
@@ -147,6 +152,7 @@ function InvoicesDataTable({
|
||||
onQuick: handleQuickPaymentReceive,
|
||||
onViewDetails: handleViewDetailInvoice,
|
||||
onPrint: handlePrintInvoice,
|
||||
onConvert: handleConvertToCreitNote,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
|
||||
@@ -124,7 +124,7 @@ export function ActionsMenu({
|
||||
onEdit,
|
||||
onDeliver,
|
||||
onDelete,
|
||||
onDrawer,
|
||||
onConvert,
|
||||
onQuick,
|
||||
onViewDetails,
|
||||
onPrint,
|
||||
@@ -145,6 +145,11 @@ export function ActionsMenu({
|
||||
text={intl.get('edit_invoice')}
|
||||
onClick={safeCallback(onEdit, original)}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={<Icon icon="convert_to" />}
|
||||
text={intl.get('convert_to_credit_note')}
|
||||
onClick={safeCallback(onConvert, original)}
|
||||
/>
|
||||
|
||||
<If condition={!original.is_delivered}>
|
||||
<MenuItem
|
||||
|
||||
Reference in New Issue
Block a user