Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop

This commit is contained in:
a.bouhuolia
2021-12-26 18:26:22 +02:00
31 changed files with 503 additions and 163 deletions

View File

@@ -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>
);

View File

@@ -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;
`;

View File

@@ -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>
);

View 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;
`;

View File

@@ -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;

View File

@@ -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>
);
}

View File

@@ -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>
);
}

View File

@@ -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 (

View File

@@ -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;
`;

View File

@@ -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>
);

View File

@@ -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;
`;

View File

@@ -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',

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
`;

View File

@@ -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>

View File

@@ -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;
`;

View File

@@ -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;
`;

View File

@@ -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>

View File

@@ -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;
`;

View File

@@ -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>

View File

@@ -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

View File

@@ -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],

View File

@@ -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'}
>

View File

@@ -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,
}),
}),
[],

View File

@@ -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>
);

View File

@@ -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>

View File

@@ -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