bitcoin-atm
bitcoin atm for pyc inc.
git clone https://9o.is/git/bitcoin-atm.git
Data.scala
(5745B)
1 package inc.pyc.chimera
2
3 import Implicits._
4 import lycia._
5 import inc.pyc._
6 import currency._
7 import bitcoin._
8 import System._
9 import org.joda.time._
10 import format._
11
12 /**
13 * Data that can be transfered across
14 * state transitions.
15 */
16 trait Data
17
18 /**
19 * Null.
20 */
21 case object NullData extends Data
22
23 /**
24 * A valid bitcoin address.
25 *
26 * @param data bitcoin address
27 */
28 case class BitcoinAddress(data: String) extends Data
29
30 /**
31 * Data to check for history audit.
32 *
33 * @param address bitcoin address
34 * @param userInfo registered user information
35 */
36 case class AuditData(
37 address: BitcoinAddress,
38 userInfo: UserInfo = UserInfo()) extends Data {
39
40 def withPhoneNumber(phone: Phone) = {
41 copy(userInfo = userInfo.withPhoneNumber(phone))
42 }
43
44 def addresses: List[String] =
45 address.data :: userInfo
46 .addresses.filterNot(_ == address.data)
47 }
48
49 /**
50 * Carries enough data to create a local (incomplete)
51 * transaction at the current price.
52 *
53 * @param audit audit data
54 * @param limit amount the user can spend
55 * @param price buy price
56 */
57 case class CreatorTx(
58 audit: AuditData,
59 limit: LeftToSpend,
60 price: Price) extends Data
61
62 /**
63 * An incomplete transaction.
64 *
65 * @param address user's bitcoin address
66 * @param price price per bitcoin at the time of transaction
67 * @param currency currency of the bills used
68 * @param currencySymbol symbol of currency
69 * @param bills sequence of bills inserted into the machine
70 * @param limit buy limit for this transaction
71 * @param userInfo information about registered user
72 * @param total sum of the bills inserted
73 * @param bitcoins calculated total of bitcoins that will be sold
74 * @param buyPrice agreed final price per bitcoin with fee included
75 */
76 case class IncompleteTx(
77 address: String,
78 price: Price,
79 currency: Currency,
80 currencySymbol: String,
81 bills: List[Int],
82 limit: Int,
83 userInfo: UserInfo,
84 total: Int,
85 bitcoins: Double,
86 buyPrice: Double) extends Data {
87
88 /** Last time the transaction was updated. */
89 val date = new DateTime
90
91 def prettyTotal = currency.symbol + total
92
93 def prettyDate = {
94 val fmt = DateTimeFormat forPattern "MMMM dd, yyyy"
95 fmt print date
96 }
97
98 def prettyTime = {
99 val fmt = DateTimeFormat forPattern "hh:mm a z"
100 fmt print date
101 }
102
103 /**
104 * Adds a bill and returns an updated IncompleteTx
105 * @param bill bill to add
106 */
107 def insertBill(bill: Currency#Value): IncompleteTx = {
108 val bills = this.bills :+ bill.id
109 copy(
110 bills = bills,
111 total = bills.sum,
112 bitcoins = (bills.sum / price.priceWithPercentage) roundBitcoin)
113 }
114
115 /**
116 * Increases the purchase limit.
117 * ie. If purchase limit is $1,000 and it needs to be set to $3,000,
118 * but $50 is the spending limit in the current transaction, then purchase
119 * limit is set to $3,000 and spending limit is set to $2,050.
120 */
121 def setLimit(newLimit: Int): IncompleteTx = {
122 val oldPurchaseLimit = userInfo.purchaseLimit getOrElse Lycia.buyLimit
123 copy(
124 limit = newLimit - oldPurchaseLimit + limit,
125 userInfo = userInfo.copy(purchaseLimit = Some(newLimit)))
126 }
127
128 /**
129 * Updates the user info and modifies the purchase
130 * limit and spending limit accordingly.
131 */
132 def withUserInfo(info: UserInfo): IncompleteTx = {
133 val newUserLimit = info.purchaseLimit getOrElse Lycia.buyLimit
134 val newTx = setLimit(newUserLimit)
135 newTx.copy(userInfo = info)
136 }
137
138 def withPhoneNumber(phone: Phone): IncompleteTx = {
139 copy(userInfo = userInfo.withPhoneNumber(phone))
140 }
141 }
142
143 case object IncompleteTx {
144 def apply(
145 address: String,
146 price: Price,
147 currency: Currency,
148 bills: List[Int],
149 limit: Int,
150 userInfo: UserInfo): IncompleteTx = IncompleteTx(
151 address,
152 price,
153 currency,
154 currency.symbol,
155 bills,
156 limit,
157 userInfo,
158 bills.sum,
159 (bills.sum / price.priceWithPercentage) roundBitcoin,
160 price.priceWithPercentage)
161 }
162
163 /**
164 * A completed transaction.
165 *
166 * @param address buyer's bitcoin address
167 * @param date date transaction was completed
168 * @param txid blockchain transaction ID
169 * @param price price per bitcoin at the time of transaction
170 * @param currency currency of the bills used
171 * @param bills sequence of bills inserted into the machine
172 * @param chimera machine name of where transaction occurred
173 * @param ticker bitcoin price ticker service
174 */
175 case class CompleteTx(
176 address: String,
177 date: DateTime,
178 txid: String,
179 price: Price,
180 total: Int,
181 bitcoins: Double,
182 currency: Currency,
183 currencySymbol: String,
184 bills: List[Int],
185 chimera: String,
186 ticker: BitcoinService.Value,
187 prettyDate: String,
188 prettyTime: String) extends Data {
189
190 def dateISO8601 = {
191 val fmt = ISODateTimeFormat.basicDateTime
192 fmt print date
193 }
194
195 def prettyTotal = currencySymbol + total
196 }
197
198 object CompleteTx {
199 def apply(tx: IncompleteTx, txid: String): CompleteTx = {
200 val date = new DateTime
201
202 CompleteTx(
203 tx.address,
204 date,
205 txid,
206 tx.price,
207 tx.total,
208 tx.bitcoins,
209 tx.currency,
210 tx.currencySymbol,
211 tx.bills,
212 Settings(system).name,
213 Lycia.servicePriceTicker,
214 prettyDate(date),
215 prettyTime(date))
216 }
217
218 def prettyDate(date: DateTime) = {
219 val fmt = DateTimeFormat forPattern "MMMM dd, yyyy"
220 fmt print date
221 }
222
223 def prettyTime(date: DateTime) = {
224 val fmt = DateTimeFormat forPattern "hh:mm a z"
225 fmt print date
226 }
227 }
228
229 /**
230 * Reason why it is in the current state.
231 * @param reason reason
232 */
233 case class Reason(data: String) extends Data