-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from Ahdeyyy/dedicated-virtual-account
Dedicated virtual account
- Loading branch information
Showing
13 changed files
with
613 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@ahdeyy/paystack": patch | ||
--- | ||
|
||
added dedicated virtual accounts endpoint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,7 +133,7 @@ const archived_request = await paystack.payment_request.archive("request id") | |
#### Create customer | ||
|
||
```typescript | ||
let customer = await paystack.customer.create({ | ||
const customer = await paystack.customer.create({ | ||
email: "[email protected]", | ||
first_name: "john", | ||
last_name: "doe", | ||
|
@@ -143,19 +143,19 @@ let customer = await paystack.customer.create({ | |
#### List customers | ||
|
||
```typescript | ||
let customer = await paystack.customer.list({ perPage: 10, page: 1 }) | ||
const customer = await paystack.customer.list({ perPage: 10, page: 1 }) | ||
``` | ||
|
||
#### Fetch customer | ||
|
||
```typescript | ||
let customer = await paystack.customer.fetch(customers_email) | ||
const customer = await paystack.customer.fetch(customers_email) | ||
``` | ||
|
||
#### Validate customer | ||
|
||
```typescript | ||
let customer = await paystack.customer.validate(customer_code, { | ||
const customer = await paystack.customer.validate(customer_code, { | ||
country, | ||
type, | ||
account_number, | ||
|
@@ -169,13 +169,13 @@ let customer = await paystack.customer.validate(customer_code, { | |
#### Update customer | ||
|
||
```typescript | ||
let customer = await paystack.customer.update(customer_code, { phone }) | ||
const customer = await paystack.customer.update(customer_code, { phone }) | ||
``` | ||
|
||
#### Whitelist/Blacklist customer | ||
|
||
```typescript | ||
let customer = await paystack.customer.whitelist_blacklist({ | ||
const customer = await paystack.customer.whitelist_blacklist({ | ||
customer: customer_code, | ||
risk_action: "deny", | ||
}) | ||
|
@@ -184,7 +184,7 @@ let customer = await paystack.customer.whitelist_blacklist({ | |
#### Deactivate Authorization | ||
|
||
```typescript | ||
let customer = await paystack.customer.deactivate_authorization( | ||
const customer = await paystack.customer.deactivate_authorization( | ||
Authorization_code | ||
) | ||
``` | ||
|
@@ -194,7 +194,7 @@ let customer = await paystack.customer.deactivate_authorization( | |
#### Create product | ||
|
||
```typescript | ||
let product = await paystack.product.create({ | ||
const product = await paystack.product.create({ | ||
name: "sakura", | ||
description: "cherry blossom", | ||
price: 10000, | ||
|
@@ -205,19 +205,19 @@ let product = await paystack.product.create({ | |
#### List products | ||
|
||
```typescript | ||
let product = await paystack.product.list({ perPage: 10, page: 1 }) | ||
const product = await paystack.product.list({ perPage: 10, page: 1 }) | ||
``` | ||
|
||
#### Fetch product | ||
|
||
```typescript | ||
let product = await paystack.product.fetch(product_id) | ||
const product = await paystack.product.fetch(product_id) | ||
``` | ||
|
||
#### Update product | ||
|
||
```typescript | ||
let product = await paystack.product.update(product_id, { price: 69420 }) | ||
const product = await paystack.product.update(product_id, { price: 69420 }) | ||
``` | ||
|
||
## ROADMAP | ||
|
@@ -254,10 +254,21 @@ let product = await paystack.product.update(product_id, { price: 69420 }) | |
- [x] Update Product | ||
- [x] Tests | ||
|
||
- [ ] Dedicated Virtual Accounts | ||
- [x] Create Dedicated Virtual Account | ||
- [x] Assign Dedicated Virtual Account | ||
- [x] List Dedicated Accounts | ||
- [x] Fetch Dedicated Account | ||
- [x] Requery Dedicated Account | ||
- [x] Deactivate Dedicated Account | ||
- [x] Split Dedicated Account Transaction | ||
- [x] Remove Split from Dedicated Account | ||
- [x] Fetch Bank Providers | ||
- [ ] Tests | ||
|
||
- [ ] Transactions | ||
- [ ] Transaction Splits | ||
- [ ] Terminal | ||
- [ ] Dedicated Virtual Accounts | ||
- [ ] Apple Pay | ||
- [ ] Subaccounts | ||
- [ ] Plans | ||
|
@@ -273,6 +284,7 @@ let product = await paystack.product.update(product_id, { price: 69420 }) | |
- [ ] Disputes | ||
- [ ] Refunds | ||
- [ ] Verification | ||
- [ ] Miscellanous | ||
|
||
## Testing | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { test, mock, expect } from "bun:test" | ||
import { Paystack } from "../paystack" | ||
|
||
// I can't test this suite properly because I don't have access to a nuban enabled business | ||
// so this test would only check if the functions accurately pings the api endpoint with | ||
// an expectation to fail | ||
|
||
const paystack = mock(() => new Paystack(import.meta.env.PAYSTACK_SECRET_KEY ?? "")) | ||
|
||
test("create DVA", async () => { | ||
let response = await paystack().dva.create({ customer: import.meta.env.CUSTOMER_CODE ?? '' }) | ||
expect(response.status).toBe(false) | ||
}) | ||
|
||
test("assign DVA", async () => { | ||
let response = await paystack().dva.assign({ | ||
email: "[email protected]", | ||
first_name: "Jane", | ||
middle_name: "Karen", | ||
last_name: "Doe", | ||
phone: "+2348100000000", | ||
preferred_bank: "test-bank", | ||
country: "NG" | ||
|
||
}) | ||
expect(response.status).toBe(false) | ||
}) | ||
test("list DVA", async () => { | ||
let response = await paystack().dva.list({ active: true, currency: "NGN" }); | ||
expect(response.status).toBe(false); | ||
if (response.status) { | ||
expect(response.data).toBeInstanceOf(Array) | ||
expect(response.meta.perPage).toBe(10) | ||
} | ||
}); | ||
|
||
test("fetch DVA", async () => { | ||
let response = await paystack().dva.fetch("foo") | ||
expect(response.status).toBe(false) | ||
}) | ||
test("requery DVA", async () => { | ||
let response = await paystack().dva.requery({ account_number: "98897", provider_slug: "wema-bank" }); | ||
expect(response.status).toBe(false); | ||
if (response.status) { | ||
expect(response.message).toBeInstanceOf(String) | ||
} | ||
}); | ||
|
||
test("delete DVA", async () => { | ||
let response = await paystack().dva.deactivate("foo") | ||
expect(response.status).toBe(false) | ||
}) | ||
|
||
test("split DVA", async () => { | ||
let response = await paystack().dva.split({ customer: "janey" }) | ||
expect(response.status).toBe(false) | ||
}) | ||
|
||
test("remove split DVA", async () => { | ||
let response = await paystack().dva.remove_split("bar") | ||
expect(response.status).toBe(false) | ||
|
||
}) | ||
test("fetch bank providers DVA", async () => { | ||
let response = await paystack().dva.fetch_bank_providers(); | ||
expect(response.status).toBe(false) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import type { AssignDVAData, AssignDVAResponse, CreateDVAData, CreateDVAResponse, DeactivateDVAResponse, FetchBankProvidersDVAResponse, FetchDVAResponse, ListDVAQuery, ListDVAResponse, RemoveSplitDVAResponse, RequeryDVAQuery, RequeryDVAResponse, SplitDVAData, SplitDVAResponse } from "./types"; | ||
|
||
export class DedicatedVirtualAccounts { | ||
private endpoint: string = "https://api.paystack.co/dedicated_account"; | ||
|
||
private secret_key: string; | ||
constructor(secret_key: string) { | ||
this.secret_key = secret_key; | ||
} | ||
|
||
/** | ||
* Create a dedicated virtual account for an existing customer | ||
* Bank Availability | ||
* We currently support Wema Bank and Titan Paystack | ||
* */ | ||
async create(data: CreateDVAData): Promise<CreateDVAResponse> { | ||
const headers = this.get_headers(); | ||
|
||
const response = await fetch(this.endpoint, { | ||
headers: headers, | ||
method: "POST", | ||
body: JSON.stringify(data) | ||
}) | ||
|
||
const response_data = await response.json() as CreateDVAResponse | ||
|
||
return response_data | ||
} | ||
|
||
/** With this endpoint, you can create a customer, validate the customer, and assign a DVA to the customer. | ||
* Bank Availability | ||
* We currently support Wema Bank and Titan Paystack. | ||
* */ | ||
async assign(data: AssignDVAData): Promise<AssignDVAResponse> { | ||
const headers = this.get_headers(); | ||
|
||
const response = await fetch(this.endpoint + "/assign", { | ||
headers: headers, | ||
method: "POST", | ||
body: JSON.stringify(data) | ||
}) | ||
|
||
const response_data = await response.json() as AssignDVAResponse; | ||
|
||
return response_data; | ||
} | ||
|
||
/** List dedicated virtual accounts available on your integration. */ | ||
async list(query: ListDVAQuery): Promise<ListDVAResponse> { | ||
const keys = Object.keys(query) | ||
const url = new URL(this.endpoint) | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i] ?? '' | ||
const value = query[key] | ||
url.searchParams.set(key, value) | ||
} | ||
const response = await fetch(url, { | ||
headers: this.get_headers(), | ||
method: "GET", | ||
}) | ||
|
||
const response_data = await response.json() as ListDVAResponse | ||
|
||
if (response_data.status) { | ||
response_data.meta.page = Number(response_data.meta.page) | ||
response_data.meta.total = Number(response_data.meta.total) | ||
response_data.meta.perPage = Number(response_data.meta.perPage) | ||
response_data.meta.skipped = Number(response_data.meta.skipped) | ||
response_data.meta.pageCount = Number(response_data.meta.pageCount) | ||
} | ||
|
||
return response_data | ||
} | ||
|
||
async fetch(dedicated_account_id: string): Promise<FetchDVAResponse> { | ||
const response = await fetch(`${this.endpoint}/${dedicated_account_id}`, { | ||
headers: this.get_headers(), | ||
method: "GET" | ||
}) | ||
const response_data = await response.json() as FetchDVAResponse | ||
return response_data | ||
} | ||
|
||
async requery(query: RequeryDVAQuery): Promise<RequeryDVAResponse> { | ||
const keys = Object.keys(query) | ||
const url = new URL(this.endpoint) | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i] ?? '' | ||
if (key === "account_number") { | ||
|
||
const value = query[key] | ||
url.searchParams.set("requery", value) | ||
continue | ||
} | ||
const value = query[key] | ||
url.searchParams.set(key, value) | ||
} | ||
|
||
const response = await fetch(url, { | ||
headers: this.get_headers(), | ||
method: "GET" | ||
}) | ||
|
||
const response_data = await response.json() as RequeryDVAResponse | ||
|
||
return response_data | ||
|
||
} | ||
|
||
async deactivate(dedicated_account_id: string): Promise<DeactivateDVAResponse> { | ||
const response = await fetch(`${this.endpoint}/${dedicated_account_id}`, { | ||
headers: this.get_headers(), | ||
method: "DELETE", | ||
|
||
}) | ||
const response_data = await response.json() as DeactivateDVAResponse; | ||
return response_data | ||
} | ||
|
||
async split(data: SplitDVAData): Promise<SplitDVAResponse> { | ||
const response = await fetch(`${this.endpoint}/split`, { | ||
headers: this.get_headers(), | ||
method: "POST", | ||
body: JSON.stringify(data) | ||
}) | ||
const response_data = await response.json() as SplitDVAResponse | ||
return response_data | ||
} | ||
|
||
|
||
/* | ||
* If you've previously set up split payment for transactions on a dedicated virtual account, | ||
* you can remove it with this endpoint | ||
* @params account_number Dedicated virtual account number | ||
* */ | ||
async remove_split(account_number: string): Promise<RemoveSplitDVAResponse> { | ||
|
||
const response = await fetch(`${this.endpoint}/split`, { | ||
headers: this.get_headers(), | ||
method: "DELETE", | ||
body: JSON.stringify({ account_number: account_number }) | ||
}) | ||
const response_data = await response.json() as RemoveSplitDVAResponse | ||
return response_data | ||
} | ||
|
||
async fetch_bank_providers(): Promise<FetchBankProvidersDVAResponse> { | ||
const response = await fetch(`${this.endpoint}/available_providers`, { | ||
headers: this.get_headers(), | ||
method: "GET", | ||
}) | ||
const response_data = await response.json() as FetchBankProvidersDVAResponse | ||
return response_data | ||
} | ||
|
||
private get_headers() { | ||
return { | ||
"Content-Type": "application/json", | ||
"Authorization": "Bearer " + this.secret_key | ||
} | ||
} | ||
} |
Oops, something went wrong.