diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit App/Base.lproj/Interface.storyboard b/SynchronyFinancial/SynchronyFinancial WatchKit App/Base.lproj/Interface.storyboard
index 82c68de..49f67ae 100644
--- a/SynchronyFinancial/SynchronyFinancial WatchKit App/Base.lproj/Interface.storyboard
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit App/Base.lproj/Interface.storyboard
@@ -99,11 +99,13 @@
-
+
+
+
@@ -199,24 +201,33 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -224,6 +235,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountCell.swift b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountCell.swift
index 8bba624..55d6587 100644
--- a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountCell.swift
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountCell.swift
@@ -11,4 +11,5 @@ import WatchKit
class AccountCell: NSObject {
@IBOutlet weak var accountName: WKInterfaceLabel!
+ @IBOutlet weak var last4Label: WKInterfaceLabel!
}
diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountTableInterfaceController.swift b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountTableInterfaceController.swift
index 6f06f1a..72518cd 100644
--- a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountTableInterfaceController.swift
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/AccountTableInterfaceController.swift
@@ -48,6 +48,7 @@ class AccountTableInterfaceController: WKInterfaceController {
for index in 0.. Void) {
var bankIds: [BankAcct] = []
Alamofire.request(Defaults.FETCH_BANKS_URL, method: .post, parameters: Defaults.headerForMulti, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in
@@ -150,6 +145,47 @@ class FetchData {
}
}
}
-
-
+
+ static func cancelPayment(accountAlias: String, confirmationNum: String, paymentId: Int, completion: @escaping (String, Error?) -> Void) {
+ var paymentHeader = Defaults.headerForCancelPmt
+ paymentHeader["account_alias"] = accountAlias
+ paymentHeader["payment_confirmation_number"] = confirmationNum
+ paymentHeader["payment_id"] = paymentId
+
+ Alamofire.request(Defaults.CANCEL_PAYMENT_URL, method: .post, parameters: paymentHeader, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in
+ switch payload.result {
+ case .success(let value):
+ let dict = JSON(value).dictionaryValue
+ guard dict["status"]?.dictionaryValue["response_code"]?.string == "0" else { return }
+ if let paymentCancelNum = dict["cancellation_confirmation_number"]?.stringValue {
+ completion(paymentCancelNum, nil)
+ }
+ case .failure(let error):
+ NSLog("Error: \(error.localizedDescription)")
+ }
+ }
+ }
+
+ static func submitPayment(for alias: String, type: PaymentType, amount: Double, bankID: String, completion: @escaping (String, String, Error?) -> Void) {
+ var paymentHeader = Defaults.headerForPmt
+ paymentHeader["account_alias"] = alias
+ paymentHeader["bank_account_id"] = bankID
+ paymentHeader["payment_amount_type"] = type.rawValue
+ paymentHeader["payment_amount"] = amount
+ paymentHeader["scheduled_payment_post_date"] = Defaults.careCreditDateFormatter.string(from: Date())
+
+ Alamofire.request(Defaults.MAKE_PAYMENT_URL, method: .post, parameters: paymentHeader, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in
+ switch payload.result {
+ case .success(let value):
+ let dict = JSON(value).dictionaryValue
+ guard dict["status"]?.dictionaryValue["response_code"]?.string == "0" else { return }
+ if let paymentConfirmationNum = dict["payment_confirmation_number"]?.stringValue,
+ let paymentID = dict["payment_id"]?.stringValue {
+ completion(paymentConfirmationNum, paymentID, nil)
+ }
+ case .failure(let error):
+ NSLog("Error: \(error.localizedDescription)")
+ }
+ }
+ }
}
diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PayBillInterfaceController.swift b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PayBillInterfaceController.swift
index 3593120..5facc30 100644
--- a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PayBillInterfaceController.swift
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PayBillInterfaceController.swift
@@ -60,6 +60,9 @@ class PayBillInterfaceController: WKInterfaceController {
let minimumFormatted = String(format: "$%.2f", valid.minPayDue)
minimumLabel.setText("Minimum Payment:\n\(minimumFormatted)")
payMinimumButton.setTitle("Pay \(minimumFormatted)")
+
+ payMinimumButton.setEnabled(valid.minPayDue > 0.0)
+ payBalanceButton.setEnabled(valid.curBalance > 0.0)
}
}
}
diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentDetailInterfaceController.swift b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentDetailInterfaceController.swift
index 30ed7b8..99ab3b1 100644
--- a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentDetailInterfaceController.swift
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentDetailInterfaceController.swift
@@ -12,18 +12,25 @@ import Foundation
class PaymentDetailInterfaceController: WKInterfaceController {
var selectedAccount: Account?
var dictForAcct: [String: Account] = [:]
+ var dictForPayment: [String: String] = [:]
var paymentButtonArmed: Bool = false
var paymentAmount: Double = 0.0
+ @IBOutlet weak var contentGroup: WKInterfaceGroup!
+ @IBOutlet weak var activityIndicator: WKInterfaceImage!
+ @IBOutlet weak var activityIndicatorLabel: WKInterfaceLabel!
@IBOutlet weak var detailButton: WKInterfaceButton!
@IBOutlet weak var amount: WKInterfaceLabel!
@IBOutlet weak var paymentButton: WKInterfaceButton!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
- guard let data = context as? [String: Any], let acct = data["acct"] as? Account, let amount = data["payment_amount"] as? Double else {
- NSLog("Error getting account object and payment amount")
- return
+
+ guard let data = context as? [String: Any],
+ let acct = data["acct"] as? Account,
+ let amount = data["payment_amount"] as? Double else {
+ NSLog("Error getting account object and payment amount")
+ return
}
self.paymentAmount = amount
@@ -33,15 +40,38 @@ class PaymentDetailInterfaceController: WKInterfaceController {
@IBAction func paymentAction() {
if paymentButtonArmed {
- popToRootController()
- } else {
-// animate(withDuration: 0.75) {
-// self.paymentButton.setBackgroundColor(UIColor.init(red: 141, green: 241, blue: 48, alpha: 1.0))
-// }
+ guard let alias = selectedAccount?.accountAlias else { return }
+ let cancel = WKAlertAction(title: "Cancel", style: .cancel, handler: {})
+ let submit = WKAlertAction(title: "Pay Now", style: .default, handler: {
+ self.contentGroup.setHidden(true)
+ self.activityIndicator.configureForActivityIndicator()
+ self.activityIndicatorLabel.setHidden(false)
+ self.activityIndicatorLabel.setVerticalAlignment(.center)
+ let type: PaymentType = self.paymentAmount == self.selectedAccount?.curBalance ? .currentBal : .minimumDue
- paymentButton.setBackgroundColor(#colorLiteral(red: 0.6092301607, green: 0.9366738796, blue: 0.2432599962, alpha: 1))
- paymentButtonArmed = true
- paymentButton.setTitle("Pay Now")
+ // process this payment using default bank account (9999) until ability to change account is implemented
+ FetchData.submitPayment(for: alias, type: type, amount: self.paymentAmount, bankID: "9999") { confirmationNum, paymentID, error in
+ guard error == nil else {
+ let dismiss = WKAlertAction(title: "Dismiss", style: .cancel, handler: {})
+ self.presentAlert(withTitle: "Error", message: "We were unable to process your payment at this time. Please try again later.", preferredStyle: .alert, actions: [dismiss])
+ return
+ }
+ self.dictForPayment.updateValue(confirmationNum, forKey: "payment_confirmation_number")
+ self.dictForPayment.updateValue(paymentID, forKey: "payment_id")
+ self.activityIndicator.stopAnimatingAsIndicator()
+ self.activityIndicatorLabel.setHidden(true)
+ self.contentGroup.setHidden(false)
+ self.presentController(withName: "PaymentResult", context: self.dictForPayment)
+ self.popToRootController()
+ }
+ })
+ presentAlert(withTitle: "Disclaimer", message: "By tapping \"Pay Now\", you are authorizing Synchrony Bank to process a one time payment in the amount of \(String(format: "$%.2f", paymentAmount)).", preferredStyle: .actionSheet, actions: [cancel, submit])
+ } else {
+ animate(withDuration: 0.5) {
+ self.paymentButton.setBackgroundColor(#colorLiteral(red: 0.6092301607, green: 0.9366738796, blue: 0.2432599962, alpha: 1))
+ self.paymentButtonArmed = true
+ self.paymentButton.setTitle("Pay Now")
+ }
}
}
diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentResultInterfaceController.swift b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentResultInterfaceController.swift
new file mode 100644
index 0000000..3208d1c
--- /dev/null
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/PaymentResultInterfaceController.swift
@@ -0,0 +1,38 @@
+//
+// PaymentResultInterfaceController.swift
+// SynchronyFinancial WatchKit Extension
+//
+// Created by Alan Maynard on 3/29/19.
+// Copyright © 2019 Alan Maynard. All rights reserved.
+//
+
+import WatchKit
+import Foundation
+
+class PaymentResultInterfaceController: WKInterfaceController {
+ @IBOutlet weak var confirmationNumberLabel: WKInterfaceLabel!
+ @IBOutlet weak var paymentIDLabel: WKInterfaceLabel!
+
+ override func awake(withContext context: Any?) {
+ super.awake(withContext: context)
+
+ if let data = context as? [String: String],
+ let paymentConfirmation = data["payment_confirmation_number"],
+ let paymentID = data["payment_id"] {
+ confirmationNumberLabel.setText(paymentConfirmation)
+ paymentIDLabel.setText(paymentID)
+ setTitle("Done")
+ }
+ }
+
+ override func willActivate() {
+ // This method is called when watch view controller is about to be visible to user
+ super.willActivate()
+ }
+
+ override func didDeactivate() {
+ // This method is called when watch view controller is no longer visible
+ super.didDeactivate()
+ }
+
+}
diff --git a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/TransactionCell.swift b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/TransactionCell.swift
index e9d39bd..8825369 100644
--- a/SynchronyFinancial/SynchronyFinancial WatchKit Extension/TransactionCell.swift
+++ b/SynchronyFinancial/SynchronyFinancial WatchKit Extension/TransactionCell.swift
@@ -10,7 +10,6 @@ import Foundation
import WatchKit
class TransactionCell: NSObject {
-
@IBOutlet weak var transactionLabel: WKInterfaceLabel!
@IBOutlet weak var valueLabel: WKInterfaceLabel!
}
diff --git a/SynchronyFinancial/SynchronyFinancial.xcodeproj/project.pbxproj b/SynchronyFinancial/SynchronyFinancial.xcodeproj/project.pbxproj
index 0195a24..4662621 100644
--- a/SynchronyFinancial/SynchronyFinancial.xcodeproj/project.pbxproj
+++ b/SynchronyFinancial/SynchronyFinancial.xcodeproj/project.pbxproj
@@ -11,7 +11,6 @@
11E6ADB92253FA050009922E /* BankAcct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E6ADB82253FA050009922E /* BankAcct.swift */; };
11E6ADBA225401DB0009922E /* BankAcct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E6ADB82253FA050009922E /* BankAcct.swift */; };
281283568A34D3C5D9C7B383 /* libPods-SynchronyFinancial WatchKit Extension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA6D46F907ADAABF49FD409 /* libPods-SynchronyFinancial WatchKit Extension.a */; };
- 481864A8224802BB0059CF7A /* PaymentDetailInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 481864A7224802BB0059CF7A /* PaymentDetailInterfaceController.swift */; };
481864A9224802BB0059CF7A /* PaymentDetailInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 481864A7224802BB0059CF7A /* PaymentDetailInterfaceController.swift */; };
48DA0058221D12E70081A500 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48DA0057221D12E70081A500 /* AccountCell.swift */; };
48F243072214C98600B9C894 /* AccountTableInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48F243062214C98600B9C894 /* AccountTableInterfaceController.swift */; };
@@ -30,6 +29,7 @@
678C38842230950100FEAAF6 /* AccountDetailsInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 678C38832230950100FEAAF6 /* AccountDetailsInterfaceController.swift */; };
678C3885223098C400FEAAF6 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48F2430B2214CBF700B9C894 /* Account.swift */; };
678C388622309F7D00FEAAF6 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48DA0057221D12E70081A500 /* AccountCell.swift */; };
+ 678C62BA224ECDFD0007AD53 /* PaymentResultInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 678C62B9224ECDFD0007AD53 /* PaymentResultInterfaceController.swift */; };
67BAC269219E254700713FEF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67BAC268219E254700713FEF /* AppDelegate.swift */; };
67BAC26E219E254700713FEF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67BAC26C219E254700713FEF /* Main.storyboard */; };
67BAC270219E254800713FEF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 67BAC26F219E254800713FEF /* Assets.xcassets */; };
@@ -106,6 +106,7 @@
676392B322429DC800740A8C /* TransactionsInterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsInterfaceController.swift; sourceTree = ""; };
676392B52242A3F800740A8C /* TransactionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionCell.swift; sourceTree = ""; };
678C38832230950100FEAAF6 /* AccountDetailsInterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDetailsInterfaceController.swift; sourceTree = ""; };
+ 678C62B9224ECDFD0007AD53 /* PaymentResultInterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentResultInterfaceController.swift; sourceTree = ""; };
67BAC265219E254700713FEF /* SynchronyFinancial.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SynchronyFinancial.app; sourceTree = BUILT_PRODUCTS_DIR; };
67BAC268219E254700713FEF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
67BAC26D219E254700713FEF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
@@ -206,6 +207,7 @@
67BAC28A219E254900713FEF /* SynchronyFinancial WatchKit Extension */ = {
isa = PBXGroup;
children = (
+ 678C62B9224ECDFD0007AD53 /* PaymentResultInterfaceController.swift */,
67293CF022542F15009E0E7A /* TransactionDetailsInterfaceController.swift */,
674BD1522239A39D0076AFD6 /* PayBillInterfaceController.swift */,
481864A7224802BB0059CF7A /* PaymentDetailInterfaceController.swift */,
@@ -489,6 +491,7 @@
678C3885223098C400FEAAF6 /* Account.swift in Sources */,
67BAC28E219E254900713FEF /* ExtensionDelegate.swift in Sources */,
674BD1542239A39D0076AFD6 /* PayBillInterfaceController.swift in Sources */,
+ 678C62BA224ECDFD0007AD53 /* PaymentResultInterfaceController.swift in Sources */,
678C38842230950100FEAAF6 /* AccountDetailsInterfaceController.swift in Sources */,
673F396E21A644570051469E /* MainMenuInterfaceController.swift in Sources */,
67E17B87223812C2008871FE /* Defaults.swift in Sources */,
diff --git a/SynchronyFinancial/SynchronyFinancial/Account.swift b/SynchronyFinancial/SynchronyFinancial/Account.swift
index 21875b7..f44c8a6 100644
--- a/SynchronyFinancial/SynchronyFinancial/Account.swift
+++ b/SynchronyFinancial/SynchronyFinancial/Account.swift
@@ -10,6 +10,7 @@ import Foundation
class Account: NSObject {
var accountAlias: String
var creditLimit: Double
+ var last4: String
//var transactions: [Transaction]
var paymentDueDate: Date
//var cycleEndDate: Date
@@ -20,9 +21,10 @@ class Account: NSObject {
var statementBal: Double
var accountName: String
- init(accountAlias: String, creditLimit: Double, paymentDueDate: Date, curBalance: Double, availCredit: Double, minPayDue: Double, statementBal: Double, accountName: String) {
+ init(_ accountAlias: String, _ creditLimit: Double, _ last4: String, _ paymentDueDate: Date, _ curBalance: Double, _ availCredit: Double, _ minPayDue: Double, _ statementBal: Double, _ accountName: String) {
self.accountAlias = accountAlias
self.creditLimit = creditLimit
+ self.last4 = last4
//self.transactions = transactions
//self.balance = transactions.map { $0.amount }.reduce(0.0, +)
self.paymentDueDate = paymentDueDate
diff --git a/SynchronyFinancial/SynchronyFinancial/Defaults.swift b/SynchronyFinancial/SynchronyFinancial/Defaults.swift
index 375d8a3..55958a8 100644
--- a/SynchronyFinancial/SynchronyFinancial/Defaults.swift
+++ b/SynchronyFinancial/SynchronyFinancial/Defaults.swift
@@ -22,6 +22,13 @@ final class Defaults {
static let token = UserDefaults.standard.string(forKey: "access_token") ?? ""
static let authHeader = ["Authorization": "Bearer \(token)"]
+ static let careCreditDateFormatter: DateFormatter = {
+ var formatter = DateFormatter()
+ formatter.dateFormat = "yyyyMMdd"
+ formatter.locale = Locale.current
+ return formatter
+ }()
+
static var headerForLogin: [String: Any] = {
return ["client_id": "carecredit",
"client_secret": "",
@@ -47,14 +54,9 @@ final class Defaults {
var account_alias = ""
// Dates
- let formatter = DateFormatter()
- formatter.locale = Locale.current
- formatter.dateFormat = "yyyyMMdd"
-
// for now lets get transactions from the past 2 weeks
- let start_date = formatter.string(from: Calendar.current.date(byAdding: .day, value: -14, to: Date()) ?? Date())
- let end_date = formatter.string(from: Date())
-
+ let start_date = careCreditDateFormatter.string(from: Calendar.current.date(byAdding: .day, value: -14, to: Date()) ?? Date())
+ let end_date = careCreditDateFormatter.string(from: Date())
return ["account_alias": account_alias,
"begin_sequence": "1",
diff --git a/SynchronyFinancial/SynchronyFinancial/Transaction.swift b/SynchronyFinancial/SynchronyFinancial/Transaction.swift
index 71c58b0..e24c2b3 100644
--- a/SynchronyFinancial/SynchronyFinancial/Transaction.swift
+++ b/SynchronyFinancial/SynchronyFinancial/Transaction.swift
@@ -12,6 +12,11 @@ public enum TransactionType: Int {
case reimbursement = 1
}
+public enum PaymentType: String {
+ case currentBal = "CBL"
+ case minimumDue = "MIN"
+}
+
class Transaction: NSObject {
var type: TransactionType
var amount: Double