19 Commits

Author SHA1 Message Date
49a638d595 Merge pull request 'replace-main-with-fix' (#1136) from replace-main-with-fix into main
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
Reviewed-on: #1136
2025-10-02 00:32:24 +02:00
599eec0e43 Replace main content with fix-ci-finally
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-10-02 00:29:28 +02:00
433c914c4a fix ci
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-10-02 00:25:43 +02:00
0338351eef reduce npm warnings 2025-10-01 23:46:49 +02:00
e1803aea3e Merge pull request 'update deps, fix ci' (#1134) from no-ergo into main
Some checks failed
CI/CD Pipeline / test (push) Failing after 51m37s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
Reviewed-on: #1134
2025-10-01 22:41:40 +02:00
7f26710a40 fix ci?
Some checks failed
CI/CD Pipeline / test (push) Has started running
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-10-01 22:24:13 +02:00
9203c61541 fix ci?
Some checks failed
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
2025-10-01 22:07:21 +02:00
3a57a1334d update npm mods
Some checks failed
CI/CD Pipeline / test (push) Failing after 17m54s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
2025-10-01 21:44:24 +02:00
72c19d7a75 Merge pull request 'no ergo yet' (#1132) from no-ergo into main
Some checks failed
CI/CD Pipeline / test (push) Failing after 16m2s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
Reviewed-on: #1132
2025-10-01 20:25:08 +02:00
a44f8b445c no ergo yet
Some checks failed
CI/CD Pipeline / test (push) Failing after 25m9s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
2025-10-01 20:23:09 +02:00
5ec457fea7 Merge pull request 'log-frontend-test-logs' (#1119) from log-frontend-test-logs into main
Some checks failed
CI/CD Pipeline / test (push) Failing after 16m52s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
Reviewed-on: #1119
2025-07-24 11:51:49 +02:00
4fcd34cfa9 generate html report
Some checks failed
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
2025-07-24 11:23:39 +02:00
d64f6f61ba reduce useless compiler warnings 2025-07-24 11:23:32 +02:00
5934bbe666 Merge pull request 'get errors' (#1117) from log-frontend-test-logs into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 21m13s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Successful in 8m6s
Reviewed-on: #1117
2025-07-24 11:01:53 +02:00
b7cc01ff1c get errors
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-07-24 11:00:49 +02:00
e9a78db048 Merge pull request 'families only have to pay einschriebgebuehr once + half price applies' (#1115) from fix-family-fees into main
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
Reviewed-on: #1115
2025-07-24 08:55:43 +02:00
0996a81d52 families only have to pay einschriebgebuehr once + half price applies
Some checks failed
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-07-24 08:52:26 +02:00
25df7a935c Merge pull request '[BUGFIX] set max items in choices.js after searching' (#1113) from show-daniels into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 24m12s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Successful in 15m49s
Reviewed-on: #1113
2025-07-20 12:02:13 +02:00
Marie Birner
55c0647b55 [BUGFIX] set max items in choices.js after searching
Some checks failed
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-07-20 11:57:45 +02:00
8 changed files with 115 additions and 71 deletions

View File

@@ -25,15 +25,15 @@ jobs:
cargo build
cd frontend && npm install && npm run build
- name: Frontend tests
run: cd frontend && npx playwright install && npx playwright test --workers 1 --reporter line
run: cd frontend && npx playwright install && npx playwright test --workers 1 --reporter html,line
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: frontend/playwright-report/
retention-days: 30
- name: Backend tests
run: cargo test --verbose
#- uses: actions/upload-artifact@v3
# if: always()
# with:
# name: playwright-report
# path: frontend/playwright-report/
# retention-days: 30
deploy-staging:
runs-on: ubuntu-latest

View File

@@ -413,6 +413,7 @@ function initNewChoice(select: HTMLInputElement) {
steering_person.setAttribute("required", "required");
}
const choice = new Choices(select, {
searchResultLimit: 100,
searchFields: ["label", "value", "customProperties.searchableText"],
removeItemButton: true,
loadingText: "Wird geladen...",
@@ -424,8 +425,10 @@ function initNewChoice(select: HTMLInputElement) {
maxItemText: (maxItemCount) => {
return `Nur ${maxItemCount} Ruderer können hinzugefügt werden`;
},
callbackOnInit: function () {
this._currentState.items.forEach(function (obj) {
callbackOnInit: function (this: Choices) {
const items = this.getValue(); // Get all selected items
const itemsArray = Array.isArray(items) ? items : [items];
itemsArray.forEach((obj: any) => {
if (boat_in_ottensheim && obj.customProperties) {
if (obj.customProperties.is_racing) {
const coxSelect = <HTMLSelectElement>(

View File

@@ -9,20 +9,20 @@
"preview": "vite preview"
},
"devDependencies": {
"@playwright/test": "^1.40.1",
"@types/d3": "^7.4.1",
"@types/node": "^20.11.4",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.21",
"sass": "^1.60.0",
"tailwindcss": "^3.3.1",
"typescript": "^4.9.5",
"vite": "^4.2.0",
"vite-plugin-static-copy": "^0.13.1"
"@playwright/test": "^1.55.1",
"@types/d3": "^7.4.3",
"@types/node": "^24.6.1",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"sass": "^1.93.2",
"tailwindcss": "^3.4.18",
"typescript": "^5.9.3",
"vite": "^7.1.7",
"vite-plugin-static-copy": "^3.1.3"
},
"dependencies": {
"choices.js": "^10.2.0",
"d3": "^7.8.5",
"terser": "^5.21.0"
"choices.js": "^11.1.0",
"d3": "^7.9.0",
"terser": "^5.44.0"
}
}

6
package-lock.json generated Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "rowt",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@@ -8,7 +8,7 @@ use crate::model::{
notification::Notification,
role::Role,
};
use chrono::NaiveDate;
use chrono::{Datelike, Local, NaiveDate};
use rocket::{fs::TempFile, tokio::io::AsyncReadExt};
use sqlx::SqlitePool;
@@ -578,4 +578,32 @@ impl User {
Ok(())
}
pub(crate) async fn has_to_pay_einschreibgebuehr_this_year(&self, db: &SqlitePool) -> bool {
if !self.has_role(db, "schnupperant").await {
if let Some(member_since_date) = &self.member_since_date {
if let Ok(member_since_date) =
NaiveDate::parse_from_str(member_since_date, "%Y-%m-%d")
{
if member_since_date.year() == Local::now().year()
&& !self.has_role(db, "no-einschreibgebuehr").await
{
return true;
}
}
}
}
false
}
pub(crate) fn has_to_pay_only_half(&self) -> bool {
if let Some(member_since_date) = &self.member_since_date {
if let Ok(member_since_date) = NaiveDate::parse_from_str(member_since_date, "%Y-%m-%d")
{
let halfprice_startdate =
NaiveDate::from_ymd_opt(Local::now().year(), 7, 1).unwrap();
return member_since_date >= halfprice_startdate;
}
}
false
}
}

View File

@@ -1,10 +1,9 @@
use super::User;
use crate::{
BOAT_STORAGE, DUAL_MEMBERSHIP, EINSCHREIBGEBUEHR, FAMILY_THREE_OR_MORE, FAMILY_TWO, FOERDERND,
REGULAR, RENNRUDERBEITRAG, SCHECKBUCH, STUDENT_OR_PUPIL, TRIAL_ROWING, TRIAL_ROWING_REDUCED,
UNTERSTUETZEND, model::family::Family,
model::family::Family, BOAT_STORAGE, DUAL_MEMBERSHIP, EINSCHREIBGEBUEHR, FAMILY_THREE_OR_MORE,
FAMILY_TWO, FOERDERND, REGULAR, RENNRUDERBEITRAG, SCHECKBUCH, STUDENT_OR_PUPIL, TRIAL_ROWING,
TRIAL_ROWING_REDUCED, UNTERSTUETZEND,
};
use chrono::{Datelike, Local, NaiveDate};
use serde::Serialize;
use sqlx::SqlitePool;
@@ -81,30 +80,52 @@ impl User {
let mut fee = Fee::new();
if let Some(family) = Family::find_by_opt_id(db, self.family_id).await {
let mut einschreibgebuehr = false;
let mut half_price = true;
for member in family.members(db).await {
fee.add_person(&member);
if member.has_role(db, "paid").await {
fee.paid();
}
fee.merge(member.fee_without_families(db).await);
fee.merge(member.fee_without_families(db, true).await);
if member.has_to_pay_einschreibgebuehr_this_year(db).await {
einschreibgebuehr = true;
}
if !member.has_to_pay_only_half() {
half_price = false;
}
}
if family.amount_family_members(db).await > 2 {
fee.add("Familie 3+ Personen".into(), FAMILY_THREE_OR_MORE);
if half_price {
fee.add(
"Familie 3+ Personen (Halbpreis)".into(),
FAMILY_THREE_OR_MORE / 2,
);
} else {
fee.add("Familie 3+ Personen".into(), FAMILY_THREE_OR_MORE);
}
} else {
fee.add("Familie 2 Personen".into(), FAMILY_TWO);
if half_price {
fee.add("Familie 2 Personen (Halbpreis)".into(), FAMILY_TWO / 2);
} else {
fee.add("Familie 2 Personen".into(), FAMILY_TWO);
}
}
if einschreibgebuehr {
fee.add("Einschreibgebühr (Familie)".into(), EINSCHREIBGEBUEHR);
}
} else {
fee.add_person(self);
if self.has_role(db, "paid").await {
fee.paid();
}
fee.merge(self.fee_without_families(db).await);
fee.merge(self.fee_without_families(db, false).await);
}
Some(fee)
}
async fn fee_without_families(&self, db: &SqlitePool) -> Fee {
async fn fee_without_families(&self, db: &SqlitePool, entry_fee_paid_with_family: bool) -> Fee {
let mut fee = Fee::new();
if !self.has_role(db, "Donau Linz").await
@@ -125,38 +146,24 @@ impl User {
let amount_boats = self.amount_boats(db).await;
if amount_boats > 0 {
fee.add(
format!("{}x Bootsplatz", amount_boats),
amount_boats * BOAT_STORAGE,
);
}
if !self.has_role(db, "schnupperant").await {
if let Some(member_since_date) = &self.member_since_date {
if let Ok(member_since_date) =
NaiveDate::parse_from_str(member_since_date, "%Y-%m-%d")
{
if member_since_date.year() == Local::now().year()
&& !self.has_role(db, "no-einschreibgebuehr").await
{
fee.add("Einschreibgebühr".into(), EINSCHREIBGEBUEHR);
}
}
if self.has_to_pay_only_half() {
fee.add(
format!("{}x Bootsplatz (Halbpreis)", amount_boats),
amount_boats * BOAT_STORAGE / 2,
);
} else {
fee.add(
format!("{}x Bootsplatz", amount_boats),
amount_boats * BOAT_STORAGE,
);
}
}
let halfprice = if let Some(member_since_date) = &self.member_since_date {
match NaiveDate::parse_from_str(member_since_date, "%Y-%m-%d") {
Ok(member_since_date) => {
let halfprice_startdate =
NaiveDate::from_ymd_opt(Local::now().year(), 7, 1).unwrap();
member_since_date >= halfprice_startdate
}
Err(_) => false,
}
} else {
false
};
if self.has_to_pay_einschreibgebuehr_this_year(db).await && !entry_fee_paid_with_family {
fee.add("Einschreibgebühr".into(), EINSCHREIBGEBUEHR);
}
let halfprice = self.has_to_pay_only_half();
if self.has_role(db, "schnupperant").await {
if self.has_role(db, "Student").await || self.has_role(db, "Schüler").await {

View File

@@ -795,6 +795,7 @@ macro_rules! special_user {
}
impl $name {
#[allow(dead_code)]
pub fn into_inner(self) -> User {
self.user
}

View File

@@ -2,7 +2,7 @@ use std::{fs::OpenOptions, io::Write};
use chrono::{Datelike, Local};
use rocket::{
Build, Data, FromForm, Request, Rocket, State, catch, catchers,
catch, catchers,
fairing::{AdHoc, Fairing, Info, Kind},
form::Form,
fs::FileServer,
@@ -13,6 +13,7 @@ use rocket::{
response::{Flash, Redirect},
routes,
time::{Duration, OffsetDateTime},
Build, Data, FromForm, Request, Rocket, State,
};
use rocket_dyn_templates::Template;
use serde::Deserialize;
@@ -20,7 +21,6 @@ use sqlx::SqlitePool;
use tera::Context;
use crate::{
SCHECKBUCH,
model::{
logbook::Logbook,
notification::Notification,
@@ -28,6 +28,7 @@ use crate::{
role::Role,
user::{User, UserWithDetails},
},
SCHECKBUCH,
};
pub(crate) mod admin;
@@ -64,7 +65,7 @@ async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_
let date = chrono::Utc::now();
if date.month() <= 3 || date.month() >= 10 {
context.insert("show_quick_ergo_button", "yes");
// context.insert("show_quick_ergo_button", "yes");
}
context.insert("achievements", &Achievements::for_user(db, &user).await);
@@ -330,13 +331,11 @@ mod test {
assert_eq!(response.status(), Status::Ok);
assert!(
response
.into_string()
.await
.unwrap()
.contains("Ruderassistent")
);
assert!(response
.into_string()
.await
.unwrap()
.contains("Ruderassistent"));
}
#[sqlx::test]