listing.rs (5758B)
1 use radroots_core::{ 2 RadrootsCoreDecimal, RadrootsCoreDiscount, RadrootsCoreMoney, RadrootsCoreQuantity, 3 RadrootsCoreQuantityPrice, RadrootsCoreUnit, 4 }; 5 6 use crate::farm::RadrootsFarmRef; 7 use crate::ids::{RadrootsDTag, RadrootsInventoryBinId}; 8 use crate::plot::RadrootsPlotRef; 9 use crate::resource_area::RadrootsResourceAreaRef; 10 11 #[cfg(not(feature = "std"))] 12 use alloc::{string::String, vec::Vec}; 13 14 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 15 #[cfg_attr( 16 feature = "serde", 17 serde(rename_all = "snake_case", tag = "kind", content = "amount") 18 )] 19 #[derive(Clone, Debug)] 20 pub enum RadrootsListingAvailability { 21 Window { 22 start: Option<u64>, 23 end: Option<u64>, 24 }, 25 Status { 26 status: RadrootsListingStatus, 27 }, 28 } 29 30 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 31 #[cfg_attr( 32 feature = "serde", 33 serde(rename_all = "snake_case", tag = "kind", content = "amount") 34 )] 35 #[derive(Clone, Debug)] 36 pub enum RadrootsListingStatus { 37 Active, 38 Sold, 39 Other { value: String }, 40 } 41 42 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 43 #[cfg_attr( 44 feature = "serde", 45 serde(rename_all = "snake_case", tag = "kind", content = "amount") 46 )] 47 #[derive(Clone, Debug)] 48 pub enum RadrootsListingDeliveryMethod { 49 Pickup, 50 LocalDelivery, 51 Shipping, 52 Other { method: String }, 53 } 54 55 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 56 #[derive(Clone, Debug)] 57 pub struct RadrootsListing { 58 pub d_tag: RadrootsDTag, 59 #[cfg_attr( 60 feature = "serde", 61 serde(default, skip_serializing_if = "Option::is_none") 62 )] 63 pub published_at: Option<u64>, 64 #[cfg_attr(feature = "serde", serde(default))] 65 pub farm: RadrootsFarmRef, 66 pub product: RadrootsListingProduct, 67 pub primary_bin_id: RadrootsInventoryBinId, 68 pub bins: Vec<RadrootsListingBin>, 69 pub resource_area: Option<RadrootsResourceAreaRef>, 70 pub plot: Option<RadrootsPlotRef>, 71 pub discounts: Option<Vec<RadrootsCoreDiscount>>, 72 pub inventory_available: Option<RadrootsCoreDecimal>, 73 pub availability: Option<RadrootsListingAvailability>, 74 pub delivery_method: Option<RadrootsListingDeliveryMethod>, 75 pub location: Option<RadrootsListingLocation>, 76 pub images: Option<Vec<RadrootsListingImage>>, 77 } 78 79 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 80 #[derive(Clone, Debug)] 81 pub struct RadrootsListingProduct { 82 pub key: String, 83 pub title: String, 84 pub category: String, 85 pub summary: Option<String>, 86 pub process: Option<String>, 87 pub lot: Option<String>, 88 pub location: Option<String>, 89 pub profile: Option<String>, 90 pub year: Option<String>, 91 } 92 93 pub const RADROOTS_LISTING_PRODUCT_TAG_KEYS: [&str; 9] = [ 94 "key", "title", "category", "summary", "process", "lot", "location", "profile", "year", 95 ]; 96 97 pub struct RadrootsListingProductTagKeys; 98 99 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 100 #[derive(Clone, Debug)] 101 pub struct RadrootsListingBin { 102 pub bin_id: RadrootsInventoryBinId, 103 pub quantity: RadrootsCoreQuantity, 104 pub price_per_canonical_unit: RadrootsCoreQuantityPrice, 105 pub display_amount: Option<RadrootsCoreDecimal>, 106 pub display_unit: Option<RadrootsCoreUnit>, 107 pub display_label: Option<String>, 108 pub display_price: Option<RadrootsCoreMoney>, 109 pub display_price_unit: Option<RadrootsCoreUnit>, 110 } 111 112 #[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))] 113 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 114 #[derive(Clone, Debug)] 115 pub struct RadrootsListingLocation { 116 pub primary: String, 117 pub city: Option<String>, 118 pub region: Option<String>, 119 pub country: Option<String>, 120 pub lat: Option<f64>, 121 pub lng: Option<f64>, 122 pub geohash: Option<String>, 123 } 124 125 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 126 #[derive(Clone, Debug)] 127 pub struct RadrootsListingImage { 128 pub url: String, 129 pub size: Option<RadrootsListingImageSize>, 130 } 131 132 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 133 #[derive(Clone, Debug)] 134 pub struct RadrootsListingImageSize { 135 pub w: u32, 136 pub h: u32, 137 } 138 139 #[cfg(all(test, feature = "std"))] 140 mod tests { 141 use crate::farm::RadrootsFarmRef; 142 143 #[test] 144 fn defaults_listing_farm_ref_to_empty_values() { 145 let farm_ref = RadrootsFarmRef::default(); 146 assert!(farm_ref.pubkey.is_empty()); 147 assert!(farm_ref.d_tag.is_empty()); 148 } 149 150 #[test] 151 fn listing_model_covers_published_draft_metadata() { 152 use crate::kinds::{KIND_LISTING_DRAFT, is_listing_kind}; 153 154 let listing = super::RadrootsListing { 155 d_tag: "listing-draft".parse().unwrap(), 156 published_at: Some(1_700_000_000), 157 farm: RadrootsFarmRef::default(), 158 product: super::RadrootsListingProduct { 159 key: "lettuce".to_string(), 160 title: "lettuce".to_string(), 161 category: "produce".to_string(), 162 summary: None, 163 process: None, 164 lot: None, 165 location: None, 166 profile: None, 167 year: None, 168 }, 169 primary_bin_id: "bin-1".parse().unwrap(), 170 bins: vec![], 171 resource_area: None, 172 plot: None, 173 discounts: None, 174 inventory_available: None, 175 availability: None, 176 delivery_method: None, 177 location: None, 178 images: None, 179 }; 180 181 assert_eq!(listing.published_at, Some(1_700_000_000)); 182 assert!(is_listing_kind(KIND_LISTING_DRAFT)); 183 } 184 }