diff options
-rw-r--r-- | app/controllers/Sale.scala | 81 | ||||
-rw-r--r-- | app/views/pages/sales/itemPage.scala.html | 120 | ||||
-rw-r--r-- | conf/routes | 51 |
3 files changed, 223 insertions, 29 deletions
diff --git a/app/controllers/Sale.scala b/app/controllers/Sale.scala index e6244c3..d6dab2d 100644 --- a/app/controllers/Sale.scala +++ b/app/controllers/Sale.scala | |||
@@ -1,5 +1,6 @@ | |||
1 | package controllers | 1 | package controllers |
2 | 2 | ||
3 | import org.omg.CosNaming._BindingIteratorImplBase | ||
3 | import play.api._ | 4 | import play.api._ |
4 | import play.api.data._ | 5 | import play.api.data._ |
5 | import play.api.data.Forms._ | 6 | import play.api.data.Forms._ |
@@ -20,6 +21,8 @@ case class SaleData(endDate: java.sql.Date, | |||
20 | longDescription: String, | 21 | longDescription: String, |
21 | initialPrice: BigDecimal) | 22 | initialPrice: BigDecimal) |
22 | 23 | ||
24 | case class BidData(offer: BigDecimal) | ||
25 | |||
23 | object Sale extends Controller { | 26 | object Sale extends Controller { |
24 | 27 | ||
25 | def sales = Auth { implicit request => | 28 | def sales = Auth { implicit request => |
@@ -82,11 +85,83 @@ object Sale extends Controller { | |||
82 | } | 85 | } |
83 | } | 86 | } |
84 | 87 | ||
88 | val bidForm = Form( | ||
89 | mapping( | ||
90 | "offer" -> bigDecimal(precision = 8, scale = 2) | ||
91 | )(BidData.apply)(BidData.unapply) | ||
92 | ) | ||
85 | 93 | ||
86 | def item(itemUuid: String) = TODO | 94 | def item(itemUuid: String) = Auth { implicit request => |
95 | DB.withSession { implicit session => | ||
96 | val item = Some(Tables.Items.filter(_.uuid === itemUuid).first) | ||
97 | |||
98 | if (item.isEmpty) { | ||
99 | Redirect(routes.Sale.sales()) | ||
100 | .flashing("error" -> "Item not found") | ||
101 | } else { | ||
102 | val seller = Tables.Users.filter(_.uuid === item.get.userUuid).first | ||
103 | val bids = Tables.Bids.filter(_.itemUuid === item.get.uuid).sortBy(_.bidDate.desc) | ||
104 | val bidders = Tables.Users | ||
105 | val bidsWithBidders = (bids join bidders on (_.userUuid === _.uuid)).run | ||
106 | Ok(views.html.pages.sales.itemPage(item.get, seller, bidsWithBidders, bidForm)) | ||
107 | } | ||
108 | } | ||
109 | } | ||
87 | 110 | ||
88 | def bids(itemUuid: String) = TODO | 111 | def bidSubmit(itemUuid: String) = Auth { implicit request => |
112 | if (request.account.isEmpty) { | ||
113 | Redirect(routes.Authentication.login()) | ||
114 | .flashing("error" -> "Authentication required") | ||
115 | } else { | ||
116 | DB.withSession { implicit session => | ||
117 | val item = Some(Tables.Items.filter(_.uuid === itemUuid).first) | ||
118 | val currentTimestamp = new java.sql.Timestamp((new java.util.Date).getTime) | ||
119 | |||
120 | if (item.isEmpty) { | ||
121 | Redirect(routes.Sale.sales()) | ||
122 | .flashing("error" -> "Item not found") | ||
123 | } else if (item.get.endDate before currentTimestamp) { | ||
124 | Redirect(routes.Sale.item(itemUuid)) | ||
125 | .flashing("error" -> "This sale has already ended") | ||
126 | } else { | ||
127 | |||
128 | bidForm.bindFromRequest.fold( | ||
129 | formsWithErrors => { | ||
130 | Redirect(routes.Sale.item(itemUuid)) | ||
131 | .flashing("error" -> "Invalid bid") | ||
132 | }, | ||
133 | validForm => { | ||
134 | |||
135 | val bids = Tables.Bids.filter(_.itemUuid === itemUuid).sortBy(_.bidDate.desc).run | ||
136 | val offersEnough = validForm.offer > item.get.initialPrice && (bids.isEmpty || validForm.offer > bids.head.offer) | ||
137 | |||
138 | val userEquity = Views.Accounts.filter(_.userUuid === request.account.get.userUuid).map(_.equity).first.get | ||
139 | val enoughFunds = validForm.offer < userEquity | ||
140 | |||
141 | if (!enoughFunds) { | ||
142 | Redirect(routes.Sale.item(itemUuid)) | ||
143 | .flashing("error" -> "You are too poor!") | ||
144 | } else if (!offersEnough) { | ||
145 | Redirect(routes.Sale.item(itemUuid)) | ||
146 | .flashing("error" -> "Please offer more.") | ||
147 | } else { | ||
148 | Tables.Bids += new Tables.Bid( | ||
149 | itemUuid = itemUuid, | ||
150 | userUuid = request.account.get.userUuid.get, | ||
151 | bidDate = currentTimestamp, | ||
152 | offer = validForm.offer | ||
153 | ) | ||
154 | |||
155 | Redirect(routes.Sale.item(itemUuid)) | ||
156 | .flashing("success" -> "Thanks!") | ||
157 | } | ||
158 | } | ||
159 | ) | ||
160 | |||
161 | } | ||
89 | 162 | ||
90 | def bidSubmit(itemUuid: String) = TODO | 163 | } |
164 | } | ||
165 | } | ||
91 | 166 | ||
92 | } | 167 | } |
diff --git a/app/views/pages/sales/itemPage.scala.html b/app/views/pages/sales/itemPage.scala.html new file mode 100644 index 0000000..adfd5da --- /dev/null +++ b/app/views/pages/sales/itemPage.scala.html | |||
@@ -0,0 +1,120 @@ | |||
1 | @(item: Tables.Item, seller: Tables.User, bids: Seq[(Tables.Bid, Tables.User)], bidForm: Form[BidData])(implicit request: AuthRequest[AnyContent], flash: Flash, token: play.filters.csrf.CSRF.Token) | ||
2 | |||
3 | @templates.ebe("Item page")(request.account) { | ||
4 | |||
5 | <h2>Item summary: @item.itemName</h2> | ||
6 | |||
7 | <div class="pure-g"> | ||
8 | <div class="pure-u-1 pure-u-lg-3-4"> | ||
9 | <div class="l-box"> | ||
10 | <table class="pure-table pure-table-horizontal"> | ||
11 | <thead> | ||
12 | <tr> | ||
13 | <td colspan="2">Item summary</td> | ||
14 | </tr> | ||
15 | </thead> | ||
16 | |||
17 | <tbody> | ||
18 | <tr> | ||
19 | <td>Item name</td> | ||
20 | <td class="align-right">@item.itemName</td> | ||
21 | </tr> | ||
22 | |||
23 | <tr> | ||
24 | <td>Short description</td> | ||
25 | <td class="align-right">@item.shortDesc</td> | ||
26 | </tr> | ||
27 | </tbody> | ||
28 | </table> | ||
29 | </div> | ||
30 | |||
31 | <div class="l-box"> | ||
32 | <table class="pure-table pure-table-horizontal"> | ||
33 | <thead> | ||
34 | <tr> | ||
35 | <td>Detailed description</td> | ||
36 | </tr> | ||
37 | </thead> | ||
38 | |||
39 | <tbody> | ||
40 | <tr> | ||
41 | <td>@item.longDesc</td> | ||
42 | </tr> | ||
43 | </tbody> | ||
44 | |||
45 | </table> | ||
46 | </div> | ||
47 | </div> | ||
48 | |||
49 | <div class="pure-u-1 pure-u-lg-1-4"> | ||
50 | <div class="l-box"> | ||
51 | <table class="pure-table pure-table-horizontal"> | ||
52 | <thead> | ||
53 | <tr> | ||
54 | <td colspan="2">Bid</td> | ||
55 | </tr> | ||
56 | </thead> | ||
57 | |||
58 | <tbody> | ||
59 | <tr> | ||
60 | <td>Current price</td> | ||
61 | <td class="align-right"> | ||
62 | @if(bids.nonEmpty) { | ||
63 | @bids.head._1.offer | ||
64 | } else { | ||
65 | @item.initialPrice | ||
66 | } € | ||
67 | </td> | ||
68 | </tr> | ||
69 | |||
70 | <tr> | ||
71 | <td colspan="2"> | ||
72 | @helper.form(action = routes.Sale.bidSubmit(item.uuid), 'class -> "pure-form") { | ||
73 | |||
74 | @helper.CSRF.formField | ||
75 | |||
76 | <div class="pure-g"> | ||
77 | <div class="pure-u-1 pure-u-lg-1-2"> | ||
78 | @views.html.fragments.forms.inputField(bidForm("offer"), "number", "Offer") | ||
79 | </div> | ||
80 | |||
81 | <div class="pure-u-1 pure-u-lg-1-2"> | ||
82 | <button type="submit" class="pure-button pure-input-1 pure-button-primary">Bid</button> | ||
83 | </div> | ||
84 | </div> | ||
85 | } | ||
86 | </td> | ||
87 | </tr> | ||
88 | </tbody> | ||
89 | </table> | ||
90 | </div> | ||
91 | |||
92 | <div class="l-box"> | ||
93 | <table class="pure-table pure-table-horizontal"> | ||
94 | <thead> | ||
95 | <tr> | ||
96 | <td colspan="2">Bid history</td> | ||
97 | </tr> | ||
98 | </thead> | ||
99 | |||
100 | <tbody> | ||
101 | @if(bids.isEmpty) { | ||
102 | <tr> | ||
103 | <td colspan="2">No bid</td> | ||
104 | </tr> | ||
105 | } | ||
106 | |||
107 | @for(bid <- bids) { | ||
108 | <tr> | ||
109 | <td>@bid._2.username</td> | ||
110 | <td>@bid._1.offer</td> | ||
111 | </tr> | ||
112 | } | ||