Manos Chorianopoulos

getStores request

......@@ -14,17 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/stephencelis/SQLite.swift",
"state" : {
"revision" : "392dd6058624d9f6c5b4c769d165ddd8c7293394",
"version" : "0.15.4"
}
},
{
"identity" : "swift-toolchain-sqlite",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-toolchain-sqlite",
"state" : {
"revision" : "b626d3002773b1a1304166643e7f118f724b2132",
"version" : "1.0.4"
"revision" : "0a9893ec030501a3956bee572d6b4fdd3ae158a1",
"version" : "0.12.2"
}
},
{
......
......@@ -2552,6 +2552,82 @@ public final class WarplySDK {
}
}
// MARK: - Stores
/// Get stores for a specific merchant
/// - Parameters:
/// - language: Language for the stores (optional, defaults to applicationLocale)
/// - merchantUuid: The UUID of the merchant whose stores to retrieve
/// - completion: Completion handler with stores array
/// - failureCallback: Failure callback with error code
public func getStores(
language: String? = nil,
merchantUuid: String? = nil,
completion: @escaping ([MerchantModel]?) -> Void,
failureCallback: @escaping (Int) -> Void
) {
let finalLanguage = language ?? self.applicationLocale
Task {
do {
let endpoint = Endpoint.getStores(language: finalLanguage, merchantUuid: merchantUuid ?? "")
let response = try await networkService.requestRaw(endpoint)
await MainActor.run {
print("🔍 [WarplySDK] getStores raw response: \(response)")
if response["MAPP_SHOPS-status"] as? Int == 1 {
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_success_get_stores_loyalty"
dynatraceEvent._parameters = nil
self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
var stores: [MerchantModel] = []
if let mappShops = response["MAPP_SHOPS"] as? [String: Any],
let result = mappShops["result"] as? [[String: Any]] {
for item in result {
stores.append(MerchantModel(dictionary: item))
}
}
print("✅ [WarplySDK] getStores loaded \(stores.count) stores")
completion(stores)
} else {
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_error_get_stores_loyalty"
dynatraceEvent._parameters = nil
self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
failureCallback(-1)
}
}
} catch {
await MainActor.run {
print("❌ [WarplySDK] getStores error: \(error)")
self.handleError(error, context: "getStores", endpoint: "getStores", failureCallback: failureCallback)
}
}
}
}
/// Get stores for a specific merchant (async/await variant)
/// - Parameters:
/// - language: Language for the stores (optional, defaults to applicationLocale)
/// - merchantUuid: The UUID of the merchant whose stores to retrieve
/// - Returns: Array of stores as MerchantModel
/// - Throws: WarplyError if the request fails
public func getStores(language: String? = nil, merchantUuid: String? = nil) async throws -> [MerchantModel] {
return try await withCheckedThrowingContinuation { continuation in
getStores(language: language, merchantUuid: merchantUuid, completion: { stores in
if let stores = stores {
continuation.resume(returning: stores)
} else {
continuation.resume(throwing: WarplyError.networkError)
}
}, failureCallback: { errorCode in
continuation.resume(throwing: WarplyError.unknownError(errorCode))
})
}
}
// MARK: - Articles
/// Get articles (carousel content)
......
......@@ -73,6 +73,7 @@ public enum Endpoint {
case getMarketPassDetails
case getMerchants(language: String, categories: [String], defaultShown: Bool, center: Double, tags: [String], uuid: String, distance: Int, parentUuids: [String])
case getMerchantCategories(language: String)
case getStores(language: String, merchantUuid: String)
// Articles
case getArticles(language: String, categories: [String]?)
......@@ -134,7 +135,7 @@ public enum Endpoint {
return "/user/v5/{appUUID}/logout"
// Standard Context endpoints - /api/mobile/v2/{appUUID}/context/
case .getCampaigns, .getAvailableCoupons, .getCouponSets, .getMerchantCategories, .getArticles:
case .getCampaigns, .getAvailableCoupons, .getCouponSets, .getMerchantCategories, .getArticles, .getStores:
return "/api/mobile/v2/{appUUID}/context/"
// Authenticated Context endpoints - /oauth/{appUUID}/context
......@@ -167,7 +168,7 @@ public enum Endpoint {
switch self {
case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized,
.getCoupons, .getCouponSets, .getAvailableCoupons,
.getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getMerchants, .getMerchantCategories, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin:
.getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getMerchants, .getMerchantCategories, .getStores, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin:
return .POST
case .getSingleCampaign, .getNetworkStatus:
return .GET
......@@ -410,6 +411,17 @@ public enum Endpoint {
]
]
// Stores - retrieve stores for a specific merchant
case .getStores(let language, let merchantUuid):
var shopsParams: [String: Any] = [
"language": language,
"action": "retrieve_stores"
]
if !merchantUuid.isEmpty {
shopsParams["merchant_uuid"] = merchantUuid
}
return ["shops": shopsParams]
// Articles - using content structure for DEI API
case .getArticles(let language, let categories):
var contentParams: [String: Any] = [
......@@ -478,7 +490,7 @@ public enum Endpoint {
return .userManagement
// Standard Context - /api/mobile/v2/{appUUID}/context/
case .getCampaigns, .getAvailableCoupons, .getCouponSets, .getMerchantCategories, .getArticles:
case .getCampaigns, .getAvailableCoupons, .getCouponSets, .getMerchantCategories, .getArticles, .getStores:
return .standardContext
// Authenticated Context - /oauth/{appUUID}/context
......@@ -520,7 +532,7 @@ public enum Endpoint {
// Standard Authentication (loyalty headers only)
case .register, .resetPassword, .requestOtp, .getCampaigns, .getAvailableCoupons, .getCouponSets, .refreshToken, .logout,
.verifyTicket, .getSingleCampaign, .sendEvent, .sendDeviceInfo,
.getMerchants, .getMerchantCategories, .getArticles, .getNetworkStatus, .deiLogin:
.getMerchants, .getMerchantCategories, .getArticles, .getStores, .getNetworkStatus, .deiLogin:
return .standard
// Bearer Token Authentication (loyalty headers + Authorization: Bearer)
......
......@@ -134,30 +134,56 @@ public class MerchantModel {
public init(dictionary: [String: Any]) {
// Parse existing fields
self.address = dictionary["address"] as? String? ?? ""
self.id = dictionary["id"] as? String? ?? ""
self.store_id = dictionary["store_id"] as? String? ?? ""
self.name = dictionary["name"] as? String? ?? ""
self.logo = dictionary["logo"] as? String? ?? ""
self.website = dictionary["website"] as? String? ?? ""
self.email = dictionary["email"] as? String? ?? ""
self.telephone = dictionary["telephone"] as? String? ?? ""
self.category = dictionary["category"] as? String? ?? ""
self.description = dictionary["description"] as? String? ?? ""
self.short_description = dictionary["short_description"] as? String? ?? ""
self.region = dictionary["region"] as? String? ?? ""
self.latitude = dictionary["latitude"] as? Double? ?? 0.0
self.longitude = dictionary["longitude"] as? Double? ?? 0.0
self.image = dictionary["image"] as? String? ?? ""
self.active = dictionary["active"] as? Bool? ?? false
self.city = dictionary["city"] as? String? ?? ""
self.country = dictionary["country"] as? String? ?? ""
self.postal_code = dictionary["postal_code"] as? String? ?? ""
self.vat = dictionary["vat"] as? String? ?? ""
self.uuid = dictionary["uuid"] as? String? ?? ""
self.category_uuid = dictionary["category_uuid"] as? String? ?? ""
self.created = dictionary["created"] as? String? ?? ""
self.parent = dictionary["parent"] as? String? ?? ""
self.address = dictionary["address"] as? String ?? ""
self.id = dictionary["id"] as? String ?? ""
// store_id may arrive as Int or String
if let storeIdInt = dictionary["store_id"] as? Int {
self.store_id = String(storeIdInt)
} else {
self.store_id = dictionary["store_id"] as? String ?? ""
}
self.name = dictionary["name"] as? String ?? ""
self.logo = dictionary["logo"] as? String ?? ""
self.website = dictionary["website"] as? String ?? ""
self.email = dictionary["email"] as? String ?? ""
self.telephone = dictionary["telephone"] as? String ?? ""
self.category = dictionary["category"] as? String ?? ""
self.description = dictionary["description"] as? String ?? ""
self.short_description = dictionary["short_description"] as? String ?? ""
self.region = dictionary["region"] as? String ?? ""
// latitude may arrive as String or Double
if let latString = dictionary["latitude"] as? String {
self.latitude = Double(latString) ?? 0.0
} else {
self.latitude = dictionary["latitude"] as? Double ?? 0.0
}
// longitude may arrive as String or Double
if let lonString = dictionary["longitude"] as? String {
self.longitude = Double(lonString) ?? 0.0
} else {
self.longitude = dictionary["longitude"] as? Double ?? 0.0
}
self.image = dictionary["image"] as? String ?? ""
// active may arrive as Int (1/0) or Bool
if let activeInt = dictionary["active"] as? Int {
self.active = activeInt == 1
} else {
self.active = dictionary["active"] as? Bool ?? false
}
self.city = dictionary["city"] as? String ?? ""
self.country = dictionary["country"] as? String ?? ""
// postal_code may arrive as Int or String
if let postalInt = dictionary["postal_code"] as? Int {
self.postal_code = String(postalInt)
} else {
self.postal_code = dictionary["postal_code"] as? String ?? ""
}
self.vat = dictionary["vat"] as? String ?? ""
self.uuid = dictionary["uuid"] as? String ?? ""
self.category_uuid = dictionary["category_uuid"] as? String ?? ""
self.created = dictionary["created"] as? String ?? ""
// parent_uuid key used by stores endpoint; fallback to parent for merchants
self.parent = dictionary["parent_uuid"] as? String ?? dictionary["parent"] as? String ?? ""
self.img_preview = dictionary["img_preview"] as? String? ?? ""
self.admin_name = dictionary["admin_name"] as? String? ?? ""
self.sorting = dictionary["sorting"] as? Int? ?? 0
......
......@@ -295,6 +295,26 @@ import UIKit
}
// MARK: - Merchants Loading
// private func loadMerchants() {
// WarplySDK.shared.getStores(merchantUuid: "86eba6980cf746cbbcca5c6446700121") { [weak self] merchants in
// guard let self = self, let merchants = merchants else {
// self?.createCouponSetsSection()
// return
// }
// self.merchants = merchants
// print("✅ [MyRewardsViewController] Loaded \(merchants.count) merchants")
// // Load merchant categories after merchants success
// self.loadMerchantCategories()
// } failureCallback: { [weak self] errorCode in
// print("Failed to load merchants: \(errorCode)")
// self?.createCouponSetsSection()
// }
// }
// TODO: DELETE loadMerchants - No matching needed
private func loadMerchants() {
// Load merchants from WarplySDK (using enhanced getMerchants method)
WarplySDK.shared.getMerchants { [weak self] merchants in
......