diff --git a/api/api.go b/api/api.go
index d0c23184dcc49065edcfbd0d2c44caf1fb839aac..4b597098e410b609ba46fb0ca2e378849473739b 100644
--- a/api/api.go
+++ b/api/api.go
@@ -67,8 +67,12 @@ func Init(dbPath string, signKey string, mail *Mail, r *mux.Router) error {
 	r.HandleFunc("/order/{id:[0-9]+}", a.authNum(a.GetOrder)).Methods("GET")
 	r.HandleFunc("/order/{id:[0-9]+}", a.authNumRole(a.UpdateOrder)).Methods("PUT")
 	r.HandleFunc("/order/{id:[0-9]+}", a.authNumRole(a.DeleteOrder)).Methods("DELETE")
+	r.HandleFunc("/order/{id:[0-9]+}/arrive", a.authNumRole(a.ArrivedOrder)).Methods("PUT")
+	r.HandleFunc("/order/{id:[0-9]+}/collected", a.authNum(a.CollectOrder)).Methods("PUT")
 	r.HandleFunc("/order/active", a.auth(a.ListActiveOrders)).Methods("GET")
 	r.HandleFunc("/order/picks", a.authOrderNum(a.ListOrderPicks)).Methods("GET")
+	r.HandleFunc("/order/unarrived", a.authNum(a.ListOrderUnarrived)).Methods("GET")
+	r.HandleFunc("/order/collectable", a.authNum(a.ListOrderCollectable)).Methods("GET")
 	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 252856c1c7be56050ea1750d418803a1f1b4bab3..99a7f73c1c61f67f90f20cbb6307958ff97b7328 100644
--- a/api/db/order.go
+++ b/api/db/order.go
@@ -9,14 +9,19 @@ import (
 	"gorm.io/gorm/clause"
 )
 
+const (
+	updateOrderDuration = 5 * 24 * time.Hour
+)
+
 type Order struct {
 	gorm.Model
-	Name        string    `json:"name"`
-	Description string    `json:"description"`
-	MemberNum   int       `json:"member_num" gorm:"column:member"`
-	Member      *Member   `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
-	Deadline    time.Time `json:"deadline"`
-	Active      bool      `json:"active" gorm:"index"`
+	Name        string     `json:"name"`
+	Description string     `json:"description"`
+	MemberNum   int        `json:"member_num" gorm:"column:member"`
+	Member      *Member    `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
+	Deadline    time.Time  `json:"deadline"`
+	Active      bool       `json:"active" gorm:"index"`
+	Arrived     *time.Time `json:"arrived,omitempty"`
 
 	Products      []OrderProduct `json:"products"`
 	Transactions  []Transaction  `json:"transactions" gorm:"foreignKey:OrderID"`
@@ -60,6 +65,29 @@ func (d *DB) ListOrderPicks(num int) (orders []Order, err error) {
 	return
 }
 
+func (d *DB) ListOrderUnarrived(memberNum int) (orders []Order, err error) {
+	err = d.db.Preload(clause.Associations).
+		Preload("Transactions.OrderPurchase").
+		Where("member = ?", memberNum).
+		Where("deadline >= ?", time.Now().Add(-updateOrderDuration)).
+		Where("active is false").
+		Where("arrived is null").
+		Find(&orders).Error
+	return
+}
+
+func (d *DB) ListOrderCollectable(memberNum int) (transactions []Transaction, err error) {
+	err = d.db.Preload("OrderPurchase.OrderProduct.Product").
+		Preload("Order").
+		Joins("left join orders on transactions.order_id = orders.id").
+		Where("transactions.member = ?", memberNum).
+		Where("collected is null or collected = false").
+		Where("orders.Arrived is not null").
+		Find(&transactions).
+		Error
+	return
+}
+
 func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transaction, err error) {
 	err = d.db.Preload(clause.Associations).
 		Preload("Products.Product").
@@ -96,7 +124,7 @@ func (d *DB) UpdateOrder(memberNum int, id int, order *Order) error {
 	if memberNum != 0 && dbOrder.MemberNum != memberNum {
 		return ErrorInvalidRequest
 	}
-	if dbOrder.Deadline.Add(5 * 24 * time.Hour).Before(time.Now()) {
+	if dbOrder.Deadline.Add(updateOrderDuration).Before(time.Now()) {
 		return ErrorInvalidRequest
 	}
 	for _, p := range order.Products {
@@ -193,6 +221,7 @@ func updateOrderTransaction(tx *gorm.DB, id int, total int, order *Order) error
 			return err
 		}
 		order.Active = true
+		order.Arrived = nil
 		order.TransactionID = nil
 	} else {
 		totalDiff := total - transaction.Total
@@ -434,3 +463,35 @@ func (d *DB) DeactivateOrders() []Order {
 	}
 	return deactivatedOrders
 }
+
+func (d *DB) ArrivedOrder(memberNum int, id int) error {
+	dbOrder, _, err := d.GetOrder(0, id)
+	if err != nil {
+		return err
+	}
+
+	if memberNum != 0 && dbOrder.MemberNum != memberNum {
+		return ErrorInvalidRequest
+	}
+	if dbOrder.Deadline.Add(updateOrderDuration).Before(time.Now()) {
+		return ErrorInvalidRequest
+	}
+	if dbOrder.Active {
+		return ErrorInvalidRequest
+	}
+
+	return d.db.Model(&Order{}).Where("id = ?", id).Update("arrived", time.Now()).Error
+}
+
+func (d *DB) CollectOrder(memberNum int, id int) error {
+	dbOrder, t, err := d.GetOrder(memberNum, id)
+	if err != nil {
+		return err
+	}
+
+	if dbOrder.Active || dbOrder.Arrived == nil {
+		return ErrorInvalidRequest
+	}
+
+	return d.db.Model(&Transaction{}).Where("id = ?", t.ID).Update("collected", true).Error
+}
diff --git a/api/db/transaction.go b/api/db/transaction.go
index e888c499d57cdd0ceb1c3283e0b233a54337d537..9bc49ed1bb7cf808a3cd071aa51d034165cdac2f 100644
--- a/api/db/transaction.go
+++ b/api/db/transaction.go
@@ -32,6 +32,7 @@ type Transaction struct {
 	Order         *Order          `json:"order,omitempty" gorm:"constraint:OnDelete:CASCADE"`
 	OrderID       *uint           `json:"-"`
 	Refund        *Order          `json:"refund,omitempty" gorm:"foreignKey:TransactionID"`
+	Collected     *bool           `json:"collected,omitempty"`
 }
 
 type Topup struct {
diff --git a/api/order.go b/api/order.go
index 259aa476c89c5afdba901a22f2a99b3dbdac9e7d..d6d80ec57a9b1a90643082560c409bc2880aeead 100644
--- a/api/order.go
+++ b/api/order.go
@@ -73,6 +73,40 @@ func (a *api) ListOrderPicks(num int, w http.ResponseWriter, req *http.Request)
 	}
 }
 
+func (a *api) ListOrderUnarrived(num int, w http.ResponseWriter, req *http.Request) {
+	orders, err := a.db.ListOrderUnarrived(num)
+	if err != nil {
+		log.Printf("Can't list unarrived orders: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(http.StatusOK)
+	err = json.NewEncoder(w).Encode(orders)
+	if err != nil {
+		log.Printf("Can't encode unarrived orders: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+	}
+}
+
+func (a *api) ListOrderCollectable(num int, w http.ResponseWriter, req *http.Request) {
+	transactions, err := a.db.ListOrderCollectable(num)
+	if err != nil {
+		log.Printf("Can't list collectable orders: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(http.StatusOK)
+	err = json.NewEncoder(w).Encode(transactions)
+	if err != nil {
+		log.Printf("Can't encode collectable orders: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+	}
+}
+
 func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) {
 	vars := mux.Vars(req)
 	id, _ := strconv.Atoi(vars["id"])
@@ -230,3 +264,50 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
 		w.WriteHeader(http.StatusInternalServerError)
 	}
 }
+
+func (a *api) ArrivedOrder(num int, role string, w http.ResponseWriter, req *http.Request) {
+	vars := mux.Vars(req)
+	id, _ := strconv.Atoi(vars["id"])
+	if role == "admin" {
+		num = 0
+	}
+
+	err := a.db.ArrivedOrder(num, id)
+	if err != nil {
+		if errors.Is(err, db.ErrorNotFound) {
+			w.WriteHeader(http.StatusNotFound)
+			return
+		}
+		if errors.Is(err, db.ErrorInvalidRequest) {
+			w.WriteHeader(http.StatusUnauthorized)
+			return
+		}
+		log.Printf("Can't arrive order %s: %v", vars["id"], err)
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	w.WriteHeader(http.StatusAccepted)
+}
+
+func (a *api) CollectOrder(num int, w http.ResponseWriter, req *http.Request) {
+	vars := mux.Vars(req)
+	id, _ := strconv.Atoi(vars["id"])
+
+	err := a.db.CollectOrder(num, id)
+	if err != nil {
+		if errors.Is(err, db.ErrorNotFound) {
+			w.WriteHeader(http.StatusNotFound)
+			return
+		}
+		if errors.Is(err, db.ErrorInvalidRequest) {
+			w.WriteHeader(http.StatusUnauthorized)
+			return
+		}
+		log.Printf("Can't collect order %s: %v", vars["id"], err)
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	w.WriteHeader(http.StatusAccepted)
+}
diff --git a/src/order/OrderCards.js b/src/order/OrderCards.js
index 3e38060438435fc03fa3f5bb4e0f16ebdc967c54..64bdfb9b3e8d5818865b712e6a8cf2b55c9ff8fd 100644
--- a/src/order/OrderCards.js
+++ b/src/order/OrderCards.js
@@ -1,25 +1,104 @@
 import React, { useState } from "react";
 import { Card, Row, Col, Button } from "react-bootstrap";
 import { LinkContainer } from "react-router-bootstrap";
+import Sender from "../Sender";
 import Fetcher from "../Fetcher";
 
 function OrderCards() {
-  const [orders, setOrders] = useState([]);
-  const order_list = orders.map((o) => (
-    <Card key={o.ID} as={Col} sm={4}>
+  const [unarrived, setUnarrived] = useState([]);
+  const [collectable, setCollectable] = useState([]);
+  const [active, setActive] = useState([]);
+  const [refetch, setRefetch] = useState(0);
+
+  const unarrived_list = unarrived.map((o) => (
+    <Card bg="dark" text="white" key={o.ID} as={Col} sm={4}>
       <Card.Body>
-        <Card.Title>{o.name}</Card.Title>
-        <Card.Text>{o.description}</Card.Text>
         <LinkContainer to={"/order/" + o.ID}>
-          <Button>Realizar pedido</Button>
+          <div>
+            <Card.Title>{o.name}</Card.Title>
+            <Card.Text>{o.description}</Card.Text>
+          </div>
         </LinkContainer>
+        <Sender
+          url={"/api/order/" + o.ID + "/arrive"}
+          method="PUT"
+          onSuccess={() => setRefetch(refetch + 1)}
+        >
+          <Button type="submit" variant="light">
+            Informar llegada
+          </Button>
+        </Sender>
       </Card.Body>
     </Card>
   ));
+
+  const collectable_list = collectable.map((t) => {
+    const purchase_list = t.order_purchase.map((o) => {
+      if (o.amount === 0) {
+        return "";
+      }
+      return (
+        <div key={o.order_product.code}>
+          {o.order_product.product.name}: {o.amount}
+          <br />
+        </div>
+      );
+    });
+    return (
+      <Card bg="secondary" text="white" key={"T-" + t.ID} as={Col} sm={4}>
+        <Card.Body>
+          <LinkContainer to={"/order/" + t.order.ID}>
+            <div>
+              <Card.Title>{t.order.name}</Card.Title>
+              <Card.Text>{purchase_list}</Card.Text>
+            </div>
+          </LinkContainer>
+          <Sender
+            url={"/api/order/" + t.order.ID + "/collected"}
+            method="PUT"
+            onSuccess={() => setRefetch(refetch + 1)}
+          >
+            <Button type="submit" variant="light">
+              Recogido
+            </Button>
+          </Sender>
+        </Card.Body>
+      </Card>
+    );
+  });
+
+  const active_list = active.map((o) => (
+    <LinkContainer to={"/order/" + o.ID}>
+      <Card bg="info" text="white" key={o.ID} as={Col} sm={4}>
+        <Card.Body>
+          <Card.Title>{o.name}</Card.Title>
+          <Card.Text>{o.description}</Card.Text>
+          <Button variant="light">Realizar pedido</Button>
+        </Card.Body>
+      </Card>
+    </LinkContainer>
+  ));
+
   return (
-    <Fetcher url={"/api/order/active"} onFetch={setOrders}>
-      <Row>{order_list}</Row>
-    </Fetcher>
+    <Row>
+      <Fetcher
+        url={"/api/order/unarrived"}
+        onFetch={setUnarrived}
+        refetch={refetch}
+      >
+        {unarrived_list}
+      </Fetcher>
+      <Fetcher
+        url={"/api/order/collectable"}
+        onFetch={setCollectable}
+        refetch={refetch}
+      >
+        {collectable_list}
+      </Fetcher>
+      <Fetcher url={"/api/order/active"} onFetch={setActive}>
+        {active_list}
+      </Fetcher>
+    </Row>
   );
 }
 
diff --git a/src/order/ShowOrder.js b/src/order/ShowOrder.js
index 5d26ecddc84ab05d44088eaa4e2bcecdd78bb77e..2bf78a8ae80d7e042628f6356285cdfdc8b2582b 100644
--- a/src/order/ShowOrder.js
+++ b/src/order/ShowOrder.js
@@ -13,6 +13,7 @@ import {
   Modal,
 } from "react-bootstrap";
 import PurchaseOrder from "./PurchaseOrder";
+import Sender from "../Sender";
 import { printDate } from "../util";
 import AuthContext from "../AuthContext";
 import { printMoney, url } from "../util";
@@ -68,6 +69,7 @@ function ShowOrderResults(props) {
     return (
       <li key={t.member.num}>
         {t.member.name} ({t.member.num}):
+        {t.collected && <Badge variant="success">Recogido</Badge>}
         <ul>{list}</ul>
       </li>
     );
@@ -173,29 +175,66 @@ class ShowOrder extends React.Component {
     const { id } = this.props.match.params;
 
     let update_button;
+    let collect_button;
     if (this.state.isLoading) {
       update_button = <Spinner animation="border" />;
     } else {
       let deadline_week = new Date(order.deadline);
       deadline_week.setDate(deadline_week.getDate() + 7);
-      if (
-        (order.member_num === parseInt(this.context.num) ||
-          this.context.role === "admin") &&
-        deadline_week > Date.now()
-      ) {
-        update_button = (
-          <ButtonGroup>
-            <LinkContainer to={"/order/edit/" + id}>
-              <Button variant="info">Modificar</Button>
-            </LinkContainer>
-            <Button
-              variant="danger"
-              onClick={() => this.setState({ showDelete: true })}
+      if (deadline_week > Date.now()) {
+        if (order.arrived && !this.state.transaction.collected) {
+          collect_button = (
+            <Sender
+              url={"/api/order/" + id + "/collected"}
+              method="PUT"
+              onSuccess={() =>
+                this.setState({ refetch: this.state.refetch + 1 })
+              }
             >
-              Cancelar
-            </Button>
-          </ButtonGroup>
-        );
+              <Button type="submit" variant="secondary">
+                Recogido
+              </Button>
+            </Sender>
+          );
+        }
+        if (
+          order.member_num === parseInt(this.context.num) ||
+          this.context.role === "admin"
+        ) {
+          let arrived_button;
+          if (!order.active && !order.arrived) {
+            arrived_button = (
+              <Sender
+                url={"/api/order/" + id + "/arrive"}
+                method="PUT"
+                onSuccess={() =>
+                  this.setState({ refetch: this.state.refetch + 1 })
+                }
+              >
+                <Button type="submit" variant="dark">
+                  Informar llegada
+                </Button>
+              </Sender>
+            );
+          }
+          update_button = (
+            <div>
+              <ButtonGroup>
+                <LinkContainer to={"/order/edit/" + id}>
+                  <Button variant="info">Modificar</Button>
+                </LinkContainer>
+                <Button
+                  variant="danger"
+                  onClick={() => this.setState({ showDelete: true })}
+                >
+                  Cancelar
+                </Button>
+              </ButtonGroup>
+              <br />
+              {arrived_button}
+            </div>
+          );
+        }
       }
     }
 
@@ -223,6 +262,7 @@ class ShowOrder extends React.Component {
               {expired}
             </p>
             {update_button}
+            {collect_button}
           </Col>
         </Row>
         <p>{this.state.order.description}</p>