Skip to content

Commit

Permalink
Merge pull request #641 from invoiceninja/develop
Browse files Browse the repository at this point in the history
Sync develop with main
  • Loading branch information
beganovich authored Apr 19, 2023
2 parents ec9f5cd + 7ba1830 commit 55397ad
Show file tree
Hide file tree
Showing 67 changed files with 1,191 additions and 231 deletions.
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default defineConfig({
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
retries: 2,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
Expand Down
2 changes: 1 addition & 1 deletion src/common/hooks/entities/useQuickCreateActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export function useQuickCreateActions() {
visible: Boolean(!gateways?.length),
},
{
key: 'connect_bank',
key: 'add_bank_account',
url: '/settings/bank_accounts/create',
section: 'settings',
visible: enterprisePlan() && Boolean(!bankAccounts?.length),
Expand Down
18 changes: 14 additions & 4 deletions src/common/queries/company-gateways.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,27 @@ export function useCompanyGatewaysQuery() {
);
}

export function useCompanyGatewayQuery(params: { id: string | undefined }) {
interface Params {
id: string | undefined;
queryParams?: string;
enabled?: boolean;
}

export function useCompanyGatewayQuery(params: Params) {
const { isAdmin } = useAdmin();

return useQuery(
route('/api/v1/company_gateways/:id', { id: params.id }),
route(`/api/v1/company_gateways/:id?${params.queryParams || ''}`, {
id: params.id,
}),
() =>
request(
'GET',
endpoint('/api/v1/company_gateways/:id', { id: params.id })
endpoint(`/api/v1/company_gateways/:id?${params.queryParams || ''}`, {
id: params.id,
})
),
{ staleTime: Infinity, enabled: isAdmin }
{ staleTime: Infinity, enabled: (params.enabled ?? true) && isAdmin }
);
}

Expand Down
2 changes: 0 additions & 2 deletions src/common/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { settingsRoutes } from '$app/pages/settings/routes';
import { authenticationRoutes } from '$app/pages/authentication/routes';
import { quoteRoutes } from '$app/pages/quotes/routes';
import { creditRoutes } from '$app/pages/credits/routes';
import { systemlogRoutes } from '$app/pages/system-logs/routes';
import { projectRoutes } from '$app/pages/projects/routes';
import { taskRoutes } from '$app/pages/tasks/routes';
import { vendorRoutes } from '$app/pages/vendors/routes';
Expand Down Expand Up @@ -56,7 +55,6 @@ export const routes = (
{reportRoutes}
{transactionRoutes}
{settingsRoutes}
{systemlogRoutes}
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
Expand Down
16 changes: 4 additions & 12 deletions src/components/layouts/Default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
Repeat,
CreditCard,
File,
ShieldOff,
Briefcase,
Clock,
PieChart,
Expand Down Expand Up @@ -157,10 +156,10 @@ export function Default(props: Props) {
icon: Repeat,
current: location.pathname.startsWith('/recurring_invoices'),
visible:
(enabled(ModuleBitmask.RecurringInvoices) &&
hasPermission('view_recurring_invoice')) ||
hasPermission('create_recurring_invoice') ||
hasPermission('edit_recurring_invoice'),
enabled(ModuleBitmask.RecurringInvoices) &&
(hasPermission('view_recurring_invoice') ||
hasPermission('create_recurring_invoice') ||
hasPermission('edit_recurring_invoice')),
rightButton: {
icon: PlusCircle,
to: '/recurring_invoices/create',
Expand Down Expand Up @@ -353,13 +352,6 @@ export function Default(props: Props) {
current: location.pathname.startsWith('/settings'),
visible: true,
},
{
name: t('system_logs'),
href: '/system_logs',
icon: ShieldOff,
current: location.pathname.startsWith('/system_logs'),
visible: companyUser?.is_admin || companyUser?.is_owner || false,
},
];

const { isOwner } = useAdmin();
Expand Down
10 changes: 9 additions & 1 deletion src/components/layouts/common/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ export function useSettingsRoutes() {
{
name: t('customize_and_preview'),
href: '/settings/invoice_design/customize',
current: location.pathname.startsWith('/settings/invoice_design/customize'),
current: location.pathname.startsWith(
'/settings/invoice_design/customize'
),
enabled: isAdmin || isOwner || false,
},
{
Expand Down Expand Up @@ -152,6 +154,12 @@ export function useSettingsRoutes() {
current: location.pathname.startsWith('/settings/users'),
enabled: isAdmin || isOwner || false,
},
{
name: t('system_logs'),
href: '/settings/system_logs',
current: location.pathname.startsWith('/settings/system_logs'),
enabled: isAdmin || isOwner || false,
},
];

return { basic, advanced };
Expand Down
2 changes: 1 addition & 1 deletion src/pages/credits/email/Email.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default function Email() {
resourceType="credit"
list={list}
defaultEmail="email_template_credit"
redirectUrl="/credits"
redirectUrl={route('/clients/:id/credits', { id: credit.client_id })}
/>
)}
</Default>
Expand Down
38 changes: 21 additions & 17 deletions src/pages/invoices/common/hooks/useHandleProductChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,37 @@ interface Props {
export function useHandleProductChange(props: Props) {
const resource = props.resource;

return (index: number, product_key: string, product: Product) => {
return (index: number, product_key: string, product?: Product) => {
const lineItem = { ...resource.line_items[index] };

lineItem.product_key = product.product_key || product_key;
lineItem.quantity = product.quantity || 1;
lineItem.cost = product.price || 0;
lineItem.product_key = product?.product_key || product_key;
lineItem.quantity = product?.quantity || 0;
lineItem.cost = product?.price || 0;

if (props.type == 'product' && product.notes) {
lineItem.notes = product.notes;
if (!product) {
lineItem.notes = '';
}

if (props.type == 'product' && product?.notes) {
lineItem.notes = product?.notes;
}

if (props.type == 'task' && product.notes && !lineItem.notes) {
if (props.type == 'task' && product?.notes && !lineItem.notes) {
lineItem.notes = product.notes;
}

lineItem.tax_name1 = product.tax_name1 || '';
lineItem.tax_name2 = product.tax_name2 || '';
lineItem.tax_name3 = product.tax_name3 || '';
lineItem.tax_name1 = product?.tax_name1 || '';
lineItem.tax_name2 = product?.tax_name2 || '';
lineItem.tax_name3 = product?.tax_name3 || '';

lineItem.tax_rate1 = product.tax_rate1 || 0;
lineItem.tax_rate2 = product.tax_rate2 || 0;
lineItem.tax_rate3 = product.tax_rate3 || 0;
lineItem.tax_rate1 = product?.tax_rate1 || 0;
lineItem.tax_rate2 = product?.tax_rate2 || 0;
lineItem.tax_rate3 = product?.tax_rate3 || 0;

lineItem.custom_value1 = product.custom_value1 || '';
lineItem.custom_value2 = product.custom_value2 || '';
lineItem.custom_value3 = product.custom_value3 || '';
lineItem.custom_value4 = product.custom_value4 || '';
lineItem.custom_value1 = product?.custom_value1 || '';
lineItem.custom_value2 = product?.custom_value2 || '';
lineItem.custom_value3 = product?.custom_value3 || '';
lineItem.custom_value4 = product?.custom_value4 || '';

return props.onChange(index, lineItem);
};
Expand Down
3 changes: 3 additions & 0 deletions src/pages/invoices/common/hooks/useResolveInputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function useResolveInputField(props: Props) {
if (property === 'product_key') {
return (
<ProductSelector
key={resource?.line_items[index][property]}
onChange={(value) =>
value.resource &&
handleProductChange(index, value.label, value.resource)
Expand All @@ -102,6 +103,8 @@ export function useResolveInputField(props: Props) {
onProductCreated={(product) =>
product && handleProductChange(index, product.product_key, product)
}
clearButton
onClearButtonClick={() => handleProductChange(index, '')}
/>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/invoices/email/Email.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default function Email() {
resourceType="invoice"
list={list}
defaultEmail="email_template_invoice"
redirectUrl="/invoices"
redirectUrl={route('/clients/:id', { id: invoice.client_id })}
/>
)}
</Default>
Expand Down
49 changes: 43 additions & 6 deletions src/pages/payments/refund/Refund.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,26 @@ import toast from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { useNavigate, useParams } from 'react-router-dom';
import { useCompanyGatewayQuery } from '$app/common/queries/company-gateways';
import { Gateway } from '$app/common/interfaces/statics';

export default function Refund() {
const { id } = useParams();
const { data: payment } = usePaymentQuery({ id });

const { data: companyGateway } = useCompanyGatewayQuery({
id: payment?.data.data.company_gateway_id,
queryParams: 'include=gateway',
enabled: Boolean(payment?.data.data.company_gateway_id),
});

const [t] = useTranslation();
const [errors, setErrors] = useState<ValidationBag>();
const [invoices, setInvoices] = useState<string[]>([]);
const [email, setEmail] = useState(false);
const [shouldShowGatewayRefund, setShouldShowGatewayRefund] =
useState<boolean>(false);
const [refundGateway, setRefundGateway] = useState<boolean>(false);

const navigate = useNavigate();
const queryClient = useQueryClient();
Expand All @@ -52,11 +63,13 @@ export default function Refund() {
const toastId = toast.loading(t('processing'));
setErrors(undefined);

request(
'POST',
endpoint('/api/v1/payments/refund?&email_receipt=:email', { email }),
values
)
let endPointUrl = '/api/v1/payments/refund?&email_receipt=:email';

if (refundGateway) {
endPointUrl += '&gateway_refund=true';
}

request('POST', endpoint(endPointUrl, { email }), values)
.then(() => {
toast.success(t('refunded_payment'), { id: toastId });
navigate('/payments');
Expand Down Expand Up @@ -113,6 +126,18 @@ export default function Refund() {
});
}, [formik.values.invoices]);

useEffect(() => {
if (companyGateway) {
const gateway: Gateway = companyGateway.data.data.gateway;

const showGatewayRefund = Object.values(gateway.options).some(
(option) => option.refund
);

setShouldShowGatewayRefund(showGatewayRefund);
}
}, [companyGateway]);

return (
<Card
title={t('refund_payment')}
Expand Down Expand Up @@ -229,7 +254,7 @@ export default function Refund() {

<Divider />

<Element leftSide={t('send_email')}>
<Element leftSide={t('send_email')} leftSideHelp={t('email_receipt')}>
<Toggle
checked={email}
onChange={() => {
Expand All @@ -238,6 +263,18 @@ export default function Refund() {
/>
</Element>

{shouldShowGatewayRefund && (
<Element
leftSide={t('gateway_refund')}
leftSideHelp={t('gateway_refund_help')}
>
<Toggle
checked={refundGateway}
onChange={(value) => setRefundGateway(value)}
/>
</Element>
)}

{errors?.errors.id && <Alert type="danger">{errors.errors.id}</Alert>}
</Card>
);
Expand Down
4 changes: 3 additions & 1 deletion src/pages/purchase-orders/email/Email.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ export default function Email() {
resourceType="purchase_order"
list={list}
defaultEmail="email_template_purchase_order"
redirectUrl="/purchase_orders"
redirectUrl={route('/vendors/:id', {
id: purchaseOrder.vendor_id,
})}
/>
)}
</Default>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/quotes/email/Email.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default function Email() {
resourceType="quote"
list={list}
defaultEmail="email_template_quote"
redirectUrl="/quotes"
redirectUrl={route('/clients/:id/quotes', { id: quote.client_id })}
/>
)}
</Default>
Expand Down
11 changes: 10 additions & 1 deletion src/pages/settings/account-management/component/Plan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ export function Plan() {

return (
<Card title={t('plan')}>
<Element leftSide={t('plan')}>{account?.plan || t('free')}</Element>
<Element leftSide={t('plan')}>
<span>
{account?.plan
? `${t(account.plan)} ${t('plan')} `
: `${t('free')} ${t('plan')} `}
</span>
<span>
/ {account.num_users} {t('users')}
</span>
</Element>

{account?.plan_expires !== '' && (
<Element leftSide={t('expires_on')}>
Expand Down
1 change: 1 addition & 0 deletions src/pages/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export * from './bank-accounts';
export * from './subscriptions/index';
export * from './schedules';
export * from './backup-restore';
export * from './system-logs/SystemLog';

export * from './group-settings/GroupSettings';
export * from './users';
Expand Down
3 changes: 3 additions & 0 deletions src/pages/settings/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ export const settingsRoutes = (
}
/>
</Route>
<Route path="/settings/system_logs">
<Route path="" element={<Settings.SystemLog />} />
</Route>
<Route path="payment_terms">
<Route path="" element={<Settings.PaymentTerms />} />
<Route path=":id/edit" element={<Settings.EditPaymentTerm />} />
Expand Down
Loading

0 comments on commit 55397ad

Please sign in to comment.