koprogo_api/infrastructure/web/handlers/
charge_distribution_handlers.rs1use crate::infrastructure::web::handlers::conformity_response::try_build_conformity_response;
2use crate::infrastructure::web::middleware::scope_guard::verify_expense_org_access;
3use crate::infrastructure::web::{AppState, AuthenticatedUser};
4use actix_web::{get, post, web, HttpResponse, Responder, ResponseError};
5use uuid::Uuid;
6
7#[post("/invoices/{expense_id}/calculate-distribution")]
11pub async fn calculate_and_save_distribution(
12 state: web::Data<AppState>,
13 user: AuthenticatedUser,
14 expense_id: web::Path<Uuid>,
15) -> impl Responder {
16 if user.role != "accountant" && user.role != "syndic" && !user.is_superadmin() {
18 return HttpResponse::Forbidden().json(serde_json::json!({
19 "error": "Only accountant, syndic, or superadmin can calculate charge distributions"
20 }));
21 }
22
23 match state
24 .charge_distribution_use_cases
25 .calculate_and_save_distribution(*expense_id)
26 .await
27 {
28 Ok(distributions) => HttpResponse::Ok().json(serde_json::json!({
29 "message": "Charge distribution calculated successfully",
30 "count": distributions.len(),
31 "distributions": distributions
32 })),
33 Err(err) => {
34 if let Some(resp) = try_build_conformity_response(&err) {
36 return resp;
37 }
38 HttpResponse::BadRequest().json(serde_json::json!({
39 "error": err
40 }))
41 }
42 }
43}
44
45#[get("/invoices/{expense_id}/distribution")]
47pub async fn get_distribution_by_expense(
48 state: web::Data<AppState>,
49 user: AuthenticatedUser,
50 expense_id: web::Path<Uuid>,
51) -> impl Responder {
52 if let Err(err) = verify_expense_org_access(
56 &user,
57 *expense_id,
58 &state.expense_use_cases,
59 &state.building_use_cases,
60 &state.acp_use_cases,
61 )
62 .await
63 {
64 return err.error_response();
65 }
66
67 match state
68 .charge_distribution_use_cases
69 .get_distribution_by_expense(*expense_id)
70 .await
71 {
72 Ok(distributions) => HttpResponse::Ok().json(distributions),
73 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
74 "error": err
75 })),
76 }
77}
78
79#[get("/owners/{owner_id}/distributions")]
81pub async fn get_distributions_by_owner(
82 state: web::Data<AppState>,
83 owner_id: web::Path<Uuid>,
84 user: AuthenticatedUser,
85) -> impl Responder {
86 if let Err(err) = crate::infrastructure::web::middleware::scope_guard::verify_owner_org_access(
90 &user,
91 *owner_id,
92 &state.owner_use_cases,
93 )
94 .await
95 {
96 return err.error_response();
97 }
98
99 match state
100 .charge_distribution_use_cases
101 .get_distributions_by_owner(*owner_id)
102 .await
103 {
104 Ok(distributions) => HttpResponse::Ok().json(distributions),
105 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
106 "error": err
107 })),
108 }
109}
110
111#[get("/owners/{owner_id}/total-due")]
113pub async fn get_total_due_by_owner(
114 state: web::Data<AppState>,
115 owner_id: web::Path<Uuid>,
116 user: AuthenticatedUser,
117) -> impl Responder {
118 if let Err(err) = crate::infrastructure::web::middleware::scope_guard::verify_owner_org_access(
122 &user,
123 *owner_id,
124 &state.owner_use_cases,
125 )
126 .await
127 {
128 return err.error_response();
129 }
130
131 match state
132 .charge_distribution_use_cases
133 .get_total_due_by_owner(*owner_id)
134 .await
135 {
136 Ok(total_due) => HttpResponse::Ok().json(serde_json::json!({
137 "owner_id": owner_id.to_string(),
138 "total_due": total_due
139 })),
140 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
141 "error": err
142 })),
143 }
144}