COGWare.OzowRefunds
1.0.1
See the version list below for details.
dotnet add package COGWare.OzowRefunds --version 1.0.1
NuGet\Install-Package COGWare.OzowRefunds -Version 1.0.1
<PackageReference Include="COGWare.OzowRefunds" Version="1.0.1" />
paket add COGWare.OzowRefunds --version 1.0.1
#r "nuget: COGWare.OzowRefunds, 1.0.1"
// Install COGWare.OzowRefunds as a Cake Addin #addin nuget:?package=COGWare.OzowRefunds&version=1.0.1 // Install COGWare.OzowRefunds as a Cake Tool #tool nuget:?package=COGWare.OzowRefunds&version=1.0.1
Ozow (instant EFT) Transaction Refunds
Process refunds for transactions submitted via the Ozow Instant EFT payment gateway
Ozow Refunds: Worth Noting
- Before a merchant can process refunds, they must transfer funds into their Ozow refund float.
- When a refund is created on the Ozow platform, it is not processed in real-time. Ozow batches refund requests and submits to the banks. The banks also take some time to process the refund into the customer's account.
- Ozow does provide a means to query refunds, however, the NotifyUrl (included in the refund request object) is the best means of receiving the refund status notification.
- For convenience, this package includes a helper method (
RefundHelper.ParseRefundNotification
) to read the request body of the Ozow refund notification and return a strongly-typed object (RefundNotification
).
Getting Started
Install the standard Nuget package into your .NET Core application.
Package Manager:
Install-Package COGWare.OzowRefunds -Version <version>
CLI:
dotnet add package --version <version> COGWare.OzowRefunds
Add Config
Add the OzowRefunds.IsProduction key to your settings file, eg:
<add key="OzowRefunds.IsProduction" value="false" />
Usage
Submit an Ozow Refund (With logging):
// Create your logger from the logging framework's extensions package (in this case, NLog)
var logger = LoggerFactory.Create(builder => builder.AddNLog()).CreateLogger<Program>();
logger.LogInformation("starting");
try {
RefundResult? refundResult = await OzowRefunds.RefundHelper.ProcessRefund(
// An instance of the RefundConfig object containing details of the
// Ozow entity that the original transaction was processed against.
// These details are available in the Ozow Merchant Console.
new RefundConfig() {
// Your merchant API key.
ApiKey = "123xyz",
// The merchant site code.
OzowSiteCode = "123-XYZ-456",
// Your merchant API secret.
PrivateKey = "xyz123"
},
// An instance of a Refund object representing the refund to be processed.
new Refund() {
// The amount to be refunded.
Amount = 1,
// Your refund identifier.
Id = "1",
// Ozow can post the status of the refund to this URL once the
// refund has been processed by the bank.
NotifyUrl = "https://yournotification.url",
// This will appear as the reference on the customer's bank statement.
RefundReason = "<Merchant> refund",
// The original (Ozow) transactionId of the payment.
TransactionId = "987qwe654rty321uio"
});
// Checks the status of the refund against the API response codes to
// determine if the refund can be considered successful.
if(refundResult!.IsSuccessful) {
// Update the status of the refund in your refund system.
Console.WriteLine("Refund processed successfully! " +
"Your refund identifier: '" + refundResult.Id + "', " +
"Ozow refund reference: '" + refundResult.RefundId + "'");
} else {
// Update the status of the refund in your refund system, optionally including the
// errors for analysis and manual resolution (if necessary).
Console.WriteLine("Refund ('" + refundResult.Id + "') failed: " +
String.Join(";", refundResult.Errors!));
}
} catch(Exception ex) {
Console.WriteLine("ERROR: " + ex.GetBaseException().Message);
}
logger.LogInformation("complete");
Submit an Ozow Refund (without logging):
try {
RefundResult? refundResult = await OzowRefunds.RefundHelper.ProcessRefund(
// An instance of the RefundConfig object containing details of the
// Ozow entity that the original transaction was processed against.
// These details are available in the Ozow Merchant Console.
new RefundConfig() {
// Your merchant API key.
ApiKey = "123xyz",
// The merchant site code.
OzowSiteCode = "123-XYZ-456",
// Your merchant API secret.
PrivateKey = "xyz123"
},
// An instance of a Refund object representing the refund to be processed.
new Refund() {
// The amount to be refunded.
Amount = 1,
// Your refund identifier.
Id = "1",
// Ozow can post the status of the refund to this URL once the
// refund has been processed by the bank.
NotifyUrl = "https://yournotification.url",
// This will appear as the reference on the customer's bank statement.
RefundReason = "<Merchant> refund",
// The original (Ozow) transactionId of the payment.
TransactionId = "987qwe654rty321uio"
});
// Checks the status of the refund against the API response codes to
// determine if the refund can be considered successful.
if(refundResult!.IsSuccessful) {
// Update the status of the refund in your refund system.
Console.WriteLine("Refund processed successfully! " +
"Your refund identifier: '" + refundResult.Id + "', " +
"Ozow refund reference: '" + refundResult.RefundId + "'");
} else {
// Update the status of the refund in your refund system, optionally including the
// errors for analysis and manual resolution (if necessary).
Console.WriteLine("Refund ('" + refundResult.Id + "') failed: " +
String.Join(";", refundResult.Errors!));
}
} catch(Exception ex) {
Console.WriteLine(ex.GetBaseException().Message);
}
Response object:
RefundResult
An object representing the response from the Ozow API.
Id
: (String
) - Your internal refund identifier.RefundId
: (String
) - The Ozow refund transaction identifer for this specific refund (null if there were errors).TransactionId
: (String
) - The original Ozow payment transaction identifier - a refund will be processed against this transaction.Amount
: (Double
) - The amount to be refunded.Errors
: (List<String>
) - An collection of errors returned when attempting to create the refund.IsSuccessful
: (Boolean
) - A flag indicating if the refund was successfully added.
Ozow Refund Notification:
When Ozow receives a refund status update from the bank, their services will attempt to send a status update notification to the NotifyUrl
specified in the refund request. They will attempt this a few times - in case of errors.
Deserializing the Refund Notification
Pass the HttpRequest object to the helper method and stand back in awe and wonder 😛 as a strongly-typed object is returned:
[HttpPost]
[Route("Notify")]
public async Task<OzowRefunds.Models.RefundNotification> Notify() {
return await OzowRefunds.RefundHelper.ParseRefundNotification(this.Request);
}
RefundNotification
RefundId
: (String
) - The Ozow refund transaction identifer for this specific refund.TransactionId
: (String
) - The original Ozow payment transaction identifier - a refund will be processed against this transaction.CurrencyCode
: (String
) - The refund currency.Amount
: (Double
) - The amount that was refunded.Status
: (Enum OzowRefundStatus
) - An enum of statuses for the refund.Pending
Complete
Submitted
Failed
Cancelled
Returned
StatusDescription
: (String
) - A description to help clarify the meaning of theStatus
enum.StatusMessage
: (String
) - Message regarding the status of the refund. This field will not always have a value.BankName
: (String
) - Name of the bank that processed the refund to the customer.AccountNumber
: (String
) - Masked account number that the refund was paid into.Hash
: (String
) - SHA512 hash used to ensure that certain fields in the message have not been altered after the hash was generated.
Alternatively, use something similar to this:
NameValueCollection ozowInput = HttpUtility.ParseQueryString(<request body goes here>);
string accountNumber = ozowInput["AccountNumber"];
double amount = Double.Parse(ozowInput["Amount"]);
string bankName = ozowInput["BankName"];
string currencyCode = ozowInput["CurrencyCode"];
string hash = ozowInput["Hash"];
string refundId = ozowInput["RefundId"];
string status = ozowInput["Status"];
string statusMessage = ozowInput["StatusMessage"];
string transactionId = ozowInput["TransactionId"];
Check Refunds
Ozow provides the ability to query refunds by date submitted and status.
This package wraps this functionality and provides a list of refund objects for a given date and status (again, with optional logging):
List<RefundListResult> refundListResult = await OzowRefunds.RefundHelper.GetRefunds(
// An instance of the RefundConfig object containing details of the
// Ozow entity that you wish to query for submitted refunds.
// These details are available in the Ozow Merchant Console.
new RefundConfig() {
// Your merchant API key.
ApiKey = "123xyz",
// The merchant site code.
OzowSiteCode = "123-XYZ-456",
// Your merchant API secret.
PrivateKey = "xyz123"
},
// Date the refund was submitted to Ozow.
DateTime.Now.AddDays(-7),
// Refunds in this status will be returned.
OzowRefunds.RefundHelper.OzowRefundStatus.Complete,
// (optional) logger
logger);
RefundListResult
Id
: (String
) - The identifier for the refund.CreatedDate
: (DateTime
) - The date the refund was created.CreatedDateUtc
: (DateTime
) - The UTC date the refund was created.MerchantCode
: (String
) - Corresponding merchant code of the refund.SiteCode
: (String
) - Corresponding site code of the refund.SiteName
: (String
) - Corresponding site name of the refund.BankToName
: (String
) - Bank the refund was sent to.CurrencyCode
: (String
) - Refund currency.Amount
: (Double
) - Refund amount.StatementReference
: (String
) - Bank reference of the refund for the payer.Status
: (String
) - Refund status.ToAccount
: (String
) - Masked account number the received the refund.PaymentDate
: (String
) - Payment date of the refund.TransactionReference
: (String
) - Reference of the transaction which was refunded.Customer
: (String
) - Refunded transaction customer.LastEvent
: (String
) - Most recent log activity of the refund.CreatedBy
: (String
) - Name of the user who created the refund.
Logging:
Implements Microsoft.Extensions.Logging, so log away with any compatible logging framework,eg: NLog
Additional documentation
- What is Ozow?
- Ozow refund API documentation
Feedback
I welcome comments, suggestions, feature requests and even honest criticism 😃
- Github Repo
- Email: lance@cogware.co.za
Want to show your appreciation?
That's mighty generous - thank you!
Buy me a coffee
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net6.0
- Microsoft.AspNetCore.Http.Abstractions (>= 2.2.0)
- Microsoft.Extensions.Logging (>= 7.0.0)
- Newtonsoft.Json (>= 13.0.3)
- RestSharp (>= 110.2.0)
- System.Configuration.ConfigurationManager (>= 7.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Prettified the readme a bit and added a "Buy me a coffee" section. Developers convert caffeine to code, after all ;)