diff --git a/api/account.go b/api/account.go index 5fd134a..e3d7b07 100644 --- a/api/account.go +++ b/api/account.go @@ -54,3 +54,15 @@ func (c *Call) GetVirtualAccountTransaction(ctx context.Context, txID string) (* } return response, err } + +// GetAccunts makes the request to get a virtual account transaction on by its ID +func (c *Call) GetAccounts(ctx context.Context, txID string) (*model.Transaction, error) { + response := &model.Transaction{} + + //path := fmt.Sprintf("/virtual-accounts/transactions/%s", txID) + err := c.makeRequest(ctx, http.MethodGet, "/accounts\n", nil, response) + if err != nil { + return nil, err + } + return response, err +} diff --git a/api/api.go b/api/api.go index c784bb2..0547987 100644 --- a/api/api.go +++ b/api/api.go @@ -21,6 +21,16 @@ type RemoteCalls interface { GetVirtualAccountByRef(ctx context.Context, reference string) (*model.VirtualAccount, error) GetVirtualAccountByBVN(ctx context.Context, bvn string) (*model.VirtualAccount, error) GetVirtualAccountTransaction(ctx context.Context, txID string) (*model.Transaction, error) + + GetBillVendors(ctx context.Context, category string) (*[]model.Vendor, error) + GetBillVendorByID(ctx context.Context, vendorID string) (*model.Vendor, error) + GetBillProducts(ctx context.Context, vendorID, category *string) (*[]model.Product, error) + GetBillProductByID(ctx context.Context, productID string) (*model.Product, error) + RunCustomerLookup(ctx context.Context, customerID string, productID string) (*model.Product, error) + CreateBill(ctx context.Context, request model.CreateBillRequest) (*model.CreateBillResponse, error) + GetBillByID(ctx context.Context, id string) (*model.BillData, error) + GetBillByReference(ctx context.Context, reference string) (*model.BillData, error) + GetAllBills(ctx context.Context, request model.GetAllBillsRequest) (*[]model.BillData, error) } // Call object diff --git a/api/bill.go b/api/bill.go new file mode 100644 index 0000000..7ee8142 --- /dev/null +++ b/api/bill.go @@ -0,0 +1,188 @@ +package api + +import ( + "context" + "fmt" + "net/http" + "net/url" + + "github.com/sendlovebox/go-lenco/model" +) + +// GetBillVendors makes the request to get bill vendors +func (c *Call) GetBillVendors(ctx context.Context, category string) (*[]model.Vendor, error) { + response := &[]model.Vendor{} + + path := "/bills/vendors" + + params := url.Values{} + params.Set("categories[]", category) + + requestPath := fmt.Sprintf("%s?%s", path, params.Encode()) + + err := c.makeRequest(ctx, http.MethodGet, requestPath, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// GetBillVendorByID makes the request to get a bill vendor by its ID +func (c *Call) GetBillVendorByID(ctx context.Context, vendorID string) (*model.Vendor, error) { + response := &model.Vendor{} + path := fmt.Sprintf("/bills/vendors/%s", vendorID) + + err := c.makeRequest(ctx, http.MethodGet, path, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// GetBillProducts makes the request to get products +func (c *Call) GetBillProducts(ctx context.Context, vendorID, category *string) (*[]model.Product, error) { + response := &[]model.Product{} + + path := "/bills/products" + params := url.Values{} + + if vendorID != nil { + params.Set("vendorIds[]", *vendorID) + } + + if category != nil { + params.Set("categories[]", *category) + } + + requestPath := fmt.Sprintf("%s?%s", path, params.Encode()) + + err := c.makeRequest(ctx, http.MethodGet, requestPath, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// GetBillProductByID makes the request to get a product by its ID +func (c *Call) GetBillProductByID(ctx context.Context, productID string) (*model.Product, error) { + response := &model.Product{} + path := fmt.Sprintf("/bills/products/%s", productID) + + err := c.makeRequest(ctx, http.MethodGet, path, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// RunCustomerLookup makes the request to run customer look up for a bill +func (c *Call) RunCustomerLookup(ctx context.Context, customerID string, productID string) (*model.Product, error) { + response := &model.Product{} + + path := fmt.Sprintf("/bills/lookup-account?customerId=%s&productId=%s", customerID, productID) + + err := c.makeRequest(ctx, http.MethodGet, path, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// CreateBill makes the request to create a bill +func (c *Call) CreateBill(ctx context.Context, request model.CreateBillRequest) (*model.CreateBillResponse, error) { + + response := &model.CreateBillResponse{} + + err := c.makeRequest(ctx, http.MethodPost, "/bills", request, response) + if err != nil { + return nil, err + } + + return response, err +} + +// GetBillByID makes the request to get a specific bill +func (c *Call) GetBillByID(ctx context.Context, id string) (*model.BillData, error) { + + response := &model.BillData{} + + path := fmt.Sprintf("/bills/%s", id) + + err := c.makeRequest(ctx, http.MethodGet, path, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// GetBillByReference makes the request to get a specific bill +func (c *Call) GetBillByReference(ctx context.Context, reference string) (*model.BillData, error) { + + response := &model.BillData{} + + path := fmt.Sprintf("/bills/by-reference/%s", reference) + + err := c.makeRequest(ctx, http.MethodGet, path, nil, response) + if err != nil { + return nil, err + } + + return response, err +} + +// GetAllBills makes the request to get all bills +func (c *Call) GetAllBills(ctx context.Context, request model.GetAllBillsRequest) (*[]model.BillData, error) { + + response := &[]model.BillData{} + + path := "/bills" + + params := url.Values{} + + if request.VendorID != nil { + params.Set("vendorIds[]", *request.VendorID) + } + + if request.ProductID != nil { + params.Set("vendorIds[]", *request.VendorID) + } + + if request.CustomerID != nil { + params.Set("customerId", *request.CustomerID) + } + + if request.Status != nil { + params.Set("status", *request.Status) + } + + if request.Category != nil { + params.Set("categories[]", string(*request.Category)) + } + + if request.Page != nil { + params.Set("page", *request.Page) + } + + if request.Start != nil { + params.Set("start", *request.Start) + } + + if request.End != nil { + params.Set("end", *request.End) + } + + requestPath := fmt.Sprintf("%s?%s", path, params.Encode()) + + err := c.makeRequest(ctx, http.MethodGet, requestPath, nil, response) + if err != nil { + return nil, err + } + + return response, err +} diff --git a/api/util.go b/api/util.go index 6830b42..edc1206 100644 --- a/api/util.go +++ b/api/util.go @@ -7,8 +7,8 @@ import ( "net/http" "github.com/go-resty/resty/v2" - "github.com/mitchellh/mapstructure" + "github.com/sendlovebox/go-lenco/model" ) diff --git a/go.mod b/go.mod index d736497..90b819e 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( ) require ( + github.com/google/uuid v1.3.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect diff --git a/go.sum b/go.sum index b098547..0641c1f 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= diff --git a/main.go b/main.go index f5077f8..fe89473 100644 --- a/main.go +++ b/main.go @@ -23,25 +23,137 @@ func main() { api.RunInSandboxMode() // to ensure it is running in sandbox mode //ctx := context.Background() - /* virtualAcc, err := api.CreateVirtualAccount(ctx, model.VirtualAccountRequest{ - AccountName: "The only Ninja", - IsStatic: true, - //TrxReference: "", - //Amount: 0, - //MinAmount: 0, - BVN: "123", - CreateNewAccount: true, - }) - if err != nil { - logger.Err(err).Msg("failed") - return - } - logger.Info().Interface("response", virtualAcc).Msg("success") */ - - /* virtualAcc, err := api.GetVirtualAccountByRef(ctx, "afede78d-c265-4080-949c-302c5c147002") - if err != nil { - logger.Err(err).Msg("failed") - return - } - logger.Info().Interface("response", virtualAcc).Msg("success") */ + /* + // ---------------CreateVirtualAccount--------------- + + virtualAcc, err := api.CreateVirtualAccount(ctx, model.VirtualAccountRequest{ + AccountName: "The only Ninja", + IsStatic: true, + //TrxReference: "", + //Amount: 0, + //MinAmount: 0, + BVN: "123", + CreateNewAccount: true, + }) + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", virtualAcc).Msg("success") + */ + + /* + // ---------------GetVirtualAccountByRef--------------- + + virtualAcc, err := api.GetVirtualAccountByRef(ctx, "afede78d-c265-4080-949c-302c5c147002") + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", virtualAcc).Msg("success") + */ + + /* + // ---------------GetBillVendors--------------- + + vendors, err := api.GetBillVendors(ctx, string(model.BillCategoryElectricity)) + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", vendors).Msg("success") + */ + + /* + // ---------------GetBillVendorByID--------------- + vendor, err := api.GetBillVendorByID(ctx, "f46c9b9f-ddc1-4466-9cf2-dda59d18b84f") + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", vendor).Msg("success") + + */ + + /* + // ---------------GetBillProducts--------------- + products, err := api.GetBillProducts(ctx, "", "") + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", products).Msg("success") + + */ + + /* + + // ---------------GetBillProductByID--------------- + product, err := api.GetBillProductByID(ctx, "c96432f5-c5b7-4eb4-a42d-9b873f8f3ff1") + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", product).Msg("success") + + */ + + /* + + + // ---------------RunCustomerLookup--------------- + product, err := api.RunCustomerLookup(ctx, "10433749628", "96c548e4-02cb-4d25-a646-8d6489374a1e") + if err != nil { + logger.Err(err).Msg("failed") + return + } + logger.Info().Interface("response", product).Msg("success") + + */ + + /* + + // ---------------CreateBill--------------- + //bill, err := api.CreateBill(ctx, model.CreateBillRequest{ + // CustomerID: "10433749628", + // DebitAccountID: "431827e5-8f9f-4340-ad37-d07185403b8b", + // ProductID: "96c548e4-02cb-4d25-a646-8d6489374a1e", + // Amount: "100", + // Reference: "testReference", + //}) + //if err != nil { + // logger.Err(err).Msg("failed") + // return + //} + //logger.Info().Interface("response", bill).Msg("success") + + */ + + // ---------------GetBillByID--------------- + + //bill, err := api.GetBillByID(ctx, "99267671-6377-427d-9142-698663a6e77b") + //if err != nil { + // logger.Err(err).Msg("failed") + // return + //} + //logger.Info().Interface("response", bill).Msg("success") + + // ---------------GetBillByReference--------------- + //bill, err := api.GetBillByReference(ctx, "testReference") + //if err != nil { + // logger.Err(err).Msg("failed") + // return + //} + //logger.Info().Interface("response", bill).Msg("success") + + // ---------------GetAllBills--------------- + //YYYY-MM-DD + //bills, err := api.GetAllBills(ctx, model.GetAllBillsRequest{Status: "successful", VendorID: "bfa5206c-6122-448b-adfd-b8b764bfa13f", Category: "cable-tv", Start: "2021-01-01", End: "2023-07-23"}) + // + //if err != nil { + // logger.Err(err).Msg("failed") + // return + //} + //logger.Info().Interface("response", bills).Msg("success") + } diff --git a/model/account.go b/model/account.go index d5390a0..bcc4d9a 100644 --- a/model/account.go +++ b/model/account.go @@ -43,9 +43,6 @@ type ( Bvn *string `mapstructure:"bvn,omitempty" json:"bvn"` IsStatic bool `mapstructure:"isStatic,omitempty" json:"isStatic"` } - - // VirtualAccountType string representation of virtual account type - VirtualAccountType string ) const ( diff --git a/model/bill.go b/model/bill.go new file mode 100644 index 0000000..88451b0 --- /dev/null +++ b/model/bill.go @@ -0,0 +1,106 @@ +package model + +type ( + // Vendor schema + Vendor struct { + ID string `mapstructure:"id,omitempty" json:"id,omitempty"` + Name string `mapstructure:"name,omitempty" json:"name,omitempty"` + Products []Product `mapstructure:"products,omitempty" json:"products,omitempty"` + } + + // Product schema + Product struct { + ID string `mapstructure:"id,omitempty" json:"id,omitempty"` + Name string `mapstructure:"name,omitempty" json:"name,omitempty"` + Vendor Vendor `mapstructure:"vendor,omitempty" json:"vendor,omitempty"` + Amount Amount `mapstructure:"amount,omitempty" json:"amount,omitempty"` + CustomerIDLabel string `mapstructure:"customerIdLabel,omitempty" json:"customerIdLabel,omitempty"` + BillCategory BillCategory `mapstructure:"billCategory,omitempty" json:"billCategory,omitempty"` + CommissionPercentage string `mapstructure:"commissionPercentage,omitempty" json:"commissionPercentage,omitempty"` + } + + // Amount schema + Amount struct { + Type AmountType + Fixed *string + Minimum *string + Maximum *string + } + + // CustomerDetails schema + CustomerDetails struct { + CustomerID string `mapstructure:"customerId,omitempty" json:"customerId,omitempty"` + CustomerName string `mapstructure:"customerName,omitempty" json:"customerName,omitempty"` + } + + // CustomerLookUpResponse schema + CustomerLookUpResponse struct { + Status bool `mapstructure:"status,omitempty" json:"status,omitempty"` + Message string `mapstructure:"message,omitempty" json:"message,omitempty"` + Data CustomerDetails `mapstructure:"data,omitempty" json:"data,omitempty"` + } + + CreateBillRequest struct { + CustomerID string `json:"customerId,omitempty"` + DebitAccountID string `json:"debitAccountId,omitempty"` + ProductID string `json:"productId,omitempty"` + Amount string `json:"amount,omitempty"` + Reference string `json:"reference,omitempty"` + } + + GetAllBillsRequest struct { + CustomerID *string `json:"customerId,omitempty"` + ProductID *string `json:"productId,omitempty"` + VendorID *string `json:"vendorId,omitempty"` + Status *string `json:"status,omitempty"` + Category *BillCategory `json:"category,omitempty"` + Start *string `json:"start,omitempty"` + End *string `json:"end,omitempty"` + Page *string `json:"page,omitempty"` + } + + CreateBillResponse struct { + Status interface{} `mapstructure:"status,omitempty" json:"status,omitempty"` + Message string `mapstructure:"message,omitempty" json:"message,omitempty"` + Data BillData `mapstructure:"data,omitempty" json:"data,omitempty"` + } + + BillData struct { + ID string `mapstructure:"id,omitempty" json:"id,omitempty"` + Amount string `mapstructure:"amount,omitempty" json:"amount,omitempty"` + Vendor Vendor `mapstructure:"vendor,omitempty" json:"vendor,omitempty"` + BillCategory BillCategory `mapstructure:"billCategory,omitempty" json:"billCategory,omitempty"` + Product Product `mapstructure:"product,omitempty" json:"product,omitempty"` + Details CustomerDetails `mapstructure:"details,omitempty" json:"details,omitempty"` + DebitAccountID string `mapstructure:"debitAccountId,omitempty" json:"debitAccountId,omitempty"` + Instructions *string `mapstructure:"instructions,omitempty" json:"instructions,omitempty"` + InitiatedAt string `mapstructure:"initiatedAt,omitempty" json:"initiatedAt,omitempty"` + Status interface{} `mapstructure:"status,omitempty" json:"status,omitempty"` + CompletedAt *string `mapstructure:"completedAt,omitempty" json:"completedAt,omitempty"` + FailedAt *string `mapstructure:"failedAt,omitempty" json:"failedAt,omitempty"` + ReasonForFailure *string `mapstructure:"reasonForFailure,omitempty" json:"reasonForFailure,omitempty"` + ClientReference *string `mapstructure:"clientReference,omitempty" json:"clientReference,omitempty"` + TransactionReference string `mapstructure:"transactionReference,omitempty" json:"transactionReference,omitempty"` + Commission *string `mapstructure:"commission,omitempty" json:"commission,omitempty"` + } + + // VirtualAccountType string representation of virtual account type + VirtualAccountType string + AmountType string + BillCategory string +) + +const ( + // AmountTypeFixed string representation of fixed amount type + AmountTypeFixed AmountType = "fixed" + // AmountTypeRange string representation of range amount type + AmountTypeRange AmountType = "range" + // BillCategoryAirtime string representation of airtime bill category + BillCategoryAirtime BillCategory = "airtime" + // BillCategoryMobileData string representation of mobile-data bill category + BillCategoryMobileData BillCategory = "mobile-data" + // BillCategoryCableTV string representation of cable-tv bill category + BillCategoryCableTV BillCategory = "cable-tv" + // BillCategoryElectricity string representation of electricity bill category + BillCategoryElectricity BillCategory = "electricity" +) diff --git a/model/model.go b/model/model.go index 21f361e..6bf9801 100644 --- a/model/model.go +++ b/model/model.go @@ -27,3 +27,21 @@ type ( Data interface{} `json:"data"` } ) + +//{ +//"id": "e0512abf-ecf4-48df-b6ff-40a8bf3b2373", +//"name": "500GB Gold Monthly HyNetFlex Unlimited Plan (4G Router)", +//"vendor": { +//"id": "70284a19-560d-430d-b1ef-a16fe9107d1f", +//"name": "MTN" +//}, +//"amount": { +//"type": "fixed", +//"fixed": "45000.00", +//"minimum": null, +//"maximum": null +//}, +//"category": "mobile-data", +//"customerIdLabel": "Mobile Number", +//"commissionPercentage": "0.80" +//},