backbone_accounting/presentation/http/
check_printing_handler.rs1use std::sync::Arc;
24
25use axum::{
26 extract::{Path, State},
27 http::StatusCode,
28 response::IntoResponse,
29 routing::{post, put},
30 Json, Router,
31};
32use rust_decimal::Decimal;
33use serde::{Deserialize, Serialize};
34use uuid::Uuid;
35
36use crate::application::service::check_printing_service::{
37 AllocationAck, CheckPrintingError, CheckPrintingService, PrintedCheckAck,
38 RecordCheck, RegisterSequence, SequenceAck,
39};
40
41#[derive(Debug, Deserialize)]
42pub struct RegisterSequenceBody {
43 pub bank_account_id: Uuid,
44 pub numbering_mode: String,
46 #[serde(default = "default_next")]
47 pub next_number: i64,
48}
49
50fn default_next() -> i64 {
51 1
52}
53
54#[derive(Debug, Deserialize)]
55pub struct AllocateBody {
56 pub bank_account_id: Uuid,
57 #[serde(default = "default_count")]
58 pub count: i64,
59}
60
61fn default_count() -> i64 {
62 1
63}
64
65#[derive(Debug, Deserialize)]
66pub struct RecordCheckBody {
67 pub bank_account_id: Uuid,
68 pub payment_id: Uuid,
69 #[serde(default)]
70 pub payment_number: Option<String>,
71 pub amount: Decimal,
72 #[serde(default)]
73 pub payee_name: Option<String>,
74 #[serde(default)]
76 pub check_number: Option<String>,
77 #[serde(default)]
78 pub actor: Option<Uuid>,
79}
80
81#[derive(Debug, Deserialize)]
82pub struct VoidBody {
83 #[serde(default)]
84 pub actor: Option<Uuid>,
85}
86
87#[derive(Debug, Serialize)]
88struct ErrorBody {
89 error: String,
90 message: String,
91}
92
93fn error_response(e: &CheckPrintingError) -> axum::response::Response {
94 let status = StatusCode::from_u16(e.http_status()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
95 (
96 status,
97 Json(ErrorBody {
98 error: e.code().to_string(),
99 message: e.to_string(),
100 }),
101 )
102 .into_response()
103}
104
105
106
107async fn register_sequence(
108 State(service): State<Arc<CheckPrintingService>>,
109 Json(body): Json<RegisterSequenceBody>,
110) -> impl IntoResponse {
111 let req = RegisterSequence {
112 bank_account_id: body.bank_account_id,
113 numbering_mode: body.numbering_mode,
114 next_number: body.next_number,
115 };
116 match service.register_sequence(req).await {
117 Ok(ack) => (StatusCode::OK, Json(SequenceAck {
118 sequence_id: ack.sequence_id,
119 bank_account_id: ack.bank_account_id,
120 numbering_mode: ack.numbering_mode,
121 next_number: ack.next_number,
122 }))
123 .into_response(),
124 Err(e) => error_response(&e),
125 }
126}
127
128async fn allocate(
129 State(service): State<Arc<CheckPrintingService>>,
130 Json(body): Json<AllocateBody>,
131) -> impl IntoResponse {
132 match service
133 .allocate_check_numbers(body.bank_account_id, body.count)
134 .await
135 {
136 Ok(ack) => (StatusCode::OK, Json(AllocationAck {
137 first: ack.first,
138 last: ack.last,
139 numbers: ack.numbers,
140 }))
141 .into_response(),
142 Err(e) => error_response(&e),
143 }
144}
145
146async fn record_check(
147 State(service): State<Arc<CheckPrintingService>>,
148 Json(body): Json<RecordCheckBody>,
149) -> impl IntoResponse {
150 let req = RecordCheck {
151 bank_account_id: body.bank_account_id,
152 payment_id: body.payment_id,
153 payment_number: body.payment_number,
154 amount: body.amount,
155 payee_name: body.payee_name,
156 check_number: body.check_number,
157 actor: body.actor,
158 };
159 match service.record_printed_check(req).await {
160 Ok(ack) => (StatusCode::CREATED, Json(PrintedCheckAck {
161 printed_check_id: ack.printed_check_id,
162 bank_account_id: ack.bank_account_id,
163 payment_id: ack.payment_id,
164 check_number: ack.check_number,
165 status: ack.status,
166 }))
167 .into_response(),
168 Err(e) => error_response(&e),
169 }
170}
171
172async fn void_check(
173 State(service): State<Arc<CheckPrintingService>>,
174 Path(printed_check_id): Path<Uuid>,
175 Json(body): Json<VoidBody>,
176) -> impl IntoResponse {
177 match service
178 .void_printed_check(printed_check_id, body.actor)
179 .await
180 {
181 Ok(ack) => (StatusCode::OK, Json(PrintedCheckAck {
182 printed_check_id: ack.printed_check_id,
183 bank_account_id: ack.bank_account_id,
184 payment_id: ack.payment_id,
185 check_number: ack.check_number,
186 status: ack.status,
187 }))
188 .into_response(),
189 Err(e) => error_response(&e),
190 }
191}
192
193pub fn create_check_printing_routes(service: Arc<CheckPrintingService>) -> Router {
196 Router::new()
197 .route("/accounting/checks/sequences", put(register_sequence))
198 .route("/accounting/checks/allocate", post(allocate))
199 .route("/accounting/checks", post(record_check))
200 .route("/accounting/checks/:id/void", post(void_check))
201 .with_state(service)
202}