From e0ab021d471ebac0520a9d9664aed60dddb3aff1 Mon Sep 17 00:00:00 2001 From: Amoh Prince <81857018+AmohPrince@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:54:42 +0300 Subject: [PATCH] added bill managers --- .changeset/eight-rules-live.md | 15 +++ src/types/bill-manager-types.ts | 144 ++++++++++++++++++++++ src/wrapper-fns/bill-manager.ts | 208 ++++++++++++++++++++++++++++++++ src/wrapper-fns/wrapper-fns.ts | 50 -------- 4 files changed, 367 insertions(+), 50 deletions(-) create mode 100644 .changeset/eight-rules-live.md create mode 100644 src/types/bill-manager-types.ts create mode 100644 src/wrapper-fns/bill-manager.ts diff --git a/.changeset/eight-rules-live.md b/.changeset/eight-rules-live.md new file mode 100644 index 0000000..0526097 --- /dev/null +++ b/.changeset/eight-rules-live.md @@ -0,0 +1,15 @@ +--- +"daraja-kit": patch +--- + +added bill manager functions. + +- billManagerOptIn +- billManagerSingleInvoicing +- billManagerBulkInvoicing +- billManagerReconciliation +- cancelSingleInvoicing +- cancelBulkInvoicing +- updateOptinDetails + +With the new updates Daraja Kit now supports 100% of daraja APIs 🎉 diff --git a/src/types/bill-manager-types.ts b/src/types/bill-manager-types.ts new file mode 100644 index 0000000..131cdd0 --- /dev/null +++ b/src/types/bill-manager-types.ts @@ -0,0 +1,144 @@ +/** + * Definition of the BulkInvoice type used for sending multiple invoices at once. + */ +export type BulkInvoice = { + /** + * Unique invoice name on your system's end. Used for referencing invoices from both Bill Manager and your system. + * Must exist, otherwise the invoice will not be sent. + */ + externalReference: string; + + /** + * Name of the recipient to receive the invoice details. Appears in the SMS sent. + */ + billedFullName: string; + + /** + * Phone number to receive invoice details via SMS. Must be a Safaricom number. + */ + billedPhoneNumber: string; + + /** + * Month and year of the billed period. + */ + billedPeriod: string; // Date(M/Y) + + /** + * Descriptive invoice name for what the customer is being billed. Appears in the invoice SMS sent to the customer. + */ + invoiceName: string; + + /** + * Date by which the customer is expected to have paid the invoice amount. + * Reminders are sent seven and three days before the due date and on the due date. + */ + dueDate: string; // String (Varchar) + + /** + * Account number being invoiced that uniquely identifies a customer. + * Can be a customer name, business name, property unit, student's name, etc. + */ + accountReference: string; // String (Varchar) + + /** + * Total invoice amount to be paid in Kenyan Shillings. No special characters like commas should be included. + */ + amount: string; // Numeric + + /** + * Additional billable items to be included in the invoice. These items will appear on the e-invoice. + */ + invoiceItems?: { + /** + * Name of the additional billable item. + */ + itemName: string; + + /** + * Amount associated with the additional billable item. + */ + amount: string; + }[]; +}; + +/** + * Definition of the ReconciliationBody type used for reconciling transactions. + */ +export type ReconciliationBody = { + /** + * M-PESA generated reference for the transaction. + */ + transactionId: string; + + /** + * Amount paid in Kenyan Shillings. + */ + paidAmount: string; + + /** + * Customer's phone number debited. + */ + msisdn: string; + + /** + * Date the payment was recorded in the BillManager System. + */ + dateCreated: string; + + /** + * Account number being invoiced that uniquely identifies a customer. + * Can be a customer name, business name, property unit, student's name, etc. + */ + accountReference: string; + + /** + * Organization's shortcode (Paybill or Buygoods - A 5 to 6 digit account number) used to identify an organization and receive the transaction. + */ + shortCode: string; +}; + +/** + * Definition of the UpdateOptinDetails type used for updating opt-in details in the Bill Manager system. + */ +export type UpdateOptinDetails = { + /** + * Organization's shortcode used to identify the organization. + */ + shortcode: string; + + /** + * Official contact email address for the organization signing up to Bill Manager. + * Appears in features sent to the customer such as invoices and payment receipts for customers to reach out to the business. + */ + email: string; + + /** + * Official contact phone number for the organization signing up to Bill Manager. + * Appears in features sent to the customer such as invoices and payment receipts for customers to reach out to the business. + */ + officialContact: string; + + /** + * Flag to enable or disable SMS payment reminders for invoices sent. + * 0 - Disable Reminders + * 1 - Enable Reminders + */ + sendReminders: number; + + /** + * Image to be embedded in the invoices and receipts sent to the customer. + * Supported formats: JPEG, JPG + */ + logo: string; + + /** + * Callback URL provided by the organization to Bill Manager during the initial opt-in process. + * Invoked by the payments API to push payments done to the paybill. + * More details on the callback URL are in the payments and reconciliation API documentation. + */ + callbackurl: string; +}; + +export type CancelSingleInvoice = { + externalReference: string; +}; diff --git a/src/wrapper-fns/bill-manager.ts b/src/wrapper-fns/bill-manager.ts new file mode 100644 index 0000000..76e6770 --- /dev/null +++ b/src/wrapper-fns/bill-manager.ts @@ -0,0 +1,208 @@ +import axios, { AxiosError } from "axios"; +import { BASE_URL, BUSINESS_SHORT_CODE } from "../env"; +import { + BillManagerOptin, + BillManagerOptInResponse, + BillManagerSingleInvoicingBody, + BillManagerSingleInvoicingResponse, +} from "../types/types"; +import { generateAccessToken } from "./access-token"; +import { + BulkInvoice, + CancelSingleInvoice, + ReconciliationBody, + UpdateOptinDetails, +} from "../types/bill-manager-types"; + +export const billManagerOptIn = async ( + data: BillManagerOptin +): Promise => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/optin`, + { ...data, PartyA: BUSINESS_SHORT_CODE }, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; + +export const billManagerSingleInvoicing = async ( + data: BillManagerSingleInvoicingBody +): Promise => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/single-invoicing`, + data, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; + +export const billManagerBulkInvoicing = async ( + data: BulkInvoice[] +): Promise<{ + Status_Message: string; + resmsg: string; + rescode: string; +}> => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/bulk-invoicing`, + data, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; + +export const billManagerReconciliation = async ( + data: Omit +): Promise<{ + resmsg: string; + rescode: string; +}> => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/reconciliation`, + { ...data, shortCode: BUSINESS_SHORT_CODE }, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; + +export const cancelSingleInvoicing = async (data: { + externalReference: string; +}): Promise<{ + resmsg: string; + rescode: string; +}> => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/reconciliation`, + data, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; + +export const cancelBulkInvoicing = async ( + data: CancelSingleInvoice[] +): Promise<{ + Status_Message: string; + resmsg: string; + rescode: string; + errors: string[]; +}> => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/reconciliation`, + data, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; + +export const updateOptinDetails = async ( + data: Omit +): Promise<{ + resmsg: string; + rescode: string; +}> => { + const { access_token } = await generateAccessToken(); + try { + const res = await axios.post( + `${BASE_URL}/v1/billmanager-invoice/change-optin-details`, + { ...data, shortCode: BUSINESS_SHORT_CODE }, + { + headers: { + Authorization: `Bearer ${access_token}`, + }, + } + ); + + return res.data; + } catch (error) { + const err = error as AxiosError; + console.error(error); + throw new Error( + `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` + ); + } +}; diff --git a/src/wrapper-fns/wrapper-fns.ts b/src/wrapper-fns/wrapper-fns.ts index f12f591..09fe59a 100644 --- a/src/wrapper-fns/wrapper-fns.ts +++ b/src/wrapper-fns/wrapper-fns.ts @@ -298,53 +298,3 @@ export const b2bPayBill = async ( ): Promise => { return await b2bBuyGoods(data); }; - -export const billManagerOptIn = async ( - data: BillManagerOptin -): Promise => { - const { access_token } = await generateAccessToken(); - try { - const res = await axios.post( - `${BASE_URL}/v1/billmanager-invoice/optin`, - { ...data, PartyA: BUSINESS_SHORT_CODE }, - { - headers: { - Authorization: `Bearer ${access_token}`, - }, - } - ); - - return res.data; - } catch (error) { - const err = error as AxiosError; - console.error(error); - throw new Error( - `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` - ); - } -}; - -export const billManagerSingleInvoicing = async ( - data: BillManagerSingleInvoicingBody -): Promise => { - const { access_token } = await generateAccessToken(); - try { - const res = await axios.post( - `${BASE_URL}/v1/billmanager-invoice/single-invoicing`, - data, - { - headers: { - Authorization: `Bearer ${access_token}`, - }, - } - ); - - return res.data; - } catch (error) { - const err = error as AxiosError; - console.error(error); - throw new Error( - `Error occurred with status code ${err.response?.status}, ${err.response?.statusText}` - ); - } -};