cart
This commit is contained in:
@@ -61,6 +61,7 @@ type App struct {
|
|||||||
fs *FileServer
|
fs *FileServer
|
||||||
hub *Hub
|
hub *Hub
|
||||||
cs *CustomerServer
|
cs *CustomerServer
|
||||||
|
OnVouchersChange func(codes []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// New constructs the commerce admin: it opens the cart/checkout disk event-log
|
// New constructs the commerce admin: it opens the cart/checkout disk event-log
|
||||||
@@ -171,6 +172,7 @@ func New(cfg Config) (*App, error) {
|
|||||||
// apply auth or CORS — the composing host (or standalone main) wraps the mux
|
// apply auth or CORS — the composing host (or standalone main) wraps the mux
|
||||||
// with those.
|
// with those.
|
||||||
func (a *App) RegisterRoutes(mux *http.ServeMux) {
|
func (a *App) RegisterRoutes(mux *http.ServeMux) {
|
||||||
|
a.fs.OnVouchersChange = a.OnVouchersChange
|
||||||
mux.HandleFunc("GET /carts", a.fs.CartsHandler)
|
mux.HandleFunc("GET /carts", a.fs.CartsHandler)
|
||||||
mux.HandleFunc("GET /cart/{id}", a.fs.CartHandler)
|
mux.HandleFunc("GET /cart/{id}", a.fs.CartHandler)
|
||||||
mux.HandleFunc("GET /checkouts", a.fs.CheckoutsHandler)
|
mux.HandleFunc("GET /checkouts", a.fs.CheckoutsHandler)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type FileServer struct {
|
|||||||
promotionsFile string
|
promotionsFile string
|
||||||
storage actor.LogStorage[cart.CartGrain]
|
storage actor.LogStorage[cart.CartGrain]
|
||||||
checkoutStorage actor.LogStorage[checkout.CheckoutGrain]
|
checkoutStorage actor.LogStorage[checkout.CheckoutGrain]
|
||||||
|
OnVouchersChange func(codes []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileServer(dataDir string, checkoutDataDir string, promotionsFile string, storage actor.LogStorage[cart.CartGrain], checkoutStorage actor.LogStorage[checkout.CheckoutGrain]) *FileServer {
|
func NewFileServer(dataDir string, checkoutDataDir string, promotionsFile string, storage actor.LogStorage[cart.CartGrain], checkoutStorage actor.LogStorage[checkout.CheckoutGrain]) *FileServer {
|
||||||
@@ -276,15 +277,37 @@ func (fs *FileServer) VoucherHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
_ = os.MkdirAll(filepath.Dir(fileName), 0755)
|
body, err := io.ReadAll(r.Body)
|
||||||
file, err := os.Create(fileName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
io.Copy(file, r.Body)
|
var parsed struct {
|
||||||
|
State struct {
|
||||||
|
Vouchers []struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
} `json:"vouchers"`
|
||||||
|
} `json:"state"`
|
||||||
|
}
|
||||||
|
var codes []string
|
||||||
|
if err := json.Unmarshal(body, &parsed); err == nil {
|
||||||
|
for _, v := range parsed.State.Vouchers {
|
||||||
|
if v.Code != "" {
|
||||||
|
codes = append(codes, v.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = os.MkdirAll(filepath.Dir(fileName), 0755)
|
||||||
|
if err := os.WriteFile(fileName, body, 0644); err != nil {
|
||||||
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if fs.OnVouchersChange != nil {
|
||||||
|
fs.OnVouchersChange(codes)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-9
@@ -18,6 +18,7 @@ type Store struct {
|
|||||||
path string
|
path string
|
||||||
version int
|
version int
|
||||||
promotions []PromotionRule
|
promotions []PromotionRule
|
||||||
|
OnChange func(id string, isDelete bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStore loads the state file at path (an absent file yields an empty store)
|
// NewStore loads the state file at path (an absent file yields an empty store)
|
||||||
@@ -72,40 +73,72 @@ func (s *Store) Upsert(rule PromotionRule) (replaced bool, err error) {
|
|||||||
if rule.ID == "" {
|
if rule.ID == "" {
|
||||||
return false, fmt.Errorf("promotion id is required")
|
return false, fmt.Errorf("promotion id is required")
|
||||||
}
|
}
|
||||||
|
var cb func(string, bool)
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer func() {
|
||||||
|
s.mu.Unlock()
|
||||||
|
if err == nil && cb != nil {
|
||||||
|
cb(rule.ID, false)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cb = s.OnChange
|
||||||
|
|
||||||
for i := range s.promotions {
|
for i := range s.promotions {
|
||||||
if s.promotions[i].ID == rule.ID {
|
if s.promotions[i].ID == rule.ID {
|
||||||
s.promotions[i] = rule
|
s.promotions[i] = rule
|
||||||
return true, s.saveLocked()
|
replaced = true
|
||||||
|
err = s.saveLocked()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.promotions = append(s.promotions, rule)
|
s.promotions = append(s.promotions, rule)
|
||||||
return false, s.saveLocked()
|
replaced = false
|
||||||
|
err = s.saveLocked()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetStatus changes the status of a rule and persists. Returns false if no rule
|
// SetStatus changes the status of a rule and persists. Returns false if no rule
|
||||||
// with the id exists.
|
// with the id exists.
|
||||||
func (s *Store) SetStatus(id string, status PromotionStatus) (bool, error) {
|
func (s *Store) SetStatus(id string, status PromotionStatus) (found bool, err error) {
|
||||||
|
var cb func(string, bool)
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer func() {
|
||||||
|
s.mu.Unlock()
|
||||||
|
if err == nil && found && cb != nil {
|
||||||
|
cb(id, false)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cb = s.OnChange
|
||||||
|
|
||||||
for i := range s.promotions {
|
for i := range s.promotions {
|
||||||
if s.promotions[i].ID == id {
|
if s.promotions[i].ID == id {
|
||||||
s.promotions[i].Status = status
|
s.promotions[i].Status = status
|
||||||
return true, s.saveLocked()
|
found = true
|
||||||
|
err = s.saveLocked()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes the rule with the id and persists. Returns false if not found.
|
// Delete removes the rule with the id and persists. Returns false if not found.
|
||||||
func (s *Store) Delete(id string) (bool, error) {
|
func (s *Store) Delete(id string) (found bool, err error) {
|
||||||
|
var cb func(string, bool)
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer func() {
|
||||||
|
s.mu.Unlock()
|
||||||
|
if err == nil && found && cb != nil {
|
||||||
|
cb(id, true)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cb = s.OnChange
|
||||||
|
|
||||||
for i := range s.promotions {
|
for i := range s.promotions {
|
||||||
if s.promotions[i].ID == id {
|
if s.promotions[i].ID == id {
|
||||||
s.promotions = append(s.promotions[:i], s.promotions[i+1:]...)
|
s.promotions = append(s.promotions[:i], s.promotions[i+1:]...)
|
||||||
return true, s.saveLocked()
|
found = true
|
||||||
|
err = s.saveLocked()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user