Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #13 from rrk12005/SWE-12-enable-payment-suite
Swe 12 enable payment suite
  • Loading branch information
ahm11003 committed Apr 8, 2019
2 parents 4aa6841 + be8b0cf commit e48f289
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 53 deletions.
Expand Up @@ -201,31 +201,60 @@
<objects> <objects>
<controller id="t8d-XB-ngB" customClass="PaymentDetailInterfaceController" customModule="SynchronyFinancial_WatchKit_App" customModuleProvider="target"> <controller id="t8d-XB-ngB" customClass="PaymentDetailInterfaceController" customModule="SynchronyFinancial_WatchKit_App" customModuleProvider="target">
<items> <items>
<label width="1" alignment="center" text="Pay From:" textAlignment="center" id="xE5-Zl-U7d"/> <imageView alignment="left" hidden="YES" id="qfi-KI-QXK"/>
<button width="1" height="40" alignment="left" title="Synchrony (1234)" id="SZD-0B-PrF" userLabel="detailButton"> <label width="1" alignment="center" hidden="YES" text="Processing ..." textAlignment="center" id="kgd-iG-og7"/>
<fontDescription key="font" type="system" pointSize="15"/> <group width="1" height="1" alignment="left" layout="vertical" id="9VF-fb-CV3">
</button> <items>
<separator alignment="left" verticalAlignment="center" id="et0-Sq-Qxm"> <label width="1" alignment="center" text="Pay From:" textAlignment="center" id="xE5-Zl-U7d"/>
<color key="color" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <button width="1" height="40" alignment="left" title="Synchrony (1234)" id="SZD-0B-PrF" userLabel="detailButton">
</separator> <fontDescription key="font" type="system" pointSize="15"/>
<label width="1" alignment="center" verticalAlignment="bottom" text="Confirm Payment" textAlignment="center" id="mT0-3D-JGP"/> </button>
<button width="1" height="49" alignment="left" verticalAlignment="bottom" title="Button" id="FgU-iZ-2XU" userLabel="paymentButton"> <separator alignment="left" verticalAlignment="center" id="et0-Sq-Qxm">
<color key="titleColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="color" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="backgroundColor" red="0.16078431369999999" green="0.6705882353" blue="0.8862745098" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> </separator>
<connections> <label width="1" alignment="center" verticalAlignment="bottom" text="Confirm Payment" textAlignment="center" id="mT0-3D-JGP"/>
<action selector="paymentAction" destination="t8d-XB-ngB" id="Zjv-zI-wCI"/> <button width="1" height="49" alignment="left" verticalAlignment="bottom" title="Button" id="FgU-iZ-2XU" userLabel="paymentButton">
</connections> <color key="titleColor" name="labelColor" catalog="System" colorSpace="catalog"/>
</button> <color key="backgroundColor" red="0.16078431369999999" green="0.6705882353" blue="0.8862745098" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="paymentAction" destination="t8d-XB-ngB" id="Zjv-zI-wCI"/>
</connections>
</button>
</items>
</group>
</items> </items>
<connections> <connections>
<outlet property="activityIndicator" destination="qfi-KI-QXK" id="wVj-x3-NzV"/>
<outlet property="activityIndicatorLabel" destination="kgd-iG-og7" id="csx-e2-1eZ"/>
<outlet property="amount" destination="mT0-3D-JGP" id="rff-wG-B82"/> <outlet property="amount" destination="mT0-3D-JGP" id="rff-wG-B82"/>
<outlet property="contentGroup" destination="9VF-fb-CV3" id="vfa-YT-ipt"/>
<outlet property="detailButton" destination="SZD-0B-PrF" id="xEw-gE-yIP"/> <outlet property="detailButton" destination="SZD-0B-PrF" id="xEw-gE-yIP"/>
<outlet property="paymentButton" destination="FgU-iZ-2XU" id="yZe-dZ-nBV"/> <outlet property="paymentButton" destination="FgU-iZ-2XU" id="yZe-dZ-nBV"/>
</connections> </connections>
</controller> </controller>
</objects> </objects>
<point key="canvasLocation" x="1085" y="186"/> <point key="canvasLocation" x="1085" y="186"/>
</scene> </scene>
<!--PaymentResult-->
<scene sceneID="mFc-oM-oG1">
<objects>
<controller identifier="PaymentResult" id="mpK-7H-pjK" customClass="PaymentResultInterfaceController" customModule="SynchronyFinancial_WatchKit_App" customModuleProvider="target">
<items>
<label width="1" alignment="center" text="Payment Result:" textAlignment="center" id="gg1-Wq-NeI"/>
<separator width="1" alignment="center" id="Y1o-3Q-hjG"/>
<label width="1" alignment="center" text="Confirmation Number:" textAlignment="center" minimumScaleFactor="0.69999999999999996" id="qAX-bM-U5t"/>
<label width="1" alignment="center" text="Label" textAlignment="center" minimumScaleFactor="0.5" id="cF3-r2-BMf"/>
<label width="1" alignment="center" verticalAlignment="center" text="Payment ID:" textAlignment="center" id="7Cr-Kh-rJ2"/>
<label width="1" alignment="center" verticalAlignment="center" text="Label" textAlignment="center" id="wSp-wZ-Ksf"/>
</items>
<connections>
<outlet property="confirmationNumberLabel" destination="cF3-r2-BMf" id="FBR-K8-kdQ"/>
<outlet property="paymentIDLabel" destination="wSp-wZ-Ksf" id="7MN-ZT-Jxw"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="1408" y="185"/>
</scene>
<!--Transactions--> <!--Transactions-->
<scene sceneID="yXO-yR-k6b"> <scene sceneID="yXO-yR-k6b">
<objects> <objects>
Expand Down
Expand Up @@ -20,7 +20,7 @@ class FetchData {
completion(false, NSError()) completion(false, NSError())
return return
} }

if let token = dict["access_token"]?.string { if let token = dict["access_token"]?.string {
// now we should save our token somewhere safe (UserDefaults) // now we should save our token somewhere safe (UserDefaults)
UserDefaults.standard.set(token, forKey: "access_token") UserDefaults.standard.set(token, forKey: "access_token")
Expand All @@ -43,17 +43,14 @@ class FetchData {
guard dict["status"]?.dictionaryValue["response_code"]?.string == "0" else { return } guard dict["status"]?.dictionaryValue["response_code"]?.string == "0" else { return }
//print(json) //print(json)
let formatter = DateFormatter()
formatter.locale = Locale.current
formatter.dateFormat = "yyyyMMdd"
if let accounts = dict["account_number_list"]?.arrayValue { if let accounts = dict["account_number_list"]?.arrayValue {
accounts.forEach { accounts.forEach {
if let accountAlias = $0.dictionaryValue["account_alias"]?.string, if let accountAlias = $0.dictionaryValue["account_alias"]?.string,
let last4 = $0["last4_acct_number"].string, let last4 = $0["last4_acct_number"].string,
let creditLimitString = $0.dictionaryValue["credit_limit"]?.string, let creditLimitString = $0.dictionaryValue["credit_limit"]?.string,
let creditLimit = Double(creditLimitString), let creditLimit = Double(creditLimitString),
let payDueDateString = $0.dictionaryValue["next_payment_due_date"]?.string, let payDueDateString = $0.dictionaryValue["next_payment_due_date"]?.string,
let paymentDueDate = formatter.date(from: payDueDateString), let paymentDueDate = Defaults.careCreditDateFormatter.date(from: payDueDateString),
let curBalString = $0.dictionaryValue["current_balance"]?.string, let curBalString = $0.dictionaryValue["current_balance"]?.string,
let currentBalance = Double(curBalString), let currentBalance = Double(curBalString),
let availCreditString = $0.dictionaryValue["available_credit"]?.string, let availCreditString = $0.dictionaryValue["available_credit"]?.string,
Expand Down Expand Up @@ -81,20 +78,17 @@ class FetchData {
var header = Defaults.headerForTransaction var header = Defaults.headerForTransaction
header["account_alias"] = accountAlias header["account_alias"] = accountAlias
var transactions: [Transaction] = [] var transactions: [Transaction] = []
let formatter = DateFormatter()
formatter.locale = Locale.current
formatter.dateFormat = "yyyyMMdd"


Alamofire.request(Defaults.TRANS_HISTORY_URL, method: .post, parameters: header, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in Alamofire.request(Defaults.TRANS_HISTORY_URL, method: .post, parameters: header, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in
switch payload.result { switch payload.result {
case .success(let value): case .success(let value):
let dict = JSON(value).dictionaryValue let dict = JSON(value).dictionaryValue
guard dict["status"]?.dictionaryValue["response_code"]?.string == "0" else { return } guard dict["status"]?.dictionaryValue["response_code"]?.string == "0" else { return }

//let's first parse the pending transactions //let's first parse the pending transactions
dict["pending_transaction_list"]?.arrayValue.forEach { dict["pending_transaction_list"]?.arrayValue.forEach {
if let desc = $0["description"].string, if let desc = $0["description"].string,
let date = formatter.date(from: $0["transaction_date"].stringValue), let date = Defaults.careCreditDateFormatter.date(from: $0["transaction_date"].stringValue),
let amountString = $0["transaction_amount"].string, let amountString = $0["transaction_amount"].string,
let amount = Double(amountString), let amount = Double(amountString),
let confirmationNum = $0["payment_confirmation_number"].string, let confirmationNum = $0["payment_confirmation_number"].string,
Expand All @@ -103,15 +97,15 @@ class FetchData {
let modifiable = $0["is_payment_modifiable"].string { let modifiable = $0["is_payment_modifiable"].string {
let type: TransactionType = $0["payment_amount_type"].stringValue == "" ? .purchase : .reimbursement let type: TransactionType = $0["payment_amount_type"].stringValue == "" ? .purchase : .reimbursement
let isModifiable: Bool = modifiable == "Y" ? true : false let isModifiable: Bool = modifiable == "Y" ? true : false

transactions.append(Transaction(type: type, amount: amount, merchantID: desc, date: date, confirmationNum: confirmationNum, paymentId: paymentId, isPending: true, isModifiable: isModifiable)) transactions.append(Transaction(type: type, amount: amount, merchantID: desc, date: date, confirmationNum: confirmationNum, paymentId: paymentId, isPending: true, isModifiable: isModifiable))
} }
} }

// let's parse just processed transactions now // let's parse just processed transactions now
dict["processed_transaction_list"]?.arrayValue.forEach { dict["processed_transaction_list"]?.arrayValue.forEach {
if let desc = $0["description"].string, if let desc = $0["description"].string,
let date = formatter.date(from: $0["transaction_date"].stringValue), let date = Defaults.careCreditDateFormatter.date(from: $0["transaction_date"].stringValue),
let amountString = $0["transaction_amount"].string, let amountString = $0["transaction_amount"].string,
let amount = Double(amountString) { let amount = Double(amountString) {
let type: TransactionType = $0["payment_amount_type"].stringValue == "" ? .purchase : .reimbursement let type: TransactionType = $0["payment_amount_type"].stringValue == "" ? .purchase : .reimbursement
Expand All @@ -125,7 +119,7 @@ class FetchData {
} }
} }
} }

static func getBankInfo(completion: @escaping ([BankAcct], Error?) -> Void) { static func getBankInfo(completion: @escaping ([BankAcct], Error?) -> Void) {
var bankIds: [BankAcct] = [] var bankIds: [BankAcct] = []
Alamofire.request(Defaults.FETCH_BANKS_URL, method: .post, parameters: Defaults.headerForMulti, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in Alamofire.request(Defaults.FETCH_BANKS_URL, method: .post, parameters: Defaults.headerForMulti, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in
Expand All @@ -151,14 +145,13 @@ class FetchData {
} }
} }
} }


static func cancelPayment(accountAlias: String, confirmationNum: String, paymentId: Int, completion: @escaping (String, Error?) -> Void){ static func cancelPayment(accountAlias: String, confirmationNum: String, paymentId: Int, completion: @escaping (String, Error?) -> Void) {

var paymentHeader = Defaults.headerForCancelPmt var paymentHeader = Defaults.headerForCancelPmt
paymentHeader["account_alias"] = accountAlias paymentHeader["account_alias"] = accountAlias
paymentHeader["payment_confirmation_number"] = confirmationNum paymentHeader["payment_confirmation_number"] = confirmationNum
paymentHeader["payment_id"] = paymentId paymentHeader["payment_id"] = paymentId

Alamofire.request(Defaults.CANCEL_PAYMENT_URL, method: .post, parameters: paymentHeader, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in Alamofire.request(Defaults.CANCEL_PAYMENT_URL, method: .post, parameters: paymentHeader, encoding: JSONEncoding.default, headers: Defaults.authHeader).responseJSON { payload in
switch payload.result { switch payload.result {
case .success(let value): case .success(let value):
Expand All @@ -172,4 +165,27 @@ class FetchData {
} }
} }
} }

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)")
}
}
}
} }
Expand Up @@ -60,6 +60,9 @@ class PayBillInterfaceController: WKInterfaceController {
let minimumFormatted = String(format: "$%.2f", valid.minPayDue) let minimumFormatted = String(format: "$%.2f", valid.minPayDue)
minimumLabel.setText("Minimum Payment:\n\(minimumFormatted)") minimumLabel.setText("Minimum Payment:\n\(minimumFormatted)")
payMinimumButton.setTitle("Pay \(minimumFormatted)") payMinimumButton.setTitle("Pay \(minimumFormatted)")

payMinimumButton.setEnabled(valid.minPayDue > 0.0)
payBalanceButton.setEnabled(valid.curBalance > 0.0)
} }
} }
} }
Expand Up @@ -12,18 +12,25 @@ import Foundation
class PaymentDetailInterfaceController: WKInterfaceController { class PaymentDetailInterfaceController: WKInterfaceController {
var selectedAccount: Account? var selectedAccount: Account?
var dictForAcct: [String: Account] = [:] var dictForAcct: [String: Account] = [:]
var dictForPayment: [String: String] = [:]
var paymentButtonArmed: Bool = false var paymentButtonArmed: Bool = false
var paymentAmount: Double = 0.0 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 detailButton: WKInterfaceButton!
@IBOutlet weak var amount: WKInterfaceLabel! @IBOutlet weak var amount: WKInterfaceLabel!
@IBOutlet weak var paymentButton: WKInterfaceButton! @IBOutlet weak var paymentButton: WKInterfaceButton!


override func awake(withContext context: Any?) { override func awake(withContext context: Any?) {
super.awake(withContext: context) 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") guard let data = context as? [String: Any],
return 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 self.paymentAmount = amount
Expand All @@ -33,15 +40,38 @@ class PaymentDetailInterfaceController: WKInterfaceController {


@IBAction func paymentAction() { @IBAction func paymentAction() {
if paymentButtonArmed { if paymentButtonArmed {
popToRootController() guard let alias = selectedAccount?.accountAlias else { return }
} else { let cancel = WKAlertAction(title: "Cancel", style: .cancel, handler: {})
// animate(withDuration: 0.75) { let submit = WKAlertAction(title: "Pay Now", style: .default, handler: {
// self.paymentButton.setBackgroundColor(UIColor.init(red: 141, green: 241, blue: 48, alpha: 1.0)) 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)) // process this payment using default bank account (9999) until ability to change account is implemented
paymentButtonArmed = true FetchData.submitPayment(for: alias, type: type, amount: self.paymentAmount, bankID: "9999") { confirmationNum, paymentID, error in
paymentButton.setTitle("Pay Now") 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")
}
} }
} }


Expand Down
@@ -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()
}

}
Expand Up @@ -10,7 +10,6 @@ import Foundation
import WatchKit import WatchKit


class TransactionCell: NSObject { class TransactionCell: NSObject {

@IBOutlet weak var transactionLabel: WKInterfaceLabel! @IBOutlet weak var transactionLabel: WKInterfaceLabel!
@IBOutlet weak var valueLabel: WKInterfaceLabel! @IBOutlet weak var valueLabel: WKInterfaceLabel!
} }

0 comments on commit e48f289

Please sign in to comment.