Files
suixinkan_uikit/suixinkan/Features/AccountDeletion/Models/StoreAccountDeregistrationSubmissionStore.swift
T

61 lines
3.2 KiB
Swift

import Foundation
import CoreFoundation
/// 本机提交意图记录,不代表后端已受理或任何注销业务状态。
protocol StoreAccountDeregistrationSubmissionTracking {
/// 是否存在本机尚无法确定结果的提交意图。
var hasUnresolvedSubmission: Bool { get }
/// 在发出 POST 前记录意图;无法记录时不允许发出申请。
func recordSubmissionIntent(previousStatus: StoreAccountDeregistrationStatus?) throws
/// 仅在服务端明确拒绝本次申请时清除此意图。
func clearRejectedSubmission()
/// 用新撤销记录核销提交意图;与重新申请前相同的旧撤销响应不能放行。
func clearCancelledSubmission(matching status: StoreAccountDeregistrationStatus) -> Bool
}
/// 按环境和门店用户 ID 隔离提交意图;不按手机号保存,不存储凭证、验证码或资产。
final class StoreAccountDeregistrationSubmissionStore: StoreAccountDeregistrationSubmissionTracking {
private let defaults: UserDefaults
private let key: String
/// 注入持久化容器便于测试;生产环境使用当前服务域名隔离测试/正式账号。
init(storeUserID: String, environment: APIEnvironment = .current, defaults: UserDefaults = .standard) {
self.defaults = defaults
key = "store_deregister_submission_intent_v1_\(environment.baseURL.host ?? "unknown")_\(storeUserID)"
}
/// 任何残留记录都按待核实处理,不因不认识的本地值而允许重新提交。
var hasUnresolvedSubmission: Bool { defaults.object(forKey: key) != nil }
/// UserDefaults 记录提交意图;不把本地写入成功等同于后端收到申请。
func recordSubmissionIntent(previousStatus: StoreAccountDeregistrationStatus? = nil) throws {
defaults.set(["previous_cancellation": previousStatus?.cancellationFingerprint ?? ""], forKey: key)
guard hasUnresolvedSubmission else { throw SubmissionPersistenceError.unavailable }
}
/// 只删除当前环境、当前门店用户对应的意图,不影响其他身份。
func clearRejectedSubmission() { defaults.removeObject(forKey: key) }
/// 旧版本只会从无记录/草稿提交,其布尔意图可由完整撤销记录核销。
func clearCancelledSubmission(matching status: StoreAccountDeregistrationStatus) -> Bool {
guard let fingerprint = status.cancellationFingerprint else { return false }
if let stored = defaults.object(forKey: key) {
if let record = stored as? [String: String], let previous = record["previous_cancellation"] {
guard previous != fingerprint else { return false }
} else {
// 仅兼容旧版本写入的 true;损坏或未知结构继续等待核验。
guard let value = stored as? NSNumber,
CFGetTypeID(value) == CFBooleanGetTypeID(), value.boolValue else { return false }
}
}
defaults.removeObject(forKey: key)
return true
}
}
/// 无法保存提交意图时阻止申请,避免在重启后失去重复提交保护。
private enum SubmissionPersistenceError: LocalizedError {
case unavailable
var errorDescription: String? { "无法保存提交核验记录,请稍后重试" }
}