Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling Invoices as a feature #46567

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2758,6 +2758,10 @@ export default {
title: 'Spend',
subtitle: 'Enable optional functionality that helps you scale your team.',
},
earnSection: {
title: 'Earn',
subtitle: 'Enable optional functionality to streamline your revenue and get paid faster.',
},
organizeSection: {
title: 'Organize',
subtitle: 'Group and analyze spend, record every tax paid.',
Expand Down Expand Up @@ -2791,6 +2795,10 @@ export default {
title: 'Workflows',
subtitle: 'Configure how spend is approved and paid.',
},
invoices: {
title: 'Invoices',
subtitle: 'Send and receive invoices.',
},
categories: {
title: 'Categories',
subtitle: 'Track and organize spend.',
Expand Down
8 changes: 8 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2810,6 +2810,10 @@ export default {
title: 'Gasto',
subtitle: 'Habilita otras funcionalidades que ayudan a aumentar tu equipo.',
},
earnSection: {
title: 'Gane',
subtitle: 'Habilita funciones opcionales para agilizar tus ingresos y recibir pagos más rápido.',
},
organizeSection: {
title: 'Organizar',
subtitle: 'Agrupa y analiza el gasto, registra cada impuesto pagado.',
Expand Down Expand Up @@ -2843,6 +2847,10 @@ export default {
title: 'Flujos de trabajo',
subtitle: 'Configura cómo se aprueba y paga los gastos.',
},
invoices: {
title: 'Facturas',
subtitle: 'Enviar y recibir facturas.',
},
categories: {
title: 'Categorías',
subtitle: 'Monitoriza y organiza los gastos.',
Expand Down
6 changes: 6 additions & 0 deletions src/libs/API/parameters/EnablePolicyInvoicesParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type EnablePolicyInvoicesParams = {
madmax330 marked this conversation as resolved.
Show resolved Hide resolved
policyID: string;
enabled: boolean;
};

export default EnablePolicyInvoicesParams;
madmax330 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ export type {default as ConnectPolicyToNetSuiteParams} from './ConnectPolicyToNe
export type {default as CreateWorkspaceReportFieldParams} from './CreateWorkspaceReportFieldParams';
export type {default as UpdateWorkspaceReportFieldInitialValueParams} from './UpdateWorkspaceReportFieldInitialValueParams';
export type {default as EnableWorkspaceReportFieldListValueParams} from './EnableWorkspaceReportFieldListValueParams';
export type {default as EnablePolicyInvoicesParams} from './EnablePolicyInvoicesParams';
madmax330 marked this conversation as resolved.
Show resolved Hide resolved
export type {default as CreateWorkspaceReportFieldListValueParams} from './CreateWorkspaceReportFieldListValueParams';
export type {default as RemoveWorkspaceReportFieldListValueParams} from './RemoveWorkspaceReportFieldListValueParams';
export type {default as OpenPolicyExpensifyCardsPageParams} from './OpenPolicyExpensifyCardsPageParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ const WRITE_COMMANDS = {
ENABLE_POLICY_WORKFLOWS: 'EnablePolicyWorkflows',
ENABLE_POLICY_REPORT_FIELDS: 'EnablePolicyReportFields',
ENABLE_POLICY_EXPENSIFY_CARDS: 'EnablePolicyExpensifyCards',
ENABLE_POLICY_INVOICES: 'EnablePolicyInvoices',
madmax330 marked this conversation as resolved.
Show resolved Hide resolved
SET_POLICY_TAXES_CURRENCY_DEFAULT: 'SetPolicyCurrencyDefaultTax',
SET_POLICY_TAXES_FOREIGN_CURRENCY_DEFAULT: 'SetPolicyForeignCurrencyDefaultTax',
SET_POLICY_CUSTOM_TAX_NAME: 'SetPolicyCustomTaxName',
Expand Down Expand Up @@ -514,6 +515,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.ENABLE_POLICY_WORKFLOWS]: Parameters.EnablePolicyWorkflowsParams;
[WRITE_COMMANDS.ENABLE_POLICY_REPORT_FIELDS]: Parameters.EnablePolicyReportFieldsParams;
[WRITE_COMMANDS.ENABLE_POLICY_EXPENSIFY_CARDS]: Parameters.EnablePolicyExpensifyCardsParams;
[WRITE_COMMANDS.ENABLE_POLICY_INVOICES]: Parameters.EnablePolicyInvoicesParams;
[WRITE_COMMANDS.JOIN_POLICY_VIA_INVITE_LINK]: Parameters.JoinPolicyInviteLinkParams;
[WRITE_COMMANDS.ACCEPT_JOIN_REQUEST]: Parameters.AcceptJoinRequestParams;
[WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams;
Expand Down
2 changes: 1 addition & 1 deletion src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ function getActiveAdminWorkspaces(policies: OnyxCollection<Policy> | null): Poli

/** Whether the user can send invoice */
function canSendInvoice(policies: OnyxCollection<Policy> | null): boolean {
return getActiveAdminWorkspaces(policies).length > 0;
return getActiveAdminWorkspaces(policies).some((policy) => policy?.areInvoicesEnabled);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check is correct, but maybe we should update it later and leave a TODO for now?
Cause invoicing settings screen isn't ready yet, and this update will block users from invoice creation.
It relates to other places where we check for areInvoicesEnabled as well.
Maybe we should confirm it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got you. Let me clarify.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that makes sense, let's put it as a todo and update it when the invoices screen is ready

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've commented out some changes to prevent the invoice creation from being blocked.

Commit - 4acdd47.

Video
Flow.mp4

cc @madmax330 @VickyStash

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I open the PR for review?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rezkiy37 let's add a link to the blocking issue in TODOs #45175, then it's fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - c79964d.

}

function hasDependentTags(policy: OnyxEntry<Policy>, policyTagList: OnyxEntry<PolicyTagList>) {
Expand Down
2 changes: 1 addition & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6041,7 +6041,7 @@ function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Pol
}

if (isInvoiceRoom(report)) {
if (isPolicyAdmin(report?.policyID ?? '-1', allPolicies)) {
if (policy?.areInvoicesEnabled && isPolicyAdmin(report?.policyID ?? '-1', allPolicies)) {
return [CONST.IOU.TYPE.INVOICE];
}
return [];
Expand Down
50 changes: 50 additions & 0 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
DeleteWorkspaceParams,
EnablePolicyConnectionsParams,
EnablePolicyExpensifyCardsParams,
EnablePolicyInvoicesParams,
EnablePolicyReportFieldsParams,
EnablePolicyTaxesParams,
EnablePolicyWorkflowsParams,
Expand Down Expand Up @@ -2916,6 +2917,54 @@ function enableDistanceRequestTax(policyID: string, customUnitName: string, cust
API.write(WRITE_COMMANDS.ENABLE_DISTANCE_REQUEST_TAX, params, onyxData);
}

function enablePolicyInvoices(policyID: string, enabled: boolean) {
madmax330 marked this conversation as resolved.
Show resolved Hide resolved
const onyxData: OnyxData = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
areInvoicesEnabled: enabled,
pendingFields: {
areInvoicesEnabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
pendingFields: {
areInvoicesEnabled: null,
},
},
},
],
failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
areInvoicesEnabled: !enabled,
pendingFields: {
areInvoicesEnabled: null,
},
},
},
],
};

const parameters: EnablePolicyInvoicesParams = {policyID, enabled};

API.write(WRITE_COMMANDS.ENABLE_POLICY_INVOICES, parameters, onyxData);
madmax330 marked this conversation as resolved.
Show resolved Hide resolved

if (enabled && getIsNarrowLayout()) {
navigateWhenEnableFeature(policyID);
}
}

function openPolicyMoreFeaturesPage(policyID: string) {
const params: OpenPolicyMoreFeaturesPageParams = {policyID};

Expand Down Expand Up @@ -3201,6 +3250,7 @@ export {
enablePolicyTaxes,
enablePolicyWorkflows,
enableDistanceRequestTax,
enablePolicyInvoices,
openPolicyMoreFeaturesPage,
openPolicyProfilePage,
openPolicyInitialPage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const useIsFocused = () => {
return isFocused || (topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE && shouldUseNarrowLayout);
};

type PolicySelector = Pick<OnyxTypes.Policy, 'type' | 'role' | 'isPolicyExpenseChatEnabled' | 'pendingAction' | 'avatarURL' | 'name' | 'id'>;
type PolicySelector = Pick<OnyxTypes.Policy, 'type' | 'role' | 'isPolicyExpenseChatEnabled' | 'pendingAction' | 'avatarURL' | 'name' | 'id' | 'areInvoicesEnabled'>;

type FloatingActionButtonAndPopoverOnyxProps = {
/** The list of policies the user has access to. */
Expand Down Expand Up @@ -97,6 +97,7 @@ const policySelector = (policy: OnyxEntry<OnyxTypes.Policy>): PolicySelector =>
pendingAction: policy.pendingAction,
avatarURL: policy.avatarURL,
name: policy.name,
areInvoicesEnabled: policy.areInvoicesEnabled,
}) as PolicySelector;

const getQuickActionIcon = (action: QuickActionName): React.FC<SvgProps> => {
Expand Down
4 changes: 2 additions & 2 deletions src/pages/iou/request/step/IOURequestStepSendFrom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ function IOURequestStepSendFrom({route, transaction, allPolicies}: IOURequestSte
const selectedWorkspace = useMemo(() => transaction?.participants?.find((participant) => participant.isSender), [transaction]);

const workspaceOptions: WorkspaceListItem[] = useMemo(() => {
const activeAdminWorkspaces = PolicyUtils.getActiveAdminWorkspaces(allPolicies);
const availableWorkspaces = PolicyUtils.getActiveAdminWorkspaces(allPolicies).filter((policy) => policy?.areInvoicesEnabled);

return activeAdminWorkspaces
return availableWorkspaces
.sort((policy1, policy2) => sortWorkspacesBySelected({policyID: policy1.id, name: policy1.name}, {policyID: policy2.id, name: policy2.name}, selectedWorkspace?.policyID))
.map((policy) => ({
text: policy.name,
Expand Down
18 changes: 18 additions & 0 deletions src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,19 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
});
}

const earnItems: Item[] = [
{
icon: Illustrations.InvoiceBlue,
titleTranslationKey: 'workspace.moreFeatures.invoices.title',
subtitleTranslationKey: 'workspace.moreFeatures.invoices.subtitle',
isActive: policy?.areInvoicesEnabled ?? false,
pendingAction: policy?.pendingFields?.areInvoicesEnabled,
action: (isEnabled: boolean) => {
Policy.enablePolicyInvoices(policy?.id ?? '-1', isEnabled);
},
},
];

const organizeItems: Item[] = [
{
icon: Illustrations.FolderOpen,
Expand Down Expand Up @@ -247,6 +260,11 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
subtitleTranslationKey: 'workspace.moreFeatures.spendSection.subtitle',
items: spendItems,
},
{
titleTranslationKey: 'workspace.moreFeatures.earnSection.title',
subtitleTranslationKey: 'workspace.moreFeatures.earnSection.subtitle',
items: earnItems,
},
{
titleTranslationKey: 'workspace.moreFeatures.organizeSection.title',
subtitleTranslationKey: 'workspace.moreFeatures.organizeSection.subtitle',
Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,9 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback<
/** Whether the Connections feature is enabled */
areConnectionsEnabled?: boolean;

/** Whether the Invoices features are enabled */
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved
areInvoicesEnabled?: boolean;

/** The verified bank account linked to the policy */
achAccount?: ACHAccount;

Expand Down
Loading