feat: add membership basic support

This commit is contained in:
Matthieu Bessat 2023-11-09 09:14:14 +01:00
parent 7a84f7d3c0
commit bbdbbbfb8a
4 changed files with 272 additions and 17 deletions

View file

@ -1,9 +1,30 @@
use url::Url;
use serde::{Serialize, Deserialize};
use anyhow::{Context, Result, anyhow};
use url::Url;
use chrono::prelude::{NaiveDate, DateTime, Utc};
use strum::{Display };
use strum::Display;
use serde::{Serialize, Deserialize};
use std::collections::HashSet;
use rand::{thread_rng, Rng};
use phonenumber;
/// ID
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash)]
pub struct Id(pub u64);
impl Id {
pub fn to_string(&self) -> String {
format!("{:x}", self.0)
}
}
impl Into<String> for Id {
fn into(self) -> String {
format!("{:x}", self.0)
}
}
pub fn generate_id() -> Id {
Id(thread_rng().gen())
}
/// permanent config to store long-term config
/// used to ingest env settings
@ -321,7 +342,7 @@ struct Organization {
slug: String
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
enum MembershipMode {
#[serde(rename = "Individuel")]
Individual,
@ -410,8 +431,9 @@ fn get_paheko_membership_from_ha_answers() {
/// for now we include the custom fields into the paheko user
/// we don't have time to implement user settings to change the custom fields mapping
/// for now, manual mapping
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
struct PahekoUser {
id: Id,
first_name: String,
last_name: String,
email: String,
@ -425,12 +447,12 @@ struct PahekoUser {
birthday: Option<NaiveDate> // we will need to validate some data before
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
struct PahekoMembership {
author: PahekoUser,
linked_users: Vec<PahekoUser>,
id: Id,
users: Vec<Id>,
campaign: String,
mode: String,
mode: MembershipMode,
inception_datum: DateTime<Utc>
}
@ -484,6 +506,21 @@ fn read_custom_field(form_answer: &FormAnswer, custom_field: HelloAssoCustomFiel
.and_then(|cf| Some(cf.answer.clone()))
}
fn parse_normalize_phone(phone_number_opt: Option<String>) -> Option<String> {
let number_raw = phone_number_opt?;
let parsed = match phonenumber::parse(Some(phonenumber::country::Id::FR), number_raw) {
Ok(r) => {
r
},
Err(_e) => {
return None;
}
};
Some(parsed.to_string())
}
async fn launch_adapter() -> Result<()> {
dotenvy::dotenv()?;
@ -509,9 +546,13 @@ async fn launch_adapter() -> Result<()> {
// dbg!(&answers);
println!("Got {} answers to the membership form. Processing...", &answers.len());
// first, request the current list of membership in paheko that were created with helloasso
// get the list of payments associated
// first step: output a list of PahekoUser with PahekoMembership
let pk_memberships: Vec<PahekoMembership> = vec![];
let mut pk_users: Vec<PahekoUser> = vec![];
let mut pk_memberships: Vec<PahekoMembership> = vec![];
let mut count: u64 = 0;
let mut names: HashSet<String> = HashSet::new();
@ -523,25 +564,65 @@ async fn launch_adapter() -> Result<()> {
names.insert(custom_field.name.clone());
count += 1;
}
pk_users.push(PahekoUser {
let paheko_user = PahekoUser {
id: generate_id(),
first_name: answer.user.first_name.clone(),
last_name: answer.user.last_name.clone(),
email: answer.user.email.clone(),
phone: read_custom_field(&answer, HelloAssoCustomFieldType::Phone),
phone: parse_normalize_phone(read_custom_field(&answer, HelloAssoCustomFieldType::Phone)),
skills: read_custom_field(&answer, HelloAssoCustomFieldType::Skills),
address: read_custom_field(&answer, HelloAssoCustomFieldType::Address).expect("to have address"),
postal_code: read_custom_field(&answer, HelloAssoCustomFieldType::PostalCode).expect("to have postal code"),
city: read_custom_field(&answer, HelloAssoCustomFieldType::City).expect("to have city"),
job: read_custom_field(&answer, HelloAssoCustomFieldType::Job),
birthday: None
});
};
let mut pk_membership = PahekoMembership {
id: generate_id(),
campaign: "".to_string(),
inception_datum: Utc::now(),
mode: answer.mode.clone(),
users: vec![paheko_user.id.clone()]
};
dbg!(&pk_membership.users);
// then create optional linked user
if answer.mode == MembershipMode::Couple {
let mut second_pk_user = paheko_user.clone();
second_pk_user.id = generate_id();
match read_custom_field(&answer, HelloAssoCustomFieldType::LinkedUserFirstName) {
Some(name) => {
second_pk_user.first_name = name
},
None => {
second_pk_user.first_name = "Conjoint".to_string();
eprintln!("Got a user with Couple mode but no additional name given!")
}
}
pk_membership.users.push(second_pk_user.id.clone());
pk_users.push(second_pk_user);
}
pk_users.push(paheko_user);
pk_memberships.push(pk_membership);
}
dbg!(pk_users);
dbg!(names);
dbg!(count);
dbg!(&pk_users);
dbg!(&pk_memberships);
dbg!(&pk_users.len());
dbg!(&pk_memberships.len());
// println!("{:?}", &pk_users.iter().map(|user| format!("{:?}", user.email)).collect::<Vec<String>>());
for u in pk_users {
println!("{} {}", u.email, u.phone.unwrap_or("".to_string()));
}
// then, request the current list of users
// match with the email address
// we consider the email address as the id for a helloasso user
// then, upload the PahekoMembership
Ok(())