-
Notifications
You must be signed in to change notification settings - Fork 0
/
wholesale.go
370 lines (312 loc) · 8.77 KB
/
wholesale.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
package handlers
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
"strconv"
"time"
"github.com/cswank/store/internal/email"
"github.com/cswank/store/internal/store"
"github.com/cswank/store/internal/templates"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
)
type formPage struct {
page
Captcha bool
CaptchaSiteKey string
ShowMessage bool
}
func Purchase(w http.ResponseWriter, req *http.Request) error {
return nil
}
func Wholesale(w http.ResponseWriter, req *http.Request) error {
if Wholesaler(req) {
return getWholesaleForm(w, req)
} else if NewWholesaler(req) {
return getWholesaleProcessing(w, req)
}
w.Header().Set("Location", "/login?from=/wholesale")
w.WriteHeader(http.StatusFound)
return nil
}
type wholesalePage struct {
page
Products map[string]map[string][]product
Items map[string]product
}
func getWholesaleForm(w http.ResponseWriter, req *http.Request) error {
cats, err := store.GetCategories()
if err != nil {
return err
}
prods, items, err := getWholesaleProducts(cats)
if err != nil {
return err
}
p := wholesalePage{
page: page{
Links: getNavbarLinks(req),
Name: cfg.Name,
Head: html["head"],
},
Products: prods,
Items: items,
}
return templates.Get("wholesale/form.html").ExecuteTemplate(w, "base", p)
}
//the wholesaler has not clicked on the verify link in the email
//that was sent, or the admin has not clicked the confirm button
func getWholesaleProcessing(w http.ResponseWriter, req *http.Request) error {
p := page{
Links: getNavbarLinks(req),
Name: cfg.Name,
Head: html["head"],
Message: "Your wholesale application is still being processed. You will receive an additional email once your application is approved and you will then be able to purchase items at wholesale prices",
}
return templates.Get("wholesale/pending.html").ExecuteTemplate(w, "base", p)
}
func Invoice(w http.ResponseWriter, req *http.Request) error {
if err := req.ParseForm(); err != nil {
return err
}
if req.Method == "GET" {
return previewInvoice(w, req)
}
return sendInvoice(w, req)
}
type invoiceEmail struct {
Number int
Date time.Time
StyleSheet string
Total float64
Price string
Products []invoiceProduct
Customer *store.User
}
type invoiceSent struct {
page
Customer *store.User
}
func sendInvoice(w http.ResponseWriter, req *http.Request) error {
products, total := getInvoiceProducts(req)
u := getUser(req)
i := invoiceEmail{
Number: 0,
Date: time.Now(),
Total: total,
StyleSheet: cfg.InvoiceStylesheet,
Customer: u,
Products: products,
Price: cfg.DefaultPrice,
}
var buf bytes.Buffer
if err := templates.Get("wholesale/invoice.html").ExecuteTemplate(&buf, "invoice", i); err != nil {
return err
}
msg := email.Msg{
To: u.Email,
From: cfg.Email,
Subject: fmt.Sprintf("Invoice #%d from %s", i.Number, cfg.Domains[0]),
Body: buf.String(),
}
if err := email.Send(msg); err != nil {
return err
}
p := invoiceSent{
page: page{
Links: getNavbarLinks(req),
Name: cfg.Name,
Head: html["head"],
},
Customer: u,
}
return templates.Get("wholesale/invoice-sent.html").ExecuteTemplate(w, "base", p)
}
type invoiceProduct struct {
Title string
Total string
Quantity int
}
type invoicePreview struct {
page
Products []invoiceProduct
Price string
Total string
}
func previewInvoice(w http.ResponseWriter, req *http.Request) error {
products, total := getInvoiceProducts(req)
p := invoicePreview{
page: page{
Links: getNavbarLinks(req),
Name: cfg.Name,
Head: html["head"],
},
Products: products,
Price: cfg.DefaultPrice,
Total: fmt.Sprintf("%.02f", total),
}
return templates.Get("wholesale/preview.html").ExecuteTemplate(w, "base", p)
}
func getInvoiceProducts(req *http.Request) ([]invoiceProduct, float64) {
var products []invoiceProduct
price, _ := strconv.ParseFloat(cfg.DefaultPrice, 32)
var total float64
for key, values := range req.Form { // range over map
for _, value := range values { // range over []string
if value == "0" {
continue
}
q, err := strconv.ParseFloat(value, 32)
if err != nil {
log.Println("couldn't parse form value", key, value, err)
continue
}
t := price * q
total += t
products = append(products, invoiceProduct{
Total: fmt.Sprintf("%.02f", t),
Title: key,
Quantity: int(q),
})
}
}
return products, total
}
func ConfirmInvoice(w http.ResponseWriter, req *http.Request) error {
return nil
}
func WholesaleApplication(w http.ResponseWriter, req *http.Request) error {
params := req.URL.Query()
p := formPage{
page: page{
Links: getNavbarLinks(req),
Name: cfg.Name,
Head: html["head"],
},
ShowMessage: params.Get("success") != "",
CaptchaSiteKey: cfg.RecaptchaSiteKey,
Captcha: true,
}
return templates.Get("wholesale/application-form.html").ExecuteTemplate(w, "base", p)
}
func getWholesaleProducts(cats []string) (map[string]map[string][]product, map[string]product, error) {
m := map[string]map[string][]product{}
m2 := map[string]product{}
for _, cat := range cats {
price, err := store.GetPrice(cat)
if err != nil {
return nil, nil, err
}
subcats, err := store.GetSubCategories(cat)
if err != nil {
return nil, nil, err
}
a := map[string][]product{}
for _, subcat := range subcats {
prods, err := store.GetProducts(cat, subcat)
if err != nil {
return nil, nil, err
}
pp := getProducts(cat, subcat, prods, price.WholesalePrice)
a[subcat] = pp
for _, p := range pp {
m2[p.ID] = p
}
}
m[cat] = a
}
return m, m2, nil
}
func WholesaleThanks(w http.ResponseWriter, req *http.Request) error {
msg := fmt.Sprintf("Your email address is confirmed. As soon as the site administrator approves your account you will be able to log into %s and make purchases at wholesale prices", cfg.Domains[0])
p := page{
Links: getNavbarLinks(req),
Name: cfg.Name,
Head: html["head"],
Message: msg,
}
return templates.Get("wholesale/thanks.html").ExecuteTemplate(w, "base", p)
}
func WholesaleApply(w http.ResponseWriter, req *http.Request) error {
if err := req.ParseForm(); err != nil {
return err
}
u := store.User{
Permission: store.Wholesaler,
}
dec := schema.NewDecoder()
dec.IgnoreUnknownKeys(true)
if err := dec.Decode(&u, req.PostForm); err != nil {
return err
}
token, row, err := u.GenerateToken()
if err != nil {
return err
}
msg := email.Msg{
To: u.Email,
From: cfg.Email,
Subject: fmt.Sprintf("Thank you for applying to %s", cfg.Domains[0]),
Body: getWholesaleVerificationBody(u, token),
}
if err := email.Send(msg); err != nil {
return err
}
msg = email.Msg{
To: cfg.Email,
From: cfg.Email,
Subject: fmt.Sprintf("New wholesaler application for %s", cfg.Domains[0]),
Body: fmt.Sprintf(
"%s has applied as a wholesaler. Click on %s to approve the application.",
u.Email,
fmt.Sprintf("https://%s/admin/wholesalers/%s", cfg.Domains[0], u.Email),
),
}
if err := email.Send(msg); err != nil {
return err
}
if err := u.Save(row); err != nil {
return err
}
w.Header().Set("Location", "/wholesale/thanks")
w.WriteHeader(http.StatusFound)
return nil
}
func getWholesaleVerificationBody(u store.User, token string) string {
tmpl := `Hello %s,
Thank you for applying at %s as a wholesaler. Please
click on this link in order to verify your email address.
https://%s/wholesale/application/%s
As soon as the site administrator approves your application you will
receive an additional email informing you that you have been approved.
You will then be able to log into %s to purchase our products.
Thanks!
%s`
return fmt.Sprintf(tmpl, u.FirstName, cfg.Domains[0], cfg.Domains[0], token, cfg.Domains[0], cfg.Email)
}
func WholesaleVerify(w http.ResponseWriter, req *http.Request) error {
vars := mux.Vars(req)
p := page{
Links: getNavbarLinks(req),
Admin: Admin(req),
Shopify: shopifyKey,
Head: html["head"],
Name: name,
}
var f func(io.Writer, string, interface{}) error
u, err := store.VerifyWholesaler(vars["token"])
if err != nil {
log.Printf("failed to confirm user %s with token %s, err: %v\n", u.Email, vars["token"], err)
f = templates.Get("wholesale/pending.html").ExecuteTemplate
p.Message = "We were unable to confirm your email address. If you applied more than 7 days ago your application has expired and you will have to re-apply. Sorry for the inconvenience."
} else if u.Verified && u.Confirmed {
f = templates.Get("wholesale/welcome.html").ExecuteTemplate
} else {
f = templates.Get("wholesale/pending.html").ExecuteTemplate
p.Message = "Thank you. Your email address has been confirmed. Once the site administrator approves your application you will receive an email from us."
}
return f(w, "base", p)
}