diff --git a/api/api.go b/api/api.go
index 57df5776f5a7138a86eaed19e70ff23caea66624..d4ea1737b52b2fd47c883670651d2961b323dfbb 100644
--- a/api/api.go
+++ b/api/api.go
@@ -58,7 +58,6 @@ func Init(dbPath string, signKey string, mail *Mail, r *mux.Router) error {
 	r.HandleFunc("/order", a.authNum(a.AddOrder)).Methods("POST")
 	r.HandleFunc("/order/{id:[0-9]+}", a.authNum(a.GetOrder)).Methods("GET")
 	r.HandleFunc("/order/active", a.auth(a.ListActiveOrders)).Methods("GET")
-	r.HandleFunc("/order/purchase", a.authNum(a.AddOrderPurchase)).Methods("POST")
-	// TODO: r.HandleFunc("/order/purchase", a.authNum(a.UpdateOrderPurchase)).Methods("PUT")
+	r.HandleFunc("/order/{id:[0-9]+}/purchase", a.authNum(a.AddOrderPurchase)).Methods("POST")
 	return nil
 }
diff --git a/api/db/order.go b/api/db/order.go
index d1e3335a734de74ab6d3a4a7fe672fab7402a887..3a4cc7e3b00eb4b8b33d4df75170cf7781d4e485 100644
--- a/api/db/order.go
+++ b/api/db/order.go
@@ -62,11 +62,8 @@ func (d *DB) AddOrder(order *Order) error {
 	return d.db.Create(&order).Error
 }
 
-func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurchase) (transaction Transaction, err error) {
-	var order Order
-	err = d.db.Preload("Products").
-		Preload("Transactions").
-		First(&order, orderID).Error
+func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurchase) (transaction Transaction, err error) {
+	order, transaction, err := d.GetOrder(memberNum, orderID)
 	if err != nil {
 		return
 	}
@@ -75,13 +72,6 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurch
 		log.Printf("Order is not active %d: %v", order.ID, purchase)
 		return
 	}
-	for _, t := range order.Transactions {
-		if t.MemberNum == memberNum {
-			log.Printf("Purchase by %d for %d when there is already one by this member: %v", memberNum, order.ID, purchase)
-			err = ErrorInvalidRequest
-			return
-		}
-	}
 
 	total := 0
 	for i, p := range purchase {
@@ -102,6 +92,11 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurch
 		}
 	}
 
+	if transaction.ID != 0 {
+		err = d.updateOrderPurchase(memberNum, &transaction, total, purchase)
+		return
+	}
+
 	transaction = Transaction{
 		MemberNum:     memberNum,
 		Total:         -total,
@@ -114,6 +109,29 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurch
 	return
 }
 
+func (d *DB) updateOrderPurchase(memberNum int, transaction *Transaction, total int, purchase []OrderPurchase) error {
+	totalDiff := -(transaction.Total + total)
+	transaction.Total = -total
+	transaction.Date = time.Now()
+
+	for i, p := range transaction.OrderPurchase {
+		for _, new_purchase := range purchase {
+			if new_purchase.ProductCode == p.ProductCode {
+				transaction.OrderPurchase[i].Amount = new_purchase.Amount
+				break
+			}
+		}
+	}
+
+	return d.db.Transaction(func(tx *gorm.DB) error {
+		err := updateMemberBalance(tx, memberNum, totalDiff)
+		if err != nil {
+			return err
+		}
+		return tx.Save(&transaction).Error
+	})
+}
+
 func (d *DB) DeactivateOrders() []Order {
 	var orders []Order
 	now := time.Now()
diff --git a/api/db/transaction.go b/api/db/transaction.go
index 408956e154f726ef1def0e74264a4d7170a16535..f51fad706f25cfb9c7a14a51b8804ce5015244da 100644
--- a/api/db/transaction.go
+++ b/api/db/transaction.go
@@ -137,24 +137,30 @@ func (d *DB) transactionQuery() *gorm.DB {
 
 func createTransaction(db *gorm.DB, transaction *Transaction) error {
 	return db.Transaction(func(tx *gorm.DB) error {
-		var member Member
-		err := tx.Where("num = ?", transaction.MemberNum).Find(&member).Error
+		err := updateMemberBalance(tx, transaction.MemberNum, transaction.Total)
 		if err != nil {
-			log.Printf("Can't find member for transaction %d: %v", transaction.MemberNum, err)
-			return ErrorNotFound
-		}
-		if member.Balance < -transaction.Total {
-			log.Printf("Member %d don't have enough money (%d-%d)", member.Num, member.Balance, transaction.Total)
-			return ErrorInvalidRequest
-		}
-		err = tx.Model(&Member{}).
-			Where("num = ?", transaction.MemberNum).
-			Update("balance", gorm.Expr("balance + ?", transaction.Total)).Error
-		if err != nil {
-			log.Printf("Can't update update member balance %d-%d: %v", member.Num, transaction.Total, err)
 			return err
 		}
-
 		return tx.Create(&transaction).Error
 	})
 }
+
+func updateMemberBalance(tx *gorm.DB, memberNum int, amount int) error {
+	var member Member
+	err := tx.Where("num = ?", memberNum).Find(&member).Error
+	if err != nil {
+		log.Printf("Can't find member for transaction %d: %v", memberNum, err)
+		return ErrorNotFound
+	}
+	if member.Balance < -amount {
+		log.Printf("Member %d don't have enough money (%d-%d)", member.Num, member.Balance, amount)
+		return ErrorInvalidRequest
+	}
+	err = tx.Model(&Member{}).
+		Where("num = ?", memberNum).
+		Update("balance", gorm.Expr("balance + ?", amount)).Error
+	if err != nil {
+		log.Printf("Can't update update member balance %d-%d: %v", member.Num, amount, err)
+	}
+	return err
+}
diff --git a/api/order.go b/api/order.go
index a296f50de53de3c1bcd17fc39e567f7d719be32d..36fea279a48b60b36eaa077f770646a04750b95d 100644
--- a/api/order.go
+++ b/api/order.go
@@ -17,11 +17,6 @@ type OrderGetResponse struct {
 	Transaction *db.Transaction `json:"transaction"`
 }
 
-type OrderPurchaseRequest struct {
-	Purchase []db.OrderPurchase `json:"purchase"`
-	OrderID  uint               `json:"order"`
-}
-
 func (a *api) refundOrders() {
 	const refundSleeptime = 10 * time.Minute
 	for {
@@ -120,27 +115,29 @@ func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) {
 }
 
 func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request) {
-	var request OrderPurchaseRequest
-	err := json.NewDecoder(req.Body).Decode(&request)
+	vars := mux.Vars(req)
+	id, _ := strconv.Atoi(vars["id"])
+	var purchase []db.OrderPurchase
+	err := json.NewDecoder(req.Body).Decode(&purchase)
 	if err != nil {
 		log.Printf("Can't parse order purchase: %v", err)
 		w.WriteHeader(http.StatusInternalServerError)
 		return
 	}
-	if len(request.Purchase) == 0 {
+	if len(purchase) == 0 {
 		log.Printf("Empty order purchase")
 		w.WriteHeader(http.StatusBadRequest)
 		return
 	}
 
-	transaction, err := a.db.AddOrderPurchase(num, request.OrderID, request.Purchase)
+	transaction, err := a.db.AddOrderPurchase(num, id, purchase)
 	if err != nil {
 		if errors.Is(err, db.ErrorNotFound) {
 			w.WriteHeader(http.StatusNotAcceptable)
 		} else if errors.Is(err, db.ErrorInvalidRequest) {
 			w.WriteHeader(http.StatusBadRequest)
 		} else {
-			log.Printf("Can't get order %d: %v", request.OrderID, err)
+			log.Printf("Can't get order %d: %v", id, err)
 			w.WriteHeader(http.StatusInternalServerError)
 		}
 		return
@@ -152,6 +149,5 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
 	if err != nil {
 		log.Printf("Can't encode order transaction: %v", err)
 		w.WriteHeader(http.StatusInternalServerError)
-		return
 	}
 }
diff --git a/api/order_test.go b/api/order_test.go
index af3626159820666a5eacc1d2f6206458bd6b5891..f78827f2d5ae47f91dd99bb34edae4bbfcf8de27 100644
--- a/api/order_test.go
+++ b/api/order_test.go
@@ -1,6 +1,7 @@
 package api
 
 import (
+	"fmt"
 	"net/http"
 	"path"
 	"strconv"
@@ -77,16 +78,13 @@ func TestOrderPurchase(t *testing.T) {
 		t.Fatal("Can't get orders:", resp.Status)
 	}
 
-	purchase := OrderPurchaseRequest{
-		OrderID: orders[0].ID,
-		Purchase: []db.OrderPurchase{
-			{
-				ProductCode: testProduct.Code,
-				Amount:      3,
-			},
+	purchase := []db.OrderPurchase{
+		{
+			ProductCode: testProduct.Code,
+			Amount:      3,
 		},
 	}
-	resp = tapi.do("POST", "/order/purchase", purchase, nil)
+	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
 	if resp.StatusCode != http.StatusCreated {
 		t.Fatal("Can't create order:", resp.Status)
 	}
@@ -176,16 +174,13 @@ func TestOrderDeactivation(t *testing.T) {
 		t.Fatal("Didn't find my new order")
 	}
 
-	purchase := OrderPurchaseRequest{
-		OrderID: orders[0].ID,
-		Purchase: []db.OrderPurchase{
-			{
-				ProductCode: testProduct.Code,
-				Amount:      3,
-			},
+	purchase := []db.OrderPurchase{
+		{
+			ProductCode: testProduct.Code,
+			Amount:      3,
 		},
 	}
-	resp = tapi.doAdmin("POST", "/order/purchase", purchase, nil)
+	resp = tapi.doAdmin("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
 	if resp.StatusCode != http.StatusCreated {
 		t.Fatal("Can't create order:", resp.Status)
 	}
@@ -263,16 +258,13 @@ func TestGetOrder(t *testing.T) {
 		t.Error("Wrong name:", body.Order.Name)
 	}
 
-	purchase := OrderPurchaseRequest{
-		OrderID: orders[0].ID,
-		Purchase: []db.OrderPurchase{
-			{
-				ProductCode: testProduct.Code,
-				Amount:      3,
-			},
+	purchase := []db.OrderPurchase{
+		{
+			ProductCode: testProduct.Code,
+			Amount:      3,
 		},
 	}
-	resp = tapi.do("POST", "/order/purchase", purchase, nil)
+	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
 	if resp.StatusCode != http.StatusCreated {
 		t.Fatal("Can't create order:", resp.Status)
 	}
@@ -289,6 +281,66 @@ func TestGetOrder(t *testing.T) {
 	}
 }
 
+func TestUpdateOrderPurchase(t *testing.T) {
+	tapi := newTestAPI(t)
+	defer tapi.close()
+	tapi.addTestMember()
+	tapi.addTestOrder()
+
+	var orders []db.Order
+	resp := tapi.do("GET", "/order/active", nil, &orders)
+	if resp.StatusCode != http.StatusOK {
+		t.Fatal("Can't get orders:", resp.Status)
+	}
+
+	purchase := []db.OrderPurchase{
+		{
+			ProductCode: testProduct.Code,
+			Amount:      3,
+		},
+	}
+	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
+	if resp.StatusCode != http.StatusCreated {
+		t.Fatal("Can't create order:", resp.Status)
+	}
+
+	purchase[0].Amount = 2
+	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
+	if resp.StatusCode != http.StatusCreated {
+		t.Fatal("Can't create order:", resp.Status)
+	}
+
+	var transactions []db.Transaction
+	resp = tapi.do("GET", "/transaction/mine", nil, &transactions)
+	if resp.StatusCode != http.StatusOK {
+		t.Fatal("Can't get transactions:", resp.Status)
+	}
+	if len(transactions) != 1 {
+		t.Fatal("Wrong number of transactions", len(orders), orders)
+	}
+	total := 2 * testProduct.Price
+	if transactions[0].Total != -total {
+		t.Fatal("Wrong total", transactions[0].Total)
+	}
+
+	resp = tapi.do("GET", "/order/active", nil, &orders)
+	if resp.StatusCode != http.StatusOK {
+		t.Fatal("Can't get orders:", resp.Status)
+	}
+	if len(orders[0].Transactions[0].OrderPurchase) != 1 {
+		t.Fatal("Wrong number of product purchases:", orders[0].Transactions[0].OrderPurchase)
+	}
+
+	var member db.Member
+	resp = tapi.do("GET", "/member/me", nil, &member)
+	if resp.StatusCode != http.StatusOK {
+		t.Error("Can't find the member:", resp.Status)
+	}
+	if member.Balance != testMember.Balance-total {
+		t.Error("Wrong product balance:", member.Balance)
+	}
+}
+
 func (tapi *testAPI) addTestOrder() {
 	resp := tapi.do("POST", "/order", testOrder, nil)
 	if resp.StatusCode != http.StatusCreated {
diff --git a/src/order/PurchaseOrder.js b/src/order/PurchaseOrder.js
index 3adb7ae707c26100c56b37338f401591c43adda2..0f0ccef5e55187bd1b85479ac3bc9e44a516f4ce 100644
--- a/src/order/PurchaseOrder.js
+++ b/src/order/PurchaseOrder.js
@@ -49,12 +49,9 @@ class PurchaseOrder extends React.Component {
         amount: parseInt(p.amount),
       };
     });
-    const body = JSON.stringify({
-      order: this.props.order.ID,
-      purchase,
-    });
+    const body = JSON.stringify(purchase);
     console.log(body);
-    fetch("/api/order/purchase", {
+    fetch("/api/order/" + this.props.order.ID + "purchase", {
       headers: { "x-authentication": this.context.token },
       method: "POST",
       body,