Skip to content

Commit c976f67

Browse files
axshaniilyamerman
andauthored
feat: Check Payments (#368)
* implement StopPayments * init Stop and Check Payments * added createCheckPaymentSimulation and e2e-test * implemented checkPayments * stopPayments refactoring * lint-fix * lint-fix * update unit client and added a test for checkPayments * lint-fix --------- Co-authored-by: Ilya Merman <[email protected]>
1 parent 9cf5661 commit c976f67

File tree

12 files changed

+447
-5
lines changed

12 files changed

+447
-5
lines changed

resources/baseResource.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export class BaseResource {
4242
.catch(error => { throw extractUnitError(error) })
4343
}
4444

45+
protected async httpGetWithInclude<T>(path: string, include?: string): Promise<T> {
46+
const params = {...(include && { include })}
47+
return this.httpGet<T>(path, { params })
48+
}
49+
4550
protected async httpPatch<T>(path: string, data: DataPayload | { data: DataPayload; }, config?: { headers?: object; params?: object; }): Promise<T> {
4651
return this.httpPatchFullPath<T>(this.resourcePath + path, data, config)
4752
}

resources/checkPayments.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Include, Meta, UnitConfig, UnitResponse } from "../types/common"
2+
import { CheckPayment, CheckPaymentStatus, ApproveCheckPaymentRequest, ReturnCheckPaymentRequest, BaseCheckPaymentListParams } from "../types/checkPayment"
3+
import { BaseResource } from "./baseResource"
4+
import { Account, Customer, Transaction } from "../types"
5+
import {responseEncoding, ResponseType} from "axios"
6+
7+
export class CheckPayments extends BaseResource {
8+
constructor(token: string, basePath: string, config?: UnitConfig) {
9+
super(token, basePath + "/check-payments", config)
10+
}
11+
12+
public async get(id: string, include?: string): Promise<UnitResponse<CheckPayment>> {
13+
return this.httpGetWithInclude<UnitResponse<CheckPayment> & Include<Account[] | Customer[] | Transaction[]> >(`/${id}`, include)
14+
}
15+
16+
public async return(request: ReturnCheckPaymentRequest): Promise<UnitResponse<CheckPayment>> {
17+
return this.httpPost<UnitResponse<CheckPayment>>(`/${request.id}/return`, {data: request.data})
18+
}
19+
20+
public async approve(request: ApproveCheckPaymentRequest): Promise<UnitResponse<CheckPayment>> {
21+
return this.httpPost<UnitResponse<CheckPayment>>(`/${request.id}/approve`, {data: request.data})
22+
}
23+
24+
public async getImage(id: string, front = true, responseEncoding: responseEncoding = "binary", responseType: ResponseType = "blob"): Promise<string> {
25+
const p = front ? "front" : "back"
26+
return this.httpGet<string>(`/${id}/${p}`, {responseEncoding, responseType})
27+
}
28+
29+
30+
public async list(params?: CheckPaymentListParams): Promise<UnitResponse<CheckPayment[]> & Meta> {
31+
const parameters: any = {
32+
"page[limit]": (params?.limit ? params.limit : 100),
33+
"page[offset]": (params?.offset ? params.offset : 0),
34+
...(params?.accountId && { "filter[accountId]": params.accountId }),
35+
...(params?.customerId && { "filter[customerId]": params.customerId }),
36+
...(params?.since && { "filter[since]": params.since }),
37+
...(params?.until && { "filter[until]": params.until }),
38+
...(params?.fromAmount && { "filter[fromAmount]": params.fromAmount }),
39+
...(params?.toAmount && { "filter[toAmount]": params.toAmount }),
40+
...(params?.checkNumber && { "filter[checkNumber]": params.checkNumber }),
41+
...(params?.tags && { "tags": params.tags }),
42+
...(params?.sort && { "sort": params.sort }),
43+
...(params?.include && { "sort": params.include })
44+
}
45+
46+
if (params?.status)
47+
params.status.forEach((s, idx) => {
48+
parameters[`filter[status][${idx}]`] = s
49+
})
50+
51+
return this.httpGet<UnitResponse<CheckPayment[]> & Meta>("", { params: parameters })
52+
}
53+
}
54+
55+
export interface CheckPaymentListParams extends BaseCheckPaymentListParams {
56+
/**
57+
* Optional. Filter by status (Processed, PendingReview, MarkedForReturn or Returned). Usage example: filter[status][0]=Processed
58+
*/
59+
status?: CheckPaymentStatus[]
60+
61+
/**
62+
* Optional. A comma-separated list of related resources to include in the response. Related resources include: customer, account, transaction.
63+
* See [Getting Related Resources](https://docs.unit.co/about-jsonapi/#intro-getting-related-resources)
64+
*/
65+
include?: string
66+
}

resources/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export * from "./payments"
2121
export * from "./repayments"
2222
export * from "./receivedPayments"
2323
export * from "./recurringPayments"
24+
export * from "./checkPayments"
25+
export * from "./stopPayments"
2426
export * from "./returns"
2527
export * from "./rewards"
2628
export * from "./simulations"

resources/simulations.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BaseResource } from "."
2-
import { UnitConfig, UnitResponse } from "../types"
2+
import { CheckPayment, CreateCheckPaymentSimulation, UnitConfig, UnitResponse } from "../types"
33
import { AchReceivedPayment, Application, ApplicationDocument, AchPayment } from "../types"
44
import {
55
ApproveApplicationSimulation,
@@ -93,6 +93,10 @@ export class Simulations extends BaseResource {
9393
)
9494
}
9595

96+
public async createCheckPayment(request: CreateCheckPaymentSimulation): Promise<UnitResponse<CheckPayment>> {
97+
return this.httpPost<UnitResponse<CheckPayment>>("/check-payments", { data: request} )
98+
}
99+
96100
public async createCardPurchase(
97101
request: CreateCardPurchaseSimulation
98102
): Promise<UnitResponse<CardTransaction>> {

resources/stopPayments.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Meta, UnitConfig, UnitResponse } from "../types/common"
2+
import { BaseCheckPaymentListParams, CreateStopPaymentRequest, StopPayment, StopPaymentStatus } from "../types/checkPayment"
3+
import { BaseResource } from "./baseResource"
4+
5+
export class StopPayments extends BaseResource {
6+
constructor(token: string, basePath: string, config?: UnitConfig) {
7+
super(token, basePath + "/stop-payments", config)
8+
}
9+
10+
public async create(request: CreateStopPaymentRequest): Promise<UnitResponse<StopPayment>> {
11+
return this.httpPost<UnitResponse<StopPayment>>("", { data: request} )
12+
}
13+
14+
public async get(id: string): Promise<UnitResponse<StopPayment>> {
15+
return this.httpGet<UnitResponse<StopPayment>>(`/${id}`)
16+
}
17+
18+
public async disable(id: string): Promise<UnitResponse<StopPayment>> {
19+
return this.httpPost<UnitResponse<StopPayment>>(`/${id}/disable`)
20+
}
21+
22+
public async list(params?: StopPaymentListParams): Promise<UnitResponse<StopPayment[]> & Meta> {
23+
const parameters: any = {
24+
"page[limit]": (params?.limit ? params.limit : 100),
25+
"page[offset]": (params?.offset ? params.offset : 0),
26+
...(params?.accountId && { "filter[accountId]": params.accountId }),
27+
...(params?.customerId && { "filter[customerId]": params.customerId }),
28+
...(params?.since && { "filter[since]": params.since }),
29+
...(params?.until && { "filter[until]": params.until }),
30+
...(params?.fromAmount && { "filter[fromAmount]": params.fromAmount }),
31+
...(params?.toAmount && { "filter[toAmount]": params.toAmount }),
32+
...(params?.checkNumber && { "filter[checkNumber]": params.checkNumber }),
33+
...(params?.tags && { "tags": params.tags }),
34+
...(params?.sort && { "sort": params.sort })
35+
}
36+
37+
if (params?.status)
38+
params.status.forEach((s, idx) => {
39+
parameters[`filter[status][${idx}]`] = s
40+
})
41+
42+
return this.httpGet<UnitResponse<StopPayment[]> & Meta>("", { params: parameters })
43+
}
44+
}
45+
46+
export interface StopPaymentListParams extends BaseCheckPaymentListParams {
47+
/**
48+
* Optional. Filter by status (Active or Disabled). Usage example: filter[status][0]=Active
49+
*/
50+
status?: StopPaymentStatus[]
51+
}

tests/checkPayments.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Unit } from "../unit"
2+
3+
import dotenv from "dotenv"
4+
dotenv.config()
5+
const unit = new Unit(process.env.UNIT_TOKEN || "test", process.env.UNIT_API_URL || "test")
6+
7+
describe("Test Check Payments", () => {
8+
test("Get Check Payments List", async () => {
9+
const checkPayments = (await unit.checkPayments.list()).data
10+
11+
checkPayments.forEach(async cp => {
12+
expect(cp.type).toBe("checkPayment")
13+
expect(cp.attributes.checkNumber).not.toBe("")
14+
expect(cp.attributes.createdAt).not.toBe("")
15+
expect(cp.attributes.updatedAt).not.toBe("")
16+
expect(cp.attributes.description).not.toBe("")
17+
expect(cp.attributes.additionalVerificationStatus).not.toBe("")
18+
expect(cp.attributes.amount).not.toBe(undefined)
19+
expect(cp.attributes.counterpartyRoutingNumber).not.toBe("")
20+
})
21+
})
22+
23+
test("Get Check Payment", async () => {
24+
const checkPayments = (await unit.checkPayments.list()).data
25+
26+
checkPayments.forEach(async cp => {
27+
expect(cp.type).toBe("checkPayment")
28+
29+
const res = (await unit.checkPayments.get(cp.id)).data
30+
31+
expect(cp.type).toBe(res.type)
32+
expect(cp.attributes.checkNumber).toBe(res.attributes.checkNumber)
33+
expect(cp.attributes.createdAt).toBe(res.attributes.createdAt)
34+
expect(cp.attributes.updatedAt).toBe(res.attributes.updatedAt)
35+
expect(cp.attributes.description).toBe(res.attributes.description)
36+
expect(cp.attributes.additionalVerificationStatus).toBe(res.attributes.additionalVerificationStatus)
37+
expect(cp.attributes.amount).toBe(res.attributes.amount)
38+
expect(cp.attributes.counterpartyRoutingNumber).toBe(res.attributes.counterpartyRoutingNumber)
39+
40+
})
41+
})
42+
})

tests/stopPayments.spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { createRelationship } from "../helpers"
2+
import { Unit } from "../unit"
3+
4+
import dotenv from "dotenv"
5+
import { createIndividualAccount } from "./testHelpers"
6+
dotenv.config()
7+
const unit = new Unit(process.env.UNIT_TOKEN || "test", process.env.UNIT_API_URL || "test")
8+
9+
describe("E2E Test", () => {
10+
test("Create Check and Stop Payments", async () => {
11+
const accountId = (await createIndividualAccount(unit)).data.id
12+
const checkNumber = "12345"
13+
const relationships = {account: createRelationship("depositAccount", accountId)}
14+
const amount = 1000
15+
16+
const checkPayment = (await unit.simulations.createCheckPayment({
17+
type: "checkPayment",
18+
attributes: {
19+
amount,
20+
checkNumber
21+
},
22+
relationships
23+
})).data
24+
25+
expect(checkPayment.type).toBe("checkPayment")
26+
27+
const response = await unit.stopPayments.create({
28+
type: "stopPayment",
29+
attributes: {
30+
amount: amount/2,
31+
checkNumber,
32+
tags: {"test": "test"}
33+
},
34+
relationships
35+
})
36+
37+
expect(response.data.type).toBe("stopPayment")
38+
})
39+
40+
test("Get Stop Payments List", async () => {
41+
const stopPayments = (await unit.stopPayments.list()).data
42+
43+
stopPayments.forEach(async sp => {
44+
expect(sp.type).toBe("stopPayment")
45+
46+
const res = (await unit.stopPayments.get(sp.id)).data
47+
48+
expect(res.type).toBe("stopPayment")
49+
expect(res.id).toBe(sp.id)
50+
expect(res.attributes.createdAt).toBe(sp.attributes.createdAt)
51+
expect(res.attributes.updatedAt).toBe(sp.attributes.updatedAt)
52+
expect(res.attributes.amount).toBe(sp.attributes.amount)
53+
expect(res.attributes.checkNumber).toBe(sp.attributes.checkNumber)
54+
expect(res.attributes.status).toBe(sp.attributes.status)
55+
56+
})
57+
})
58+
})

0 commit comments

Comments
 (0)