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