Skip to content

Commit

Permalink
Merge branch 'main' into new-api
Browse files Browse the repository at this point in the history
  • Loading branch information
vamsii777 committed Feb 18, 2025
2 parents b205d81 + 3c662b4 commit 500b2cb
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 3 deletions.
277 changes: 277 additions & 0 deletions Sources/RazorpayKit/Models/Currency.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
import Foundation
/// Represents currencies supported by Razorpay for international payments
///
/// This enum contains all the currencies that can be used for payments through Razorpay's payment gateway.
/// Each case represents a currency with its ISO 4217 currency code.
///
/// ## Usage Example
/// ```swift
/// let paymentData: [String: Any] = [
/// "amount": 1000,
/// "currency": Currency.indianRupee.rawValue
/// ]
/// ```
public enum Currency: String, CaseIterable {
/// Indian Rupee (₹)
case indianRupee = "INR"

/// United States Dollar ($)
case usDollar = "USD"

/// Euro (€)
case euro = "EUR"

/// British Pound Sterling (£)
case britishPound = "GBP"

/// Japanese Yen (¥)
case japaneseYen = "JPY"

/// Canadian Dollar (C$)
case canadianDollar = "CAD"

/// Australian Dollar (A$)
case australianDollar = "AUD"

/// New Zealand Dollar (NZ$)
case newZealandDollar = "NZD"

/// Singapore Dollar (S$)
case singaporeDollar = "SGD"

/// Hong Kong Dollar (HK$)
case hongKongDollar = "HKD"

/// Malaysian Ringgit (RM)
case malaysianRinggit = "MYR"

/// United Arab Emirates Dirham (د.إ)
case uaeDirham = "AED"

/// Swiss Franc (Fr)
case swissFranc = "CHF"

/// Chinese Yuan (¥)
case chineseYuan = "CNY"

/// South African Rand (R)
case southAfricanRand = "ZAR"

/// Sri Lankan Rupee (Rs)
case sriLankanRupee = "LKR"

/// Swedish Krona (kr)
case swedishKrona = "SEK"

/// Saudi Riyal (﷼)
case saudiRiyal = "SAR"

/// Thai Baht (฿)
case thaiBaht = "THB"

/// Russian Ruble (₽)
case russianRuble = "RUB"

/// Turkish Lira (₺)
case turkishLira = "TRY"

/// Israeli New Shekel (₪)
case israeliNewShekel = "ILS"

/// Danish Krone (kr)
case danishKrone = "DKK"

/// Polish Złoty (zł)
case polishZloty = "PLN"

/// Norwegian Krone (kr)
case norwegianKrone = "NOK"

/// Hungarian Forint (Ft)
case hungarianForint = "HUF"

/// Czech Koruna (Kč)
case czechKoruna = "CZK"

/// Qatari Riyal (﷼)
case qatariRiyal = "QAR"

/// Kuwaiti Dinar (د.ك)
case kuwaitiDinar = "KWD"

/// Bahraini Dinar (.د.ب)
case bahrainiDinar = "BHD"

/// Omani Rial (﷼)
case omaniRial = "OMR"

/// Mexican Peso ($)
case mexicanPeso = "MXN"

/// Taiwan New Dollar (NT$)
case taiwanDollar = "TWD"

/// South Korean Won (₩)
case southKoreanWon = "KRW"

/// Indonesian Rupiah (Rp)
case indonesianRupiah = "IDR"

/// Philippine Peso (₱)
case philippinePeso = "PHP"

/// Vietnamese Dong (₫)
case vietnameseDong = "VND"

/// Bangladeshi Taka (৳)
case bangladeshiTaka = "BDT"

/// Brazilian Real (R$)
case brazilianReal = "BRL"

/// Egyptian Pound (£)
case egyptianPound = "EGP"

/// Nigerian Naira (₦)
case nigerianNaira = "NGN"

/// Ghanaian Cedi (₵)
case ghanaianCedi = "GHS"

/// Kenyan Shilling (KSh)
case kenyanShilling = "KES"
}

extension Currency {
/// Returns a description of the currency including its name and code
public var description: String {
switch self {
case .indianRupee: return "Indian Rupee (INR)"
case .usDollar: return "US Dollar (USD)"
case .euro: return "Euro (EUR)"
case .britishPound: return "British Pound Sterling (GBP)"
case .japaneseYen: return "Japanese Yen (JPY)"
case .canadianDollar: return "Canadian Dollar (CAD)"
case .australianDollar: return "Australian Dollar (AUD)"
case .newZealandDollar: return "New Zealand Dollar (NZD)"
case .singaporeDollar: return "Singapore Dollar (SGD)"
case .hongKongDollar: return "Hong Kong Dollar (HKD)"
case .malaysianRinggit: return "Malaysian Ringgit (MYR)"
case .uaeDirham: return "UAE Dirham (AED)"
case .swissFranc: return "Swiss Franc (CHF)"
case .chineseYuan: return "Chinese Yuan (CNY)"
case .southAfricanRand: return "South African Rand (ZAR)"
case .sriLankanRupee: return "Sri Lankan Rupee (LKR)"
case .swedishKrona: return "Swedish Krona (SEK)"
case .saudiRiyal: return "Saudi Riyal (SAR)"
case .thaiBaht: return "Thai Baht (THB)"
case .russianRuble: return "Russian Ruble (RUB)"
case .turkishLira: return "Turkish Lira (TRY)"
case .israeliNewShekel: return "Israeli New Shekel (ILS)"
case .danishKrone: return "Danish Krone (DKK)"
case .polishZloty: return "Polish Złoty (PLN)"
case .norwegianKrone: return "Norwegian Krone (NOK)"
case .hungarianForint: return "Hungarian Forint (HUF)"
case .czechKoruna: return "Czech Koruna (CZK)"
case .qatariRiyal: return "Qatari Riyal (QAR)"
case .kuwaitiDinar: return "Kuwaiti Dinar (KWD)"
case .bahrainiDinar: return "Bahraini Dinar (BHD)"
case .omaniRial: return "Omani Rial (OMR)"
case .mexicanPeso: return "Mexican Peso (MXN)"
case .taiwanDollar: return "Taiwan New Dollar (TWD)"
case .southKoreanWon: return "South Korean Won (KRW)"
case .indonesianRupiah: return "Indonesian Rupiah (IDR)"
case .philippinePeso: return "Philippine Peso (PHP)"
case .vietnameseDong: return "Vietnamese Dong (VND)"
case .bangladeshiTaka: return "Bangladeshi Taka (BDT)"
case .brazilianReal: return "Brazilian Real (BRL)"
case .egyptianPound: return "Egyptian Pound (EGP)"
case .nigerianNaira: return "Nigerian Naira (NGN)"
case .ghanaianCedi: return "Ghanaian Cedi (GHS)"
case .kenyanShilling: return "Kenyan Shilling (KES)"
}
}

/// The exponent for the currency, indicating the number of decimal places
/// Used to convert currency units to their smallest denomination
/// For example:
/// - INR has exponent 2, so ₹1 = 100 paise
/// - JPY has exponent 0, so ¥1 = 1 yen
public var exponent: Int {
switch self {
// Zero decimal currencies
case .japaneseYen, .hungarianForint, .taiwanDollar, .southKoreanWon,
.indonesianRupiah, .vietnameseDong:
return 0

// Three decimal currencies
case .bahrainiDinar, .kuwaitiDinar, .omaniRial:
return 3

// Two decimal currencies (most common)
default:
return 2
}
}

/// Converts a decimal amount to the smallest currency unit
/// For example:
/// - convertToSmallestUnit(10.5) for INR returns 1050 (paise)
/// - convertToSmallestUnit(10.5) for JPY returns 10 (yen)
/// - convertToSmallestUnit(10.5) for BHD returns 10500 (fils)
public func convertToSmallestUnit(_ amount: Decimal) -> Int {
let multiplier = Decimal(pow(10.0, Double(exponent)))
return NSDecimalNumber(decimal: amount * multiplier).intValue
}

/// Converts an amount in smallest currency unit back to decimal
/// For example:
/// - convertFromSmallestUnit(1050) for INR returns 10.50 (rupees)
/// - convertFromSmallestUnit(10) for JPY returns 10.00 (yen)
/// - convertFromSmallestUnit(10500) for BHD returns 10.500 (dinar)
public func convertFromSmallestUnit(_ amount: Int) -> Decimal {
let divisor = Decimal(pow(10.0, Double(exponent)))
return Decimal(amount) / divisor
}
}

// Example usage extension
extension Currency {
/// Returns the symbol for the currency
public var symbol: String {
switch self {
case .indianRupee: return ""
case .usDollar, .mexicanPeso: return "$"
case .euro: return ""
case .britishPound, .egyptianPound: return "£"
case .japaneseYen, .chineseYuan: return "¥"
case .malaysianRinggit: return "RM"
case .uaeDirham: return "د.إ"
case .swissFranc: return "Fr"
case .southAfricanRand: return "R"
case .sriLankanRupee: return "Rs"
case .swedishKrona, .norwegianKrone, .danishKrone: return "kr"
case .saudiRiyal, .qatariRiyal, .omaniRial: return ""
case .thaiBaht: return "฿"
case .russianRuble: return ""
case .turkishLira: return ""
case .israeliNewShekel: return ""
case .polishZloty: return ""
case .hungarianForint: return "Ft"
case .czechKoruna: return ""
case .kuwaitiDinar: return "د.ك"
case .bahrainiDinar: return ".د.ب"
case .taiwanDollar: return "NT$"
case .southKoreanWon: return ""
case .indonesianRupiah: return "Rp"
case .philippinePeso: return ""
case .vietnameseDong: return ""
case .bangladeshiTaka: return ""
case .brazilianReal: return "R$"
case .nigerianNaira: return ""
case .ghanaianCedi: return ""
case .kenyanShilling: return "KSh"
default: return self.rawValue
}
}
}
14 changes: 11 additions & 3 deletions Sources/RazorpayKit/Resources/Payment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import AsyncHTTPClient
/// ### Payment Management
/// - ``all(queryParams:extraHeaders:)``
/// - ``fetch(paymentID:queryParams:extraHeaders:)``
/// - ``capture(paymentID:amount:data:extraHeaders:)``
/// - ``capture(paymentID:amount:currency:data:extraHeaders:)``
/// - ``edit(paymentID:data:extraHeaders:)``
///
/// ### Refunds
Expand Down Expand Up @@ -67,11 +67,12 @@ public protocol PaymentRoutes: RazorpayAPIRoute {
/// - Parameters:
/// - paymentID: The unique identifier of the payment to capture
/// - amount: The amount to capture in smallest currency unit (e.g., paise for INR)
/// - currency: The currency of the payment
/// - data: Additional data for the capture request
/// - extraHeaders: Optional additional headers for the request
/// - Returns: A dictionary containing the capture response
/// - Throws: An error if the capture fails
func capture(paymentID: String, amount: Int, data: [String: Any], extraHeaders: [String: String]?) async throws -> [String: Any]
func capture(paymentID: String, amount: Int, currency: Currency, extraHeaders: [String: String]?) async throws -> [String: Any]

/// Initiates a refund for a payment with the given ID and amount.
/// - Parameters:
Expand Down Expand Up @@ -275,9 +276,16 @@ public struct RazorpayPaymentRoutes: PaymentRoutes {
return try await RZPRUTL.processResponse(response)
}

@available(*, deprecated, message: "Use capture(paymentID:amount:currency:data:extraHeaders:) instead")
public func capture(paymentID: String, amount: Int, data: [String: Any], extraHeaders: [String: String]? = nil) async throws -> [String: Any] {
var captureData = data
// Default to INR for backward compatibility
return try await capture(paymentID: paymentID, amount: amount, currency: .indianRupee, extraHeaders: extraHeaders)
}

public func capture(paymentID: String, amount: Int, currency: Currency, extraHeaders: [String: String]? = nil) async throws -> [String: Any] {
var captureData = [String: Any]()
captureData["amount"] = amount
captureData["currency"] = currency.rawValue
let url = "\(APIConstants.v1)\(APIConstants.paymentURL)/\(paymentID)/capture"
let requestBody = try HTTPClientRequest.Body.json(captureData)
let response = try await client.sendRequest(method: .POST, path: url, body: requestBody, headers: RZPRUTL.convertToHTTPHeaders(extraHeaders))
Expand Down
7 changes: 7 additions & 0 deletions Tests/RazorpayKitTests/RazorpayKitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ struct RazorpayKitTests {
#expect(response["id"] as? String == paymentId, "Fetched payment ID should match the requested payment ID")
}

@Test("Capture Payment")
func capturePayment() async throws {
let paymentId = "pay_29QQoUBi66xm2f"
let response = try await razorpayClient.payment.capture(paymentID: paymentId, amount: 100, currency: .indianRupee)
#expect(response["id"] != nil, "Captured payment should have an ID")
}

@Test func refundPayment() async throws {
let paymentId = "pay_29QQoUBi66xm2f"
let refundData: [String: Any] = ["amount": 100]
Expand Down

0 comments on commit 500b2cb

Please sign in to comment.