wb_cache/test/simulation/scriptwriter/entity/
customer.rs

1use fieldx::fxstruct;
2use rand_distr::Distribution;
3use rand_distr::Gamma;
4use rand_distr::Poisson;
5
6use crate::test::simulation::db::entity::Customer as DbCustomer;
7use crate::test::simulation::types::simerr;
8use crate::test::simulation::types::Result;
9
10#[derive(Clone, Debug)]
11#[fxstruct(no_new, builder(post_build), get)]
12pub struct Customer {
13    #[fieldx(copy)]
14    pub id:            i32,
15    pub first_name:    String,
16    pub last_name:     String,
17    pub email:         String,
18    #[fieldx(copy, set, default(-1))]
19    pub registered_on: i32,
20
21    #[fieldx(copy)]
22    erratic_quotient: f64,
23    #[fieldx(copy)]
24    orders_per_day:   f64,
25
26    /// The Gamma for Negative Binomial distribution used to sample the number of items of this product sold to a single
27    /// customer per day.
28    #[fieldx(optional, builder(off), set(private), get("_nb_gamma", as_ref))]
29    nb_gamma: Gamma<f64>,
30}
31
32impl Customer {
33    fn post_build(mut self) -> Self {
34        let eq = self.erratic_quotient();
35        let shape = self.orders_per_day() / eq;
36        self.set_nb_gamma(Gamma::new(shape, eq).unwrap());
37
38        self
39    }
40
41    #[inline(always)]
42    pub fn nb_gamma(&self) -> &Gamma<f64> {
43        self._nb_gamma().unwrap()
44    }
45
46    pub fn daily_purchases(&self) -> Result<f64> {
47        let mut rng = &mut rand::rng();
48        let lambda = self.nb_gamma().sample(&mut rng);
49        if lambda == 0. {
50            return Ok(0.0);
51        }
52        Ok(Poisson::new(lambda)
53            .map_err(|err| {
54                let err = simerr!("Poisson(lambda={lambda}): {}", err);
55                err.context(format!(
56                    "Customer EQ: {}; orders per day: {}",
57                    self.erratic_quotient(),
58                    self.orders_per_day()
59                ));
60                err
61            })?
62            .sample(&mut rng) as f64)
63    }
64}
65
66impl From<Customer> for DbCustomer {
67    fn from(customer: Customer) -> Self {
68        DbCustomer {
69            id:            customer.id,
70            first_name:    customer.first_name,
71            last_name:     customer.last_name,
72            email:         customer.email,
73            registered_on: customer.registered_on,
74        }
75    }
76}