Skip to content

Commit 2e9f456

Browse files
authored
[Feature] Rejected APP refund flow (#234)
* Create refund APP payment API, hook up to frontend * Fix TS error
1 parent b22b6ce commit 2e9f456

File tree

11 files changed

+158
-24
lines changed

11 files changed

+158
-24
lines changed

components/admin/requests/processing/TasksCard.tsx

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ import {
3838
UploadDocumentsResponse,
3939
UploadDocumentsRequest,
4040
UPLOAD_DOCUMENTS_MUTATION,
41+
RefundPaymentResponse,
42+
RefundPaymentRequest,
43+
REFUND_PAYMENT_MUTATION,
4144
} from '@tools/admin/requests/processing-tasks-card';
4245
import ReviewInformationStep from '@components/admin/requests/processing/ReviewInformationStep';
4346
import { clientUploadToS3, getFileName } from '@lib/utils/s3-utils';
@@ -118,6 +121,13 @@ export default function ProcessingTasksCard({ applicationId }: ProcessingTasksCa
118121
refetch();
119122
};
120123

124+
const [refundPayment, { loading: refundPaymentLoading }] =
125+
useMutation<RefundPaymentResponse, RefundPaymentRequest>(REFUND_PAYMENT_MUTATION);
126+
const handleRefundPayment = async () => {
127+
await refundPayment({ variables: { input: { applicationId } } });
128+
refetch();
129+
};
130+
121131
const toast = useToast();
122132

123133
const handleSubmitDocuments = async (applicationDoc: File) => {
@@ -195,14 +205,14 @@ export default function ProcessingTasksCard({ applicationId }: ProcessingTasksCa
195205
reviewRequestCompleted,
196206
reviewRequestCompletedEmployee,
197207
reviewRequestCompletedUpdatedAt,
208+
paymentRefunded,
209+
paymentRefundedEmployee,
210+
paymentRefundedUpdatedAt,
198211
},
199212
},
200213
} = data;
201214
const shopifyOrderUrl = `https://${process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN}/admin/orders/${shopifyConfirmationNumber}`;
202215

203-
/** Placeholder boolean status for customer refund */
204-
const customerRefunded = false;
205-
206216
return (
207217
<PermitHolderInfoCard colSpan={7} header={_header}>
208218
<Divider mt="8px" />
@@ -233,40 +243,30 @@ export default function ProcessingTasksCard({ applicationId }: ProcessingTasksCa
233243
</>
234244
) : undefined
235245
}
236-
isCompleted={false}
246+
isCompleted={paymentRefunded}
237247
showLog={showTaskLog}
238248
log={
239-
showTaskLog && appHolepunchedEmployee
249+
showTaskLog && paymentRefundedEmployee
240250
? {
241251
name: formatFullName(
242-
appHolepunchedEmployee.firstName,
243-
appHolepunchedEmployee.lastName
252+
paymentRefundedEmployee.firstName,
253+
paymentRefundedEmployee.lastName
244254
),
245-
date: appHolepunchedUpdatedAt,
255+
date: paymentRefundedUpdatedAt,
246256
}
247257
: null
248258
}
249259
>
250-
{customerRefunded ? (
251-
<Button
252-
variant="ghost"
253-
textDecoration="underline black"
254-
// TODO: Add click handler
255-
// onClick={() => {}}
256-
>
257-
<Text textStyle="caption" color="black">
258-
Undo
259-
</Text>
260-
</Button>
261-
) : (
260+
{!paymentRefunded && (
262261
<Button
263262
marginLeft="auto"
264263
height="35px"
265264
bg="background.gray"
266265
_hover={{ bg: 'background.grayHover' }}
267266
color="black"
268-
// TODO: Add click handler
269-
// onClick={() => {}}
267+
onClick={handleRefundPayment}
268+
isDisabled={refundPaymentLoading}
269+
isLoading={refundPaymentLoading}
270270
>
271271
<Text textStyle="xsmall-medium">Mark as complete</Text>
272272
</Button>

lib/application-processing/field-resolvers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,16 @@ export const applicationProcessingAppMailedEmployeeResolver: FieldResolver<
133133
.applicationProcessing()
134134
.appMailedEmployee();
135135
};
136+
137+
/**
138+
* Get the employee that refunded the APP payment (rejected APPs)
139+
*/
140+
export const applicationProcessingPaymentRefundedEmployeeResolver: FieldResolver<
141+
ApplicationProcessing & { id: number },
142+
Employee
143+
> = async (parent, _, { prisma }) => {
144+
return await prisma.application
145+
.findUnique({ where: { id: parent.id } })
146+
.applicationProcessing()
147+
.paymentRefundedEmployee();
148+
};

lib/application-processing/resolvers.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
UpdateApplicationProcessingMailOutResult,
2323
UpdateApplicationProcessingUploadDocumentsResult,
2424
UpdateApplicationProcessingReviewRequestInformationResult,
25+
MutationUpdateApplicationProcessingRefundPaymentArgs,
26+
UpdateApplicationProcessingRefundPaymentResult,
2527
} from '@lib/graphql/types';
2628
import { getPermanentPermitExpiryDate } from '@lib/utils/permit-expiry';
2729
import { generateApplicationInvoicePdf } from '@lib/invoices/utils';
@@ -1021,7 +1023,51 @@ export const updateApplicationProcessingMailOut: Resolver<
10211023
}
10221024

10231025
if (!updatedApplicationProcessing) {
1024-
throw new ApolloError('Error assigning APP number to application');
1026+
throw new ApolloError('Error updating mail-out status of application');
1027+
}
1028+
1029+
return { ok: true };
1030+
};
1031+
1032+
/**
1033+
* Refund payment of rejected application
1034+
* @returns Status of the operation (ok)
1035+
*/
1036+
export const updateApplicationProcessingRefundPayment: Resolver<
1037+
MutationUpdateApplicationProcessingRefundPaymentArgs,
1038+
UpdateApplicationProcessingRefundPaymentResult
1039+
> = async (_parent, args, { prisma, session }) => {
1040+
// TODO: Validation
1041+
const { input } = args;
1042+
const { applicationId } = input;
1043+
1044+
if (!session) {
1045+
// TODO: Create error
1046+
throw new ApolloError('Not authenticated');
1047+
}
1048+
1049+
const { id: employeeId } = session;
1050+
1051+
let updatedApplicationProcessing;
1052+
try {
1053+
updatedApplicationProcessing = await prisma.application.update({
1054+
where: { id: applicationId },
1055+
data: {
1056+
applicationProcessing: {
1057+
update: {
1058+
paymentRefunded: true,
1059+
paymentRefundedUpdatedAt: new Date(),
1060+
paymentRefundedEmployee: { connect: { id: employeeId } },
1061+
},
1062+
},
1063+
},
1064+
});
1065+
} catch {
1066+
// TODO: Error handling
1067+
}
1068+
1069+
if (!updatedApplicationProcessing) {
1070+
throw new ApolloError('Error updating payment refund status of application');
10251071
}
10261072

10271073
return { ok: true };

lib/application-processing/schema.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export default gql`
2929
appMailed: Boolean!
3030
appMailedEmployee: Employee
3131
appMailedUpdatedAt: Date
32+
paymentRefunded: Boolean!
33+
paymentRefundedEmployee: Employee
34+
paymentRefundedUpdatedAt: Date
3235
}
3336
3437
# Approve application
@@ -138,4 +141,13 @@ export default gql`
138141
type UpdateApplicationProcessingMailOutResult {
139142
ok: Boolean!
140143
}
144+
145+
# Refund application payment (cannot undo)
146+
input UpdateApplicationProcessingRefundPaymentInput {
147+
applicationId: Int!
148+
}
149+
150+
type UpdateApplicationProcessingRefundPaymentResult {
151+
ok: Boolean!
152+
}
141153
`;

lib/applications/field-resolvers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export const applicationProcessingResolver: FieldResolver<
6060
| 'reviewRequestCompletedEmployee'
6161
| 'documentsUrlEmployee'
6262
| 'appMailedEmployee'
63+
| 'paymentRefundedEmployee'
6364
>
6465
> = async (parent, _args, { prisma }) => {
6566
const applicationProcessing = await prisma.application

lib/graphql/resolvers.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
updateApplicationProcessingUploadDocuments,
4646
updateApplicationProcessingMailOut,
4747
updateApplicationProcessingReviewRequestInformation,
48+
updateApplicationProcessingRefundPayment,
4849
} from '@lib/application-processing/resolvers'; // Application processing resolvers
4950
import { Context } from '@lib/graphql/context'; // Context type
5051
import { dateScalar } from '@lib/graphql/scalars'; // Custom date scalar implementation
@@ -79,6 +80,7 @@ import {
7980
applicationProcessingAppNumberEmployeeResolver,
8081
applicationProcessingDocumentsUrlEmployeeResolver,
8182
applicationProcessingInvoiceResolver,
83+
applicationProcessingPaymentRefundedEmployeeResolver,
8284
applicationProcessingReviewRequestCompletedEmployeeResolver,
8385
applicationProcessingWalletCardCreatedEmployeeResolver,
8486
} from '@lib/application-processing/field-resolvers';
@@ -219,6 +221,9 @@ const resolvers = {
219221
updateApplicationProcessingMailOut: authorize(updateApplicationProcessingMailOut, [
220222
'SECRETARY',
221223
]),
224+
updateApplicationProcessingRefundPayment: authorize(updateApplicationProcessingRefundPayment, [
225+
'SECRETARY',
226+
]),
222227

223228
// Employees
224229
createEmployee: authorize(createEmployee),
@@ -277,6 +282,7 @@ const resolvers = {
277282
reviewRequestCompletedEmployee: applicationProcessingReviewRequestCompletedEmployeeResolver,
278283
documentsUrlEmployee: applicationProcessingDocumentsUrlEmployeeResolver,
279284
appMailedEmployee: applicationProcessingAppMailedEmployeeResolver,
285+
paymentRefundedEmployee: applicationProcessingPaymentRefundedEmployeeResolver,
280286
},
281287
};
282288

lib/graphql/schema.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ export default gql`
106106
updateApplicationProcessingMailOut(
107107
input: UpdateApplicationProcessingMailOutInput!
108108
): UpdateApplicationProcessingMailOutResult
109+
updateApplicationProcessingRefundPayment(
110+
input: UpdateApplicationProcessingRefundPaymentInput!
111+
): UpdateApplicationProcessingRefundPaymentResult
109112
110113
# Employees
111114
createEmployee(input: CreateEmployeeInput!): CreateEmployeeResult!

lib/graphql/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ export type ApplicationProcessing = {
141141
appMailed: Scalars['Boolean'];
142142
appMailedEmployee: Maybe<Employee>;
143143
appMailedUpdatedAt: Maybe<Scalars['Date']>;
144+
paymentRefunded: Scalars['Boolean'];
145+
paymentRefundedEmployee: Maybe<Employee>;
146+
paymentRefundedUpdatedAt: Maybe<Scalars['Date']>;
144147
};
145148

146149
export type ApplicationStatus =
@@ -589,6 +592,7 @@ export type Mutation = {
589592
updateApplicationProcessingGenerateInvoice: Maybe<UpdateApplicationProcessingGenerateInvoiceResult>;
590593
updateApplicationProcessingUploadDocuments: Maybe<UpdateApplicationProcessingUploadDocumentsResult>;
591594
updateApplicationProcessingMailOut: Maybe<UpdateApplicationProcessingMailOutResult>;
595+
updateApplicationProcessingRefundPayment: Maybe<UpdateApplicationProcessingRefundPaymentResult>;
592596
createEmployee: CreateEmployeeResult;
593597
updateEmployee: UpdateEmployeeResult;
594598
deleteEmployee: DeleteEmployeeResult;
@@ -740,6 +744,11 @@ export type MutationUpdateApplicationProcessingMailOutArgs = {
740744
};
741745

742746

747+
export type MutationUpdateApplicationProcessingRefundPaymentArgs = {
748+
input: UpdateApplicationProcessingRefundPaymentInput;
749+
};
750+
751+
743752
export type MutationCreateEmployeeArgs = {
744753
input: CreateEmployeeInput;
745754
};
@@ -1390,6 +1399,15 @@ export type UpdateApplicationProcessingMailOutResult = {
13901399
ok: Scalars['Boolean'];
13911400
};
13921401

1402+
export type UpdateApplicationProcessingRefundPaymentInput = {
1403+
applicationId: Scalars['Int'];
1404+
};
1405+
1406+
export type UpdateApplicationProcessingRefundPaymentResult = {
1407+
__typename?: 'UpdateApplicationProcessingRefundPaymentResult';
1408+
ok: Scalars['Boolean'];
1409+
};
1410+
13931411
export type UpdateApplicationProcessingReviewRequestInformationInput = {
13941412
applicationId: Scalars['Int'];
13951413
reviewRequestCompleted: Scalars['Boolean'];

prisma/schema.prisma

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ model Employee {
109109
mailedApplicationProcessings ApplicationProcessing[] @relation("application_processing_app_mailed_employee_idToemployees")
110110
assignedAppNumberApplicationProcessings ApplicationProcessing[] @relation("application_processing_app_number_employee_idToemployees")
111111
setDocumentsUrlApplicationProcessings ApplicationProcessing[] @relation("application_processing_documents_url_employee_idToemployees")
112+
refundedPaymentApplicationProcessings ApplicationProcessing[] @relation("application_processing_payment_refunded_employee_idToemployees")
112113
reviewRequestApplicationProcessings ApplicationProcessing[] @relation("application_processing_review_request_completed_employee_idToemployees")
113114
createdWalletCardApplicationProcessings ApplicationProcessing[] @relation("application_processing_wallet_card_created_employee_idToemployees")
114115
@@ -223,13 +224,17 @@ model ApplicationProcessing {
223224
appMailed Boolean @default(false) @map("app_mailed")
224225
appMailedEmployeeId Int? @map("app_mailed_employee_id")
225226
appMailedUpdatedAt DateTime @default(now()) @map("app_mailed_updated_at") @db.Timestamptz(6)
227+
paymentRefunded Boolean @default(false) @map("payment_refunded")
228+
paymentRefundedEmployeeId Int? @map("payment_refunded_employee_id")
229+
paymentRefundedUpdatedAt DateTime @default(now()) @map("payment_refunded_updated_at") @db.Timestamptz(6)
226230
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
227231
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
228232
appHolepunchedEmployee Employee? @relation("application_processing_app_holepunched_employee_idToemployees", fields: [appHolepunchedEmployeeId], references: [id])
229233
appMailedEmployee Employee? @relation("application_processing_app_mailed_employee_idToemployees", fields: [appMailedEmployeeId], references: [id])
230234
appNumberEmployee Employee? @relation("application_processing_app_number_employee_idToemployees", fields: [appNumberEmployeeId], references: [id])
231235
documentsUrlEmployee Employee? @relation("application_processing_documents_url_employee_idToemployees", fields: [documentsUrlEmployeeId], references: [id])
232236
applicationInvoice ApplicationInvoice? @relation("application_invoicesToapplication_processing", fields: [invoiceNumber], references: [invoiceNumber])
237+
paymentRefundedEmployee Employee? @relation("application_processing_payment_refunded_employee_idToemployees", fields: [paymentRefundedEmployeeId], references: [id])
233238
reviewRequestEmployee Employee? @relation("application_processing_review_request_completed_employee_idToemployees", fields: [reviewRequestCompletedEmployeeId], references: [id])
234239
walletCardCreatedEmployee Employee? @relation("application_processing_wallet_card_created_employee_idToemployees", fields: [walletCardCreatedEmployeeId], references: [id])
235240
application Application? @relation("application_processingToapplications")

prisma/schema.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ CREATE TABLE application_processing (
236236
app_mailed BOOLEAN NOT NULL DEFAULT false,
237237
app_mailed_employee_id INTEGER,
238238
app_mailed_updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
239+
payment_refunded BOOLEAN NOT NULL DEFAULT false,
240+
payment_refunded_employee_id INTEGER,
241+
payment_refunded_updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
239242
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
240243
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
241244

@@ -245,7 +248,8 @@ CREATE TABLE application_processing (
245248
FOREIGN KEY(review_request_completed_employee_id) REFERENCES employees(id),
246249
FOREIGN KEY(invoice_number) REFERENCES application_invoices(invoice_number),
247250
FOREIGN KEY(documents_url_employee_id) REFERENCES employees(id),
248-
FOREIGN KEY(app_mailed_employee_id) REFERENCES employees(id)
251+
FOREIGN KEY(app_mailed_employee_id) REFERENCES employees(id),
252+
FOREIGN KEY(payment_refunded_employee_id) REFERENCES employees(id)
249253
);
250254

251255
-- Create applications table

0 commit comments

Comments
 (0)