Compare commits

...

29 Commits

Author SHA1 Message Date
a.bouhuolia
da699a766a Merge branch 'develop' into main 2022-01-13 15:40:55 +02:00
a.bouhuolia
a958c6088a chore: dump version. 2022-01-13 15:35:40 +02:00
a.bouhuolia
572d59577c chore: dump version changlogs. 2022-01-13 15:34:54 +02:00
Ahmed Bouhuolia
21ae8aabfc Merge pull request #22 from bigcapitalhq/BIG-261-hide-convert-to-invoice-button-on-the-context-menu-if-already-converted
fix: `BIG-261` Hide convert to invoice button on the context menu if invoice already converted.
2022-01-13 15:18:49 +02:00
a.bouhuolia
8f267b98e4 fix(ContactBalanceSummary): BIG-288 percentage of column. 2022-01-12 20:15:00 +02:00
a.bouhuolia
dcfe92076b Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop 2022-01-11 18:10:23 +02:00
a.bouhuolia
79cb7f1a1d fix(PaymentReceive): depend on loading state instead fetching. 2022-01-11 18:10:17 +02:00
a.bouhuolia
1380e288e0 fix(BalanceSheet): BIG-281 report alerts re-positioning. 2022-01-11 18:09:12 +02:00
Ahmed Bouhuolia
b055908e12 Merge pull request #19 from bigcapitalhq/BIG-274-duplicated-description-in-payment-receive-details
`BIG-274` Duplicated description in payment receive details.
2022-01-11 17:29:19 +02:00
Ahmed Bouhuolia
20c140474b Merge pull request #20 from bigcapitalhq/BIG-277-separate-customer-and-vendor-activate-inactivate-alerts
BIG-277 Separate customer and vendor.
2022-01-11 17:28:47 +02:00
Ahmed Bouhuolia
9ee5eba92b Merge branch 'develop' into BIG-277-separate-customer-and-vendor-activate-inactivate-alerts 2022-01-11 17:28:30 +02:00
Ahmed Bouhuolia
e755a2a318 Merge pull request #21 from bigcapitalhq/BIG-263-optimize-sales-print-templates
`Big 263` optimize sales print templates
2022-01-11 17:25:44 +02:00
elforjani13
1656691940 feat(PaymentReceivePdf): payment pdf preview. 2022-01-11 14:34:41 +02:00
elforjani13
dd7d11ffb7 feat(CreditNotePdf): credit note pdf preview. 2022-01-11 14:33:51 +02:00
elforjani13
5c847be420 BIG-277 Separate customer and vendor. 2022-01-09 21:18:45 +02:00
a.bouhuolia
da3193195c fix: BIG-274 Duplicated description in payment receive details. 2022-01-09 21:12:54 +02:00
a.bouhuolia
e3141250b6 fix: BIG-261 Hide convert to invoice button on the context menu if already converted. 2022-01-09 13:07:32 +02:00
a.bouhuolia
f1899e1ce1 Merge branch 'develop' into main 2022-01-08 18:20:08 +02:00
elforjani13
76d6cd0eaa fix(MoneyOutForm): BIG-270 publish & draft cashflow. 2022-01-08 18:14:39 +02:00
elforjani13
90b4f86a0d fix(MoneyInForm): BIG-270 publish & draft cashflow. 2022-01-08 18:14:17 +02:00
Ahmed Bouhuolia
5766d25bd1 Merge pull request #18 from bigcapitalhq/BIG-271-hotjar-client-application-integration
`BIG-271` Hotjar client application integration.
2022-01-08 18:06:54 +02:00
elforjani13
6a5d96e869 BIG-271 Hotjar client application integration. 2022-01-08 17:59:30 +02:00
Ahmed Bouhuolia
69f16d1977 Merge pull request #17 from bigcapitalhq/BIG-270-publish-and-draft-cashflow-transaction-should-be-always-publish
BIG-270 Publish and draft cashflow transaction.
2022-01-08 17:02:54 +02:00
elforjani13
9973693a86 BIG-270 Publish and draft cashflow transaction. 2022-01-08 16:59:31 +02:00
Ahmed Bouhuolia
11851d114d Merge pull request #16 from bigcapitalhq/develop
Release 1.5.5
2022-01-04 22:35:49 +02:00
elforjani13
3a3dd7a565 fix(VendorForm): placeholder phone number. 2022-01-04 22:31:01 +02:00
elforjani13
687dda1e7c fix(inviteUserFrom): fix localiztion. 2022-01-04 21:31:58 +02:00
elforjani13
bfa809c831 feat(VendorList): add note accessor & personal phone. 2022-01-04 20:47:43 +02:00
elforjani13
07145e92ab feat(CustomerList): add note accessor & personal phone. 2022-01-04 20:47:28 +02:00
57 changed files with 929 additions and 186 deletions

View File

@@ -2,6 +2,20 @@
All notable changes to Bigcapital server-side will be in this file.
## [1.5.8] - 13-01-2022
### Added
- Add payment receive PDF print.
- Add credit note PDF print.
### Fixed
- fix: Payment receive initial loading state depends on request loading state instead fetching.
- fix: Balance sheet report alert positioning.
- fix: Separate customer and vendor inactivate and activate alerts.
- fix: Hide convert to invoice button if the invoice is already converted.
- fix: Customer and vendor balance summary percentage of column option.
- fix: Remove duplicated details in sales and purchases details drawers.
## [1.5.3] - 03-01-2020
### Fixed

View File

@@ -1,6 +1,6 @@
{
"name": "bigcapital-client",
"version": "1.5.3",
"version": "1.5.8",
"private": true,
"dependencies": {
"@babel/core": "7.8.4",

View File

@@ -2,7 +2,11 @@
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicons/favicon-32.ico" sizes="32x32">
<link
rel="icon"
href="%PUBLIC_URL%/favicons/favicon-32.ico"
sizes="32x32"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
@@ -15,6 +19,22 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- Hotjar Tracking Code for https://app.bigcapital.ly/ -->
<script>
(function (h, o, t, j, a, r) {
h.hj =
h.hj ||
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = { hjid: 2774528, hjsv: 6 };
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
</script>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
@@ -41,7 +61,11 @@
To create a production bundle, use `npm run build` or `yarn build`.
-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flexboxgrid/6.3.1/flexboxgrid.min.css" type="text/css" >
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/flexboxgrid/6.3.1/flexboxgrid.min.css"
type="text/css"
/>
<!-- <link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet"> -->
<!-- <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> -->
</body>

View File

@@ -21,5 +21,5 @@ export const CommercialDocEntriesTable = styled(DataTable)`
`;
export const CommercialDocFooter = styled.div`
margin-top: 25px;
margin-top: 28px;
`;

View File

@@ -32,6 +32,8 @@ import ReconcileVendorCreditDialog from '../containers/Dialogs/ReconcileVendorCr
import LockingTransactionsDialog from '../containers/Dialogs/LockingTransactionsDialog';
import UnlockingTransactionsDialog from '../containers/Dialogs/UnlockingTransactionsDialog';
import UnlockingPartialTransactionsDialog from '../containers/Dialogs/UnlockingPartialTransactionsDialog';
import CreditNotePdfPreviewDialog from '../containers/Dialogs/CreditNotePdfPreviewDialog';
import PaymentReceivePdfPreviewDialog from '../containers/Dialogs/PaymentReceivePdfPreviewDialog';
/**
* Dialogs container.
@@ -74,6 +76,8 @@ export default function DialogsContainer() {
<UnlockingPartialTransactionsDialog
dialogName={'unlocking-partial-transactions'}
/>
<CreditNotePdfPreviewDialog dialogName={'credit-note-pdf-preview'} />
<PaymentReceivePdfPreviewDialog dialogName={'payment-pdf-preview'} />
</div>
);
}

View File

@@ -0,0 +1,67 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components';
import { useActivateContact } from 'hooks/query';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
/**
* Customer activate alert.
*/
function CustomerActivateAlert({
name,
// #withAlertStoreConnect
isOpen,
payload: { customerId, service },
// #withAlertActions
closeAlert,
}) {
const { mutateAsync: activateContact, isLoading } = useActivateContact();
// Handle activate constomer alert cancel.
const handleCancelActivateCustomer = () => {
closeAlert(name);
};
// Handle confirm customer activated.
const handleConfirmCustomerActivate = () => {
activateContact(customerId)
.then(() => {
AppToaster.show({
message: intl.get('customer.alert.activated_message'),
intent: Intent.SUCCESS,
});
})
.catch((error) => {})
.finally(() => {
closeAlert(name);
});
};
return (
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'activate'} />}
intent={Intent.WARNING}
isOpen={isOpen}
onCancel={handleCancelActivateCustomer}
loading={isLoading}
onConfirm={handleConfirmCustomerActivate}
>
<p>{intl.get('customer.alert.are_you_sure_want_to_activate_this_customer')}</p>
</Alert>
);
}
export default compose(
withAlertStoreConnect(),
withAlertActions,
)(CustomerActivateAlert);

View File

@@ -0,0 +1,69 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components';
import { useInactivateContact } from 'hooks/query';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
/**
* customer inactivate alert.
*/
function CustomerInactivateAlert({
name,
// #withAlertStoreConnect
isOpen,
payload: { customerId, service },
// #withAlertActions
closeAlert,
}) {
const { mutateAsync: inactivateContact, isLoading } = useInactivateContact();
// Handle cancel inactivate alert.
const handleCancelInactivateCustomer = () => {
closeAlert(name);
};
// Handle confirm contact Inactive.
const handleConfirmCustomerInactive = () => {
inactivateContact(customerId)
.then(() => {
AppToaster.show({
message: intl.get('the_contact_has_been_inactivated_successfully'),
intent: Intent.SUCCESS,
});
})
.catch((error) => {})
.finally(() => {
closeAlert(name);
});
};
return (
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'inactivate'} />}
intent={Intent.WARNING}
isOpen={isOpen}
onCancel={handleCancelInactivateCustomer}
onConfirm={handleConfirmCustomerInactive}
loading={isLoading}
>
<p>
{intl.get(
'customer.alert.are_you_sure_want_to_inactivate_this_customer',
)}
</p>
</Alert>
);
}
export default compose(
withAlertStoreConnect(),
withAlertActions,
)(CustomerInactivateAlert);

View File

@@ -0,0 +1,69 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components';
import { useActivateContact } from 'hooks/query';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
/**
* Vendor activate alert.
*/
function VendorActivateAlert({
name,
// #withAlertStoreConnect
isOpen,
payload: { vendorId },
// #withAlertActions
closeAlert,
}) {
const { mutateAsync: activateContact, isLoading } = useActivateContact();
// Handle activate vendor alert cancel.
const handleCancelActivateVendor = () => {
closeAlert(name);
};
// Handle confirm vendor activated.
const handleConfirmVendorActivate = () => {
activateContact(vendorId)
.then(() => {
AppToaster.show({
message: intl.get('vendor.alert.activated_message'),
intent: Intent.SUCCESS,
});
})
.catch((error) => {})
.finally(() => {
closeAlert(name);
});
};
return (
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'activate'} />}
intent={Intent.WARNING}
isOpen={isOpen}
onCancel={handleCancelActivateVendor}
loading={isLoading}
onConfirm={handleConfirmVendorActivate}
>
<p>
{intl.get('vendor.alert.are_you_sure_want_to_activate_this_vendor')}
</p>
</Alert>
);
}
export default compose(
withAlertStoreConnect(),
withAlertActions,
)(VendorActivateAlert);

View File

@@ -0,0 +1,68 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components';
import { useInactivateContact } from 'hooks/query';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
/**
* Vendor inactivate alert.
*/
function VendorInactivateAlert({
name,
// #withAlertStoreConnect
isOpen,
payload: { vendorId },
// #withAlertActions
closeAlert,
}) {
const { mutateAsync: inactivateContact, isLoading } = useInactivateContact();
// Handle cancel inactivate alert.
const handleCancelInactivateVendor = () => {
closeAlert(name);
};
// Handle confirm contact Inactive.
const handleConfirmVendorInactive = () => {
inactivateContact(vendorId)
.then(() => {
AppToaster.show({
message: intl.get('vendor.alert.inactivated_message'),
intent: Intent.SUCCESS,
});
})
.catch((error) => {})
.finally(() => {
closeAlert(name);
});
};
return (
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'inactivate'} />}
intent={Intent.WARNING}
isOpen={isOpen}
onCancel={handleCancelInactivateVendor}
onConfirm={handleConfirmVendorInactive}
loading={isLoading}
>
<p>
{intl.get('vendor.alert.are_you_sure_want_to_inactivate_this_vendor')}
</p>
</Alert>
);
}
export default compose(
withAlertStoreConnect(),
withAlertActions,
)(VendorInactivateAlert);

View File

@@ -3,11 +3,11 @@ import React from 'react';
const CustomerDeleteAlert = React.lazy(() =>
import('../Alerts/Customers/CustomerDeleteAlert'),
);
const ContactActivateAlert = React.lazy(() =>
import('../Alerts/Contacts/ContactActivateAlert'),
const CustomerActivateAlert = React.lazy(() =>
import('../Alerts/Customers/CustomerActivateAlert'),
);
const ContactInactivateAlert = React.lazy(() =>
import('../Alerts/Contacts/ContactInactivateAlert'),
const CustomerInactivateAlert = React.lazy(() =>
import('../Alerts/Customers/CustomerInactivateAlert'),
);
/**
@@ -15,6 +15,6 @@ const ContactInactivateAlert = React.lazy(() =>
*/
export default [
{ name: 'customer-delete', component: CustomerDeleteAlert },
{ name: 'contact-activate', component: ContactActivateAlert },
{ name: 'contact-inactivate', component: ContactInactivateAlert },
{ name: 'customer-activate', component: CustomerActivateAlert },
{ name: 'customer-inactivate', component: CustomerInactivateAlert },
];

View File

@@ -89,15 +89,17 @@ function CustomersTable({
// Handle cancel/confirm inactive.
const handleInactiveCustomer = ({ id, contact_service }) => {
openAlert('contact-inactivate', {
contactId: id,
service: contact_service,
openAlert('customer-inactivate', {
customerId: id,
});
};
// Handle cancel/confirm activate.
const handleActivateCustomer = ({ id, contact_service }) => {
openAlert('contact-activate', { contactId: id, service: contact_service });
openAlert('customer-activate', {
customerId: id,
service: contact_service,
});
};
// Handle view detail contact.

View File

@@ -1,5 +1,13 @@
import React, { useMemo } from 'react';
import { Menu, MenuItem, MenuDivider, Intent } from '@blueprintjs/core';
import {
Menu,
MenuItem,
MenuDivider,
Intent,
Tooltip,
Position,
Classes,
} from '@blueprintjs/core';
import clsx from 'classnames';
import intl from 'react-intl-universal';
@@ -79,7 +87,7 @@ export function ActionsMenu({
* Phone number accessor.
*/
export function PhoneNumberAccessor(row) {
return <div className={'work_phone'}>{row.work_phone}</div>;
return <div className={'work_phone'}>{row.personal_phone}</div>;
}
/**
@@ -89,6 +97,24 @@ export function BalanceAccessor(row) {
return <Money amount={row.closing_balance} currency={row.currency_code} />;
}
/**
* Note column accessor.
*/
export function NoteAccessor(row) {
return (
<If condition={row.note}>
<Tooltip
className={Classes.TOOLTIP_INDICATOR}
content={row.note}
position={Position.LEFT_TOP}
hoverOpenDelay={50}
>
<Icon icon={'file-alt'} iconSize={16} />
</Tooltip>
</If>
);
}
/**
* Retrieve customers table columns.
*/
@@ -123,12 +149,20 @@ export function useCustomersTableColumns() {
},
{
id: 'work_phone',
Header: intl.get('work_phone'),
Header: intl.get('phone_number'),
accessor: PhoneNumberAccessor,
className: 'phone_number',
width: 100,
clickable: true,
},
{
id: 'note',
Header: intl.get('note'),
accessor: NoteAccessor,
disableSortBy: true,
width: 85,
clickable: true,
},
{
id: 'balance',
Header: intl.get('receivable_balance'),

View File

@@ -0,0 +1,47 @@
import React from 'react';
import { AnchorButton } from '@blueprintjs/core';
import { DialogContent, PdfDocumentPreview, T } from 'components';
import { usePdfCreditNote } from 'hooks/query';
import withDialogActions from 'containers/Dialog/withDialogActions';
import { compose } from 'utils';
function CreditNotePdfPreviewDialogContent({
subscriptionForm: { creditNoteId },
}) {
const { isLoading, pdfUrl } = usePdfCreditNote(creditNoteId);
return (
<DialogContent>
<div class="dialog__header-actions">
<AnchorButton
href={pdfUrl}
target={'__blank'}
minimal={true}
outlined={true}
>
<T id={'pdf_preview.preview.button'} />
</AnchorButton>
<AnchorButton
href={pdfUrl}
download={'creditNote.pdf'}
minimal={true}
outlined={true}
>
<T id={'pdf_preview.download.button'} />
</AnchorButton>
</div>
<PdfDocumentPreview
height={760}
width={1000}
isLoading={isLoading}
url={pdfUrl}
/>
</DialogContent>
);
}
export default compose(withDialogActions)(CreditNotePdfPreviewDialogContent);

View File

@@ -0,0 +1,42 @@
import React from 'react';
import classNames from 'classnames';
import { T, Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { CLASSES } from 'common/classes';
import { compose } from 'utils';
const PdfPreviewDialogContent = React.lazy(() =>
import('./CreditNotePdfPreviewDialogContent'),
);
/**
* Credit note PDF previwe dialog.
*/
function CreditNotePdfPreviewDialog({
dialogName,
payload = { creditNoteId: null },
isOpen,
}) {
return (
<Dialog
name={dialogName}
title={<T id={'credit_note_preview.dialog.title'} />}
className={classNames(CLASSES.DIALOG_PDF_PREVIEW)}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
style={{ width: '1000px' }}
>
<DialogSuspense>
<PdfPreviewDialogContent
dialogName={dialogName}
subscriptionForm={payload}
/>
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(CreditNotePdfPreviewDialog);

View File

@@ -29,7 +29,7 @@ const defaultInitialValues = {
cashflow_account_id: '',
credit_account_id: '',
description: '',
published: '',
publish: '',
};
function MoneyInForm({
@@ -73,7 +73,7 @@ function MoneyInForm({
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
const form = {
...omit(values, ['currency_code']),
published: submitPayload.publish,
publish: true,
};
setSubmitting(true);
createCashflowTransactionMutate(form)

View File

@@ -14,7 +14,7 @@ const Schema = Yup.object().shape({
.min(3)
.max(DATATYPES_LENGTH.TEXT)
.label(intl.get('description')),
published: Yup.boolean(),
publish: Yup.boolean(),
});
export const CreateMoneyInFormSchema = Schema;

View File

@@ -29,7 +29,7 @@ const defaultInitialValues = {
cashflow_account_id: '',
credit_account_id: '',
description: '',
published: '',
publish: '',
};
function MoneyOutForm({
@@ -73,7 +73,7 @@ function MoneyOutForm({
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
const form = {
...omit(values, ['currency_code']),
published: submitPayload.publish,
publish: true,
};
setSubmitting(true);
createCashflowTransactionMutate(form)

View File

@@ -14,7 +14,7 @@ const Schema = Yup.object().shape({
.min(3)
.max(DATATYPES_LENGTH.TEXT)
.label(intl.get('description')),
published: Yup.boolean(),
publish: Yup.boolean(),
});
export const CreateMoneyOutSchema = Schema;

View File

@@ -0,0 +1,49 @@
import React from 'react';
import { AnchorButton } from '@blueprintjs/core';
import { DialogContent, PdfDocumentPreview, T } from 'components';
import { usePdfPaymentReceive } from 'hooks/query';
import withDialogActions from 'containers/Dialog/withDialogActions';
import { compose } from 'utils';
function PaymentReceivePdfPreviewDialogContent({
subscriptionForm: { paymentReceiveId },
}) {
const { isLoading, pdfUrl } = usePdfPaymentReceive(paymentReceiveId);
return (
<DialogContent>
<div class="dialog__header-actions">
<AnchorButton
href={pdfUrl}
target={'__blank'}
minimal={true}
outlined={true}
>
<T id={'pdf_preview.preview.button'} />
</AnchorButton>
<AnchorButton
href={pdfUrl}
download={'payment.pdf'}
minimal={true}
outlined={true}
>
<T id={'pdf_preview.download.button'} />
</AnchorButton>
</div>
<PdfDocumentPreview
height={760}
width={1000}
isLoading={isLoading}
url={pdfUrl}
/>
</DialogContent>
);
}
export default compose(withDialogActions)(
PaymentReceivePdfPreviewDialogContent,
);

View File

@@ -0,0 +1,44 @@
import React from 'react';
import classNames from 'classnames';
import { T, Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { CLASSES } from 'common/classes';
import { compose } from 'utils';
// Lazy loading the content.
const PdfPreviewDialogContent = React.lazy(() =>
import('./PaymentReceivePdfPreviewContent'),
);
/**
* Payment receive PDF preview dialog.
*/
function PaymentReceivePdfPreviewDialog({
dialogName,
payload = { paymentReceiveId: null },
isOpen,
}) {
return (
<Dialog
name={dialogName}
title={<T id={'payment_receive_preview.dialog.title'} />}
className={classNames(CLASSES.DIALOG_PDF_PREVIEW)}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
style={{ width: '1000px' }}
>
<DialogSuspense>
<PdfPreviewDialogContent
dialogName={dialogName}
subscriptionForm={payload}
/>
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(PaymentReceivePdfPreviewDialog);

View File

@@ -65,6 +65,11 @@ function CreditNoteDetailActionsBar({
openDialog('reconcile-credit-note', { creditNoteId });
};
// Handle print credit note.
const handlePrintCreditNote = () => {
openDialog('credit-note-pdf-preview', { creditNoteId });
};
return (
<DrawerActionsBar>
<NavbarGroup>
@@ -88,6 +93,14 @@ function CreditNoteDetailActionsBar({
<NavbarDivider />
</If>
</Can>
<Can I={CreditNoteAction.View} a={AbilitySubject.CreditNote}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" />}
text={<T id={'print'} />}
onClick={handlePrintCreditNote}
/>
</Can>
<Can I={CreditNoteAction.Delete} a={AbilitySubject.CreditNote}>
<Button
className={Classes.MINIMAL}

View File

@@ -15,9 +15,14 @@ import { useCreditNoteDetailDrawerContext } from './CreditNoteDetailDrawerProvid
*/
export default function CreditNoteDetailFooter() {
const { creditNote } = useCreditNoteDetailDrawerContext();
return (
<CommercialDocFooter>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<If condition={creditNote.terms_conditions}>
<DetailItem label={<T id={'note'} />} children={creditNote.note} />
</If>
<If condition={creditNote.terms_conditions}>
<DetailItem label={<T id={'terms_conditions'} />}>
{creditNote.terms_conditions}

View File

@@ -42,6 +42,12 @@ export default function CreditNoteDetailHeader() {
<Row>
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('credit_note.drawer.label_credit_note_date')}
>
<FormatDate value={creditNote.formatted_credit_note_date} />
</DetailItem>
<DetailItem
label={intl.get('credit_note.drawer.label_credit_note_no')}
>
@@ -53,12 +59,6 @@ export default function CreditNoteDetailHeader() {
{creditNote.customer?.display_name}
</CustomerDrawerLink>
</DetailItem>
<DetailItem
label={intl.get('credit_note.drawer.label_credit_note_date')}
>
<FormatDate value={creditNote.formatted_credit_note_date} />
</DetailItem>
</DetailsMenu>
</Col>
@@ -77,11 +77,6 @@ export default function CreditNoteDetailHeader() {
label={intl.get('reference')}
children={defaultTo(creditNote.reference_no, '-')}
/>
<DetailItem
label={intl.get('note')}
children={defaultTo(creditNote.note, '-')}
/>
<DetailItem
label={<T id={'credit_note.drawer.label_created_at'} />}
children={<FormatDate value={creditNote.created_at} />}

View File

@@ -12,7 +12,6 @@ import {
DetailItem,
Row,
Col,
ButtonLink,
CustomerDrawerLink,
} from 'components';
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';

View File

@@ -1,42 +1,29 @@
import React from 'react';
import styled from 'styled-components';
import {
T,
TotalLines,
TotalLine,
TotalLineBorderStyle,
TotalLineTextStyle,
CommercialDocFooter,
DetailsMenu,
If,
DetailItem,
} from 'components';
import { usePaymentMadeDetailContext } from './PaymentMadeDetailProvider';
/**
* Payment made - Details panel - Footer.
*/
export default function PaymentMadeDetailFooter() {
export function PaymentMadeDetailFooter() {
const { paymentMade } = usePaymentMadeDetailContext();
return (
<PaymentMadeFooterRoot>
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
<TotalLine
title={<T id={'payment_made.details.subtotal'} />}
value={paymentMade.amount}
borderStyle={TotalLineBorderStyle.SingleDark}
/>
<TotalLine
title={<T id={'payment_made.details.total'} />}
value={paymentMade.formatted_amount}
borderStyle={TotalLineBorderStyle.DoubleDark}
textStyle={TotalLineTextStyle.Bold}
/>
</PaymentMadeTotalLines>
</PaymentMadeFooterRoot>
<CommercialDocFooter>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<If condition={paymentMade.statement}>
<DetailItem label={<T id={'payment_made.details.statement'} />}>
{paymentMade.statement}
</DetailItem>
</If>
</DetailsMenu>
</CommercialDocFooter>
);
}
export const PaymentMadeFooterRoot = styled.div``;
export const PaymentMadeTotalLines = styled(TotalLines)`
margin-left: auto;
`;

View File

@@ -34,6 +34,10 @@ export default function PaymentMadeDetailHeader() {
<Row>
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('payment_date')}
children={<FormatDate value={paymentMade.payment_date} />}
/>
<DetailItem
label={intl.get('payment_made.details.payment_number')}
children={defaultTo(paymentMade.payment_number, '-')}
@@ -47,11 +51,6 @@ export default function PaymentMadeDetailHeader() {
label={intl.get('payment_account')}
children={paymentMade.payment_account?.name}
/>
<DetailItem
label={intl.get('payment_date')}
children={<FormatDate value={paymentMade.payment_date} />}
/>
</DetailsMenu>
</Col>
<Col xs={6}>
@@ -61,8 +60,8 @@ export default function PaymentMadeDetailHeader() {
minLabelSize={'180px'}
>
<DetailItem
label={intl.get('description')}
children={defaultTo(paymentMade.statement, '-')}
label={intl.get('reference')}
children={defaultTo(paymentMade.reference, '-')}
/>
<DetailItem
label={intl.get('created_at')}

View File

@@ -20,8 +20,7 @@ function PaymentMadeDetailProvider({ paymentMadeId, ...props }) {
enabled: !!paymentMadeId,
},
);
//provider.
// Provider state.
const provider = {
paymentMadeId,
paymentMade,

View File

@@ -4,7 +4,8 @@ import { CommercialDocBox } from 'components';
import PaymentMadeDetailHeader from './PaymentMadeDetailHeader';
import PaymentMadeDetailTable from './PaymentMadeDetailTable';
import PaymentMadeDetailFooter from './PaymentMadeDetailFooter';
import PaymentMadeDetailTableFooter from './PaymentMadeDetailTableFooter';
import { PaymentMadeDetailFooter } from './PaymentMadeDetailFooter';
/**
* Payment made detail tab.
@@ -15,6 +16,7 @@ export default function PaymentMadeDetailTab() {
<CommercialDocBox>
<PaymentMadeDetailHeader />
<PaymentMadeDetailTable />
<PaymentMadeDetailTableFooter />
<PaymentMadeDetailFooter />
</CommercialDocBox>
);

View File

@@ -0,0 +1,42 @@
import React from 'react';
import styled from 'styled-components';
import {
T,
TotalLines,
TotalLine,
TotalLineBorderStyle,
TotalLineTextStyle,
} from 'components';
import { usePaymentMadeDetailContext } from './PaymentMadeDetailProvider';
/**
* Payment made - Details panel - Footer.
*/
export default function PaymentMadeDetailTableFooter() {
const { paymentMade } = usePaymentMadeDetailContext();
return (
<PaymentMadeFooterRoot>
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
<TotalLine
title={<T id={'payment_made.details.subtotal'} />}
value={paymentMade.amount}
borderStyle={TotalLineBorderStyle.SingleDark}
/>
<TotalLine
title={<T id={'payment_made.details.total'} />}
value={paymentMade.formatted_amount}
borderStyle={TotalLineBorderStyle.DoubleDark}
textStyle={TotalLineTextStyle.Bold}
/>
</PaymentMadeTotalLines>
</PaymentMadeFooterRoot>
);
}
export const PaymentMadeFooterRoot = styled.div``;
export const PaymentMadeTotalLines = styled(TotalLines)`
margin-left: auto;
`;

View File

@@ -62,6 +62,11 @@ function PaymentReceiveActionsBar({
openDialog('notify-payment-via-sms', { paymentReceiveId });
};
// Handle print payment receive.
const handlePrintPaymentReceive = () => {
openDialog('payment-pdf-preview', { paymentReceiveId });
};
return (
<DrawerActionsBar>
<NavbarGroup>
@@ -74,6 +79,14 @@ function PaymentReceiveActionsBar({
/>
<NavbarDivider />
</Can>
<Can I={PaymentReceiveAction.View} a={AbilitySubject.PaymentReceive}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" />}
text={<T id={'print'} />}
onClick={handlePrintPaymentReceive}
/>
</Can>
<Can I={PaymentReceiveAction.Delete} a={AbilitySubject.PaymentReceive}>
<Button
className={Classes.MINIMAL}

View File

@@ -10,7 +10,6 @@ import {
DetailItem,
CommercialDocHeader,
CommercialDocTopHeader,
ButtonLink,
CustomerDrawerLink,
} from 'components';
import { usePaymentReceiveDetailContext } from './PaymentReceiveDetailProvider';
@@ -34,6 +33,10 @@ export default function PaymentReceiveDetailHeader() {
<Row>
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('payment_date')}
children={<FormatDate value={paymentReceive.payment_date} />}
/>
<DetailItem
label={intl.get('payment_receive.details.payment_number')}
children={defaultTo(paymentReceive.payment_receive_no, '-')}
@@ -48,10 +51,6 @@ export default function PaymentReceiveDetailHeader() {
label={intl.get('deposit_account')}
children={paymentReceive.deposit_account?.name}
/>
<DetailItem
label={intl.get('payment_date')}
children={<FormatDate value={paymentReceive.payment_date} />}
/>
</DetailsMenu>
</Col>
@@ -62,8 +61,8 @@ export default function PaymentReceiveDetailHeader() {
minLabelSize={'180px'}
>
<DetailItem
label={intl.get('description')}
children={defaultTo(paymentReceive.statement, '')}
label={intl.get('reference')}
children={defaultTo(paymentReceive.reference_no, '-')}
/>
<DetailItem
label={intl.get('created_at')}

View File

@@ -0,0 +1,23 @@
import React from 'react';
import {
CommercialDocFooter,
T,
If,
DetailsMenu,
DetailItem,
} from '../../../components';
import { useVendorCreditDetailDrawerContext } from './VendorCreditDetailDrawerProvider';
export function VendorCreditDetailFooter() {
const { vendorCredit } = useVendorCreditDetailDrawerContext();
return (
<CommercialDocFooter>
<DetailsMenu direction={'horizantal'} minLabelSize={'150px'}>
<If condition={vendorCredit.note}>
<DetailItem label={<T id={'note'} />} children={vendorCredit.note} />
</If>
</DetailsMenu>
</CommercialDocFooter>
);
}

View File

@@ -38,6 +38,11 @@ export default function VendorCreditDetailHeader() {
<Row>
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('vendor_credit.drawer.label_vendor_credit_date')}
>
<FormatDate value={vendorCredit.formatted_vendor_credit_date} />
</DetailItem>
<DetailItem
label={intl.get('vendor_credit.drawer.label_vendor_credit_no')}
>
@@ -49,12 +54,6 @@ export default function VendorCreditDetailHeader() {
{vendorCredit.vendor?.display_name}
</VendorDrawerLink>
</DetailItem>
<DetailItem
label={intl.get('vendor_credit.drawer.label_vendor_credit_date')}
>
<FormatDate value={vendorCredit.formatted_vendor_credit_date} />
</DetailItem>
</DetailsMenu>
</Col>
<Col xs={6}>
@@ -72,10 +71,6 @@ export default function VendorCreditDetailHeader() {
label={intl.get('reference')}
children={defaultTo(vendorCredit.reference_no, '-')}
/>
<DetailItem
label={intl.get('note')}
children={defaultTo(vendorCredit.note, '-')}
/>
<DetailItem
label={<T id={'vendor_credit.drawer.label_created_at'} />}
children={<FormatDate value={vendorCredit.created_at} />}

View File

@@ -5,6 +5,7 @@ import { CommercialDocBox } from 'components';
import VendorCreditDetailHeader from './VendorCreditDetailHeader';
import VendorCreditDetailTable from './VendorCreditDetailTable';
import VendorCreditDetailDrawerFooter from './VendorCreditDetailDrawerFooter';
import { VendorCreditDetailFooter } from './VendorCreditDetailFooter';
/**
* Vendor credit details panel.
@@ -16,6 +17,7 @@ export default function VendorCreditDetailPanel() {
<VendorCreditDetailHeader />
<VendorCreditDetailTable />
<VendorCreditDetailDrawerFooter />
<VendorCreditDetailFooter />
</CommercialDocBox>
);
}

View File

@@ -67,6 +67,7 @@ function BalanceSheet({
onNumberFormatSubmit={handleNumberFormatSubmit}
/>
<BalanceSheetLoadingBar />
<BalanceSheetAlerts />
<DashboardPageContent>
<FinancialStatement>
@@ -80,7 +81,6 @@ function BalanceSheet({
</FinancialStatement>
</DashboardPageContent>
<BalanceSheetAlerts />
</BalanceSheetProvider>
);
}

View File

@@ -70,6 +70,7 @@ function CashFlowStatement({
/>
<CashFlowStatementLoadingBar />
<CashFlowStatementAlerts />
<DashboardPageContent>
<FinancialStatement>
<CashFlowStatementHeader

View File

@@ -52,7 +52,7 @@ export default function CustomersBalanceSummaryGeneralPanelContent() {
<Row>
<Col xs={5}>
<FastField name={'percentage'} type={'checkbox'}>
<FastField name={'percentage_column'} type={'checkbox'}>
{({ field }) => (
<FormGroup labelInfo={<FieldHint />}>
<Checkbox

View File

@@ -1,6 +1,5 @@
import React, { useMemo, useCallback } from 'react';
import React from 'react';
import intl from 'react-intl-universal';
import classNames from 'classnames';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
@@ -15,11 +14,9 @@ export default function CustomersBalanceSummaryTable({
// #ownProps
companyName,
}) {
const {
isCustomersBalanceLoading,
CustomerBalanceSummary: { tableRows },
CustomerBalanceSummary: { table },
} = useCustomersBalanceSummaryContext();
const columns = useCustomersSummaryColumns();
@@ -39,7 +36,7 @@ export default function CustomersBalanceSummaryTable({
<DataTable
className="bigcapital-datatable--financial-report"
columns={columns}
data={tableRows}
data={table.data}
rowClassNames={rowClassNames}
noInitialFetch={true}
/>

View File

@@ -1,5 +1,6 @@
import React from 'react';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { If } from 'components';
import FinancialLoadingBar from '../FinancialLoadingBar';
@@ -9,29 +10,53 @@ import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProv
* Retrieve customers balance summary columns.
*/
export const useCustomersSummaryColumns = () => {
return React.useMemo(
() => [
{
Header: intl.get('customer_name'),
accessor: 'cells[0].value',
className: 'customer_name',
width: 240,
},
{
Header: intl.get('total'),
accessor: 'cells[1].value',
className: 'total',
width: 140,
},
{
Header: intl.get('percentage_of_column'),
accessor: 'cells[2].value',
className: 'total',
width: 140,
},
],
[],
);
const {
CustomerBalanceSummary: { table },
} = useCustomersBalanceSummaryContext();
return React.useMemo(() => {
return dynamicColumns(table.columns || []);
}, [table.columns]);
};
/**
* Account name column accessor.
*/
const accountNameColumnAccessor = () => ({
Header: intl.get('customer_name'),
accessor: 'cells[0].value',
className: 'customer_name',
width: 240,
});
/**
* Total column accessor.
*/
const totalColumnAccessor = () => ({
Header: intl.get('total'),
accessor: 'cells[1].value',
className: 'total',
width: 140,
});
/**
* Percentage column accessor.
*/
const percentageColumnAccessor = () => ({
Header: intl.get('percentage_of_column'),
accessor: 'cells[2].value',
className: 'total',
width: 140,
});
const dynamicColumns = (columns) => {
return R.map(
R.compose(
R.when(R.pathEq(['key'], 'name'), accountNameColumnAccessor),
R.when(R.pathEq(['key'], 'total'), totalColumnAccessor),
R.when(R.pathEq(['key'], 'percentage_of_column'), percentageColumnAccessor),
),
)(columns);
};
/**

View File

@@ -58,14 +58,14 @@ export default function VendorsBalanceSummaryHeaderGeneralContent() {
<Row>
<Col xs={5}>
<FastField name={'percentage'} type={'checkbox'}>
<FastField name={'percentage_column'} type={'checkbox'}>
{({ field }) => (
<FormGroup labelInfo={<FieldHint />}>
<Checkbox
inline={true}
small={true}
label={<T id={'percentage_of_column'} />}
name={'percentage'}
name={'percentage_column'}
{...field}
/>
</FormGroup>

View File

@@ -14,10 +14,8 @@ export default function VendorsBalanceSummaryTable({
//#ownProps
organizationName,
}) {
const {
VendorBalanceSummary,
VendorBalanceSummary: { table },
isVendorsBalanceLoading,
} = useVendorsBalanceSummaryContext();
@@ -39,7 +37,7 @@ export default function VendorsBalanceSummaryTable({
<DataTable
className={'bigcapital-datatable--financial-report'}
columns={columns}
data={VendorBalanceSummary?.tableRows}
data={table?.data}
rowClassNames={rowClassNames}
noInitialFetch={true}
/>

View File

@@ -1,8 +1,8 @@
import React, { useMemo } from 'react';
import React from 'react';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { If } from 'components';
import { getColumnWidth } from 'utils';
import FinancialLoadingBar from '../FinancialLoadingBar';
import { useVendorsBalanceSummaryContext } from './VendorsBalanceSummaryProvider';
@@ -10,28 +10,65 @@ import { useVendorsBalanceSummaryContext } from './VendorsBalanceSummaryProvider
* Retrieve vendors balance summary columns.
*/
export const useVendorsBalanceColumns = () => {
return useMemo(() => [
{
Header: intl.get('vendor_name'),
accessor: 'cells[0].value',
className: 'customer_name',
width: 240,
sticky: 'left',
textOverview: true,
},
{
Header: intl.get('total'),
accessor: 'cells[1].value',
className: 'total',
width: 140,
},
{
Header: intl.get('percentage_of_column'),
accessor: 'cells[2].value',
// className: 'total',
width: 140,
},
]);
const {
VendorBalanceSummary: { table },
} = useVendorsBalanceSummaryContext();
return React.useMemo(() => {
return dynamicColumns(table.columns || []);
}, [table.columns]);
};
/**
* Vendor name accessor.
*/
const vendorColumnAccessor = () => ({
Header: intl.get('vendor_name'),
accessor: 'cells[0].value',
className: 'vendor_name',
width: 240,
align: 'left',
textOverview: true,
});
/**
* Percentage column accessor.
*/
const percentageColumnAccessor = () => ({
Header: intl.get('percentage_of_column'),
accessor: 'cells[2].value',
className: 'total',
width: 140,
align: 'right',
textOverview: true,
});
/**
* Total column accessor.
*/
const totalColumnAccessor = () => ({
Header: intl.get('total'),
accessor: 'cells[1].value',
className: 'total',
width: 140,
align: 'right',
textOverview: true,
});
/**
* Composes the response columns to table component columns.
*/
const dynamicColumns = (columns) => {
return R.map(
R.compose(
R.when(R.pathEq(['key'], 'name'), vendorColumnAccessor),
R.when(R.pathEq(['key'], 'total'), totalColumnAccessor),
R.when(
R.pathEq(['key'], 'percentage_of_column'),
percentageColumnAccessor,
),
),
)(columns);
};
/**

View File

@@ -3,7 +3,6 @@ import { isEmpty } from 'lodash';
import {
getFieldsFromResourceMeta,
transformTableQueryToParams,
isTableEmptyStatus,
} from 'utils';
import { transformItemsTableState } from './utils';

View File

@@ -83,11 +83,13 @@ export function ActionsMenu({
text={intl.get('edit_estimate')}
onClick={safeCallback(onEdit, original)}
/>
<MenuItem
icon={<Icon icon="convert_to" />}
text={intl.get('convert_to_invoice')}
onClick={safeCallback(onConvert, original)}
/>
<If condition={!original.is_converted_to_invoice}>
<MenuItem
icon={<Icon icon="convert_to" />}
text={intl.get('convert_to_invoice')}
onClick={safeCallback(onConvert, original)}
/>
</If>
<If condition={!original.is_delivered}>
<MenuItem

View File

@@ -11,12 +11,11 @@ const InvoicesDrawerContent = lazy(() => import('./InvoiceDrawerContent'));
*/
function InvoiceDrawer({
name,
//#withDrawer
isOpen,
payload: { invoiceId },
}) {
return (
<Drawer isOpen={isOpen} name={name}>
<DrawerSuspense>

View File

@@ -16,7 +16,7 @@ const PaymentReceivesListContext = createContext();
*/
function PaymentReceivesListProvider({ query, tableStateChanged, ...props }) {
// Fetch payment receives resource views and fields.
const { data: paymentReceivesViews, isFetching: isViewsLoading } =
const { data: paymentReceivesViews, isLoading: isViewsLoading } =
useResourceViews('payment_receives');
// Fetch the payment receives resource fields.

View File

@@ -2,7 +2,7 @@ import React from 'react';
import 'style/pages/PaymentReceive/List.scss';
import { DashboardContentTable, DashboardPageContent } from 'components';
import { DashboardPageContent } from 'components';
import PaymentReceiveActionsBar from './PaymentReceiveActionsBar';
import { PaymentReceivesListProvider } from './PaymentReceiptsListProvider';
import PaymentReceiveViewTabs from './PaymentReceiveViewTabs';

View File

@@ -48,7 +48,7 @@ function VendorFormAfterPrimarySection() {
{({ field, meta: { error, touched } }) => (
<InputGroup
intent={inputIntent({ error, touched })}
placeholder={intl.get('Mobile')}
placeholder={intl.get('mobile')}
{...field}
/>
)}

View File

@@ -3,15 +3,15 @@ import React from 'react';
const VendorDeleteAlert = React.lazy(() =>
import('../Alerts/Vendors/VendorDeleteAlert'),
);
const ContactActivateAlert = React.lazy(() =>
import('../Alerts/Contacts/ContactActivateAlert'),
const VendorActivateAlert = React.lazy(() =>
import('../Alerts/Vendors/VendorActivateAlert'),
);
const ContactInactivateAlert = React.lazy(() =>
import('../Alerts/Contacts/ContactInactivateAlert'),
const VendorInactivateAlert = React.lazy(() =>
import('../Alerts/Vendors/VendorInactivateAlert'),
);
export default [
{ name: 'vendor-delete', component: VendorDeleteAlert },
{ name: 'contact-activate', component: ContactActivateAlert },
{ name: 'contact-inactivate', component: ContactInactivateAlert },
{ name: 'vendor-activate', component: VendorActivateAlert },
{ name: 'vendor-inactivate', component: VendorInactivateAlert },
];

View File

@@ -67,15 +67,15 @@ function VendorsTable({
// Handle cancel/confirm inactive.
const handleInactiveVendor = ({ id, contact_service }) => {
openAlert('contact-inactivate', {
contactId: id,
openAlert('vendor-inactivate', {
vendorId: id,
service: contact_service,
});
};
// Handle cancel/confirm activate.
// Handle cancel/confirm activate.
const handleActivateVendor = ({ id, contact_service }) => {
openAlert('contact-activate', { contactId: id, service: contact_service });
openAlert('vendor-activate', { vendorId: id, service: contact_service });
};
// Handle click delete vendor.

View File

@@ -6,7 +6,9 @@ import {
MenuItem,
MenuDivider,
Position,
Tooltip,
Intent,
Classes,
} from '@blueprintjs/core';
import intl from 'react-intl-universal';
@@ -114,6 +116,24 @@ export function BalanceAccessor({ closing_balance, currency_code }) {
return <Money amount={closing_balance} currency={currency_code} />;
}
/**
* Note column accessor.
*/
export function NoteAccessor(row) {
return (
<If condition={row.note}>
<Tooltip
className={Classes.TOOLTIP_INDICATOR}
content={row.note}
position={Position.LEFT_TOP}
hoverOpenDelay={50}
>
<Icon icon={'file-alt'} iconSize={16} />
</Tooltip>
</If>
);
}
/**
* Retrieve the vendors table columns.
*/
@@ -148,12 +168,20 @@ export function useVendorsTableColumns() {
},
{
id: 'work_phone',
Header: intl.get('work_phone'),
Header: intl.get('phone_number'),
accessor: PhoneNumberAccessor,
className: 'work_phone',
width: 100,
clickable: true,
},
{
id: 'note',
Header: intl.get('note'),
accessor: NoteAccessor,
disableSortBy: true,
width: 85,
clickable: true,
},
{
id: 'balance',
Header: intl.get('receivable_balance'),

View File

@@ -2,6 +2,7 @@ import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import { useRequestPdf } from '../utils';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
@@ -341,3 +342,10 @@ export function useRefundCreditTransaction(id, props, requestProps) {
},
);
}
/**
* Retrieve the credit note pdf document data,
*/
export function usePdfCreditNote(creditNoteId) {
return useRequestPdf(`sales/credit_notes/${creditNoteId}`);
}

View File

@@ -304,12 +304,11 @@ export function useCustomerBalanceSummaryReport(query, props) {
},
{
select: (res) => ({
columns: res.data.columns,
query: res.data.query,
tableRows: res.data.table.rows,
table: res.data.table,
}),
defaultData: {
tableRows: [],
table: {},
query: {},
},
...props,
@@ -334,12 +333,11 @@ export function useVendorsBalanceSummaryReport(query, props) {
{
select: (res) => ({
columns: res.data.columns,
query: res.data.query,
tableRows: res.data.table.data,
table: res.data.table,
}),
defaultData: {
tableRows: [],
table: {},
query: {},
},
...props,

View File

@@ -48,6 +48,10 @@ export function useCreateInvoice(props) {
// Invalidate invoice customer.
queryClient.invalidateQueries([t.CUSTOMER, values.customer_id]);
// Invalidate estimates.
queryClient.invalidateQueries(t.SALE_ESTIMATES);
queryClient.invalidateQueries(t.SALE_ESTIMATE);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
@@ -92,6 +96,10 @@ export function useDeleteInvoice(props) {
// Invalidate specific invoice.
queryClient.invalidateQueries([t.SALE_INVOICE, id]);
// Invalidate estimates.
queryClient.invalidateQueries(t.SALE_ESTIMATES);
queryClient.invalidateQueries(t.SALE_ESTIMATE);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},

View File

@@ -2,6 +2,8 @@ import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import { transformPagination, saveInvoke } from 'utils';
import { useRequestPdf } from '../utils';
import t from './types';
// Common invalidate queries.
@@ -31,11 +33,11 @@ const commonInvalidateQueries = (client) => {
client.invalidateQueries(t.CREDIT_NOTE);
client.invalidateQueries(t.CREDIT_NOTES);
// Invalidate reconcile.
client.invalidateQueries(t.RECONCILE_CREDIT_NOTE);
client.invalidateQueries(t.RECONCILE_CREDIT_NOTES);
// Invalidate invoices payment transactions.
client.invalidateQueries(t.SALE_INVOICE_PAYMENT_TRANSACTIONS);
};
@@ -224,3 +226,10 @@ export function usePaymentReceiveSMSDetail(
},
);
}
/**
* Retrieve the payment receive pdf document data.
*/
export function usePdfPaymentReceive(paymentReceiveId) {
return useRequestPdf(`sales/payment_receives/${paymentReceiveId}`);
}

View File

@@ -78,7 +78,7 @@
"new": "جديد",
"invite_user": "دعوة مستخدم",
"your_access_to_your_team": "سيتلقى زميلك في الفريق رسالة بريد إلكتروني تتيح له الوصول إلى فريقك.",
"invite": "التصنيف",
"invite": "دعوة",
"count": "العدد",
"item_type": "نوع المنتج",
"item_name": "اسم المنتج",
@@ -1759,5 +1759,18 @@
"global_error.you_dont_have_permissions": "ليس لديك صلاحية الوصول إلى هذه الصفحة.",
"global_error.transactions_locked": "تم قفل المعاملات التي تمت قبل {lockedToDate}. ومن ثم لا يمكن القيام بأي عمل.",
"global_error.authorized_user_inactive": "المستخدم المصرح له تم تعطيلة."
}
"global_error.authorized_user_inactive": "المستخدم المصرح له تم تعطيلة.",
"vendor.alert.activated_message": "تم تفعيل المورد بنجاح.",
"vendor.alert.are_you_sure_want_to_activate_this_vendor": "هل أنت متأكد أنك تريد تفعيل هذا المورد؟ ستتمكن من تعطيله لاحقًا",
"vendor.alert.inactivated_message": "تم إلغاء تنشيط المورد بنجاح.",
"vendor.alert.are_you_sure_want_to_inactivate_this_vendor":"هل أنت متأكد أنك تريد إلغاء تنشيط هذا المورد؟ ستكون قادرًا على تنشيطه لاحقًا",
"customer.alert.activated_message":"تم تفعيل الزبون بنجاح.",
"customer.alert.are_you_sure_want_to_activate_this_customer": "هل أنت متأكد أنك تريد تفعيل هذا الزبون؟ ستتمكن من تعطيله لاحقًا",
"customer.alert.inactivated_message": "تم إلغاء تنشيط الزبون بنجاح.",
"customer.alert.are_you_sure_want_to_inactivate_this_customer":"هل أنت متأكد أنك تريد إلغاء تنشيط هذا الزبون؟ ستكون قادرًا على تنشيطه لاحقًا",
"credit_note_preview.dialog.title":"معاينة إشعار الدائن PDF",
"payment_receive_preview.dialog.title":"معاينة سند الزبون PDF"
}

View File

@@ -866,7 +866,7 @@
"published_at": "Published at",
"customers_balance_summary": "Customers Balance Summary",
"vendors_balance_summary": "Vendors Balance Summary",
"percentage_of_column": "Percentage",
"percentage_of_column": "% of column",
"customers_transactions": "Customers Transactions",
"vendors_transactions": "Vendors Transactions",
"reference_type": "Reference type",
@@ -1192,6 +1192,7 @@
"payment_made.details.payment_number": "Payment #",
"payment_made.details.subtotal": "Subtotal",
"payment_made.details.total": "TOTAL",
"payment_made.details.statement": "Statement",
"payment_receive.details.payment_number": "Payment #",
"payment_receive.details.total": "TOTAL",
"payment_receive.details.subtotal": "Subtotal",
@@ -1736,8 +1737,22 @@
"payment_made.drawer.title": "Payment made details {number}",
"manual_journal.drawer.title": "Manual journal details ({number})",
"expense.drawer.title": "Expense details",
"global_error.you_dont_have_permissions": "You do not have permissions to access this page.",
"global_error.transactions_locked": "Transactions before {lockedToDate} has been locked. Hence action cannot be performed.",
"global_error.authorized_user_inactive": "The authorized user is inactive."
"global_error.authorized_user_inactive": "The authorized user is inactive.",
"the_vendor_has_been_inactivated_successfully": "The contact has been inactivated successfully.",
"vendor.alert.activated_message": "The vendor has been activated successfully.",
"vendor.alert.are_you_sure_want_to_inactivate_this_vendor":"Are you sure want to inactivate this vendor? You will to able to activate it later.",
"vendor.alert.inactivated_message": "The vendor has been inactivated successfully.",
"vendor.alert.are_you_sure_want_to_activate_this_vendor": "Are you sure want to activate this vendor? You will to able to inactivate it later.",
"customer.alert.activated_message":"The customer has been activated successfully.",
"customer.alert.are_you_sure_want_to_activate_this_customer": "Are you sure want to activate this customer? You will to able to inactivate it later.",
"customer.alert.inactivated_message": "The customer has been inactivated successfully.",
"customer.alert.are_you_sure_want_to_inactivate_this_customer":"Are you sure want to inactivate this customer? You will to able to activate it later.",
"credit_note_preview.dialog.title":"Credit Note PDF Preview",
"payment_receive_preview.dialog.title":"Payment Receive PDF Preview"
}