1use reqwest::{Method, RequestBuilder};
2use serde::{Deserialize, Serialize};
3
4use crate::{ApiRequest, PixClient};
5
6pub struct CobEndpoint<'a> {
7 inner: &'a PixClient,
8}
9
10#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
11#[allow(non_camel_case_types)]
12pub enum CobrancaStatus {
13 ATIVA,
14 CONCLUIDA,
15 REMOVIDA_PELO_USUARIO_RECEBEDOR,
16 REMOVIDA_PELO_PSP,
17}
18
19#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub struct CobrancaImediata {
21 pub calendario: Calendario,
23 pub devedor: Devedor,
24 pub valor: Valor,
26
27 #[serde(rename = "chave")]
29 pub chave_pix_recebedor: String,
30
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub txid: Option<String>,
34
35 #[serde(rename = "loc")]
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub location: Option<Location>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub status: Option<String>,
41
42 #[serde(rename = "solicitacaoPagador")]
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub solicitacao_pagador: Option<String>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 #[serde(rename = "infoAdicionais")]
49 pub info_adicionais: Option<Vec<InfoAdicionais>>,
50}
51
52impl CobrancaImediata {
53 pub fn new(valor: f64, chave_pix_recebedor: String, devedor: Devedor) -> CobrancaImediata {
55 let valor = Valor::new(valor, false);
56
57 Self {
58 calendario: Default::default(),
59 devedor,
60 valor,
61 chave_pix_recebedor,
62 txid: None,
63 location: None,
64 status: None,
65 solicitacao_pagador: None,
66 info_adicionais: None,
67 }
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
72pub struct Calendario {
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub criacao: Option<String>,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub apresentacao: Option<String>,
77 pub expiracao: i64,
79}
80
81impl Default for Calendario {
82 fn default() -> Self {
83 Self {
84 criacao: None,
85 apresentacao: None,
86 expiracao: 3600,
87 }
88 }
89}
90
91#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
92pub struct Devedor {
93 #[serde(skip_serializing_if = "Option::is_none")]
94 cnpj: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 cpf: Option<String>,
97 nome: String,
98}
99
100impl Devedor {
101 pub fn new_pessoa_juridica(cnpj: String, nome: String) -> Self {
102 Self {
103 cnpj: Some(cnpj),
104 cpf: None,
105 nome,
106 }
107 }
108
109 pub fn new_pessoa_fisica(cpf: String, nome: String) -> Self {
110 Self {
111 cnpj: None,
112 cpf: Some(cpf),
113 nome,
114 }
115 }
116}
117
118#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct Valor {
120 pub original: String,
121 #[serde(rename = "modalidadeAlteracao")]
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub permite_alteracao: Option<i32>,
126}
127
128impl Valor {
129 pub fn new(valor_original: f64, permite_alteracao: bool) -> Valor {
131 let permite_alteracao = if permite_alteracao { Some(1) } else { None };
132 Self {
133 original: format!("{:.2}", valor_original),
134 permite_alteracao,
135 }
136 }
137}
138
139#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
140pub struct Location {
141 id: i64,
142 #[serde(rename = "location")]
143 pub url: String,
144 #[serde(rename = "tipoCob")]
145 tipo_cob: String,
146 criacao: String,
147}
148
149#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
150pub struct InfoAdicionais {
151 pub nome: String,
152 pub valor: String,
153}
154
155impl PixClient {
156 pub fn cob(&self) -> CobEndpoint {
157 CobEndpoint { inner: self }
158 }
159}
160
161impl<'a> CobEndpoint<'a> {
162 pub fn criar_cobranca_txid(&self, txid: String, payload: CobrancaImediata) -> ApiRequest<CobrancaImediata> {
163 let endpoint = format!("{}/cob/{}", &*self.inner.base_endpoint, txid);
164 self.inner.request_with_headers(Method::PUT, &*endpoint, payload)
165 }
166
167 pub fn consultar_cobranca_txid(&self, txid: String, payload: CobrancaImediata) -> ApiRequest<CobrancaImediata> {
168 let endpoint = format!("{}/cob/{}", &*self.inner.base_endpoint, txid);
169 self.inner.request_with_headers(Method::GET, &*endpoint, payload)
170 }
171 pub fn revisar_cobranca_txid(&self, txid: String, payload: CobrancaImediata) -> ApiRequest<CobrancaImediata> {
172 let endpoint = format!("{}/cob/{}", &*self.inner.base_endpoint, txid);
173 self.inner.request_with_headers(Method::POST, &*endpoint, payload)
174 }
175
176 pub fn criar_cobranca_imediata(&self, payload: CobrancaImediata) -> ApiRequest<CobrancaImediata> {
179 let endpoint = format!("{}/cob", &*self.inner.base_endpoint);
180 self.inner.request_with_headers(Method::POST, &*endpoint, payload)
181 }
182
183 pub fn consultar_cobrancas(&self) -> RequestBuilder {
184 let endpoint = format!("{}/cob", &*self.inner.base_endpoint);
185 self.inner.inner_client.request(Method::GET, &endpoint)
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn t_value() {
195 let new_value = Valor::new(512.614, false);
196 println!(": {:?}", new_value);
197
198 let new_integer_value = Valor::new(400f64, false);
199 println!(": {:?}", new_integer_value);
200 }
201}