about summary refs log tree commit diff stats
path: root/crates/rocie-server/src/api/set/auth/product.rs
blob: c043739e1ce59406163c2303a3b6bb6f06a93543 (plain) (blame)
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
// rocie - An enterprise grocery management system
//
// Copyright (C) 2026 Benedikt Peetz <benedikt.peetz@b-peetz.de>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This file is part of Rocie.
//
// You should have received a copy of the License along with this program.
// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.

use actix_identity::Identity;
use actix_web::{HttpResponse, Responder, Result, post, web};
use serde::Deserialize;
use utoipa::ToSchema;

use crate::{
    app::App,
    storage::sql::{
        barcode::Barcode,
        insert::Operations,
        product::{Product, ProductId, ProductIdStub},
        product_parent::ProductParentId,
        unit::Unit,
        unit_property::UnitPropertyId,
    },
};

#[derive(Deserialize, ToSchema)]
struct ProductStub {
    /// The name of the product
    name: String,

    /// The Unit Property to use for this product.
    unit_property: UnitPropertyId,

    /// A description.
    #[schema(nullable = false)]
    description: Option<String>,

    /// A parent of this product, otherwise the parent will be the root of the parent tree.
    #[schema(nullable = false)]
    parent: Option<ProductParentId>,
}

/// Register a product
#[utoipa::path(
    responses(
        (
            status = 200,
            description = "Product successfully registered in database",
            body = ProductId,
        ),
        (
            status = UNAUTHORIZED,
            description = "You did not login before calling this endpoint",
        ),
        (
            status = INTERNAL_SERVER_ERROR,
            description = "Server encountered error",
            body = String,
        )
    ),
    request_body = ProductStub,
)]
#[post("/product/new")]
pub(crate) async fn register_product(
    app: web::Data<App>,
    product_stub: web::Json<ProductStub>,
    _user: Identity,
) -> Result<impl Responder> {
    let product_stub = product_stub.into_inner();
    let mut ops = Operations::new("register product");

    let product = Product::register(
        product_stub.name,
        product_stub.description,
        product_stub.parent,
        product_stub.unit_property,
        &mut ops,
    );

    ops.apply(&app).await?;

    Ok(HttpResponse::Ok().json(product.id))
}

/// Associate a barcode with a product
#[utoipa::path(
    responses(
        (
            status = OK,
            description = "Barcode successfully associated with product",
        ),
        (
            status = NOT_FOUND,
            description = "Product id not found in database",
        ),
        (
            status = UNAUTHORIZED,
            description = "You did not login before calling this endpoint",
        ),
        (
            status = BAD_REQUEST,
            description = "Unit used in request has not been registered yet",
            body = String,
        ),
        (
            status = INTERNAL_SERVER_ERROR,
            description = "Server encountered error",
            body = String,
        )
    ),
    params (
        (
            "id" = ProductId,
            description = "The id of the product to associated the barcode with"
        ),
    ),
    request_body = Barcode,
)]
#[post("/product/{id}/associate")]
pub(crate) async fn associate_barcode(
    app: web::Data<App>,
    id: web::Path<ProductIdStub>,
    barcode: web::Json<Barcode>,
    _user: Identity,
) -> Result<impl Responder> {
    let mut ops = Operations::new("associated barcode with product");

    {
        let units = Unit::get_all(&app).await?;
        if !units.into_iter().any(|unit| unit.id == barcode.amount.unit) {
            return Ok(HttpResponse::BadRequest()
                .body("The used unit has not been registered; it cannot be used.\n"));
        }
    }

    match Product::from_id(&app, id.into_inner().into()).await? {
        Some(product) => {
            product.associate_barcode(barcode.into_inner(), &mut ops);

            ops.apply(&app).await?;

            Ok(HttpResponse::Ok().finish())
        }
        None => Ok(HttpResponse::NotFound().finish()),
    }
}