1use chrono::{DateTime, FixedOffset, NaiveDate};
2use rust_decimal::Decimal;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7 auth::User,
8 entity_ref::{ExternalId, ExternalIdEntity},
9 helpers::slugify,
10 organizations::Organization,
11 EntityRefPathParam, Error, Id, Ref, RefTarget, Slug, SlugEntity, Style, StyleSummary,
12};
13use samling_clorinde::{
14 client::GenericClient,
15 queries::{price::get_price_id, pricelist::get_pricelist_id},
16};
17
18#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
20pub struct PriceList {
21 pub id: Id<Self>,
22 pub slug: Slug<Self>,
23 pub external_id: Option<ExternalId<Self>>,
24 pub name: String,
25 pub created_by: Option<Id<User>>,
26 pub created_at: DateTime<FixedOffset>,
27 pub updated_at: DateTime<FixedOffset>,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
32pub struct PriceListSummary {
33 pub id: Id<PriceList>,
34 pub slug: Slug<PriceList>,
35 pub external_id: Option<ExternalId<PriceList>>,
36 pub name: String,
37}
38
39impl EntityRefPathParam for PriceList {
40 fn parameter_name() -> &'static str {
41 "price_list_ref"
42 }
43}
44
45impl RefTarget for PriceList {
46 async fn lookup_id(
47 client: &impl GenericClient,
48 organization_id: Id<Organization>,
49 entity_ref: &crate::entity_ref::Ref<Self>,
50 ) -> crate::Result<Option<Id<Self>>> {
51 let (id, external_id, slug) = entity_ref.to_owned().take_all_inner();
52 Ok(get_pricelist_id()
53 .bind(
54 client,
55 &organization_id.into(),
56 &id,
57 &external_id.as_deref(),
58 &slug,
59 )
60 .opt()
61 .await?
62 .map(|id| id.into()))
63 }
64}
65
66#[derive(Debug, Clone, Deserialize)]
68pub struct CreatePriceList {
69 pub name: String,
70 pub slug: Option<Slug<PriceList>>,
71 pub external_id: Option<ExternalId<PriceList>>,
72}
73
74impl ExternalIdEntity for CreatePriceList {
75 type RefTarget = PriceList;
76
77 fn external_id(&self) -> Option<ExternalId<Self::RefTarget>> {
78 self.external_id.clone()
79 }
80
81 fn set_external_id(&mut self, value: ExternalId<Self::RefTarget>) {
82 self.external_id = Some(value);
83 }
84}
85
86impl SlugEntity for CreatePriceList {
87 type RefTarget = PriceList;
88 fn generate_slug(&self, prefix: &str) -> Option<Slug<Self::RefTarget>> {
89 Some(Slug::new(slugify(&[prefix, &self.name])))
90 }
91
92 fn slug(&self) -> Option<Slug<Self::RefTarget>> {
93 self.slug.clone()
94 }
95
96 fn set_slug(&mut self, value: Slug<Self::RefTarget>) {
97 self.slug = Some(value);
98 }
99}
100
101#[derive(Debug, Clone, Deserialize)]
103pub struct UpdatePriceList {
104 pub name: Option<String>,
105 pub slug: Option<Slug<PriceList>>,
106 pub external_id: Option<ExternalId<PriceList>>,
107}
108
109impl From<CreatePriceList> for UpdatePriceList {
110 fn from(pricelist: CreatePriceList) -> Self {
111 UpdatePriceList {
112 name: Some(pricelist.name),
113 slug: pricelist.slug,
114 external_id: pricelist.external_id,
115 }
116 }
117}
118
119impl SlugEntity for UpdatePriceList {
120 type RefTarget = PriceList;
121 fn slug(&self) -> Option<Slug<Self::RefTarget>> {
122 self.slug.clone()
123 }
124
125 fn set_slug(&mut self, value: Slug<Self::RefTarget>) {
126 self.slug = Some(value);
127 }
128}
129
130impl ExternalIdEntity for UpdatePriceList {
131 type RefTarget = PriceList;
132
133 fn external_id(&self) -> Option<ExternalId<Self::RefTarget>> {
134 self.external_id.clone()
135 }
136
137 fn set_external_id(&mut self, value: ExternalId<Self::RefTarget>) {
138 self.external_id = Some(value);
139 }
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
144pub struct Price {
145 pub id: Id<Self>,
146 pub r#type: PriceType,
147 pub uom: Option<String>,
148 pub currency: String,
149 #[serde(serialize_with = "rust_decimal::serde::float::serialize")]
150 pub amount: Decimal,
151 pub start: NaiveDate,
152 pub end: NaiveDate,
153 pub external_id: Option<ExternalId<Self>>,
154 pub created_by: Option<Id<User>>,
155 pub style: StyleSummary,
156 pub list: PriceListSummary,
157 pub created_at: DateTime<FixedOffset>,
158 pub updated_at: DateTime<FixedOffset>,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
163pub struct NestedPrice {
164 pub id: Id<Price>,
165 #[serde(serialize_with = "rust_decimal::serde::float::serialize")]
166 pub amount: Decimal,
167 pub start: NaiveDate,
168 pub end: NaiveDate,
169 pub r#type: PriceType,
170 pub uom: Option<String>,
171 pub currency: String,
172 pub list: PriceListSummary,
173}
174impl NestedPrice {
175 pub(crate) fn is_unit_price(&self) -> bool {
176 self.r#type == PriceType::Unit
177 }
178 pub(crate) fn is_retail_price(&self) -> bool {
179 self.r#type == PriceType::Retail
180 }
181}
182
183impl EntityRefPathParam for Price {
184 fn parameter_name() -> &'static str {
185 "price_ref"
186 }
187}
188
189impl RefTarget for Price {
190 async fn lookup_id(
191 client: &impl GenericClient,
192 organization_id: Id<Organization>,
193 entity_ref: &crate::entity_ref::Ref<Self>,
194 ) -> crate::Result<Option<Id<Self>>> {
195 let (id, external_id, slug) = entity_ref.to_owned().take_all_inner();
196 if slug.is_some() {
197 Err(Error::SlugReferenceUnsupported(Self::short_type_name()))
198 } else {
199 Ok(get_price_id()
200 .bind(
201 client,
202 &organization_id.into(),
203 &id,
204 &external_id.as_deref(),
205 )
206 .opt()
207 .await?
208 .map(|id| id.into()))
209 }
210 }
211}
212
213#[derive(Debug, Clone, Deserialize)]
215pub struct CreatePrice {
216 pub r#type: PriceType,
217 pub uom: Option<String>,
218 pub currency: String,
219 pub amount: Decimal,
220 pub start: NaiveDate,
221 pub end: NaiveDate,
222 pub list: Ref<PriceList>,
223 pub style: Ref<Style>,
224 pub external_id: Option<ExternalId<Price>>,
225}
226
227impl ExternalIdEntity for CreatePrice {
228 type RefTarget = Price;
229
230 fn external_id(&self) -> Option<ExternalId<Self::RefTarget>> {
231 self.external_id.clone()
232 }
233
234 fn set_external_id(&mut self, value: ExternalId<Self::RefTarget>) {
235 self.external_id = Some(value);
236 }
237}
238
239#[derive(Debug, Clone, Deserialize)]
241pub struct UpdatePrice {
242 pub r#type: Option<PriceType>,
243 pub uom: Option<String>,
244 pub currency: Option<String>,
245 pub amount: Option<Decimal>,
246 pub start: Option<NaiveDate>,
247 pub end: Option<NaiveDate>,
248 pub style: Option<Ref<Style>>,
249 pub list: Option<Ref<PriceList>>,
250 pub external_id: Option<ExternalId<Price>>,
251}
252
253impl From<CreatePrice> for UpdatePrice {
254 fn from(price: CreatePrice) -> Self {
255 UpdatePrice {
256 r#type: Some(price.r#type),
257 uom: price.uom,
258 currency: Some(price.currency),
259 amount: Some(price.amount),
260 start: Some(price.start),
261 end: Some(price.end),
262 style: Some(price.style),
263 list: Some(price.list),
264 external_id: price.external_id,
265 }
266 }
267}
268
269impl ExternalIdEntity for UpdatePrice {
270 type RefTarget = Price;
271
272 fn external_id(&self) -> Option<ExternalId<Self::RefTarget>> {
273 self.external_id.clone()
274 }
275
276 fn set_external_id(&mut self, value: ExternalId<Self::RefTarget>) {
277 self.external_id = Some(value);
278 }
279}
280
281#[derive(
282 Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, JsonSchema,
283)]
284pub enum PriceType {
285 Unit,
286 Retail,
287}