1use chrono::NaiveDateTime;
2use serde::{Deserialize, Serialize};
3
4use crate::api_client::MsEntity;
5
6use super::{
7 assortment::{Barcode, BuyPrice, MinPrice, SalePrice},
8 characteristic::Characteristic,
9 deserialize_option_date_from_str,
10 product::{CreateSalePrice, Pack},
11 Meta, MetaWrapper,
12};
13#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub struct Variant {
74 pub account_id: uuid::Uuid,
75 pub archived: bool,
76 pub barcodes: Option<Vec<Barcode>>,
77 pub buy_price: Option<BuyPrice>,
78 pub characteristics: Vec<Characteristic>,
79 pub code: Option<String>,
80 pub description: Option<String>,
81 pub discount_prohibited: bool,
82 pub external_code: String,
83 pub id: uuid::Uuid,
84 pub images: Option<MetaWrapper>,
85 pub meta: Meta,
86 pub min_price: Option<MinPrice>,
87 pub name: String,
88 pub packs: Option<Vec<Pack>>,
89 pub product: MetaWrapper,
90 pub sale_prices: Vec<SalePrice>,
91 pub things: Option<Vec<String>>,
92 #[serde(deserialize_with = "deserialize_option_date_from_str")]
93 pub updated: Option<NaiveDateTime>,
94}
95impl Variant {
96 pub fn create(product: Meta, characteristics: Vec<Characteristic>) -> CreateVariantBuilder {
97 CreateVariantBuilder {
98 product: MetaWrapper { meta: product },
99 characteristics,
100 ..Default::default()
101 }
102 }
103 pub fn update() -> UpdateVariantBuilder {
104 UpdateVariantBuilder::default()
105 }
106}
107impl MsEntity for Variant {
108 fn url() -> String {
109 String::from("https://api.moysklad.ru/api/remap/1.2/entity/variant")
110 }
111}
112#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct CreateVariant {
115 #[serde(skip_serializing_if = "Option::is_none")]
116 barcodes: Option<Vec<Barcode>>,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 buy_price: Option<BuyPrice>,
119 characteristics: Vec<Characteristic>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 code: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 description: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 discount_prohibited: Option<bool>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 external_code: Option<String>,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 images: Option<MetaWrapper>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 min_price: Option<MinPrice>,
132 name: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 packs: Option<Vec<Pack>>,
135 product: MetaWrapper,
136 sale_prices: Option<Vec<CreateSalePrice>>,
137}
138#[derive(Default)]
139pub struct CreateVariantBuilder {
140 barcodes: Option<Vec<Barcode>>,
141 buy_price: Option<BuyPrice>,
142 characteristics: Vec<Characteristic>,
143 code: Option<String>,
144 description: Option<String>,
145 discount_prohibited: Option<bool>,
146 external_code: Option<String>,
147 images: Option<MetaWrapper>,
148 min_price: Option<MinPrice>,
149 name: Option<String>,
150 packs: Option<Vec<Pack>>,
151 product: MetaWrapper,
152 sale_prices: Option<Vec<CreateSalePrice>>,
153}
154impl CreateVariantBuilder {
155 pub fn barcode<T>(&mut self, barcode: T) -> &mut Self
156 where
157 T: ToString,
158 {
159 self.barcodes.get_or_insert(vec![]).push(Barcode {
160 ean13: barcode.to_string(),
161 });
162 self
163 }
164 pub fn buy_price(&mut self, value: f64, currency: Meta) -> &mut Self {
165 let _ = self.buy_price.insert(BuyPrice {
166 value,
167 currency: MetaWrapper { meta: currency },
168 });
169 self
170 }
171 pub fn characteristic(&mut self, char: Characteristic) -> &mut Self {
172 self.characteristics.push(char);
173 self
174 }
175 pub fn code<T>(&mut self, code: T) -> &mut Self
176 where
177 T: ToString,
178 {
179 let _ = self.code.insert(code.to_string());
180 self
181 }
182 pub fn description<T>(&mut self, description: T) -> &mut Self
183 where
184 T: ToString,
185 {
186 let _ = self.description.insert(description.to_string());
187 self
188 }
189 pub fn discount_prohibited(&mut self, discount_prohibited: bool) -> &mut Self {
190 let _ = self.discount_prohibited.insert(discount_prohibited);
191 self
192 }
193 pub fn external_code<T>(&mut self, external_code: T) -> &mut Self
194 where
195 T: ToString,
196 {
197 let _ = self.external_code.insert(external_code.to_string());
198 self
199 }
200 pub fn min_price(&mut self, value: f64, currency: Meta) -> &mut Self {
201 let _ = self.min_price.insert(MinPrice {
202 value,
203 currency: MetaWrapper { meta: currency },
204 });
205 self
206 }
207 pub fn name<T>(&mut self, name: T) -> &mut Self
208 where
209 T: ToString,
210 {
211 let _ = self.name.insert(name.to_string());
212 self
213 }
214 pub fn sale_price(
215 &mut self,
216 value: f64,
217 currency_meta: &Meta,
218 price_type_meta: &Meta,
219 ) -> &mut Self {
220 self.sale_prices
221 .get_or_insert(vec![])
222 .push(CreateSalePrice {
223 value,
224 currency: MetaWrapper {
225 meta: currency_meta.to_owned(),
226 },
227 price_type: MetaWrapper {
228 meta: price_type_meta.to_owned(),
229 },
230 });
231 self
232 }
233 pub fn build(&self) -> CreateVariant {
234 CreateVariant {
235 barcodes: self.barcodes.to_owned(),
236 buy_price: self.buy_price.to_owned(),
237 characteristics: self.characteristics.to_owned(),
238 code: self.code.to_owned(),
239 description: self.description.to_owned(),
240 discount_prohibited: self.discount_prohibited,
241 external_code: self.external_code.to_owned(),
242 images: self.images.to_owned(),
243 min_price: self.min_price.to_owned(),
244 name: self.name.to_owned(),
245 packs: self.packs.to_owned(),
246 product: self.product.to_owned(),
247 sale_prices: self.sale_prices.to_owned(),
248 }
249 }
250}
251#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
252#[serde(rename_all = "camelCase")]
253pub struct UpdateVariant {
254 #[serde(skip_serializing_if = "Option::is_none")]
255 barcodes: Option<Vec<Barcode>>,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 buy_price: Option<BuyPrice>,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 characteristics: Option<Vec<Characteristic>>,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 code: Option<String>,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 description: Option<String>,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 discount_prohibited: Option<bool>,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 external_code: Option<String>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 id: Option<uuid::Uuid>,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 images: Option<MetaWrapper>,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 meta: Option<Meta>,
274 #[serde(skip_serializing_if = "Option::is_none")]
275 min_price: Option<MinPrice>,
276 #[serde(skip_serializing_if = "Option::is_none")]
277 name: Option<String>,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 packs: Option<Vec<Pack>>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 product: Option<MetaWrapper>,
282 #[serde(skip_serializing_if = "Option::is_none")]
283 sale_prices: Option<Vec<CreateSalePrice>>,
284}
285#[derive(Default)]
286pub struct UpdateVariantBuilder {
287 barcodes: Option<Vec<Barcode>>,
288 buy_price: Option<BuyPrice>,
289 characteristics: Option<Vec<Characteristic>>,
290 code: Option<String>,
291 description: Option<String>,
292 discount_prohibited: Option<bool>,
293 external_code: Option<String>,
294 id: Option<uuid::Uuid>,
295 images: Option<MetaWrapper>,
296 meta: Option<Meta>,
297 min_price: Option<MinPrice>,
298 name: Option<String>,
299 packs: Option<Vec<Pack>>,
300 product: Option<MetaWrapper>,
301 sale_prices: Option<Vec<CreateSalePrice>>,
302}
303impl UpdateVariantBuilder {
304 pub fn barcode<T>(&mut self, barcode: T) -> &mut Self
305 where
306 T: ToString,
307 {
308 self.barcodes.get_or_insert(vec![]).push(Barcode {
309 ean13: barcode.to_string(),
310 });
311 self
312 }
313 pub fn buy_price(&mut self, value: f64, currency: Meta) -> &mut Self {
314 let _ = self.buy_price.insert(BuyPrice {
315 value,
316 currency: MetaWrapper { meta: currency },
317 });
318 self
319 }
320 pub fn characteristic(&mut self, char: Characteristic) -> &mut Self {
321 self.characteristics.get_or_insert(vec![]).push(char);
322 self
323 }
324 pub fn code<T>(&mut self, code: T) -> &mut Self
325 where
326 T: ToString,
327 {
328 let _ = self.code.insert(code.to_string());
329 self
330 }
331 pub fn description<T>(&mut self, description: T) -> &mut Self
332 where
333 T: ToString,
334 {
335 let _ = self.description.insert(description.to_string());
336 self
337 }
338 pub fn discount_prohibited(&mut self, discount_prohibited: bool) -> &mut Self {
339 let _ = self.discount_prohibited.insert(discount_prohibited);
340 self
341 }
342 pub fn external_code<T>(&mut self, external_code: T) -> &mut Self
343 where
344 T: ToString,
345 {
346 let _ = self.external_code.insert(external_code.to_string());
347 self
348 }
349 pub fn id(&mut self, id: uuid::Uuid) -> &mut Self {
350 let _ = self.id.insert(id);
351 self
352 }
353 pub fn meta(&mut self, meta: Meta) -> &mut Self {
354 let _ = self.meta.insert(meta);
355 self
356 }
357 pub fn min_price(&mut self, value: f64, currency: Meta) -> &mut Self {
358 let _ = self.min_price.insert(MinPrice {
359 value,
360 currency: MetaWrapper { meta: currency },
361 });
362 self
363 }
364 pub fn name<T>(&mut self, name: T) -> &mut Self
365 where
366 T: ToString,
367 {
368 let _ = self.name.insert(name.to_string());
369 self
370 }
371 pub fn product(&mut self, product_meta: Meta) -> &mut Self {
372 let _ = self.product.insert(MetaWrapper { meta: product_meta });
373 self
374 }
375 pub fn sale_price(
376 &mut self,
377 value: f64,
378 currency_meta: &Meta,
379 price_type_meta: &Meta,
380 ) -> &mut Self {
381 self.sale_prices
382 .get_or_insert(vec![])
383 .push(CreateSalePrice {
384 value,
385 currency: MetaWrapper {
386 meta: currency_meta.to_owned(),
387 },
388 price_type: MetaWrapper {
389 meta: price_type_meta.to_owned(),
390 },
391 });
392 self
393 }
394 pub fn build(&self) -> UpdateVariant {
395 UpdateVariant {
396 barcodes: self.barcodes.to_owned(),
397 buy_price: self.buy_price.to_owned(),
398 characteristics: self.characteristics.to_owned(),
399 code: self.code.to_owned(),
400 description: self.description.to_owned(),
401 discount_prohibited: self.discount_prohibited,
402 external_code: self.external_code.to_owned(),
403 images: self.images.to_owned(),
404 min_price: self.min_price.to_owned(),
405 name: self.name.to_owned(),
406 packs: self.packs.to_owned(),
407 product: self.product.to_owned(),
408 sale_prices: self.sale_prices.to_owned(),
409 id: self.id,
410 meta: self.meta.to_owned(),
411 }
412 }
413}